Merge pull request #5984 from jtattermusch/perf_tests_script

Add python script for running performance tests
diff --git a/BUILD b/BUILD
index 7f8d8a42..fc4dfe8 100644
--- a/BUILD
+++ b/BUILD
@@ -41,67 +41,82 @@
 
 
 
+
 cc_library(
   name = "gpr",
   srcs = [
-    "src/core/profiling/timers.h",
-    "src/core/support/backoff.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/backoff.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",
@@ -130,20 +145,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",
   ],
   includes = [
     "include",
@@ -154,329 +155,323 @@
 )
 
 
+
 cc_library(
   name = "grpc",
   srcs = [
-    "src/core/census/grpc_filter.h",
-    "src/core/census/grpc_plugin.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/channel_stack_builder.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/compress_filter.h",
-    "src/core/channel/connected_channel.h",
-    "src/core/channel/context.h",
-    "src/core/channel/http_client_filter.h",
-    "src/core/channel/http_server_filter.h",
-    "src/core/channel/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/http/format_request.h",
-    "src/core/http/httpcli.h",
-    "src/core/http/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/unix_sockets_posix.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/channel_init.h",
-    "src/core/surface/channel_stack_type.h",
-    "src/core/surface/completion_queue.h",
-    "src/core/surface/event_string.h",
-    "src/core/surface/init.h",
-    "src/core/surface/lame_client.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/census/grpc_plugin.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/channel_stack_builder.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/compress_filter.c",
-    "src/core/channel/connected_channel.c",
-    "src/core/channel/http_client_filter.c",
-    "src/core/channel/http_server_filter.c",
-    "src/core/channel/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/http/format_request.c",
-    "src/core/http/httpcli.c",
-    "src/core/http/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/unix_sockets_posix.c",
-    "src/core/iomgr/unix_sockets_posix_noop.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_init.c",
-    "src/core/surface/channel_ping.c",
-    "src/core/surface/channel_stack_type.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/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/http/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/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/grpc_security.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/status.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/census.h",
+    "include/grpc/status.h",
   ],
   includes = [
     "include",
@@ -486,6 +481,7 @@
     "//external:libssl",
     "//external:zlib",
     ":gpr",
+    "//external:nanopb",
   ],
   copts = [
     "-std=gnu99",
@@ -493,6 +489,7 @@
 )
 
 
+
 cc_library(
   name = "grpc_codegen_lib",
   srcs = [
@@ -503,21 +500,21 @@
     "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",
-    "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",
   ],
   includes = [
     "include",
@@ -529,294 +526,288 @@
 )
 
 
+
 cc_library(
   name = "grpc_unsecure",
   srcs = [
-    "src/core/census/grpc_filter.h",
-    "src/core/census/grpc_plugin.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/channel_stack_builder.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/compress_filter.h",
-    "src/core/channel/connected_channel.h",
-    "src/core/channel/context.h",
-    "src/core/channel/http_client_filter.h",
-    "src/core/channel/http_server_filter.h",
-    "src/core/channel/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/http/format_request.h",
-    "src/core/http/httpcli.h",
-    "src/core/http/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/unix_sockets_posix.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/channel_init.h",
-    "src/core/surface/channel_stack_type.h",
-    "src/core/surface/completion_queue.h",
-    "src/core/surface/event_string.h",
-    "src/core/surface/init.h",
-    "src/core/surface/lame_client.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/census/grpc_plugin.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/channel_stack_builder.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/compress_filter.c",
-    "src/core/channel/connected_channel.c",
-    "src/core/channel/http_client_filter.c",
-    "src/core/channel/http_server_filter.c",
-    "src/core/channel/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/http/format_request.c",
-    "src/core/http/httpcli.c",
-    "src/core/http/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/unix_sockets_posix.c",
-    "src/core/iomgr/unix_sockets_posix_noop.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_init.c",
-    "src/core/surface/channel_ping.c",
-    "src/core/surface/channel_stack_type.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/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",
@@ -824,6 +815,7 @@
   ],
   deps = [
     ":gpr",
+    "//external:nanopb",
   ],
   copts = [
     "-std=gnu99",
@@ -831,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",
@@ -851,24 +844,18 @@
 )
 
 
+
 cc_library(
   name = "grpc++",
   srcs = [
+    "src/cpp/client/create_channel_internal.h",
     "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/cpp/client/create_channel_internal.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",
@@ -876,14 +863,21 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.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/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",
@@ -893,7 +887,6 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
-    "src/cpp/codegen/codegen_init.cc",
   ],
   hdrs = [
     "include/grpc++/alarm.h",
@@ -906,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",
@@ -940,37 +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/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",
   ],
   includes = [
     "include",
@@ -984,32 +977,13 @@
 )
 
 
+
 cc_library(
   name = "grpc++_codegen_lib",
   srcs = [
     "src/cpp/codegen/codegen_init.cc",
   ],
   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/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/async_stream.h",
     "include/grpc++/impl/codegen/async_unary_call.h",
     "include/grpc++/impl/codegen/call.h",
@@ -1041,16 +1015,38 @@
     "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 = [
@@ -1059,7 +1055,6 @@
     "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",
@@ -1067,9 +1062,11 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.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/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
@@ -1084,7 +1081,6 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
-    "src/cpp/codegen/codegen_init.cc",
   ],
   hdrs = [
     "include/grpc++/alarm.h",
@@ -1097,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",
@@ -1131,37 +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/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",
   ],
   includes = [
     "include",
@@ -1175,6 +1171,7 @@
 )
 
 
+
 cc_library(
   name = "grpc_plugin_support",
   srcs = [
@@ -1226,6 +1223,7 @@
 )
 
 
+
 cc_library(
   name = "grpc_csharp_ext",
   srcs = [
@@ -1245,55 +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/backoff.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",
@@ -1322,32 +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/backoff.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",
@@ -1358,329 +1357,323 @@
 )
 
 
+
 objc_library(
   name = "grpc_objc",
   srcs = [
-    "src/core/census/grpc_context.c",
-    "src/core/census/grpc_filter.c",
-    "src/core/census/grpc_plugin.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/channel_stack_builder.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/compress_filter.c",
-    "src/core/channel/connected_channel.c",
-    "src/core/channel/http_client_filter.c",
-    "src/core/channel/http_server_filter.c",
-    "src/core/channel/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/http/format_request.c",
-    "src/core/http/httpcli.c",
-    "src/core/http/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/unix_sockets_posix.c",
-    "src/core/iomgr/unix_sockets_posix_noop.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_init.c",
-    "src/core/surface/channel_ping.c",
-    "src/core/surface/channel_stack_type.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/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/http/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/grpc_security.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/status.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/census.h",
-    "src/core/census/grpc_filter.h",
-    "src/core/census/grpc_plugin.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/channel_stack_builder.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/compress_filter.h",
-    "src/core/channel/connected_channel.h",
-    "src/core/channel/context.h",
-    "src/core/channel/http_client_filter.h",
-    "src/core/channel/http_server_filter.h",
-    "src/core/channel/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/http/format_request.h",
-    "src/core/http/httpcli.h",
-    "src/core/http/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/unix_sockets_posix.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/channel_init.h",
-    "src/core/surface/channel_stack_type.h",
-    "src/core/surface/completion_queue.h",
-    "src/core/surface/event_string.h",
-    "src/core/surface/init.h",
-    "src/core/surface/lame_client.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",
+    "include/grpc/status.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",
@@ -1689,6 +1682,7 @@
   deps = [
     ":gpr_objc",
     "//external:libssl_objc",
+    "//external:nanopb",
   ],
   sdk_dylibs = ["libz"],
 )
diff --git a/Makefile b/Makefile
index 6c100f6..2286abe 100644
--- a/Makefile
+++ b/Makefile
@@ -95,6 +95,16 @@
 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)
@@ -109,7 +119,7 @@
 CXX_easan = clang++
 LD_easan = clang
 LDXX_easan = clang++
-CPPFLAGS_easan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+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
@@ -120,7 +130,7 @@
 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
+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
 
@@ -130,7 +140,7 @@
 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
+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
@@ -159,7 +169,7 @@
 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
 
@@ -177,7 +187,7 @@
 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
@@ -925,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_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
@@ -966,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
@@ -2268,52 +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/backoff.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 \
@@ -2342,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))))
 
@@ -2397,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))))
 
@@ -2419,185 +2434,185 @@
 
 
 LIBGRPC_SRC = \
-    src/core/census/grpc_context.c \
-    src/core/census/grpc_filter.c \
-    src/core/census/grpc_plugin.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/channel_stack_builder.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/compress_filter.c \
-    src/core/channel/connected_channel.c \
-    src/core/channel/http_client_filter.c \
-    src/core/channel/http_server_filter.c \
-    src/core/channel/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/http/format_request.c \
-    src/core/http/httpcli.c \
-    src/core/http/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/unix_sockets_posix.c \
-    src/core/iomgr/unix_sockets_posix_noop.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_init.c \
-    src/core/surface/channel_ping.c \
-    src/core/surface/channel_stack_type.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/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/http/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/grpc_security.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/status.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/census.h \
+    include/grpc/status.h \
 
 LIBGRPC_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_SRC))))
 
@@ -2659,21 +2674,21 @@
     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 \
-    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 \
 
 LIBGRPC_CODEGEN_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CODEGEN_LIB_SRC))))
 
@@ -2696,13 +2711,13 @@
 
 
 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 \
@@ -2780,147 +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/census/grpc_plugin.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/channel_stack_builder.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/compress_filter.c \
-    src/core/channel/connected_channel.c \
-    src/core/channel/http_client_filter.c \
-    src/core/channel/http_server_filter.c \
-    src/core/channel/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/http/format_request.c \
-    src/core/http/httpcli.c \
-    src/core/http/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/unix_sockets_posix.c \
-    src/core/iomgr/unix_sockets_posix_noop.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_init.c \
-    src/core/surface/channel_ping.c \
-    src/core/surface/channel_stack_type.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/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 \
@@ -2928,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))))
 
@@ -2977,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 \
@@ -3022,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))))
 
@@ -3060,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))))
 
@@ -3096,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 \
@@ -3109,14 +3120,21 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.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/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 \
@@ -3126,7 +3144,6 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
-    src/cpp/codegen/codegen_init.cc \
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/alarm.h \
@@ -3139,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 \
@@ -3173,37 +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/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 \
 
 LIBGRPC++_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
 
@@ -3272,26 +3289,6 @@
     src/cpp/codegen/codegen_init.cc \
 
 PUBLIC_HEADERS_CXX += \
-    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/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/async_stream.h \
     include/grpc++/impl/codegen/async_unary_call.h \
     include/grpc++/impl/codegen/call.h \
@@ -3323,6 +3320,26 @@
     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))))
 
@@ -3376,6 +3393,7 @@
 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))))
 
@@ -3422,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 \
@@ -3433,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))))
 
@@ -3476,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 \
@@ -3494,9 +3512,11 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.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/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
@@ -3511,7 +3531,6 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
-    src/cpp/codegen/codegen_init.cc \
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/alarm.h \
@@ -3524,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 \
@@ -3558,37 +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/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 \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -3697,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))))
 
@@ -3750,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))))
 
@@ -3800,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))))
 
@@ -3851,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))))
 
@@ -3898,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 \
@@ -3916,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))))
 
@@ -3959,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))))
 
@@ -4324,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))))
 
@@ -4352,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))))
 
@@ -4389,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))))
 
@@ -4426,6 +4454,7 @@
 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))))
 
@@ -4463,6 +4492,7 @@
 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))))
 
@@ -4500,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))))
 
@@ -4537,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))))
 
@@ -4574,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))))
 
@@ -4611,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))))
 
@@ -4648,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))))
 
@@ -4685,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))))
 
@@ -4722,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))))
 
@@ -4748,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))))
 
@@ -4785,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))))
 
@@ -4822,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))))
 
@@ -4859,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))))
 
@@ -4896,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))))
 
@@ -4922,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))))
 
@@ -4959,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))))
 
@@ -4985,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))))
 
@@ -5022,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))))
 
@@ -5059,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))))
 
@@ -5096,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))))
 
@@ -5133,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))))
 
@@ -5170,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))))
 
@@ -5196,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))))
 
@@ -5233,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))))
 
@@ -5259,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))))
 
@@ -5285,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))))
 
@@ -5322,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))))
 
@@ -5359,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))))
 
@@ -5396,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))))
 
@@ -5422,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))))
 
@@ -5459,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))))
 
@@ -5485,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))))
 
@@ -5511,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))))
 
@@ -5537,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))))
 
@@ -5563,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))))
 
@@ -5589,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))))
 
@@ -5640,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))))
 
@@ -5665,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))))
 
@@ -5703,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))))
 
@@ -5777,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))))
 
@@ -5850,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))))
 
@@ -7731,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 \
 
@@ -7795,6 +7896,38 @@
 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 \
 
@@ -7987,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 \
 
@@ -9043,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 \
 
@@ -13416,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/http/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/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 25aba87..534f4c1 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -2,8 +2,10 @@
 recursive-exclude src/python/grpcio/grpc/_cython *.so *.pyd
 graft src/python/grpcio/tests
 graft src/core
+graft src/boringssl
 graft include/grpc
 graft third_party/boringssl
+graft third_party/nanopb
 graft third_party/zlib
 include src/python/grpcio/commands.py
 include src/python/grpcio/grpc_version.py
diff --git a/binding.gyp b/binding.gyp
index 2ee383a..a1cdf2e 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -492,50 +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/backoff.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"', {
@@ -558,167 +558,167 @@
         'gpr',
       ],
       'sources': [
-        'src/core/census/grpc_context.c',
-        'src/core/census/grpc_filter.c',
-        'src/core/census/grpc_plugin.c',
-        'src/core/channel/channel_args.c',
-        'src/core/channel/channel_stack.c',
-        'src/core/channel/channel_stack_builder.c',
-        'src/core/channel/client_channel.c',
-        'src/core/channel/compress_filter.c',
-        'src/core/channel/connected_channel.c',
-        'src/core/channel/http_client_filter.c',
-        'src/core/channel/http_server_filter.c',
-        'src/core/channel/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/http/format_request.c',
-        'src/core/http/httpcli.c',
-        'src/core/http/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/unix_sockets_posix.c',
-        'src/core/iomgr/unix_sockets_posix_noop.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_init.c',
-        'src/core/surface/channel_ping.c',
-        'src/core/surface/channel_stack_type.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/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/http/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 fc170cc..43d3c68 100644
--- a/build.yaml
+++ b/build.yaml
@@ -13,16 +13,16 @@
   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,63 +54,63 @@
   - include/grpc/support/tls_pthread.h
   - include/grpc/support/useful.h
   headers:
-  - src/core/profiling/timers.h
-  - src/core/support/backoff.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/backoff.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
@@ -247,261 +247,217 @@
   - include/grpc/grpc.h
   - include/grpc/status.h
   headers:
-  - src/core/census/grpc_filter.h
-  - src/core/census/grpc_plugin.h
-  - src/core/channel/channel_args.h
-  - src/core/channel/channel_stack.h
-  - src/core/channel/channel_stack_builder.h
-  - src/core/channel/client_channel.h
-  - src/core/channel/compress_filter.h
-  - src/core/channel/connected_channel.h
-  - src/core/channel/context.h
-  - src/core/channel/http_client_filter.h
-  - src/core/channel/http_server_filter.h
-  - src/core/channel/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/http/format_request.h
-  - src/core/http/httpcli.h
-  - src/core/http/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/unix_sockets_posix.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/channel_init.h
-  - src/core/surface/channel_stack_type.h
-  - src/core/surface/completion_queue.h
-  - src/core/surface/event_string.h
-  - src/core/surface/init.h
-  - src/core/surface/lame_client.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/census/grpc_plugin.c
-  - src/core/channel/channel_args.c
-  - src/core/channel/channel_stack.c
-  - src/core/channel/channel_stack_builder.c
-  - src/core/channel/client_channel.c
-  - src/core/channel/compress_filter.c
-  - src/core/channel/connected_channel.c
-  - src/core/channel/http_client_filter.c
-  - src/core/channel/http_server_filter.c
-  - src/core/channel/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/http/format_request.c
-  - src/core/http/httpcli.c
-  - src/core/http/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/unix_sockets_posix.c
-  - src/core/iomgr/unix_sockets_posix_noop.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_init.c
-  - src/core/surface/channel_ping.c
-  - src/core/surface/channel_stack_type.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/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
@@ -512,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/http/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
@@ -568,6 +522,77 @@
   - 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
@@ -610,6 +635,10 @@
   dll: true
   filegroups:
   - 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
@@ -683,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
@@ -691,6 +720,8 @@
   dll: true
   filegroups:
   - grpc_base
+  - grpc_transport_chttp2_server_insecure
+  - grpc_transport_chttp2_client_insecure
   - grpc_codegen
   - census
   - nanopb
@@ -702,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
@@ -1543,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
@@ -1563,6 +1606,18 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: http_fuzzer_test
+  build: fuzzer
+  language: c
+  src:
+  - test/core/http/fuzzer.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  corpus_dirs:
+  - test/core/http/corpus
 - name: http_parser_test
   build: test
   language: c
@@ -1631,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
@@ -1994,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
@@ -2775,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
@@ -2788,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
@@ -2798,6 +2877,19 @@
     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
@@ -2806,8 +2898,8 @@
     DEFINES: _DEBUG DEBUG
   easan:
     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++
     DEFINES: _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
     LD: clang
@@ -2856,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
@@ -2891,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
diff --git a/config.m4 b/config.m4
index 8a5b239..653b287 100644
--- a/config.m4
+++ b/config.m4
@@ -36,211 +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/backoff.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/census/grpc_plugin.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/channel_stack_builder.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/compress_filter.c \
-    src/core/channel/connected_channel.c \
-    src/core/channel/http_client_filter.c \
-    src/core/channel/http_server_filter.c \
-    src/core/channel/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/http/format_request.c \
-    src/core/http/httpcli.c \
-    src/core/http/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/unix_sockets_posix.c \
-    src/core/iomgr/unix_sockets_posix_noop.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_init.c \
-    src/core/surface/channel_ping.c \
-    src/core/surface/channel_stack_type.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/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/http/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 \
@@ -546,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/http)
-  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/gRPC.podspec b/gRPC.podspec
index 2a3ed15..08330eb 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -63,18 +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/backoff.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',
@@ -103,532 +117,518 @@
                       '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/backoff.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/census/grpc_plugin.h',
-                      'src/core/channel/channel_args.h',
-                      'src/core/channel/channel_stack.h',
-                      'src/core/channel/channel_stack_builder.h',
-                      'src/core/channel/client_channel.h',
-                      'src/core/channel/compress_filter.h',
-                      'src/core/channel/connected_channel.h',
-                      'src/core/channel/context.h',
-                      'src/core/channel/http_client_filter.h',
-                      'src/core/channel/http_server_filter.h',
-                      'src/core/channel/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/http/format_request.h',
-                      'src/core/http/httpcli.h',
-                      'src/core/http/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/unix_sockets_posix.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/channel_init.h',
-                      'src/core/surface/channel_stack_type.h',
-                      'src/core/surface/completion_queue.h',
-                      'src/core/surface/event_string.h',
-                      'src/core/surface/init.h',
-                      'src/core/surface/lame_client.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/grpc_security.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/status.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/census.h',
-                      'src/core/census/grpc_context.c',
-                      'src/core/census/grpc_filter.c',
-                      'src/core/census/grpc_plugin.c',
-                      'src/core/channel/channel_args.c',
-                      'src/core/channel/channel_stack.c',
-                      'src/core/channel/channel_stack_builder.c',
-                      'src/core/channel/client_channel.c',
-                      'src/core/channel/compress_filter.c',
-                      'src/core/channel/connected_channel.c',
-                      'src/core/channel/http_client_filter.c',
-                      'src/core/channel/http_server_filter.c',
-                      'src/core/channel/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/http/format_request.c',
-                      'src/core/http/httpcli.c',
-                      'src/core/http/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/unix_sockets_posix.c',
-                      'src/core/iomgr/unix_sockets_posix_noop.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_init.c',
-                      'src/core/surface/channel_ping.c',
-                      'src/core/surface/channel_stack_type.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/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/http/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',
+                      'include/grpc/status.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',
                       '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/backoff.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/census/grpc_plugin.h',
-                              'src/core/channel/channel_args.h',
-                              'src/core/channel/channel_stack.h',
-                              'src/core/channel/channel_stack_builder.h',
-                              'src/core/channel/client_channel.h',
-                              'src/core/channel/compress_filter.h',
-                              'src/core/channel/connected_channel.h',
-                              'src/core/channel/context.h',
-                              'src/core/channel/http_client_filter.h',
-                              'src/core/channel/http_server_filter.h',
-                              'src/core/channel/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/http/format_request.h',
-                              'src/core/http/httpcli.h',
-                              'src/core/http/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/unix_sockets_posix.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/channel_init.h',
-                              'src/core/surface/channel_stack_type.h',
-                              'src/core/surface/completion_queue.h',
-                              'src/core/surface/event_string.h',
-                              'src/core/surface/init.h',
-                              'src/core/surface/lame_client.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 eeda035..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,391 +88,377 @@
   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/backoff.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/backoff.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( include/grpc/grpc_security.h )
+  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/status.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 )
   s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
   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/census.h )
-  s.files += %w( src/core/census/grpc_filter.h )
-  s.files += %w( src/core/census/grpc_plugin.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/channel_stack_builder.h )
-  s.files += %w( src/core/channel/client_channel.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/http/format_request.h )
-  s.files += %w( src/core/http/httpcli.h )
-  s.files += %w( src/core/http/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/unix_sockets_posix.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/channel_init.h )
-  s.files += %w( src/core/surface/channel_stack_type.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/lame_client.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( include/grpc/status.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/census/grpc_plugin.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/channel_stack_builder.c )
-  s.files += %w( src/core/channel/client_channel.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/http/format_request.c )
-  s.files += %w( src/core/http/httpcli.c )
-  s.files += %w( src/core/http/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/unix_sockets_posix.c )
-  s.files += %w( src/core/iomgr/unix_sockets_posix_noop.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_init.c )
-  s.files += %w( src/core/surface/channel_ping.c )
-  s.files += %w( src/core/surface/channel_stack_type.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/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/http/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/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index ed48411..607511e 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -134,6 +134,8 @@
 #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"
@@ -156,6 +158,8 @@
 #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
@@ -217,6 +221,7 @@
 #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 */
@@ -246,6 +251,8 @@
 #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 */
diff --git a/package.json b/package.json
index fe08577..4da7c70 100644
--- a/package.json
+++ b/package.json
@@ -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,321 +87,321 @@
     "src/node/src/grpc_extension.js",
     "src/node/src/metadata.js",
     "src/node/src/server.js",
-    "include/grpc/grpc_security.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/status.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/census.h",
-    "src/core/census/grpc_filter.h",
-    "src/core/census/grpc_plugin.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/channel_stack_builder.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/compress_filter.h",
-    "src/core/channel/connected_channel.h",
-    "src/core/channel/context.h",
-    "src/core/channel/http_client_filter.h",
-    "src/core/channel/http_server_filter.h",
-    "src/core/channel/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/http/format_request.h",
-    "src/core/http/httpcli.h",
-    "src/core/http/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/unix_sockets_posix.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/channel_init.h",
-    "src/core/surface/channel_stack_type.h",
-    "src/core/surface/completion_queue.h",
-    "src/core/surface/event_string.h",
-    "src/core/surface/init.h",
-    "src/core/surface/lame_client.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",
+    "include/grpc/status.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/census/grpc_plugin.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/channel_stack_builder.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/compress_filter.c",
-    "src/core/channel/connected_channel.c",
-    "src/core/channel/http_client_filter.c",
-    "src/core/channel/http_server_filter.c",
-    "src/core/channel/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/http/format_request.c",
-    "src/core/http/httpcli.c",
-    "src/core/http/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/unix_sockets_posix.c",
-    "src/core/iomgr/unix_sockets_posix_noop.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_init.c",
-    "src/core/surface/channel_ping.c",
-    "src/core/surface/channel_stack_type.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/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/http/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",
@@ -831,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",
@@ -859,76 +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/backoff.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/backoff.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 4a99922..a40cd16 100644
--- a/package.xml
+++ b/package.xml
@@ -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,391 +92,377 @@
     <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/backoff.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/backoff.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="include/grpc/grpc_security.h" 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/status.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" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
     <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/census.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/grpc_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/grpc_plugin.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/channel_stack_builder.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_channel.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/http/format_request.h" role="src" />
-    <file baseinstalldir="/" name="src/core/http/httpcli.h" role="src" />
-    <file baseinstalldir="/" name="src/core/http/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/unix_sockets_posix.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/channel_init.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_stack_type.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/lame_client.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="include/grpc/status.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/census/grpc_plugin.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/channel_stack_builder.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_channel.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/http/format_request.c" role="src" />
-    <file baseinstalldir="/" name="src/core/http/httpcli.c" role="src" />
-    <file baseinstalldir="/" name="src/core/http/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/unix_sockets_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/unix_sockets_posix_noop.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_init.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_ping.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_stack_type.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/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/http/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/src/core/census/aggregation.h b/src/core/census/aggregation.h
deleted file mode 100644
index e0ef963..0000000
--- a/src/core/census/aggregation.h
+++ /dev/null
@@ -1,66 +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 <stddef.h>
-
-#ifndef GRPC_CORE_CENSUS_AGGREGATION_H
-#define GRPC_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_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 11120a2..0000000
--- a/src/core/census/grpc_filter.c
+++ /dev/null
@@ -1,198 +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 4699e4d..0000000
--- a/src/core/census/grpc_filter.h
+++ /dev/null
@@ -1,44 +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_CORE_CENSUS_GRPC_FILTER_H
-#define GRPC_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_CORE_CENSUS_GRPC_FILTER_H */
diff --git a/src/core/census/grpc_plugin.c b/src/core/census/grpc_plugin.c
deleted file mode 100644
index 3ca9400..0000000
--- a/src/core/census/grpc_plugin.c
+++ /dev/null
@@ -1,70 +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_plugin.h"
-
-#include <limits.h>
-
-#include <grpc/census.h>
-
-#include "src/core/census/grpc_filter.h"
-#include "src/core/channel/channel_stack_builder.h"
-#include "src/core/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/census/grpc_plugin.h b/src/core/census/grpc_plugin.h
deleted file mode 100644
index 9321c2c..0000000
--- a/src/core/census/grpc_plugin.h
+++ /dev/null
@@ -1,40 +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_CORE_CENSUS_GRPC_PLUGIN_H
-#define GRPC_CORE_CENSUS_GRPC_PLUGIN_H
-
-void census_grpc_plugin_init(void);
-void census_grpc_plugin_destroy(void);
-
-#endif /* GRPC_CORE_CENSUS_GRPC_PLUGIN_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 bc6eaea..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_CORE_CENSUS_MLOG_H
-#define GRPC_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_CORE_CENSUS_MLOG_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 f8d8dad..0000000
--- a/src/core/census/rpc_metric_id.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_CORE_CENSUS_RPC_METRIC_ID_H
-#define GRPC_CORE_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_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 e0382fa..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 "src/core/channel/channel_args.h"
-#include <grpc/grpc.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 e19440f..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_CORE_CHANNEL_CHANNEL_ARGS_H
-#define GRPC_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_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 52362f0..0000000
--- a/src/core/channel/channel_stack.h
+++ /dev/null
@@ -1,260 +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_CORE_CHANNEL_CHANNEL_STACK_H
-#define GRPC_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_CORE_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/channel/channel_stack_builder.c b/src/core/channel/channel_stack_builder.c
deleted file mode 100644
index 1b1004e..0000000
--- a/src/core/channel/channel_stack_builder.c
+++ /dev/null
@@ -1,258 +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/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/channel/channel_stack_builder.h b/src/core/channel/channel_stack_builder.h
deleted file mode 100644
index 15f395e..0000000
--- a/src/core/channel/channel_stack_builder.h
+++ /dev/null
@@ -1,155 +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_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H
-#define GRPC_CORE_CHANNEL_CHANNEL_STACK_BUILDER_H
-
-#include <stdbool.h>
-
-#include "src/core/channel/channel_args.h"
-#include "src/core/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_CHANNEL_CHANNEL_STACK_BUILDER_H */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
deleted file mode 100644
index ad1ded9..0000000
--- a/src/core/channel/client_channel.c
+++ /dev/null
@@ -1,526 +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 422f7f8..0000000
--- a/src/core/channel/client_channel.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_CORE_CHANNEL_CLIENT_CHANNEL_H
-#define GRPC_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_CORE_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
deleted file mode 100644
index 6f5a974..0000000
--- a/src/core/channel/compress_filter.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.
- *
- */
-
-#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 8c208ac..0000000
--- a/src/core/channel/compress_filter.h
+++ /dev/null
@@ -1,65 +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_CORE_CHANNEL_COMPRESS_FILTER_H
-#define GRPC_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_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 df11d54..0000000
--- a/src/core/channel/connected_channel.c
+++ /dev/null
@@ -1,176 +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/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/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/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/channel/connected_channel.h b/src/core/channel/connected_channel.h
deleted file mode 100644
index 7c0c835..0000000
--- a/src/core/channel/connected_channel.h
+++ /dev/null
@@ -1,42 +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_CORE_CHANNEL_CONNECTED_CHANNEL_H
-#define GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H
-
-#include "src/core/channel/channel_stack_builder.h"
-
-bool grpc_add_connected_filter(grpc_channel_stack_builder *builder,
-                               void *arg_must_be_null);
-
-#endif /* GRPC_CORE_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/channel/context.h b/src/core/channel/context.h
deleted file mode 100644
index db217dc..0000000
--- a/src/core/channel/context.h
+++ /dev/null
@@ -1,49 +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_CORE_CHANNEL_CONTEXT_H
-#define GRPC_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_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 582427d..0000000
--- a/src/core/channel/http_client_filter.c
+++ /dev/null
@@ -1,255 +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 6f619bb..0000000
--- a/src/core/channel/http_client_filter.h
+++ /dev/null
@@ -1,44 +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_CORE_CHANNEL_HTTP_CLIENT_FILTER_H
-#define GRPC_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_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 1a2e0c5..0000000
--- a/src/core/channel/http_server_filter.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 "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 528c864..0000000
--- a/src/core/channel/http_server_filter.h
+++ /dev/null
@@ -1,42 +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_CORE_CHANNEL_HTTP_SERVER_FILTER_H
-#define GRPC_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_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 84b4657..0000000
--- a/src/core/channel/subchannel_call_holder.h
+++ /dev/null
@@ -1,97 +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_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H
-#define GRPC_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.
-
-    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_CHANNEL_SUBCHANNEL_CALL_HOLDER_H */
diff --git a/src/core/client_config/client_config.c b/src/core/client_config/client_config.c
deleted file mode 100644
index c500af2..0000000
--- a/src/core/client_config/client_config.c
+++ /dev/null
@@ -1,74 +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/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/client_config/client_config.h b/src/core/client_config/client_config.h
deleted file mode 100644
index 9b37fdc..0000000
--- a/src/core/client_config/client_config.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_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H
-#define GRPC_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_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 93248fc..0000000
--- a/src/core/client_config/connector.h
+++ /dev/null
@@ -1,92 +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_CORE_CLIENT_CONFIG_CONNECTOR_H
-#define GRPC_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;
-
-  /** 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_CLIENT_CONFIG_CONNECTOR_H */
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 e6d2d8f..0000000
--- a/src/core/client_config/initial_connect_string.h
+++ /dev/null
@@ -1,50 +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_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
-#define GRPC_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_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 b7a4c9c..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_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H
-#define GRPC_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_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 2833f11..0000000
--- a/src/core/client_config/lb_policies/pick_first.c
+++ /dev/null
@@ -1,421 +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) {
-  if (args->num_subchannels == 0) return NULL;
-  pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
-  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 3a3f195..0000000
--- a/src/core/client_config/lb_policies/pick_first.h
+++ /dev/null
@@ -1,43 +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_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H
-#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_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 /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H */
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 114ece6..0000000
--- a/src/core/client_config/lb_policies/round_robin.c
+++ /dev/null
@@ -1,542 +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 7e6f176..0000000
--- a/src/core/client_config/lb_policies/round_robin.h
+++ /dev/null
@@ -1,46 +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_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H
-#define GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_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 /* GRPC_CORE_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H */
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 ffebc2a..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_CORE_CLIENT_CONFIG_LB_POLICY_H
-#define GRPC_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_CORE_CLIENT_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 842ba96..0000000
--- a/src/core/client_config/lb_policy_factory.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H
-#define GRPC_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_CORE_CLIENT_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 f3a08a3..0000000
--- a/src/core/client_config/lb_policy_registry.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_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H
-#define GRPC_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_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 96f88fe..0000000
--- a/src/core/client_config/resolver.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_CORE_CLIENT_CONFIG_RESOLVER_H
-#define GRPC_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_CORE_CLIENT_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 477f8db..0000000
--- a/src/core/client_config/resolver_factory.h
+++ /dev/null
@@ -1,82 +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_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H
-#define GRPC_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_CORE_CLIENT_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 1e4cebe..0000000
--- a/src/core/client_config/resolver_registry.h
+++ /dev/null
@@ -1,65 +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_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H
-#define GRPC_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_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 2b2ee97..0000000
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ /dev/null
@@ -1,309 +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/iomgr/timer.h"
-#include "src/core/support/backoff.h"
-#include "src/core/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_subchannel **subchannels;
-  grpc_subchannel_args args;
-  grpc_lb_policy *lb_policy;
-  size_t i;
-  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();
-    subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
-    size_t naddrs = 0;
-    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;
-      grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
-          exec_ctx, r->subchannel_factory, &args);
-      if (subchannel != NULL) {
-        subchannels[naddrs++] = subchannel;
-      }
-    }
-    memset(&lb_policy_args, 0, sizeof(lb_policy_args));
-    lb_policy_args.subchannels = subchannels;
-    lb_policy_args.num_subchannels = naddrs;
-    lb_policy = grpc_lb_policy_create(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_free(subchannels);
-  } 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/client_config/resolvers/dns_resolver.h b/src/core/client_config/resolvers/dns_resolver.h
deleted file mode 100644
index b24280b..0000000
--- a/src/core/client_config/resolvers/dns_resolver.h
+++ /dev/null
@@ -1,42 +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_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
-#define GRPC_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_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 3cb7d79..0000000
--- a/src/core/client_config/resolvers/sockaddr_resolver.c
+++ /dev/null
@@ -1,372 +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>
-
-#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/iomgr/unix_sockets_posix.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);
-}
-
-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, 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/client_config/resolvers/sockaddr_resolver.h b/src/core/client_config/resolvers/sockaddr_resolver.h
deleted file mode 100644
index f050329..0000000
--- a/src/core/client_config/resolvers/sockaddr_resolver.h
+++ /dev/null
@@ -1,50 +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_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H
-#define GRPC_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_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_CORE_CLIENT_CONFIG_RESOLVERS_SOCKADDR_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 e0e1879..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/json/json.h"
-#include "src/core/support/string.h"
-#include "src/core/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_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 04bd3ca..0000000
--- a/src/core/client_config/resolvers/zookeeper_resolver.h
+++ /dev/null
@@ -1,42 +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_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
-#define GRPC_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_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 c5cd504..0000000
--- a/src/core/client_config/subchannel.c
+++ /dev/null
@@ -1,678 +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/support/backoff.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/channel_init.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;
-  /** 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/client_config/subchannel.h b/src/core/client_config/subchannel.h
deleted file mode 100644
index 83e1c58..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_CORE_CLIENT_CONFIG_SUBCHANNEL_H
-#define GRPC_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_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 c638f37..0000000
--- a/src/core/client_config/subchannel_factory.h
+++ /dev/null
@@ -1,66 +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_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
-#define GRPC_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_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 24cc76c..0000000
--- a/src/core/client_config/subchannel_index.c
+++ /dev/null
@@ -1,262 +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));
-  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/client_config/subchannel_index.h b/src/core/client_config/subchannel_index.h
deleted file mode 100644
index 3cd5d12..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_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H
-#define GRPC_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_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 af013d8..0000000
--- a/src/core/client_config/uri_parser.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_CORE_CLIENT_CONFIG_URI_PARSER_H
-#define GRPC_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 /* GRPC_CORE_CLIENT_CONFIG_URI_PARSER_H */
diff --git a/src/core/compression/algorithm_metadata.h b/src/core/compression/algorithm_metadata.h
deleted file mode 100644
index 34abf1d..0000000
--- a/src/core/compression/algorithm_metadata.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_CORE_COMPRESSION_ALGORITHM_METADATA_H
-#define GRPC_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_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 2810a38..0000000
--- a/src/core/compression/compression_algorithm.c
+++ /dev/null
@@ -1,203 +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, 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/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 20b78c0..0000000
--- a/src/core/compression/message_compress.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_CORE_COMPRESSION_MESSAGE_COMPRESS_H
-#define GRPC_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_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 91ec140..0000000
--- a/src/core/debug/trace.h
+++ /dev/null
@@ -1,43 +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_CORE_DEBUG_TRACE_H
-#define GRPC_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_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/http/format_request.c b/src/core/http/format_request.c
deleted file mode 100644
index ac9bb8a..0000000
--- a/src/core/http/format_request.c
+++ /dev/null
@@ -1,120 +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/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/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/http/format_request.h b/src/core/http/format_request.h
deleted file mode 100644
index dfd6fad..0000000
--- a/src/core/http/format_request.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_CORE_HTTP_FORMAT_REQUEST_H
-#define GRPC_CORE_HTTP_FORMAT_REQUEST_H
-
-#include <grpc/support/slice.h>
-#include "src/core/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_HTTP_FORMAT_REQUEST_H */
diff --git a/src/core/http/httpcli.c b/src/core/http/httpcli.c
deleted file mode 100644
index 1c0d333..0000000
--- a/src/core/http/httpcli.c
+++ /dev/null
@@ -1,293 +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/http/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/http/format_request.h"
-#include "src/core/http/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_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/http/httpcli.h b/src/core/http/httpcli.h
deleted file mode 100644
index 0bf4f2f..0000000
--- a/src/core/http/httpcli.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_CORE_HTTP_HTTPCLI_H
-#define GRPC_CORE_HTTP_HTTPCLI_H
-
-#include <stddef.h>
-
-#include <grpc/support/time.h>
-
-#include "src/core/http/parser.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"
-
-/* 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_HTTP_HTTPCLI_H */
diff --git a/src/core/http/httpcli_security_connector.c b/src/core/http/httpcli_security_connector.c
deleted file mode 100644
index a1a32f7..0000000
--- a/src/core/http/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/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/security/handshake.h"
-#include "src/core/support/string.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/http/parser.c b/src/core/http/parser.c
deleted file mode 100644
index ebec8a5..0000000
--- a/src/core/http/parser.c
+++ /dev/null
@@ -1,313 +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/http/parser.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-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:
-  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:
-  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') {
-    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->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) {
-        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/http/parser.h b/src/core/http/parser.h
deleted file mode 100644
index 39517e4..0000000
--- a/src/core/http/parser.h
+++ /dev/null
@@ -1,116 +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_CORE_HTTP_PARSER_H
-#define GRPC_CORE_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_HTTP_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 d5e1f45..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_CORE_IOMGR_CLOSURE_H
-#define GRPC_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_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 b4be852..0000000
--- a/src/core/iomgr/endpoint.h
+++ /dev/null
@@ -1,102 +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_CORE_IOMGR_ENDPOINT_H
-#define GRPC_CORE_IOMGR_ENDPOINT_H
-
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/time.h>
-#include "src/core/iomgr/pollset.h"
-#include "src/core/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_IOMGR_ENDPOINT_H */
diff --git a/src/core/iomgr/endpoint_pair.h b/src/core/iomgr/endpoint_pair.h
deleted file mode 100644
index 59015d8..0000000
--- a/src/core/iomgr/endpoint_pair.h
+++ /dev/null
@@ -1,47 +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_CORE_IOMGR_ENDPOINT_PAIR_H
-#define GRPC_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_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 66d19a4..0000000
--- a/src/core/iomgr/endpoint_pair_posix.c
+++ /dev/null
@@ -1,83 +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_POSIX_SOCKET
-
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/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/iomgr/tcp_posix.h"
-#include "src/core/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/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c
deleted file mode 100644
index 2024f58..0000000
--- a/src/core/iomgr/endpoint_pair_windows.c
+++ /dev/null
@@ -1,97 +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/endpoint_pair.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include "src/core/iomgr/socket_windows.h"
-#include "src/core/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/iomgr/exec_ctx.c b/src/core/iomgr/exec_ctx.c
deleted file mode 100644
index 893fe45..0000000
--- a/src/core/iomgr/exec_ctx.c
+++ /dev/null
@@ -1,151 +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 <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-
-#include "src/core/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/iomgr/exec_ctx.h b/src/core/iomgr/exec_ctx.h
deleted file mode 100644
index 07b54a0..0000000
--- a/src/core/iomgr/exec_ctx.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_CORE_IOMGR_EXEC_CTX_H
-#define GRPC_CORE_IOMGR_EXEC_CTX_H
-
-#include "src/core/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_IOMGR_EXEC_CTX_H */
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 f66b356..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_CORE_IOMGR_EXECUTOR_H
-#define GRPC_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_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 b4d038a..0000000
--- a/src/core/iomgr/fd_posix.c
+++ /dev/null
@@ -1,454 +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_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/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
deleted file mode 100644
index 1993ada..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_CORE_IOMGR_FD_POSIX_H
-#define GRPC_CORE_IOMGR_FD_POSIX_H
-
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/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_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 37e277d..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/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/thd.h>
-
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/socket_windows.h"
-#include "src/core/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/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
deleted file mode 100644
index 570b892..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_CORE_IOMGR_IOCP_WINDOWS_H
-#define GRPC_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_CORE_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
deleted file mode 100644
index 3ab4430..0000000
--- a/src/core/iomgr/iomgr.c
+++ /dev/null
@@ -1,175 +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/exec_ctx.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_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/iomgr/iomgr.h b/src/core/iomgr/iomgr.h
deleted file mode 100644
index e1237a4..0000000
--- a/src/core/iomgr/iomgr.h
+++ /dev/null
@@ -1,43 +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_CORE_IOMGR_IOMGR_H
-#define GRPC_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_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 1cad318..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_CORE_IOMGR_IOMGR_INTERNAL_H
-#define GRPC_CORE_IOMGR_IOMGR_INTERNAL_H
-
-#include <stdbool.h>
-
-#include <grpc/support/sync.h>
-#include "src/core/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_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 2f7f347..0000000
--- a/src/core/iomgr/iomgr_posix.c
+++ /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.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/debug/trace.h"
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/iomgr_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 698fb6a..0000000
--- a/src/core/iomgr/iomgr_posix.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_CORE_IOMGR_IOMGR_POSIX_H
-#define GRPC_CORE_IOMGR_IOMGR_POSIX_H
-
-#include "src/core/iomgr/iomgr_internal.h"
-
-#endif /* GRPC_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 2d10413..0000000
--- a/src/core/iomgr/iomgr_windows.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_WINSOCK_SOCKET
-
-#include "src/core/iomgr/sockaddr_win32.h"
-
-#include <grpc/support/log.h>
-
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/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/iomgr/pollset.h b/src/core/iomgr/pollset.h
deleted file mode 100644
index 9500b1a..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_CORE_IOMGR_POLLSET_H
-#define GRPC_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.
- * 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_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 e0cfc44..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_CORE_IOMGR_POLLSET_POSIX_H
-#define GRPC_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_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 204c625..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_CORE_IOMGR_POLLSET_SET_H
-#define GRPC_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_CORE_IOMGR_POLLSET_SET_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 80f4877..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_CORE_IOMGR_POLLSET_SET_POSIX_H
-#define GRPC_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_CORE_IOMGR_POLLSET_SET_POSIX_H */
diff --git a/src/core/iomgr/pollset_set_windows.c b/src/core/iomgr/pollset_set_windows.c
deleted file mode 100644
index 3b8eca2..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(pollset_set) { 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 0f040fe..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_CORE_IOMGR_POLLSET_SET_WINDOWS_H
-#define GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H
-
-#include "src/core/iomgr/pollset_set.h"
-
-#endif /* GRPC_CORE_IOMGR_POLLSET_SET_WINDOWS_H */
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
deleted file mode 100644
index 1a99224..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/iocp_windows.h"
-#include "src/core/iomgr/iomgr_internal.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 f1d1585..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_CORE_IOMGR_POLLSET_WINDOWS_H
-#define GRPC_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_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 aa0d7d1..0000000
--- a/src/core/iomgr/resolve_address.h
+++ /dev/null
@@ -1,72 +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_CORE_IOMGR_RESOLVE_ADDRESS_H
-#define GRPC_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. */
-extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
-    const char *name, const char *default_port);
-
-#endif /* GRPC_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 26b3aa8..0000000
--- a/src/core/iomgr/resolve_address_posix.c
+++ /dev/null
@@ -1,178 +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/resolve_address.h"
-#include "src/core/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/iomgr/executor.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/unix_sockets_posix.h"
-#include "src/core/support/block_annotate.h"
-#include "src/core/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/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c
deleted file mode 100644
index 472e797..0000000
--- a/src/core/iomgr/resolve_address_windows.c
+++ /dev/null
@@ -1,169 +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/resolve_address.h"
-#include "src/core/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/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"
-
-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/iomgr/sockaddr.h b/src/core/iomgr/sockaddr.h
deleted file mode 100644
index 68241bd..0000000
--- a/src/core/iomgr/sockaddr.h
+++ /dev/null
@@ -1,47 +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_CORE_IOMGR_SOCKADDR_H
-#define GRPC_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_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 a398096..0000000
--- a/src/core/iomgr/sockaddr_posix.h
+++ /dev/null
@@ -1,44 +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_CORE_IOMGR_SOCKADDR_POSIX_H
-#define GRPC_CORE_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_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 a3c3a87..0000000
--- a/src/core/iomgr/sockaddr_utils.c
+++ /dev/null
@@ -1,227 +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/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/iomgr/unix_sockets_posix.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;
-    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/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h
deleted file mode 100644
index 43dc7a4..0000000
--- a/src/core/iomgr/sockaddr_utils.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_IOMGR_SOCKADDR_UTILS_H
-#define GRPC_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_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 ef306e3..0000000
--- a/src/core/iomgr/sockaddr_win32.h
+++ /dev/null
@@ -1,43 +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_CORE_IOMGR_SOCKADDR_WIN32_H
-#define GRPC_CORE_IOMGR_SOCKADDR_WIN32_H
-
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-// must be included after the above
-#include <mswsock.h>
-
-#endif /* GRPC_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 570dacc..0000000
--- a/src/core/iomgr/socket_utils_common_posix.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_POSIX_SOCKET
-
-#include "src/core/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/iomgr/sockaddr_utils.h"
-#include "src/core/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
-}
-
-/* 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 e16885f..0000000
--- a/src/core/iomgr/socket_utils_linux.c
+++ /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.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_LINUX_SOCKETUTILS
-
-#include "src/core/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/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 3908550..0000000
--- a/src/core/iomgr/socket_utils_posix.h
+++ /dev/null
@@ -1,113 +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_CORE_IOMGR_SOCKET_UTILS_POSIX_H
-#define GRPC_CORE_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);
-
-/* 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_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 c1f419e..0000000
--- a/src/core/iomgr/socket_windows.c
+++ /dev/null
@@ -1,100 +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>
-
-// 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/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 6fe3c6e..0000000
--- a/src/core/iomgr/socket_windows.h
+++ /dev/null
@@ -1,111 +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_CORE_IOMGR_SOCKET_WINDOWS_H
-#define GRPC_CORE_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/iomgr/exec_ctx.h"
-#include "src/core/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_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 c36f8de..0000000
--- a/src/core/iomgr/tcp_client.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_CORE_IOMGR_TCP_CLIENT_H
-#define GRPC_CORE_IOMGR_TCP_CLIENT_H
-
-#include <grpc/support/time.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/pollset_set.h"
-#include "src/core/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_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 1d3f9b6..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/iomgr/unix_sockets_posix.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) ||
-      (!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/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
deleted file mode 100644
index da83f7b..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/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"
-#include "src/core/iomgr/tcp_windows.h"
-#include "src/core/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/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
deleted file mode 100644
index e8f7381..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 d846ec5..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_CORE_IOMGR_TCP_POSIX_H
-#define GRPC_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_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 93247e9..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_CORE_IOMGR_TCP_SERVER_H
-#define GRPC_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_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 74ee68a..0000000
--- a/src/core/iomgr/tcp_server_posix.c
+++ /dev/null
@@ -1,607 +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 <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/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/iomgr/unix_sockets_posix.h"
-#include "src/core/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/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 9b1db5f..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/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"
-#include "src/core/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/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h
deleted file mode 100644
index 78bc133..0000000
--- a/src/core/iomgr/tcp_windows.h
+++ /dev/null
@@ -1,57 +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_CORE_IOMGR_TCP_WINDOWS_H
-#define GRPC_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_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 048e244..0000000
--- a/src/core/iomgr/time_averaged_stats.h
+++ /dev/null
@@ -1,88 +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_CORE_IOMGR_TIME_AVERAGED_STATS_H
-#define GRPC_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_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 f444643..0000000
--- a/src/core/iomgr/timer.c
+++ /dev/null
@@ -1,356 +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 <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-#include "src/core/iomgr/time_averaged_stats.h"
-#include "src/core/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/iomgr/timer.h b/src/core/iomgr/timer.h
deleted file mode 100644
index 1e2d1cb..0000000
--- a/src/core/iomgr/timer.h
+++ /dev/null
@@ -1,108 +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_CORE_IOMGR_TIMER_H
-#define GRPC_CORE_IOMGR_TIMER_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/time.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/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_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 c2912ef..0000000
--- a/src/core/iomgr/timer_heap.h
+++ /dev/null
@@ -1,57 +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_CORE_IOMGR_TIMER_HEAP_H
-#define GRPC_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_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 1741591..0000000
--- a/src/core/iomgr/udp_server.c
+++ /dev/null
@@ -1,418 +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 <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/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/iomgr/unix_sockets_posix.h"
-#include "src/core/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;
-  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;
-
-  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/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
deleted file mode 100644
index 148c04f..0000000
--- a/src/core/iomgr/udp_server.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_IOMGR_UDP_SERVER_H
-#define GRPC_CORE_IOMGR_UDP_SERVER_H
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/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_IOMGR_UDP_SERVER_H */
diff --git a/src/core/iomgr/unix_sockets_posix.c b/src/core/iomgr/unix_sockets_posix.c
deleted file mode 100644
index 174a7e7..0000000
--- a/src/core/iomgr/unix_sockets_posix.c
+++ /dev/null
@@ -1,103 +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/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/iomgr/unix_sockets_posix.h b/src/core/iomgr/unix_sockets_posix.h
deleted file mode 100644
index e842ba3..0000000
--- a/src/core/iomgr/unix_sockets_posix.h
+++ /dev/null
@@ -1,61 +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_CORE_IOMGR_UNIX_SOCKETS_POSIX_H
-#define GRPC_CORE_IOMGR_UNIX_SOCKETS_POSIX_H
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/support/string_util.h>
-
-#include "src/core/client_config/resolver_factory.h"
-#include "src/core/client_config/uri_parser.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/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_IOMGR_UNIX_SOCKETS_POSIX_H */
diff --git a/src/core/iomgr/unix_sockets_posix_noop.c b/src/core/iomgr/unix_sockets_posix_noop.c
deleted file mode 100644
index 045467b..0000000
--- a/src/core/iomgr/unix_sockets_posix_noop.c
+++ /dev/null
@@ -1,61 +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/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/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 7b2be9e..0000000
--- a/src/core/iomgr/wakeup_fd_nospecial.c
+++ /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.
- *
- */
-
-/*
- * 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/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/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c
deleted file mode 100644
index dd2fd1f..0000000
--- a/src/core/iomgr/wakeup_fd_pipe.c
+++ /dev/null
@@ -1,102 +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_WAKEUP_FD
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/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/iomgr/wakeup_fd_pipe.h b/src/core/iomgr/wakeup_fd_pipe.h
deleted file mode 100644
index eb3e02b..0000000
--- a/src/core/iomgr/wakeup_fd_pipe.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_CORE_IOMGR_WAKEUP_FD_PIPE_H
-#define GRPC_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_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 07778c4..0000000
--- a/src/core/iomgr/wakeup_fd_posix.c
+++ /dev/null
@@ -1,72 +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_WAKEUP_FD
-
-#include <stddef.h>
-#include "src/core/iomgr/wakeup_fd_pipe.h"
-#include "src/core/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/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h
deleted file mode 100644
index d7e3cf4..0000000
--- a/src/core/iomgr/wakeup_fd_posix.h
+++ /dev/null
@@ -1,101 +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.
- *
- */
-
-/*
- * 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_IOMGR_WAKEUP_FD_POSIX_H
-#define GRPC_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_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 2b923ba..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_CORE_IOMGR_WORKQUEUE_H
-#define GRPC_CORE_IOMGR_WORKQUEUE_H
-
-#include "src/core/iomgr/closure.h"
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/pollset.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 /* GRPC_CORE_IOMGR_WORKQUEUE_H */
diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c
deleted file mode 100644
index 2b42e6d..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_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/iomgr/workqueue_posix.h b/src/core/iomgr/workqueue_posix.h
deleted file mode 100644
index 89937b1..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_CORE_IOMGR_WORKQUEUE_POSIX_H
-#define GRPC_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_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 7e81869..0000000
--- a/src/core/iomgr/workqueue_windows.h
+++ /dev/null
@@ -1,37 +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_CORE_IOMGR_WORKQUEUE_WINDOWS_H
-#define GRPC_CORE_IOMGR_WORKQUEUE_WINDOWS_H
-
-#endif /* GRPC_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 aea9d5d..0000000
--- a/src/core/json/json.h
+++ /dev/null
@@ -1,88 +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_CORE_JSON_JSON_H
-#define GRPC_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_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 7205a94..0000000
--- a/src/core/json/json_common.h
+++ /dev/null
@@ -1,49 +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_CORE_JSON_JSON_COMMON_H
-#define GRPC_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_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 f25f44b..0000000
--- a/src/core/json/json_reader.h
+++ /dev/null
@@ -1,160 +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_CORE_JSON_JSON_READER_H
-#define GRPC_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_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 d4ebce1..0000000
--- a/src/core/json/json_string.c
+++ /dev/null
@@ -1,379 +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/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 c392126..0000000
--- a/src/core/json/json_writer.h
+++ /dev/null
@@ -1,97 +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.
- *
- */
-
-/* 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_JSON_JSON_WRITER_H
-#define GRPC_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_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/support/cpu_linux.c b/src/core/lib/support/cpu_linux.c
similarity index 100%
rename from src/core/support/cpu_linux.c
rename to src/core/lib/support/cpu_linux.c
diff --git a/src/core/support/cpu_posix.c b/src/core/lib/support/cpu_posix.c
similarity index 100%
rename from src/core/support/cpu_posix.c
rename to src/core/lib/support/cpu_posix.c
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/support/histogram.c b/src/core/lib/support/histogram.c
similarity index 100%
rename from src/core/support/histogram.c
rename to src/core/lib/support/histogram.c
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/support/log_android.c b/src/core/lib/support/log_android.c
similarity index 100%
rename from src/core/support/log_android.c
rename to src/core/lib/support/log_android.c
diff --git a/src/core/support/log_linux.c b/src/core/lib/support/log_linux.c
similarity index 100%
rename from src/core/support/log_linux.c
rename to src/core/lib/support/log_linux.c
diff --git a/src/core/support/log_posix.c b/src/core/lib/support/log_posix.c
similarity index 100%
rename from src/core/support/log_posix.c
rename to src/core/lib/support/log_posix.c
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/support/string_posix.c b/src/core/lib/support/string_posix.c
similarity index 100%
rename from src/core/support/string_posix.c
rename to src/core/lib/support/string_posix.c
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/support/subprocess_posix.c b/src/core/lib/support/subprocess_posix.c
similarity index 100%
rename from src/core/support/subprocess_posix.c
rename to src/core/lib/support/subprocess_posix.c
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/support/sync.c b/src/core/lib/support/sync.c
similarity index 100%
rename from src/core/support/sync.c
rename to src/core/lib/support/sync.c
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/support/thd_posix.c b/src/core/lib/support/thd_posix.c
similarity index 100%
rename from src/core/support/thd_posix.c
rename to src/core/lib/support/thd_posix.c
diff --git a/src/core/support/thd_win32.c b/src/core/lib/support/thd_win32.c
similarity index 100%
rename from src/core/support/thd_win32.c
rename to src/core/lib/support/thd_win32.c
diff --git a/src/core/support/time.c b/src/core/lib/support/time.c
similarity index 100%
rename from src/core/support/time.c
rename to src/core/lib/support/time.c
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/surface/version.c b/src/core/lib/surface/version.c
similarity index 100%
rename from src/core/surface/version.c
rename to src/core/lib/surface/version.c
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 3067f52..0000000
--- a/src/core/profiling/basic_timers.c
+++ /dev/null
@@ -1,274 +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 GRPC_BASIC_PROFILER
-
-#include "src/core/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_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 1154a1d..0000000
--- a/src/core/security/auth_filters.h
+++ /dev/null
@@ -1,42 +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_CORE_SECURITY_AUTH_FILTERS_H
-#define GRPC_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_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 d18f695..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_CORE_SECURITY_B64_H
-#define GRPC_CORE_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_SECURITY_B64_H */
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
deleted file mode 100644
index e2c23ef..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 c8348bc..0000000
--- a/src/core/security/credentials.c
+++ /dev/null
@@ -1,1281 +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/http/httpcli.h"
-#include "src/core/http/parser.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_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/security/credentials.h b/src/core/security/credentials.h
deleted file mode 100644
index bfa7cc7..0000000
--- a/src/core/security/credentials.h
+++ /dev/null
@@ -1,377 +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_CORE_SECURITY_CREDENTIALS_H
-#define GRPC_CORE_SECURITY_CREDENTIALS_H
-
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-#include <grpc/support/sync.h>
-#include "src/core/transport/metadata_batch.h"
-
-#include "src/core/http/httpcli.h"
-#include "src/core/http/parser.h"
-#include "src/core/security/json_token.h"
-#include "src/core/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_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 3872e86..0000000
--- a/src/core/security/google_default_credentials.c
+++ /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.
- *
- */
-
-#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/http/httpcli.h"
-#include "src/core/http/parser.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_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/security/handshake.c b/src/core/security/handshake.c
deleted file mode 100644
index 9fb10a0..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 <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/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/security/handshake.h b/src/core/security/handshake.h
deleted file mode 100644
index 4872045..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_CORE_SECURITY_HANDSHAKE_H
-#define GRPC_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_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 d183f9b..0000000
--- a/src/core/security/json_token.h
+++ /dev/null
@@ -1,118 +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_CORE_SECURITY_JSON_TOKEN_H
-#define GRPC_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_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 0bb8e05..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/http/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.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/security/jwt_verifier.h b/src/core/security/jwt_verifier.h
deleted file mode 100644
index d898d21..0000000
--- a/src/core/security/jwt_verifier.h
+++ /dev/null
@@ -1,136 +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_CORE_SECURITY_JWT_VERIFIER_H
-#define GRPC_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_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 58b081d..0000000
--- a/src/core/security/secure_endpoint.c
+++ /dev/null
@@ -1,384 +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 <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/debug/trace.h"
-#include "src/core/support/string.h"
-#include "src/core/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/security/secure_endpoint.h b/src/core/security/secure_endpoint.h
deleted file mode 100644
index 7368f84..0000000
--- a/src/core/security/secure_endpoint.h
+++ /dev/null
@@ -1,49 +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_CORE_SECURITY_SECURE_ENDPOINT_H
-#define GRPC_CORE_SECURITY_SECURE_ENDPOINT_H
-
-#include <grpc/support/slice.h>
-#include "src/core/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_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 fbec263..0000000
--- a/src/core/security/security_connector.c
+++ /dev/null
@@ -1,812 +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);
-    } 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/security/security_connector.h b/src/core/security/security_connector.h
deleted file mode 100644
index 6f915eb..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_CORE_SECURITY_SECURITY_CONNECTOR_H
-#define GRPC_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_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 f6afc0f..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/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/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/security/security_context.h b/src/core/security/security_context.h
deleted file mode 100644
index 61601f5..0000000
--- a/src/core/security/security_context.h
+++ /dev/null
@@ -1,114 +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_CORE_SECURITY_SECURITY_CONTEXT_H
-#define GRPC_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_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 f3c411d..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 da29ca9..0000000
--- a/src/core/security/server_secure_chttp2.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 <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/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"
-
-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/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 ce8ff92..0000000
--- a/src/core/statistics/census_interface.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_CORE_STATISTICS_CENSUS_INTERFACE_H
-#define GRPC_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_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 3802d1c..0000000
--- a/src/core/statistics/census_log.c
+++ /dev/null
@@ -1,603 +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.
- *
- */
-
-/* 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 <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/statistics/census_log.h b/src/core/statistics/census_log.h
deleted file mode 100644
index e7ce0d4..0000000
--- a/src/core/statistics/census_log.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_STATISTICS_CENSUS_LOG_H
-#define GRPC_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_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 c78d6fd..0000000
--- a/src/core/statistics/census_rpc_stats.c
+++ /dev/null
@@ -1,253 +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 <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/statistics/census_tracing.h"
-#include "src/core/statistics/hash_table.h"
-#include "src/core/statistics/window_stats.h"
-#include "src/core/support/murmur_hash.h"
-#include "src/core/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/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h
deleted file mode 100644
index f7f220e..0000000
--- a/src/core/statistics/census_rpc_stats.h
+++ /dev/null
@@ -1,101 +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_CORE_STATISTICS_CENSUS_RPC_STATS_H
-#define GRPC_CORE_STATISTICS_CENSUS_RPC_STATS_H
-
-#include <grpc/support/port_platform.h>
-#include "src/core/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_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 ad82498..0000000
--- a/src/core/statistics/census_tracing.c
+++ /dev/null
@@ -1,241 +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_tracing.h"
-#include "src/core/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/statistics/hash_table.h"
-#include "src/core/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/statistics/census_tracing.h b/src/core/statistics/census_tracing.h
deleted file mode 100644
index b611e95..0000000
--- a/src/core/statistics/census_tracing.h
+++ /dev/null
@@ -1,96 +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_CORE_STATISTICS_CENSUS_TRACING_H
-#define GRPC_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_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 3ef79c0..0000000
--- a/src/core/statistics/hash_table.c
+++ /dev/null
@@ -1,303 +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/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/statistics/hash_table.h b/src/core/statistics/hash_table.h
deleted file mode 100644
index f4bf2ba..0000000
--- a/src/core/statistics/hash_table.h
+++ /dev/null
@@ -1,131 +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_CORE_STATISTICS_HASH_TABLE_H
-#define GRPC_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_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 eb29686..0000000
--- a/src/core/statistics/window_stats.c
+++ /dev/null
@@ -1,316 +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/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/statistics/window_stats.h b/src/core/statistics/window_stats.h
deleted file mode 100644
index 7742771..0000000
--- a/src/core/statistics/window_stats.h
+++ /dev/null
@@ -1,173 +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_CORE_STATISTICS_WINDOW_STATS_H
-#define GRPC_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_CORE_STATISTICS_WINDOW_STATS_H */
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
deleted file mode 100644
index fd9fb8f..0000000
--- a/src/core/support/alloc.c
+++ /dev/null
@@ -1,90 +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/alloc.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <stdlib.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) { gpr_free(((void **)ptr)[-1]); }
diff --git a/src/core/support/backoff.c b/src/core/support/backoff.c
deleted file mode 100644
index 4ccfb77..0000000
--- a/src/core/support/backoff.c
+++ /dev/null
@@ -1,76 +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/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/support/backoff.h b/src/core/support/backoff.h
deleted file mode 100644
index 0f933c3..0000000
--- a/src/core/support/backoff.h
+++ /dev/null
@@ -1,68 +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_CORE_SUPPORT_BACKOFF_H
-#define GRPC_CORE_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_SUPPORT_BACKOFF_H */
diff --git a/src/core/support/block_annotate.h b/src/core/support/block_annotate.h
deleted file mode 100644
index 79a1803..0000000
--- a/src/core/support/block_annotate.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_SUPPORT_BLOCK_ANNOTATE_H
-#define GRPC_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_CORE_SUPPORT_BLOCK_ANNOTATE_H */
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
deleted file mode 100644
index eff46a1..0000000
--- a/src/core/support/cmdline.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 <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/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/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_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 2902456..0000000
--- a/src/core/support/env.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_SUPPORT_ENV_H
-#define GRPC_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_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 256212b..0000000
--- a/src/core/support/env_posix.c
+++ /dev/null
@@ -1,57 +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_ENV
-
-#include "src/core/support/env.h"
-
-#include <stdlib.h>
-
-#include <grpc/support/log.h>
-
-#include <grpc/support/string_util.h>
-#include "src/core/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/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/host_port.c b/src/core/support/host_port.c
deleted file mode 100644
index 31243a7..0000000
--- a/src/core/support/host_port.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.
- *
- */
-
-#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/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/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 5896654..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_CORE_SUPPORT_LOAD_FILE_H
-#define GRPC_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_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_win32.c b/src/core/support/log_win32.c
deleted file mode 100644
index 89ec091..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 <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/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 0f0b399..0000000
--- a/src/core/support/murmur_hash.h
+++ /dev/null
@@ -1,44 +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_CORE_SUPPORT_MURMUR_HASH_H
-#define GRPC_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_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 8e0bbfa..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/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/support/stack_lockfree.h b/src/core/support/stack_lockfree.h
deleted file mode 100644
index d6fd06d..0000000
--- a/src/core/support/stack_lockfree.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_CORE_SUPPORT_STACK_LOCKFREE_H
-#define GRPC_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_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 8ff1688..0000000
--- a/src/core/support/string.h
+++ /dev/null
@@ -1,121 +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_CORE_SUPPORT_STRING_H
-#define GRPC_CORE_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_SUPPORT_STRING_H */
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
deleted file mode 100644
index 0780907..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 <stdarg.h>
-#include <stdio.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 c9ae8d9..0000000
--- a/src/core/support/string_win32.h
+++ /dev/null
@@ -1,47 +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_CORE_SUPPORT_STRING_WIN32_H
-#define GRPC_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_CORE_SUPPORT_STRING_WIN32_H */
diff --git a/src/core/support/subprocess_windows.c b/src/core/support/subprocess_windows.c
deleted file mode 100644
index 6afbefe..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 <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/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_posix.c b/src/core/support/sync_posix.c
deleted file mode 100644
index be4d0ac..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 <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-#include <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 33b904e..0000000
--- a/src/core/support/thd_internal.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_CORE_SUPPORT_THD_INTERNAL_H
-#define GRPC_CORE_SUPPORT_THD_INTERNAL_H
-
-/* Internal interfaces between modules within the gpr support library.  */
-
-#endif /* GRPC_CORE_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
deleted file mode 100644
index f999e08..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 <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/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 871c99a..0000000
--- a/src/core/support/time_precise.h
+++ /dev/null
@@ -1,42 +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_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_H */
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
deleted file mode 100644
index 2c344d3..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 <limits.h>
-#include <process.h>
-#include <src/core/support/time_precise.h>
-#include <sys/timeb.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 df6f869..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_CORE_SUPPORT_TMPFILE_H
-#define GRPC_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_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 1085285..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 <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include "src/core/iomgr/timer.h"
-#include "src/core/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/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 af53829..0000000
--- a/src/core/surface/api_trace.h
+++ /dev/null
@@ -1,65 +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_CORE_SURFACE_API_TRACE_H
-#define GRPC_CORE_SURFACE_API_TRACE_H
-
-#include <grpc/support/log.h>
-#include "src/core/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_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 4a418fa..0000000
--- a/src/core/surface/byte_buffer_reader.c
+++ /dev/null
@@ -1,123 +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/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/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 6f1cd1d..0000000
--- a/src/core/surface/call.c
+++ /dev/null
@@ -1,1491 +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; }
-
-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/surface/call.h b/src/core/surface/call.h
deleted file mode 100644
index d2edf03..0000000
--- a/src/core/surface/call.h
+++ /dev/null
@@ -1,116 +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_CORE_SURFACE_CALL_H
-#define GRPC_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>
-#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_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 0442116..0000000
--- a/src/core/surface/call_log_batch.c
+++ /dev/null
@@ -1,118 +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/call.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-#include "src/core/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/surface/call_test_only.h b/src/core/surface/call_test_only.h
deleted file mode 100644
index fdc43a3..0000000
--- a/src/core/surface/call_test_only.h
+++ /dev/null
@@ -1,64 +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_CORE_SURFACE_CALL_TEST_ONLY_H
-#define GRPC_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_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 0010b64..0000000
--- a/src/core/surface/channel.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 "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/channel_init.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(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/surface/channel.h b/src/core/surface/channel.h
deleted file mode 100644
index 6a803ff..0000000
--- a/src/core/surface/channel.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_CORE_SURFACE_CHANNEL_H
-#define GRPC_CORE_SURFACE_CHANNEL_H
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/client_config/subchannel_factory.h"
-#include "src/core/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_SURFACE_CHANNEL_H */
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
deleted file mode 100644
index 1826793..0000000
--- a/src/core/surface/channel_connectivity.c
+++ /dev/null
@@ -1,207 +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/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;
-  }
-  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/surface/channel_create.c b/src/core/surface/channel_create.c
deleted file mode 100644
index 123447c..0000000
--- a/src/core/surface/channel_create.c
+++ /dev/null
@@ -1,223 +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;
-  } 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/surface/channel_init.c b/src/core/surface/channel_init.c
deleted file mode 100644
index ac962f3..0000000
--- a/src/core/surface/channel_init.c
+++ /dev/null
@@ -1,146 +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/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/surface/channel_init.h b/src/core/surface/channel_init.h
deleted file mode 100644
index 06faef6..0000000
--- a/src/core/surface/channel_init.h
+++ /dev/null
@@ -1,86 +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_CORE_SURFACE_CHANNEL_INIT_H
-#define GRPC_CORE_SURFACE_CHANNEL_INIT_H
-
-#include "src/core/channel/channel_stack_builder.h"
-#include "src/core/surface/channel_stack_type.h"
-#include "src/core/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_SURFACE_CHANNEL_INIT_H */
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/channel_stack_type.c b/src/core/surface/channel_stack_type.c
deleted file mode 100644
index 1a6e949..0000000
--- a/src/core/surface/channel_stack_type.c
+++ /dev/null
@@ -1,54 +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/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/surface/channel_stack_type.h b/src/core/surface/channel_stack_type.h
deleted file mode 100644
index 75a1b9c..0000000
--- a/src/core/surface/channel_stack_type.h
+++ /dev/null
@@ -1,58 +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_CORE_SURFACE_CHANNEL_STACK_TYPE_H
-#define GRPC_CORE_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_SURFACE_CHANNEL_STACK_TYPE_H */
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
deleted file mode 100644
index b22818e..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;
-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/surface/completion_queue.h b/src/core/surface/completion_queue.h
deleted file mode 100644
index 213d89c..0000000
--- a/src/core/surface/completion_queue.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_SURFACE_COMPLETION_QUEUE_H
-#define GRPC_CORE_SURFACE_COMPLETION_QUEUE_H
-
-/* Internal API for completion queues */
-
-#include <grpc/grpc.h>
-#include "src/core/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_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 85a372b..0000000
--- a/src/core/surface/event_string.c
+++ /dev/null
@@ -1,81 +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/event_string.h"
-
-#include <stdio.h>
-
-#include <grpc/byte_buffer.h>
-#include <grpc/support/string_util.h>
-#include "src/core/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/surface/event_string.h b/src/core/surface/event_string.h
deleted file mode 100644
index d0598ce..0000000
--- a/src/core/surface/event_string.h
+++ /dev/null
@@ -1,42 +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_CORE_SURFACE_EVENT_STRING_H
-#define GRPC_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_CORE_SURFACE_EVENT_STRING_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
deleted file mode 100644
index 3c4db3e..0000000
--- a/src/core/surface/init.c
+++ /dev/null
@@ -1,239 +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 <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/census/grpc_plugin.h"
-#include "src/core/channel/channel_stack.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/client_config/lb_policies/pick_first.h"
-#include "src/core/client_config/lb_policies/round_robin.h"
-#include "src/core/client_config/lb_policy_registry.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/channel_init.h"
-#include "src/core/surface/completion_queue.h"
-#include "src/core/surface/init.h"
-#include "src/core/surface/lame_client.h"
-#include "src/core/surface/server.h"
-#include "src/core/surface/surface_trace.h"
-#include "src/core/transport/chttp2_transport.h"
-#include "src/core/transport/connectivity_state.h"
-#include "src/core/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/surface/init.h b/src/core/surface/init.h
deleted file mode 100644
index 5e358c7..0000000
--- a/src/core/surface/init.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_CORE_SURFACE_INIT_H
-#define GRPC_CORE_SURFACE_INIT_H
-
-void grpc_register_security_filters(void);
-void grpc_security_pre_init(void);
-int grpc_is_initialized(void);
-
-#endif /* GRPC_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 e0d66a8..0000000
--- a/src/core/surface/init_secure.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.
- *
- */
-
-#include "src/core/surface/init.h"
-
-#include <limits.h>
-#include <string.h>
-
-#include "src/core/debug/trace.h"
-#include "src/core/security/auth_filters.h"
-#include "src/core/security/credentials.h"
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/security/security_connector.h"
-#include "src/core/surface/channel_init.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);
-}
-
-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/surface/init_unsecure.c b/src/core/surface/init_unsecure.c
deleted file mode 100644
index 278fcc8..0000000
--- a/src/core/surface/init_unsecure.c
+++ /dev/null
@@ -1,38 +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/init.h"
-
-void grpc_security_pre_init(void) {}
-
-void grpc_register_security_filters(void) {}
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
deleted file mode 100644
index 25f3a74..0000000
--- a/src/core/surface/lame_client.c
+++ /dev/null
@@ -1,155 +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/lame_client.h"
-
-#include <grpc/grpc.h>
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.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/call.h"
-#include "src/core/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/surface/lame_client.h b/src/core/surface/lame_client.h
deleted file mode 100644
index 3f3abd2..0000000
--- a/src/core/surface/lame_client.h
+++ /dev/null
@@ -1,41 +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_CORE_SURFACE_LAME_CLIENT_H
-#define GRPC_CORE_SURFACE_LAME_CLIENT_H
-
-#include "src/core/channel/channel_stack.h"
-
-extern const grpc_channel_filter grpc_lame_filter;
-
-#endif /* GRPC_CORE_SURFACE_LAME_CLIENT_H */
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 cc75222..0000000
--- a/src/core/surface/secure_channel_create.c
+++ /dev/null
@@ -1,319 +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/channel/channel_args.h"
-#include "src/core/channel/client_channel.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;
-  }
-  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_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);
-
-  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/surface/server.c b/src/core/surface/server.c
deleted file mode 100644
index a92f2b3..0000000
--- a/src/core/surface/server.c
+++ /dev/null
@@ -1,1319 +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/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 {
-  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/surface/server.h b/src/core/surface/server.h
deleted file mode 100644
index cd62ead..0000000
--- a/src/core/surface/server.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_CORE_SURFACE_SERVER_H
-#define GRPC_CORE_SURFACE_SERVER_H
-
-#include <grpc/grpc.h>
-#include "src/core/channel/channel_stack.h"
-#include "src/core/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_SURFACE_SERVER_H */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
deleted file mode 100644
index 546760e..0000000
--- a/src/core/surface/server_chttp2.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 <grpc/grpc.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.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"
-
-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/surface/surface_trace.h b/src/core/surface/surface_trace.h
deleted file mode 100644
index a55a88e..0000000
--- a/src/core/surface/surface_trace.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_SURFACE_SURFACE_TRACE_H
-#define GRPC_CORE_SURFACE_SURFACE_TRACE_H
-
-#include <grpc/support/log.h>
-#include "src/core/debug/trace.h"
-#include "src/core/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_SURFACE_SURFACE_TRACE_H */
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 ab42d07..0000000
--- a/src/core/transport/byte_stream.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TRANSPORT_BYTE_STREAM_H
-#define GRPC_CORE_TRANSPORT_BYTE_STREAM_H
-
-#include <grpc/support/slice_buffer.h>
-#include "src/core/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_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 68010e3..0000000
--- a/src/core/transport/chttp2/alpn.h
+++ /dev/null
@@ -1,49 +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_CORE_TRANSPORT_CHTTP2_ALPN_H
-#define GRPC_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_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 3d31162..0000000
--- a/src/core/transport/chttp2/bin_encoder.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/transport/chttp2/bin_encoder.h"
-
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include "src/core/transport/chttp2/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/transport/chttp2/bin_encoder.h b/src/core/transport/chttp2/bin_encoder.h
deleted file mode 100644
index edb6f2d..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_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H
-#define GRPC_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_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 560a667..0000000
--- a/src/core/transport/chttp2/frame.h
+++ /dev/null
@@ -1,69 +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_CORE_TRANSPORT_CHTTP2_FRAME_H
-#define GRPC_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_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 6cc6d4e..0000000
--- a/src/core/transport/chttp2/frame_data.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/transport/chttp2/frame_data.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/internal.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 9dbaa60..0000000
--- a/src/core/transport/chttp2/frame_data.h
+++ /dev/null
@@ -1,101 +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_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_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/iomgr/exec_ctx.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_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 b980e47..0000000
--- a/src/core/transport/chttp2/frame_goaway.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/transport/chttp2/frame.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_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 2412cd7..0000000
--- a/src/core/transport/chttp2/frame_ping.h
+++ /dev/null
@@ -1,56 +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_CORE_TRANSPORT_CHTTP2_FRAME_PING_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_PING_H
-
-#include <grpc/support/slice.h>
-#include "src/core/iomgr/exec_ctx.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_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 f725c5d..0000000
--- a/src/core/transport/chttp2/frame_rst_stream.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_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H
-
-#include <grpc/support/slice.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/transport/chttp2/frame.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_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 59dbff9..0000000
--- a/src/core/transport/chttp2/frame_settings.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_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/transport/chttp2/frame.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_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 9b7ca3c..0000000
--- a/src/core/transport/chttp2/frame_window_update.h
+++ /dev/null
@@ -1,56 +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_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
-
-#include <grpc/support/slice.h>
-#include "src/core/iomgr/exec_ctx.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_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 6d86eb7..0000000
--- a/src/core/transport/chttp2/hpack_encoder.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_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/transport/metadata.h"
-#include "src/core/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_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 b6e3692..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 <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/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 6a6d136..0000000
--- a/src/core/transport/chttp2/hpack_parser.h
+++ /dev/null
@@ -1,116 +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_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H
-#define GRPC_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_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 c984ca3..0000000
--- a/src/core/transport/chttp2/hpack_table.h
+++ /dev/null
@@ -1,108 +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_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include "src/core/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_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 4290df3..0000000
--- a/src/core/transport/chttp2/http2_errors.h
+++ /dev/null
@@ -1,56 +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_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H
-#define GRPC_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_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 ebc85d3..0000000
--- a/src/core/transport/chttp2/huffsyms.c
+++ /dev/null
@@ -1,105 +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/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 9c4f09d..0000000
--- a/src/core/transport/chttp2/huffsyms.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H
-#define GRPC_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_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 52454f3..0000000
--- a/src/core/transport/chttp2/incoming_metadata.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TRANSPORT_CHTTP2_INCOMING_METADATA_H
-#define GRPC_CORE_TRANSPORT_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_CORE_TRANSPORT_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 0690cb3..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_CORE_TRANSPORT_CHTTP2_INTERNAL_H
-#define GRPC_CORE_TRANSPORT_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 /* GRPC_CORE_TRANSPORT_CHTTP2_INTERNAL_H */
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 c6e066b..0000000
--- a/src/core/transport/chttp2/status_conversion.h
+++ /dev/null
@@ -1,50 +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_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H
-#define GRPC_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_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 957a58a..0000000
--- a/src/core/transport/chttp2/stream_map.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H
-#define GRPC_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_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 c4802e0..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_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/transport/chttp2/timeout_encoding.h b/src/core/transport/chttp2/timeout_encoding.h
deleted file mode 100644
index f8e2522..0000000
--- a/src/core/transport/chttp2/timeout_encoding.h
+++ /dev/null
@@ -1,47 +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_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H
-#define GRPC_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H
-
-#include <grpc/support/time.h>
-#include "src/core/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_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 7ab9d22..0000000
--- a/src/core/transport/chttp2/varint.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_CORE_TRANSPORT_CHTTP2_VARINT_H
-#define GRPC_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_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 b45bf31..0000000
--- a/src/core/transport/chttp2_transport.c
+++ /dev/null
@@ -1,1785 +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 {
-      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/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
deleted file mode 100644
index 9a6cf0e..0000000
--- a/src/core/transport/chttp2_transport.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_CORE_TRANSPORT_CHTTP2_TRANSPORT_H
-#define GRPC_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_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 b4a3ce9..0000000
--- a/src/core/transport/connectivity_state.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_CORE_TRANSPORT_CONNECTIVITY_STATE_H
-#define GRPC_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_CORE_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
deleted file mode 100644
index 7ed28fe..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/iomgr/iomgr_internal.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"
-
-/* 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 5ab3978..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_CORE_TRANSPORT_METADATA_H
-#define GRPC_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_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 9337b28..0000000
--- a/src/core/transport/metadata_batch.h
+++ /dev/null
@@ -1,125 +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_CORE_TRANSPORT_METADATA_BATCH_H
-#define GRPC_CORE_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/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_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
deleted file mode 100644
index 30bbb89..0000000
--- a/src/core/transport/static_metadata.c
+++ /dev/null
@@ -1,160 +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, 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/transport/static_metadata.h b/src/core/transport/static_metadata.h
deleted file mode 100644
index 85442f8..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_CORE_TRANSPORT_STATIC_METADATA_H
-#define GRPC_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_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 f43e56f..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_CORE_TRANSPORT_TRANSPORT_H
-#define GRPC_CORE_TRANSPORT_TRANSPORT_H
-
-#include <stddef.h>
-
-#include "src/core/channel/context.h"
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/pollset_set.h"
-#include "src/core/transport/byte_stream.h"
-#include "src/core/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_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
deleted file mode 100644
index d9ecc4d..0000000
--- a/src/core/transport/transport_impl.h
+++ /dev/null
@@ -1,81 +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_CORE_TRANSPORT_TRANSPORT_IMPL_H
-#define GRPC_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) */
-
-  /* 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_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 8453412..0000000
--- a/src/core/transport/transport_op_string.c
+++ /dev/null
@@ -1,140 +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/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/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/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
deleted file mode 100644
index c0106f7..0000000
--- a/src/core/tsi/fake_transport_security.c
+++ /dev/null
@@ -1,527 +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/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 6b8e596..0000000
--- a/src/core/tsi/fake_transport_security.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_CORE_TSI_FAKE_TRANSPORT_SECURITY_H
-#define GRPC_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_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 8df5826..0000000
--- a/src/core/tsi/ssl_transport_security.c
+++ /dev/null
@@ -1,1536 +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/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/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, 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/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
deleted file mode 100644
index 612f5c6..0000000
--- a/src/core/tsi/ssl_transport_security.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_CORE_TSI_SSL_TRANSPORT_SECURITY_H
-#define GRPC_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_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_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 6ea85fe..0000000
--- a/src/core/tsi/ssl_types.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_CORE_TSI_SSL_TYPES_H
-#define GRPC_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 /* GRPC_CORE_TSI_SSL_TYPES_H */
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 ecc0371..0000000
--- a/src/core/tsi/transport_security.h
+++ /dev/null
@@ -1,111 +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_CORE_TSI_TRANSPORT_SECURITY_H
-#define GRPC_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_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 0850180..0000000
--- a/src/core/tsi/transport_security_interface.h
+++ /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.
- *
- */
-
-#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H
-#define GRPC_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_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */
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 db636a5..de8b2db 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -41,7 +41,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.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/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/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 45e9e27..33a8f75 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -46,7 +46,7 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/slice_buffer.h>
 
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 
 namespace {
 
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/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_context.cc b/src/cpp/server/server_context.cc
index 5d12ce2..0422650 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -42,8 +42,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/channel/compress_filter.h"
-#include "src/core/surface/call.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 {
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/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/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/src/client.js b/src/node/src/client.js
index 2459e28..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');
 
@@ -353,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();
     };
@@ -375,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();
@@ -395,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 {
@@ -414,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(
@@ -440,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] =
@@ -481,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 {
@@ -500,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);
     });
@@ -533,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();
@@ -595,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] =
@@ -643,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:
@@ -654,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
@@ -703,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);
   });
@@ -761,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/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 edbfc0a..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')),
@@ -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/private/GRPCReachabilityFlagNames.xmacro.h b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
index 02871d5..4b92504 100644
--- a/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
+++ b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
@@ -54,7 +54,9 @@
        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)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 27cd8d6..3c57ad7 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -30,211 +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/backoff.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/census/grpc_plugin.c',
-  'src/core/channel/channel_args.c',
-  'src/core/channel/channel_stack.c',
-  'src/core/channel/channel_stack_builder.c',
-  'src/core/channel/client_channel.c',
-  'src/core/channel/compress_filter.c',
-  'src/core/channel/connected_channel.c',
-  'src/core/channel/http_client_filter.c',
-  'src/core/channel/http_server_filter.c',
-  'src/core/channel/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/http/format_request.c',
-  'src/core/http/httpcli.c',
-  'src/core/http/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/unix_sockets_posix.c',
-  'src/core/iomgr/unix_sockets_posix_noop.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_init.c',
-  'src/core/surface/channel_ping.c',
-  'src/core/surface/channel_stack_type.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/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/http/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/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/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index db7cac3..9b617e1 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -50,21 +50,18 @@
 }
 
 VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
-  size_t length = 0;
-  char *string = NULL;
-  size_t offset = 0;
+  VALUE rb_string;
   grpc_byte_buffer_reader reader;
   gpr_slice next;
   if (buffer == NULL) {
     return Qnil;
-
   }
-  length = grpc_byte_buffer_length(buffer);
-  string = xmalloc(length + 1);
+  rb_string = rb_str_buf_new(grpc_byte_buffer_length(buffer));
   grpc_byte_buffer_reader_init(&reader, buffer);
   while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
-    memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
-    offset += GPR_SLICE_LENGTH(next);
+    rb_str_cat(rb_string, (const char *) GPR_SLICE_START_PTR(next),
+               GPR_SLICE_LENGTH(next));
+    gpr_slice_unref(next);
   }
-  return rb_str_new(string, length);
+  return rb_string;
 }
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index cd0aa6a..b0829ef 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -551,13 +551,26 @@
 /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
  * cleaned up */
 static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
+  size_t i = 0;
+
   grpc_metadata_array_destroy(&st->send_metadata);
   grpc_metadata_array_destroy(&st->send_trailing_metadata);
   grpc_metadata_array_destroy(&st->recv_metadata);
   grpc_metadata_array_destroy(&st->recv_trailing_metadata);
+
   if (st->recv_status_details != NULL) {
     gpr_free(st->recv_status_details);
   }
+
+  if (st->recv_message != NULL) {
+    grpc_byte_buffer_destroy(st->recv_message);
+  }
+
+  for (i = 0; i < st->op_num; i++) {
+    if (st->ops[i].op == GRPC_OP_SEND_MESSAGE) {
+      grpc_byte_buffer_destroy(st->ops[i].data.send_message);
+    }
+  }
 }
 
 /* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
@@ -643,7 +656,6 @@
         break;
       case GRPC_OP_SEND_MESSAGE:
         rb_struct_aset(result, sym_send_message, Qtrue);
-        grpc_byte_buffer_destroy(st->ops[i].data.send_message);
         break;
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
         rb_struct_aset(result, sym_send_close, Qtrue);
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/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/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/tools/dockerfile/clang_update.include b/templates/tools/dockerfile/clang_update.include
index 83ab3e0..4f827c8 100644
--- a/templates/tools/dockerfile/clang_update.include
+++ b/templates/tools/dockerfile/clang_update.include
@@ -1,5 +1,5 @@
 #=================
-# Update clang to a version with improved tsan
+# Update clang to a version with improved tsan and fuzzing capabilities
 
 RUN apt-get update && apt-get -y install python cmake && apt-get clean
 
@@ -29,4 +29,4 @@
   -DCMAKE_INSTALL_PREFIX:STRING=/usr ${'\\'}
   -DLLVM_TARGETS_TO_BUILD:STRING=X86 ${'\\'}
   ../llvm
-RUN make -C llvm-build && make -C llvm-build install && rm -rf llvm-build
+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/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/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/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index c7130f9..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/support/string.h"
-#include "src/core/surface/completion_queue.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/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>
diff --git a/test/core/bad_client/tests/badreq.c b/test/core/bad_client/tests/badreq.c
index 95d46d5..fd3d13f 100644
--- a/test/core/bad_client/tests/badreq.c
+++ b/test/core/bad_client/tests/badreq.c
@@ -35,7 +35,7 @@
 
 #include <string.h>
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define PFX_STR                      \
diff --git a/test/core/bad_client/tests/connection_prefix.c b/test/core/bad_client/tests/connection_prefix.c
index 000ecca..87826af 100644
--- a/test/core/bad_client/tests/connection_prefix.c
+++ b/test/core/bad_client/tests/connection_prefix.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
 
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
diff --git a/test/core/bad_client/tests/headers.c b/test/core/bad_client/tests/headers.c
index 4ecdb64..f66f14d 100644
--- a/test/core/bad_client/tests/headers.c
+++ b/test/core/bad_client/tests/headers.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
 
 #define PFX_STR                      \
diff --git a/test/core/bad_client/tests/initial_settings_frame.c b/test/core/bad_client/tests/initial_settings_frame.c
index 2104892..b303f03 100644
--- a/test/core/bad_client/tests/initial_settings_frame.c
+++ b/test/core/bad_client/tests/initial_settings_frame.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
 
 #define PFX_STR "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
diff --git a/test/core/bad_client/tests/server_registered_method.c b/test/core/bad_client/tests/server_registered_method.c
index d280804..c35457c 100644
--- a/test/core/bad_client/tests/server_registered_method.c
+++ b/test/core/bad_client/tests/server_registered_method.c
@@ -35,7 +35,7 @@
 
 #include <string.h>
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define PFX_STR                                               \
diff --git a/test/core/bad_client/tests/simple_request.c b/test/core/bad_client/tests/simple_request.c
index e535be1..6cb44ee 100644
--- a/test/core/bad_client/tests/simple_request.c
+++ b/test/core/bad_client/tests/simple_request.c
@@ -35,7 +35,7 @@
 
 #include <string.h>
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define PFX_STR                                                            \
diff --git a/test/core/bad_client/tests/unknown_frame.c b/test/core/bad_client/tests/unknown_frame.c
index 729a6d9..44d1e35 100644
--- a/test/core/bad_client/tests/unknown_frame.c
+++ b/test/core/bad_client/tests/unknown_frame.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
 
 #define PFX_STR                      \
diff --git a/test/core/bad_client/tests/window_overflow.c b/test/core/bad_client/tests/window_overflow.c
index a9117de..b6d0101 100644
--- a/test/core/bad_client/tests/window_overflow.c
+++ b/test/core/bad_client/tests/window_overflow.c
@@ -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"                                       \
diff --git a/test/core/bad_ssl/bad_ssl_test.c b/test/core/bad_ssl/bad_ssl_test.c
index e2babfa..013b8ea 100644
--- a/test/core/bad_ssl/bad_ssl_test.c
+++ b/test/core/bad_ssl/bad_ssl_test.c
@@ -41,8 +41,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/subprocess.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/end2end/cq_verifier.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
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 000ac73..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>
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 c4c288d..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>
 
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c
index 91fa63e..bc7040d 100644
--- a/test/core/client_config/lb_policies_test.c
+++ b/test/core/client_config/lb_policies_test.c
@@ -41,13 +41,13 @@
 #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"
@@ -873,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;
@@ -882,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 */
@@ -936,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
index 75d1eb6..dc6a614 100644
--- a/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
@@ -31,15 +31,15 @@
  *
  */
 
-#include "src/core/client_config/resolvers/dns_resolver.h"
+#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/iomgr/resolve_address.h"
-#include "src/core/iomgr/timer.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) {}
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/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 3687f7c..baf8e8e 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -44,8 +44,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/support/string.h"
-#include "src/core/surface/event_string.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 77589a7..7501df9 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -39,9 +39,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/support/string.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"
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index 4d89a8f..9d091d5 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -41,13 +41,13 @@
 #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/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 "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 19a2495..8d8d5e7 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -41,13 +41,13 @@
 #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/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 "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 8be8e35..7386691 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -39,8 +39,8 @@
 #include <grpc/support/alloc.h>
 #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/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"
diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c
index f2d72f0..e238023 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+pipe.c
@@ -41,13 +41,13 @@
 #include <grpc/support/sync.h>
 #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/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/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+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
index c84bd72..f1b4c5d 100644
--- a/test/core/end2end/fixtures/h2_full+trace.c
+++ b/test/core/end2end/fixtures/h2_full+trace.c
@@ -41,13 +41,13 @@
 #include <grpc/support/sync.h>
 #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/support/env.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/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"
 
diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c
index c56d2fc..cd88ed2 100644
--- a/test/core/end2end/fixtures/h2_full.c
+++ b/test/core/end2end/fixtures/h2_full.c
@@ -41,12 +41,12 @@
 #include <grpc/support/sync.h>
 #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/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/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 279061b..ee188cc 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -39,9 +39,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include "src/core/channel/channel_args.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/security/credentials.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"
diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c
index 1e9aa62..299e44e 100644
--- a/test/core/end2end/fixtures/h2_proxy.c
+++ b/test/core/end2end/fixtures/h2_proxy.c
@@ -41,12 +41,12 @@
 #include <grpc/support/sync.h>
 #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/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/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 3306872..5fc8b32 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -40,17 +40,17 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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/support/env.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/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"
 
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index d64c85a..739e553 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -40,16 +40,16 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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 "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"
 
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 67180a5..f5312ca 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -40,16 +40,16 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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 "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"
 
diff --git a/test/core/end2end/fixtures/h2_ssl+poll.c b/test/core/end2end/fixtures/h2_ssl+poll.c
index 4c3bc64..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/string.h"
-#include "src/core/support/tmpfile.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 6a4e8dc..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/string.h"
-#include "src/core/support/tmpfile.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 f5fcb91..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/string.h"
-#include "src/core/support/tmpfile.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_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 3228c05..cc0d6bf 100644
--- a/test/core/end2end/fixtures/h2_uds.c
+++ b/test/core/end2end/fixtures/h2_uds.c
@@ -44,13 +44,13 @@
 #include <grpc/support/sync.h>
 #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/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/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/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index fe7a275..e8c07ac 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
@@ -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/call_creds.c b/test/core/end2end/tests/call_creds.c
index 417f7e8..f749a60 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -42,8 +42,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.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"
 #include "test/core/end2end/cq_verifier.h"
 
 static const char iam_token[] = "token";
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index 135bdf0..e5a1556 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index c9092e3..9c25885 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -43,9 +43,9 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/surface/call_test_only.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"
 
 enum { TIMEOUT = 200000 };
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index 5455428..576d81e 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 53b5ca5..7f56313 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index 7200782..2196fbd 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -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 };
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index 1891318..2774e50 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -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; }
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index 5de82c9..e5031af 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index 4051ded..09f452f 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index f480009..433622e 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -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 };
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index a7d1661..d3ac2d5 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index a8ed793..bc634ef 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -42,7 +42,7 @@
 #include <grpc/support/log.h>
 #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 };
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 ff3d919..2807504 100644
--- a/test/core/fling/fling_stream_test.c
+++ b/test/core/fling/fling_stream_test.c
@@ -47,7 +47,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.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/fling_test.c b/test/core/fling/fling_test.c
index 4e16b7f..46456a2 100644
--- a/test/core/fling/fling_test.c
+++ b/test/core/fling/fling_test.c
@@ -38,7 +38,7 @@
 #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
index 5e2b709..a676420 100644
--- a/test/core/http/format_request_test.c
+++ b/test/core/http/format_request_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/http/format_request.h"
+#include "src/core/lib/http/format_request.h"
 
 #include <string.h>
 
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
index bdb7a02..1fdbcd0 100644
--- a/test/core/http/httpcli_test.c
+++ b/test/core/http/httpcli_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/http/httpcli.h"
+#include "src/core/lib/http/httpcli.h"
 
 #include <string.h>
 
@@ -41,7 +41,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
index 21845b6..71db3e7 100644
--- a/test/core/http/httpscli_test.c
+++ b/test/core/http/httpscli_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/http/httpcli.h"
+#include "src/core/lib/http/httpcli.h"
 
 #include <string.h>
 
@@ -41,7 +41,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/http/parser_test.c b/test/core/http/parser_test.c
index 338a301..149919d 100644
--- a/test/core/http/parser_test.c
+++ b/test/core/http/parser_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/http/parser.h"
+#include "src/core/lib/http/parser.h"
 
 #include <stdarg.h>
 #include <string.h>
@@ -178,6 +178,37 @@
   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,
@@ -186,6 +217,10 @@
 
   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"
diff --git a/test/core/http/test_server.py b/test/core/http/test_server.py
index ecde494..9f8d052 100755
--- a/test/core/http/test_server.py
+++ b/test/core/http/test_server.py
@@ -36,8 +36,8 @@
 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'))
+_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()
 
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 c38f509..aae94e7 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -35,8 +35,8 @@
 
 #include <grpc/support/log.h>
 
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
 int main(int argc, char **argv) {
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 b2a0997..7aec91a 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -31,11 +31,11 @@
  *
  */
 
-#include "src/core/iomgr/resolve_address.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/iomgr/executor.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 dd23a99..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>
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 955bf44..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>
 
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 042e936..0c55ef0 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -31,13 +31,13 @@
  *
  */
 
-#include "src/core/iomgr/udp_server.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/iomgr/iomgr.h"
-#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
 #include "test/core/util/test_config.h"
 
 #include <netinet/in.h>
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 1916d4b..33fc98e 100644
--- a/test/core/json/json_rewrite_test.c
+++ b/test/core/json/json_rewrite_test.c
@@ -39,8 +39,8 @@
 #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 3b07fcd..630e1b0 100644
--- a/test/core/json/json_stream_error_test.c
+++ b/test/core/json/json_stream_error_test.c
@@ -39,8 +39,8 @@
 #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 e9b81e2..13ee5bb 100644
--- a/test/core/json/json_test.c
+++ b/test/core/json/json_test.c
@@ -37,8 +37,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
-#include "src/core/json/json.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/support/string.h"
 
 #include "test/core/util/test_config.h"
 
@@ -64,6 +64,7 @@
     /* 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. */
     {
         " [ [ ] , { } , [ ] ] ", "[[],{},[]]",
@@ -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 7ed3372..b8c6954 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.c
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -55,7 +55,7 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/iomgr/socket_utils_posix.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 3a6b969..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/http/httpcli.h"
-#include "src/core/security/json_token.h"
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
-#include "src/core/support/tmpfile.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. -- */
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 d2f8d1d..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/http/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>
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 31a56ea..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/string.h"
-#include "src/core/support/tmpfile.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) {
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 7cbb0c0..fef8e9e 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/statistics/census_log.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>
diff --git a/test/core/statistics/census_stub_test.c b/test/core/statistics/census_stub_test.c
index e734a34..df5d25b 100644
--- a/test/core/statistics/census_stub_test.c
+++ b/test/core/statistics/census_stub_test.c
@@ -36,8 +36,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.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 7ff5bb7..903d297 100644
--- a/test/core/statistics/hash_table_test.c
+++ b/test/core/statistics/hash_table_test.c
@@ -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 <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include "src/core/support/murmur_hash.h"
-#include "src/core/support/string.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) {
diff --git a/test/core/statistics/rpc_stats_test.c b/test/core/statistics/rpc_stats_test.c
index 3ece3ca..dc2f70b 100644
--- a/test/core/statistics/rpc_stats_test.c
+++ b/test/core/statistics/rpc_stats_test.c
@@ -39,9 +39,9 @@
 #include <grpc/support/string.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/statistics/census_tracing.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 2c64e89..2cc3ddd 100644
--- a/test/core/statistics/trace_test.c
+++ b/test/core/statistics/trace_test.c
@@ -41,9 +41,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_tracing.h"
-#include "src/core/statistics/census_tracing.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 9ed7ee1..ed0d7bb 100644
--- a/test/core/statistics/window_stats_test.c
+++ b/test/core/statistics/window_stats_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/statistics/window_stats.h"
+#include "src/core/lib/statistics/window_stats.h"
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <stdlib.h>
diff --git a/test/core/support/backoff_test.c b/test/core/support/backoff_test.c
index 870b60b..13cba7d 100644
--- a/test/core/support/backoff_test.c
+++ b/test/core/support/backoff_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/support/backoff.h"
+#include "src/core/lib/support/backoff.h"
 
 #include <grpc/support/log.h>
 
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 a14fdc6..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/string.h"
-#include "src/core/support/tmpfile.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)
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/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
index c8aacdb..629bce9 100644
--- a/test/core/surface/byte_buffer_reader_test.c
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -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 4f534de..fa9b363 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -31,14 +31,14 @@
  *
  */
 
-#include "src/core/surface/completion_queue.h"
+#include "src/core/lib/surface/completion_queue.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/iomgr/iomgr.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/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 815b03c..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>
 
@@ -41,7 +41,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include "src/core/support/string.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 f5de087..818ce09 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.c
+++ b/test/core/transport/chttp2/hpack_encoder_test.c
@@ -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 <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/hpack_parser.h"
-#include "src/core/transport/metadata.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 4c0fa2e..6a2dadf 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/hpack_table.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -41,7 +41,7 @@
 #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 b7dd60e..7cc698e 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/timeout_encoding.h"
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -40,7 +40,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.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/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 667d3f0..49b5b8b 100644
--- a/test/core/tsi/transport_security_test.c
+++ b/test/core/tsi/transport_security_test.c
@@ -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 {
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index d211016..fea7e52 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -49,8 +49,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/http/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
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index c7b9d63..ea01b46 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -47,7 +47,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/http/httpcli.h"
+#include "src/core/lib/http/httpcli.h"
 
 typedef struct freereq {
   gpr_mu *mu;
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
index 4cbedc0..081782d 100644
--- a/test/core/util/port_windows.c
+++ b/test/core/util/port_windows.c
@@ -46,9 +46,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/http/httpcli.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/env.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
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 f408048..7ffaa6f 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -39,7 +39,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 
 double g_fixture_slowdown_factor = 1.0;
 
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/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc
index 4c6dd60..4b5cf02 100644
--- a/test/cpp/common/auth_property_iterator_test.cc
+++ b/test/cpp/common/auth_property_iterator_test.cc
@@ -38,7 +38,7 @@
 #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 123d494..c421910 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -38,7 +38,7 @@
 #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 dc8c2bb..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;
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 4759818..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"
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/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 114d715..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();
+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_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 514d4fa..2fcd9f3 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -46,7 +46,7 @@
 #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/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 f0fccf4..f1fb3c9 100644
--- a/test/cpp/interop/interop_test.cc
+++ b/test/cpp/interop/interop_test.cc
@@ -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/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/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 6c05799..6cca7de 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -45,7 +45,7 @@
 #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"
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/distrib/node/run_distrib_test.sh b/test/distrib/node/run_distrib_test.sh
index 9b8f157..13a42fc 100755
--- a/test/distrib/node/run_distrib_test.sh
+++ b/test/distrib/node/run_distrib_test.sh
@@ -28,23 +28,31 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+function finish() {
+  rv=$?
+  kill $STATIC_PID || true
+  curl "localhost:32767/drop/$STATIC_PORT" || true
+  exit $rv
+}
+
+trap finish EXIT
+
 NODE_VERSION=$1
 source ~/.nvm/nvm.sh
-set -ex
 
 cd $(dirname $0)
 
 nvm install $NODE_VERSION
+set -ex
 
 npm install -g node-static
 
-# Kill off existing static servers
-kill -9 $(ps aux | grep '[n]ode .*static' | awk '{print $2}') || true
-
 STATIC_SERVER=127.0.0.1
-STATIC_PORT=8080
+# If port_server is running, get port from that. Otherwise, assume we're in
+# docker and use 8080
+STATIC_PORT=$(curl 'localhost:32767/get' || echo '8080')
 
-# Serves the input_artifacts directory statically at localhost:8080
+# Serves the input_artifacts directory statically at localhost:
 static "$EXTERNAL_GIT_ROOT/input_artifacts" -a $STATIC_SERVER -p $STATIC_PORT &
 STATIC_PID=$!
 
@@ -52,6 +60,4 @@
 
 npm install --unsafe-perm $STATIC_URL/grpc.tgz --grpc_node_binary_host_mirror=$STATIC_URL
 
-kill -9 $STATIC_PID
-
 ./distrib_test.js
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/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 593baec..70d4141 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -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_include_guards.py b/tools/distrib/check_include_guards.py
index 977f40e..463e316 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -167,7 +167,7 @@
 args = argp.parse_args()
 
 KNOWN_BAD = set([
-    'src/core/proto/grpc/lb/v0/load_balancer.pb.h',
+    'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h',
 ])
 
 
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index 51c4d75..e0a6094 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -60,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/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 b848f23..6c7aece 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -68,7 +68,7 @@
 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
+# Update clang to a version with improved tsan and fuzzing capabilities
 
 RUN apt-get update && apt-get -y install python cmake && apt-get clean
 
@@ -98,7 +98,7 @@
   -DCMAKE_INSTALL_PREFIX:STRING=/usr \
   -DLLVM_TARGETS_TO_BUILD:STRING=X86 \
   ../llvm
-RUN make -C llvm-build && make -C llvm-build install && rm -rf llvm-build
+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
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/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 253262c..fe7962b 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -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,38 +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/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++/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 134b16f..30bf7bf 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -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,52 +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/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 \
+src/cpp/client/create_channel_internal.h \
 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/cpp/client/create_channel_internal.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 \
@@ -857,14 +850,21 @@
 src/cpp/client/credentials.cc \
 src/cpp/client/generic_stub.cc \
 src/cpp/client/insecure_credentials.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/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 \
@@ -873,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/codegen_init.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 e326adc..55f4ffe 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -760,19 +760,33 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h \
-include/grpc/byte_buffer.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/status.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/census.h \
+include/grpc/status.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_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 5044ed2..bb7177f 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -760,324 +760,338 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h \
-include/grpc/byte_buffer.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/status.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/census.h \
-src/core/census/grpc_filter.h \
-src/core/census/grpc_plugin.h \
-src/core/channel/channel_args.h \
-src/core/channel/channel_stack.h \
-src/core/channel/channel_stack_builder.h \
-src/core/channel/client_channel.h \
-src/core/channel/compress_filter.h \
-src/core/channel/connected_channel.h \
-src/core/channel/context.h \
-src/core/channel/http_client_filter.h \
-src/core/channel/http_server_filter.h \
-src/core/channel/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/http/format_request.h \
-src/core/http/httpcli.h \
-src/core/http/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/unix_sockets_posix.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/channel_init.h \
-src/core/surface/channel_stack_type.h \
-src/core/surface/completion_queue.h \
-src/core/surface/event_string.h \
-src/core/surface/init.h \
-src/core/surface/lame_client.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 \
+include/grpc/status.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/census/grpc_plugin.c \
-src/core/channel/channel_args.c \
-src/core/channel/channel_stack.c \
-src/core/channel/channel_stack_builder.c \
-src/core/channel/client_channel.c \
-src/core/channel/compress_filter.c \
-src/core/channel/connected_channel.c \
-src/core/channel/http_client_filter.c \
-src/core/channel/http_server_filter.c \
-src/core/channel/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/http/format_request.c \
-src/core/http/httpcli.c \
-src/core/http/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/unix_sockets_posix.c \
-src/core/iomgr/unix_sockets_posix_noop.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_init.c \
-src/core/surface/channel_ping.c \
-src/core/surface/channel_stack_type.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/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/http/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 \
@@ -1106,76 +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/backoff.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/backoff.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/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_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/run_tests/build_artifact_node.sh b/tools/run_tests/build_artifact_node.sh
index 6aa4824..ef3476a 100755
--- a/tools/run_tests/build_artifact_node.sh
+++ b/tools/run_tests/build_artifact_node.sh
@@ -30,9 +30,9 @@
 
 NODE_TARGET_ARCH=$1
 source ~/.nvm/nvm.sh
-set -ex
 
 nvm use 4
+set -ex
 
 cd $(dirname $0)/../..
 
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/build_artifact_python.sh
index 7ba04d7..1f23f9f 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -35,15 +35,18 @@
 if [ "$SKIP_PIP_INSTALL" == "" ]
 then
   pip install --upgrade six
-  pip install --upgrade setuptools
+  # There's a bug in newer versions of setuptools (see
+  # https://bitbucket.org/pypa/setuptools/issues/503/pkg_resources_vendorpackagingrequirementsi)
+  pip install --upgrade 'setuptools==18'
   pip install -rrequirements.txt
 fi
 
+export GRPC_PYTHON_USE_CUSTOM_BDIST=0
+export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+
 # Build the source distribution first because MANIFEST.in cannot override
 # exclusion of built shared objects among package resources (for some
 # inexplicable reason).
-GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
-GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
 ${SETARCH_CMD} python setup.py  \
     sdist
 
@@ -51,15 +54,11 @@
 # and thus ought to be run in a shell command separate of others. Further, it
 # trashes the actual bdist_wheel output, so it should be run first so that
 # bdist_wheel may be run unmolested.
-GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
-GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
 ${SETARCH_CMD} python setup.py  \
     build_tagged_ext
 
 # Wheel has a bug where directories don't get excluded.
 # https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
-GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
-GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
 ${SETARCH_CMD} python setup.py  \
     bdist_wheel
 
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index 9c4af07..cbe0e31 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -31,9 +31,9 @@
 
 NODE_VERSION=$1
 source ~/.nvm/nvm.sh
-set -ex
 
 nvm use $NODE_VERSION
+set -ex
 
 CONFIG=${CONFIG:-opt}
 
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/build_package_node.sh
index aca90a3..540c826 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -29,9 +29,9 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 source ~/.nvm/nvm.sh
-set -ex
 
 nvm use 4
+set -ex
 
 cd $(dirname $0)/../..
 
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 a858170..325e9aa 100644
--- a/tools/run_tests/configs.json
+++ b/tools/run_tests/configs.json
@@ -3,6 +3,14 @@
     "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"
   }, 
   {
diff --git a/tools/run_tests/pre_build_node.sh b/tools/run_tests/pre_build_node.sh
index 11f46d6..1f55df0 100755
--- a/tools/run_tests/pre_build_node.sh
+++ b/tools/run_tests/pre_build_node.sh
@@ -31,9 +31,9 @@
 
 NODE_VERSION=$1
 source ~/.nvm/nvm.sh
-set -ex
 
 nvm use $NODE_VERSION
+set -ex
 
 export GRPC_CONFIG=${CONFIG:-opt}
 
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index d338900..b94dc3e 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -30,9 +30,9 @@
 
 NODE_VERSION=$1
 source ~/.nvm/nvm.sh
-set -ex
 
 nvm use $NODE_VERSION
+set -ex
 
 CONFIG=${CONFIG:-opt}
 
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 dc11c0b..71bb7b1 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -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():
@@ -183,7 +188,7 @@
                                               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],
@@ -191,7 +196,7 @@
                                           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)
@@ -464,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:
@@ -511,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']]
 
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/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 06dc6d0..d7c9839 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -891,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"
@@ -923,6 +939,22 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "http_fuzzer_test", 
+    "src": [
+      "test/core/http/fuzzer.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "http_parser_test", 
     "src": [
       "test/core/http/parser_test.c"
@@ -1013,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": [], 
@@ -1544,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"
@@ -3772,18 +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/backoff.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", 
@@ -3830,62 +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/backoff.c", 
-      "src/core/support/backoff.h", 
-      "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"
@@ -3924,143 +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/grpc_plugin.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/channel_stack_builder.h", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/compress_filter.h", 
-      "src/core/channel/connected_channel.h", 
-      "src/core/channel/context.h", 
-      "src/core/channel/http_client_filter.h", 
-      "src/core/channel/http_server_filter.h", 
-      "src/core/channel/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/http/format_request.h", 
-      "src/core/http/httpcli.h", 
-      "src/core/http/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/unix_sockets_posix.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/channel_init.h", 
-      "src/core/surface/channel_stack_type.h", 
-      "src/core/surface/completion_queue.h", 
-      "src/core/surface/event_string.h", 
-      "src/core/surface/init.h", 
-      "src/core/surface/lame_client.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", 
@@ -4082,304 +4146,304 @@
       "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/grpc_plugin.c", 
-      "src/core/census/grpc_plugin.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/channel_stack_builder.c", 
-      "src/core/channel/channel_stack_builder.h", 
-      "src/core/channel/client_channel.c", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/compress_filter.c", 
-      "src/core/channel/compress_filter.h", 
-      "src/core/channel/connected_channel.c", 
-      "src/core/channel/connected_channel.h", 
-      "src/core/channel/context.h", 
-      "src/core/channel/http_client_filter.c", 
-      "src/core/channel/http_client_filter.h", 
-      "src/core/channel/http_server_filter.c", 
-      "src/core/channel/http_server_filter.h", 
-      "src/core/channel/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/http/format_request.c", 
-      "src/core/http/format_request.h", 
-      "src/core/http/httpcli.c", 
-      "src/core/http/httpcli.h", 
-      "src/core/http/httpcli_security_connector.c", 
-      "src/core/http/parser.c", 
-      "src/core/http/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/unix_sockets_posix.c", 
-      "src/core/iomgr/unix_sockets_posix.h", 
-      "src/core/iomgr/unix_sockets_posix_noop.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_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_init.c", 
-      "src/core/surface/channel_init.h", 
-      "src/core/surface/channel_ping.c", 
-      "src/core/surface/channel_stack_type.c", 
-      "src/core/surface/channel_stack_type.h", 
-      "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/lame_client.h", 
-      "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/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"
@@ -4552,129 +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/grpc_plugin.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/channel_stack_builder.h", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/compress_filter.h", 
-      "src/core/channel/connected_channel.h", 
-      "src/core/channel/context.h", 
-      "src/core/channel/http_client_filter.h", 
-      "src/core/channel/http_server_filter.h", 
-      "src/core/channel/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/http/format_request.h", 
-      "src/core/http/httpcli.h", 
-      "src/core/http/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/unix_sockets_posix.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/channel_init.h", 
-      "src/core/surface/channel_stack_type.h", 
-      "src/core/surface/completion_queue.h", 
-      "src/core/surface/event_string.h", 
-      "src/core/surface/init.h", 
-      "src/core/surface/lame_client.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", 
@@ -4695,270 +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/grpc_plugin.c", 
-      "src/core/census/grpc_plugin.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/channel_stack_builder.c", 
-      "src/core/channel/channel_stack_builder.h", 
-      "src/core/channel/client_channel.c", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/compress_filter.c", 
-      "src/core/channel/compress_filter.h", 
-      "src/core/channel/connected_channel.c", 
-      "src/core/channel/connected_channel.h", 
-      "src/core/channel/context.h", 
-      "src/core/channel/http_client_filter.c", 
-      "src/core/channel/http_client_filter.h", 
-      "src/core/channel/http_server_filter.c", 
-      "src/core/channel/http_server_filter.h", 
-      "src/core/channel/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/http/format_request.c", 
-      "src/core/http/format_request.h", 
-      "src/core/http/httpcli.c", 
-      "src/core/http/httpcli.h", 
-      "src/core/http/parser.c", 
-      "src/core/http/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/unix_sockets_posix.c", 
-      "src/core/iomgr/unix_sockets_posix.h", 
-      "src/core/iomgr/unix_sockets_posix_noop.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_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_init.c", 
-      "src/core/surface/channel_init.h", 
-      "src/core/surface/channel_ping.c", 
-      "src/core/surface/channel_stack_type.c", 
-      "src/core/surface/channel_stack_type.h", 
-      "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/lame_client.h", 
-      "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/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"
@@ -4970,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"
@@ -5104,7 +5168,6 @@
       "src/cpp/client/create_channel_internal.h", 
       "src/cpp/client/secure_credentials.h", 
       "src/cpp/common/core_codegen.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", 
@@ -5205,7 +5268,6 @@
       "src/cpp/common/completion_queue.cc", 
       "src/cpp/common/core_codegen.cc", 
       "src/cpp/common/core_codegen.h", 
-      "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", 
diff --git a/tools/run_tests/stress_test/README.md b/tools/run_tests/stress_test/README.md
index 1a48e90..84f9719 100644
--- a/tools/run_tests/stress_test/README.md
+++ b/tools/run_tests/stress_test/README.md
@@ -67,8 +67,10 @@
   - `<grpc_root_dir>$ tools/run_tests/stress_test/run_stress_tests_on_gke.py --help`

 

 > **Example**

-> `$ tools/run_tests/stress_test/run_stress_tests_on_gke.py --project_id=sree-gce --test_duration_secs=180 --num_clients=5`

+> ```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

+> ```

 

-> Launches the 5 instances of stress test clients, 1 instance of stress test server and runs the test for 180 seconds. The test would be run on the default container cluster (that you have set in `gcloud`) in the project `sree-gce`.

-

-> Note: we currently do not have the ability to launch multiple instances of the server. This can be added very easily in future

+> 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/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/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/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj
index 9281fa3..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,123 +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\backoff.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\backoff.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\backoff.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cmdline.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cmdline.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_iphone.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_iphone.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\histogram.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\histogram.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\host_port.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\host_port.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\load_file.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\load_file.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_android.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_android.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\murmur_hash.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice_buffer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\stack_lockfree.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_precise.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_precise.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tls_pthread.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tls_pthread.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\wrap_memcpy.c">
+    <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 b85060f..b932420 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
@@ -1,140 +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\backoff.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\cmdline.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_iphone.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_linux.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_posix.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\cpu_windows.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_linux.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_posix.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\env_win32.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\histogram.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\host_port.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\load_file.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.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_android.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_linux.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_posix.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\log_win32.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\murmur_hash.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.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\slice_buffer.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\stack_lockfree.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.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_posix.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\string_win32.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_posix.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\subprocess_windows.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.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_posix.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\sync_win32.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.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_posix.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\thd_win32.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.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_posix.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_precise.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\time_win32.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\tls_pthread.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_posix.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\tmpfile_win32.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\support\wrap_memcpy.c">
-      <Filter>src\core\support</Filter>
+    <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>
@@ -219,85 +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\backoff.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\block_annotate.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\env.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\load_file.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\murmur_hash.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\stack_lockfree.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.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\string_win32.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\thd_internal.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\time_precise.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\support\tmpfile.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\tmpfile.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
   </ItemGroup>
 
@@ -323,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 d29e689..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,62 +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\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" />
   </ItemGroup>
   <ItemGroup>
+    <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\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\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">
@@ -372,6 +359,12 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
+    <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">
@@ -380,6 +373,12 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.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\async_generic_service.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\create_default_thread_pool.cc">
@@ -388,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">
@@ -406,8 +407,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.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 c9b3bb9..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,6 +22,15 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
+    <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">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -52,6 +43,15 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.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\async_generic_service.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -64,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>
@@ -91,9 +94,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
-      <Filter>src\cpp\codegen</Filter>
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
@@ -126,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>
@@ -228,114 +321,12 @@
     <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\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>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h">
+    <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\secure_auth_context.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">
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\core_codegen.h">
@@ -344,9 +335,15 @@
     <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>
diff --git a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj
index de2526b..fa56d2a 100644
--- a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj
+++ b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj
@@ -147,26 +147,6 @@
   </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\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\async_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
@@ -198,6 +178,26 @@
     <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">
diff --git a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters
index 3cc0082..3259e98 100644
--- a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters
@@ -6,66 +6,6 @@
     </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\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\async_stream.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
@@ -159,6 +99,66 @@
     <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>
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 3d1aee0..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,37 +333,6 @@
     <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\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" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
@@ -342,8 +342,6 @@
     <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">
@@ -358,12 +356,16 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
+    <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\core_codegen.cc">
     </ClCompile>
+    <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">
@@ -392,8 +394,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.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 70a23bf..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,6 +22,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_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\channel_arguments.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -34,6 +34,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <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>
@@ -76,9 +79,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
-      <Filter>src\cpp\codegen</Filter>
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
@@ -111,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>
@@ -213,99 +306,6 @@
     <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\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>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index ebc3674..c20f8d7 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -267,485 +267,485 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
     <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\grpc_security.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\census\grpc_plugin.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\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.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\http\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\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\unix_sockets_posix.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\channel_init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel_stack_type.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\lame_client.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\census\grpc_plugin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\secure\server_secure_chttp2.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack_builder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\format_request.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\httpcli.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.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_epoll.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\unix_sockets_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\unix_sockets_posix_noop.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_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_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_init.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\channel_stack_type.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.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\http\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 e5bff0e..f03b207 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -1,488 +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\census\grpc_plugin.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\channel\channel_args.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\channel_stack.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\channel_stack_builder.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\client_channel.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\compress_filter.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\connected_channel.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_client_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\http_server_filter.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\subchannel_call_holder.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\client_config\client_config.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\connector.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\default_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\initial_connect_string.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\lb_policies\load_balancer_api.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\pick_first.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_policies\round_robin.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_policy.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_factory.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\lb_policy_registry.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.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_factory.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_registry.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\resolvers\dns_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\resolvers\sockaddr_resolver.c">
-      <Filter>src\core\client_config\resolvers</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.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_factory.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\subchannel_index.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\uri_parser.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\compression\compression_algorithm.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\compression\message_compress.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.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\tracing.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\format_request.c">
-      <Filter>src\core\http</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\httpcli.c">
-      <Filter>src\core\http</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\parser.c">
-      <Filter>src\core\http</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\closure.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.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_posix.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_pair_windows.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\exec_ctx.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\executor.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\fd_posix.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\iocp_windows.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.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_posix.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_windows.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_epoll.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_multipoller_with_poll_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_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_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_set_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\pollset_windows.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_posix.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\resolve_address_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\sockaddr_utils.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_common_posix.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_linux.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_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_windows.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_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\tcp_client_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_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_posix.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_server_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\tcp_windows.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\time_averaged_stats.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.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\timer_heap.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\udp_server.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\unix_sockets_posix.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\unix_sockets_posix_noop.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_eventfd.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\wakeup_fd_nospecial.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\wakeup_fd_pipe.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\wakeup_fd_posix.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\workqueue_posix.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\workqueue_windows.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\json\json.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_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_multipoller_with_epoll.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_multipoller_with_poll_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_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_posix.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_set_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\pollset_windows.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_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\resolve_address_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\sockaddr_utils.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_common_posix.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_linux.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_utils_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\socket_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_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_init.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\channel_stack_type.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\completion_queue.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\event_string.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\init.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\lame_client.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\metadata_array.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.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_chttp2.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\http\httpcli_security_connector.c">
-      <Filter>src\core\http</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>
@@ -495,22 +495,22 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
-      <Filter>include\grpc</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\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">
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
@@ -531,421 +531,421 @@
     <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\census\grpc_plugin.h">
-      <Filter>src\core\census</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_args.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\channel_stack.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\channel_stack_builder.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\client_channel.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\compress_filter.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\connected_channel.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\context.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_client_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\http_server_filter.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\channel\subchannel_call_holder.h">
-      <Filter>src\core\channel</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\client_config.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\connector.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\initial_connect_string.h">
-      <Filter>src\core\client_config</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\load_balancer_api.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\pick_first.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_policies\round_robin.h">
-      <Filter>src\core\client_config\lb_policies</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.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_factory.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\lb_policy_registry.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.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_factory.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\resolver_registry.h">
-      <Filter>src\core\client_config</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\dns_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\resolvers\sockaddr_resolver.h">
-      <Filter>src\core\client_config\resolvers</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.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_factory.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\subchannel_index.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\client_config\uri_parser.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.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\compress_filter.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\connected_channel.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\context.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\format_request.h">
-      <Filter>src\core\http</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\httpcli.h">
-      <Filter>src\core\http</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\parser.h">
-      <Filter>src\core\http</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\closure.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.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\endpoint_pair.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\exec_ctx.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\executor.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\fd_posix.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\iocp_windows.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.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_internal.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\iomgr_posix.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.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_posix.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.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_posix.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_set_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\pollset_windows.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\resolve_address.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.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_posix.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_utils.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\sockaddr_win32.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_utils_posix.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\socket_windows.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_client.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_posix.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_server.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\tcp_windows.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\time_averaged_stats.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.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\timer_heap.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\udp_server.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\unix_sockets_posix.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\wakeup_fd_pipe.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\wakeup_fd_posix.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\workqueue.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\workqueue_posix.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\workqueue_windows.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\json\json.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.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\pollset_set_windows.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\pollset_windows.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\resolve_address.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.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\sockaddr_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\sockaddr_utils.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\sockaddr_win32.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\socket_utils_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\socket_windows.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_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel_init.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\channel_stack_type.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\completion_queue.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\event_string.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\init.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\lame_client.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>
@@ -980,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\http">
-      <UniqueIdentifier>{404fdb9e-a69c-81d4-035b-465c826115a9}</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
index a6a5a85..7d7a609 100644
--- a/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj
+++ b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj
@@ -152,21 +152,21 @@
     <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" />
-    <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" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\vsprojects\dummy.c">
diff --git a/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters
index be1e623..891dff0 100644
--- a/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters
@@ -16,18 +16,36 @@
     <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>
@@ -43,24 +61,6 @@
     <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>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 487ffe0..668f8a5 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -147,11 +147,11 @@
   </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" />
@@ -159,20 +159,20 @@
     <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">
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 68c75e8..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>
@@ -42,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>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 4f2336a..e89cc8a 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -260,428 +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\census\grpc_plugin.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\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.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\http\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\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\unix_sockets_posix.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\channel_init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel_stack_type.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\lame_client.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\census\grpc_plugin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack_builder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\format_request.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\httpcli.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\unix_sockets_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\unix_sockets_posix_noop.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_init.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\channel_stack_type.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.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 e31ece7..c9f1ad6 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -1,428 +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\census\grpc_plugin.c">
-      <Filter>src\core\census</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_args.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\channel_stack.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\channel_stack_builder.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\client_channel.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\compress_filter.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\connected_channel.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_client_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\http_server_filter.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\channel\subchannel_call_holder.c">
-      <Filter>src\core\channel</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\client_config.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\connector.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\default_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\initial_connect_string.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_policies\load_balancer_api.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\pick_first.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_policies\round_robin.c">
-      <Filter>src\core\client_config\lb_policies</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.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_factory.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\lb_policy_registry.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.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_factory.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\resolver_registry.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\resolvers\dns_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\resolvers\sockaddr_resolver.c">
-      <Filter>src\core\client_config\resolvers</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.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_factory.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\subchannel_index.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\client_config\uri_parser.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.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\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.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_builder.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\format_request.c">
-      <Filter>src\core\http</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\httpcli.c">
-      <Filter>src\core\http</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\http\parser.c">
-      <Filter>src\core\http</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.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\http_client_filter.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_server_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\subchannel_call_holder.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\client_config\client_config.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.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\executor.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\fd_posix.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\iocp_windows.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.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_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\iomgr_windows.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_epoll.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_multipoller_with_poll_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_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_posix.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_set_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\pollset_windows.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_posix.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\resolve_address_windows.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\sockaddr_utils.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_common_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\socket_utils_linux.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_utils_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\socket_windows.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_posix.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_client_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\tcp_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_posix.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_server_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\tcp_windows.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\time_averaged_stats.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\timer.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\timer_heap.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\udp_server.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\unix_sockets_posix.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\unix_sockets_posix_noop.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\wakeup_fd_eventfd.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_nospecial.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_pipe.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_posix.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\workqueue_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_windows.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\json\json.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\json\json_reader.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_string.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_writer.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\proto\grpc\lb\v0\load_balancer.pb.c">
-      <Filter>src\core\proto\grpc\lb\v0</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\alarm.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\api_trace.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\byte_buffer.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_reader.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\call.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_details.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_log_batch.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.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_connectivity.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_create.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_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\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\channel_stack_type.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\completion_queue.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\event_string.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\init.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\lame_client.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\metadata_array.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.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_chttp2.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>
@@ -441,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>
@@ -468,379 +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\census\grpc_plugin.h">
-      <Filter>src\core\census</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_args.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\channel_stack.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\channel_stack_builder.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\client_channel.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\compress_filter.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\connected_channel.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\context.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_client_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\http_server_filter.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\channel\subchannel_call_holder.h">
-      <Filter>src\core\channel</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\client_config.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\connector.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\initial_connect_string.h">
-      <Filter>src\core\client_config</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\load_balancer_api.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\pick_first.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_policies\round_robin.h">
-      <Filter>src\core\client_config\lb_policies</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.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_factory.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\lb_policy_registry.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.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_factory.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\resolver_registry.h">
-      <Filter>src\core\client_config</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\dns_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\resolvers\sockaddr_resolver.h">
-      <Filter>src\core\client_config\resolvers</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.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_factory.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\subchannel_index.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\client_config\uri_parser.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.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\compress_filter.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\connected_channel.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\context.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\format_request.h">
-      <Filter>src\core\http</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\httpcli.h">
-      <Filter>src\core\http</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\http\parser.h">
-      <Filter>src\core\http</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\closure.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.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\endpoint_pair.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\exec_ctx.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\executor.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\fd_posix.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\iocp_windows.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.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_internal.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\iomgr_posix.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.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_posix.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.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_posix.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_set_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\pollset_windows.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\resolve_address.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.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_posix.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_utils.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\sockaddr_win32.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_utils_posix.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\socket_windows.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_client.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_posix.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_server.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\tcp_windows.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\time_averaged_stats.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.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\timer_heap.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\udp_server.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\unix_sockets_posix.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\wakeup_fd_pipe.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\wakeup_fd_posix.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\workqueue.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\workqueue_posix.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\workqueue_windows.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\json\json.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.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\pollset_set_windows.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\pollset_windows.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\resolve_address.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.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\sockaddr_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\sockaddr_utils.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\sockaddr_win32.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\socket_utils_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\socket_windows.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_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel_init.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\channel_stack_type.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\completion_queue.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\event_string.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\init.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\lame_client.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>
@@ -875,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\http">
-      <UniqueIdentifier>{46faed8e-5cd4-98b0-05ed-ff2ac7bc2d46}</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/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 f3b311b..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">
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>