diff --git a/BUILD b/BUILD
index dccb0e425707104649de3c40728eaf33fb5bff6e..a19631e6df608f6955bfb5a63f86e6a5a78563ba 100644
--- a/BUILD
+++ b/BUILD
@@ -665,6 +665,7 @@ cc_library(
     "src/cpp/proto/proto_utils.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
+    "src/cpp/server/dynamic_thread_pool.cc",
     "src/cpp/server/fixed_size_thread_pool.cc",
     "src/cpp/server/insecure_server_credentials.cc",
     "src/cpp/server/server.cc",
@@ -690,6 +691,7 @@ cc_library(
     "include/grpc++/config_protobuf.h",
     "include/grpc++/create_channel.h",
     "include/grpc++/credentials.h",
+    "include/grpc++/dynamic_thread_pool.h",
     "include/grpc++/fixed_size_thread_pool.h",
     "include/grpc++/generic_stub.h",
     "include/grpc++/impl/call.h",
@@ -750,6 +752,7 @@ cc_library(
     "src/cpp/proto/proto_utils.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
+    "src/cpp/server/dynamic_thread_pool.cc",
     "src/cpp/server/fixed_size_thread_pool.cc",
     "src/cpp/server/insecure_server_credentials.cc",
     "src/cpp/server/server.cc",
@@ -775,6 +778,7 @@ cc_library(
     "include/grpc++/config_protobuf.h",
     "include/grpc++/create_channel.h",
     "include/grpc++/credentials.h",
+    "include/grpc++/dynamic_thread_pool.h",
     "include/grpc++/fixed_size_thread_pool.h",
     "include/grpc++/generic_stub.h",
     "include/grpc++/impl/call.h",
diff --git a/Makefile b/Makefile
index 083c01aaacb64418c8ac5779c1421c114d563a6c..996fcfa1fc4aaa23fb97586223d315f331db400f 100644
--- a/Makefile
+++ b/Makefile
@@ -851,6 +851,7 @@ credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
 cxx_byte_buffer_test: $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test
 cxx_slice_test: $(BINDIR)/$(CONFIG)/cxx_slice_test
 cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
+dynamic_thread_pool_test: $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
 fixed_size_thread_pool_test: $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
@@ -1532,7 +1533,7 @@ buildtests: buildtests_c buildtests_cxx
 
 buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test
 
 test: test_c test_cxx
 
@@ -2803,6 +2804,8 @@ test_cxx: buildtests_cxx
 	$(Q) $(BINDIR)/$(CONFIG)/cxx_slice_test || ( echo test cxx_slice_test failed ; exit 1 )
 	$(E) "[RUN]     Testing cxx_time_test"
 	$(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 )
+	$(E) "[RUN]     Testing dynamic_thread_pool_test"
+	$(Q) $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test || ( echo test dynamic_thread_pool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing fixed_size_thread_pool_test"
@@ -3943,6 +3946,7 @@ LIBGRPC++_SRC = \
     src/cpp/proto/proto_utils.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
+    src/cpp/server/dynamic_thread_pool.cc \
     src/cpp/server/fixed_size_thread_pool.cc \
     src/cpp/server/insecure_server_credentials.cc \
     src/cpp/server/server.cc \
@@ -3968,6 +3972,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpc++/config_protobuf.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/dynamic_thread_pool.h \
     include/grpc++/fixed_size_thread_pool.h \
     include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
@@ -4119,7 +4124,6 @@ LIBGRPC++_TEST_UTIL_SRC = \
     $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \
     test/cpp/util/cli_call.cc \
     test/cpp/util/create_test_channel.cc \
-    test/cpp/util/fake_credentials.cc \
     test/cpp/util/subprocess.cc \
 
 
@@ -4166,7 +4170,6 @@ endif
 endif
 $(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/fake_credentials.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
 
 
@@ -4186,6 +4189,7 @@ LIBGRPC++_UNSECURE_SRC = \
     src/cpp/proto/proto_utils.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
+    src/cpp/server/dynamic_thread_pool.cc \
     src/cpp/server/fixed_size_thread_pool.cc \
     src/cpp/server/insecure_server_credentials.cc \
     src/cpp/server/server.cc \
@@ -4211,6 +4215,7 @@ PUBLIC_HEADERS_CXX += \
     include/grpc++/config_protobuf.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/dynamic_thread_pool.h \
     include/grpc++/fixed_size_thread_pool.h \
     include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
@@ -8449,6 +8454,46 @@ endif
 endif
 
 
+DYNAMIC_THREAD_POOL_TEST_SRC = \
+    test/cpp/server/dynamic_thread_pool_test.cc \
+
+DYNAMIC_THREAD_POOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DYNAMIC_THREAD_POOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: openssl_dep_error
+
+else
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: $(PROTOBUF_DEP) $(DYNAMIC_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(DYNAMIC_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/server/dynamic_thread_pool_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_dynamic_thread_pool_test: $(DYNAMIC_THREAD_POOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(DYNAMIC_THREAD_POOL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 END2END_TEST_SRC = \
     test/cpp/end2end/end2end_test.cc \
 
diff --git a/build.json b/build.json
index f06c6cb8c5687eed6a53adf42070bf1587c96ff7..dd633070ff9f2d6d537fccc5b23fba253eb60642 100644
--- a/build.json
+++ b/build.json
@@ -43,6 +43,7 @@
         "include/grpc++/config_protobuf.h",
         "include/grpc++/create_channel.h",
         "include/grpc++/credentials.h",
+        "include/grpc++/dynamic_thread_pool.h",
         "include/grpc++/fixed_size_thread_pool.h",
         "include/grpc++/generic_stub.h",
         "include/grpc++/impl/call.h",
@@ -90,6 +91,7 @@
         "src/cpp/proto/proto_utils.cc",
         "src/cpp/server/async_generic_service.cc",
         "src/cpp/server/create_default_thread_pool.cc",
+        "src/cpp/server/dynamic_thread_pool.cc",
         "src/cpp/server/fixed_size_thread_pool.cc",
         "src/cpp/server/insecure_server_credentials.cc",
         "src/cpp/server/server.cc",
@@ -611,7 +613,6 @@
       "headers": [
         "test/cpp/util/cli_call.h",
         "test/cpp/util/create_test_channel.h",
-        "test/cpp/util/fake_credentials.h",
         "test/cpp/util/subprocess.h"
       ],
       "src": [
@@ -620,7 +621,6 @@
         "test/cpp/util/echo_duplicate.proto",
         "test/cpp/util/cli_call.cc",
         "test/cpp/util/create_test_channel.cc",
-        "test/cpp/util/fake_credentials.cc",
         "test/cpp/util/subprocess.cc"
       ],
       "deps": [
@@ -2046,6 +2046,21 @@
         "gpr"
       ]
     },
+    {
+      "name": "dynamic_thread_pool_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/server/dynamic_thread_pool_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
     {
       "name": "end2end_test",
       "build": "test",
diff --git a/include/grpc++/config.h b/include/grpc++/config.h
index 1362c0a1fa81adeeaa6704a32438907c5a6f81d3..889dc39eb7b3899e271ddf38196a19d95a451eb4 100644
--- a/include/grpc++/config.h
+++ b/include/grpc++/config.h
@@ -79,6 +79,7 @@
 
 #ifdef GRPC_CXX0X_NO_NULLPTR
 #include <memory>
+namespace grpc {
 const class {
  public:
   template <class T>
@@ -98,6 +99,7 @@ const class {
  private:
   void operator&() const = delete;
 } nullptr = {};
+}
 #endif
 
 #ifndef GRPC_CUSTOM_STRING
diff --git a/test/cpp/util/fake_credentials.h b/include/grpc++/dynamic_thread_pool.h
similarity index 60%
rename from test/cpp/util/fake_credentials.h
rename to include/grpc++/dynamic_thread_pool.h
index e1ba7bb9e4ae47fe869e4ad6897beee963c02b17..bc4e2d4d749da309e9e3c3888419bb1e6d23d492 100644
--- a/test/cpp/util/fake_credentials.h
+++ b/include/grpc++/dynamic_thread_pool.h
@@ -31,21 +31,51 @@
  *
  */
 
-#ifndef GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
-#define GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
+#ifndef GRPCXX_DYNAMIC_THREAD_POOL_H
+#define GRPCXX_DYNAMIC_THREAD_POOL_H
 
-#include <memory>
+#include <grpc++/config.h>
+
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
+#include <grpc++/thread_pool_interface.h>
+
+#include <list>
+#include <queue>
 
 namespace grpc {
-class Credentials;
-class ServerCredentials;
 
-namespace testing {
+class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface {
+ public:
+  explicit DynamicThreadPool(int reserve_threads);
+  ~DynamicThreadPool();
+
+  void Add(const std::function<void()>& callback) GRPC_OVERRIDE;
+
+ private:
+  class DynamicThread {
+  public:
+    DynamicThread(DynamicThreadPool *pool);
+    ~DynamicThread();
+  private:
+    DynamicThreadPool *pool_;
+    std::unique_ptr<grpc::thread> thd_;
+    void ThreadFunc();
+  };
+  grpc::mutex mu_;
+  grpc::condition_variable cv_;
+  grpc::condition_variable shutdown_cv_;
+  bool shutdown_;
+  std::queue<std::function<void()>> callbacks_;
+  int reserve_threads_;
+  int nthreads_;
+  int threads_waiting_;
+  std::list<DynamicThread*> dead_threads_;
 
-std::shared_ptr<Credentials> FakeTransportSecurityCredentials();
-std::shared_ptr<ServerCredentials> FakeTransportSecurityServerCredentials();
+  void ThreadFunc();
+  static void ReapThreads(std::list<DynamicThread*>* tlist);
+};
 
-}  // namespace testing
 }  // namespace grpc
 
-#endif  // GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
+#endif  // GRPCXX_DYNAMIC_THREAD_POOL_H
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index b05e4d65de547f04d462a4bf7dba8a1e2312c23b..3287b090f3597f2f4e6d771abac3bb05304d8fcf 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -452,8 +452,8 @@ char *grpc_channel_get_target(grpc_channel *channel);
     clients will want to simply pass NULL. See grpc_channel_args definition for
     more on this. The data in 'args' need only live through the invocation of
     this function. */
-grpc_channel *grpc_channel_create(const char *target,
-                                  const grpc_channel_args *args);
+grpc_channel *grpc_insecure_channel_create(const char *target,
+                                           const grpc_channel_args *args);
 
 /** Create a lame client: this client fails every operation attempted on it. */
 grpc_channel *grpc_lame_client_channel_create(const char *target);
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 4dd058063dc6ce0c912427335fd4f32b2091213e..29eddc57a867114914e52d714e3e6b0179c25b08 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -140,9 +140,6 @@ grpc_credentials *grpc_access_token_credentials_create(
 grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
                                               const char *authority_selector);
 
-/* Creates a fake transport security credentials object for testing. */
-grpc_credentials *grpc_fake_transport_security_credentials_create(void);
-
 /* --- Secure channel creation. --- */
 
 /* The caller of the secure_channel_create functions may override the target
@@ -182,10 +179,6 @@ 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);
 
-/* Creates a fake server transport security credentials object for testing. */
-grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
-    void);
-
 /* --- Server-side secure ports. --- */
 
 /* Add a HTTP2 over an encrypted link over tcp listener.
@@ -206,7 +199,6 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
 /* TODO(jboeuf): Define some well-known property names. */
 
 #define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
-#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
 #define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
 
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 4bf24e7db31b0d4b96bfe5cdf4e907d1be3c05f8..9fc8589fbb407773757173c0ab1458588cf0ccbb 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -284,19 +284,19 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       grpc_channel_args_get_compression_algorithm(args);
 
   channeld->mdstr_request_compression_algorithm_key =
-      grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY);
+      grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0);
 
   channeld->mdstr_outgoing_compression_algorithm_key =
-      grpc_mdstr_from_string(mdctx, "grpc-encoding");
+      grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
 
   for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
-    char *algorith_name;
-    GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorith_name) != 0);
+    char *algorithm_name;
+    GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
     channeld->mdelem_compression_algorithms[algo_idx] =
         grpc_mdelem_from_metadata_strings(
             mdctx,
             grpc_mdstr_ref(channeld->mdstr_outgoing_compression_algorithm_key),
-            grpc_mdstr_from_string(mdctx, algorith_name));
+            grpc_mdstr_from_string(mdctx, algorithm_name, 0));
   }
 
   GPR_ASSERT(!is_last);
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 6ae84880707d2b19d023af3ddc55870b7b5c8d3b..91125cb14953bf42e1f5f358e01f8dd331564b8a 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -233,7 +233,7 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
 
   tmp = gpr_strvec_flatten(&v, NULL);
   gpr_strvec_destroy(&v);
-  result = grpc_mdstr_from_string(mdctx, tmp);
+  result = grpc_mdstr_from_string(mdctx, tmp, 0);
   gpr_free(tmp);
 
   return result;
@@ -260,7 +260,7 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
   channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
   channeld->user_agent = grpc_mdelem_from_metadata_strings(
-      mdctx, grpc_mdstr_from_string(mdctx, "user-agent"),
+      mdctx, grpc_mdstr_from_string(mdctx, "user-agent", 0),
       user_agent_from_args(mdctx, args));
 }
 
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 7c798d2fb462ea8470ce2257d33b8f888baaee46..9d89eb9bf2a7ef622cbd6cfe3f0931bf719e32d0 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -250,9 +250,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
   channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
   channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
   channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
-  channeld->path_key = grpc_mdstr_from_string(mdctx, ":path");
-  channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority");
-  channeld->host_key = grpc_mdstr_from_string(mdctx, "host");
+  channeld->path_key = grpc_mdstr_from_string(mdctx, ":path", 0);
+  channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority", 0);
+  channeld->host_key = grpc_mdstr_from_string(mdctx, "host", 0);
   channeld->content_type =
       grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
 
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 8f634fcd7a3c090c18b5412d5b6f928db95eba8c..cc680507ffcde704d85d565fb4974d6bd3aeaa32 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -250,6 +250,7 @@ static void on_accept(void *arg, int from_iocp) {
   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
@@ -281,10 +282,26 @@ static void on_accept(void *arg, int from_iocp) {
     }
   } else {
     if (!sp->shutting_down) {
-      getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len);
-      peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name);
+      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);
+      ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
+                           peer_name_string);
       gpr_free(fd_name);
       gpr_free(peer_name_string);
     }
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 9a69f53a5a3bc554e045865b7923c3772db4b3be..e86b5430b2ca90f5d9a8389bd1ec6abad279a26c 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -80,7 +80,7 @@ static void bubble_up_error(grpc_call_element *elem, const char *error_msg) {
   channel_data *chand = elem->channel_data;
   grpc_transport_stream_op_add_cancellation(
       &calld->op, GRPC_STATUS_UNAUTHENTICATED,
-      grpc_mdstr_from_string(chand->md_ctx, error_msg));
+      grpc_mdstr_from_string(chand->md_ctx, error_msg, 0));
   grpc_call_next_op(elem, &calld->op);
 }
 
@@ -316,10 +316,10 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
           sc, "client_auth_filter");
   chand->md_ctx = metadata_context;
-  chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
-  chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
-  chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
-  chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
+  chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0);
+  chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0);
+  chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0);
+  chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0);
 }
 
 /* Destructor for channel data */
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 7f4141967d47c4ed57ea48e35f8007fc80e46530..8d40da47c179599fa3888f267aa5cb4223ab2bfc 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -52,6 +52,8 @@ typedef enum {
   GRPC_CREDENTIALS_ERROR
 } grpc_credentials_status;
 
+#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
+
 #define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
 #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
 #define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
@@ -112,6 +114,12 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
 
 /* --- grpc_credentials. --- */
 
+/* Creates a fake transport security credentials object for testing. */
+grpc_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);
+
 /* It is the caller's responsibility to gpr_free the result if not NULL. */
 char *grpc_get_well_known_google_credentials_file_path(void);
 
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index a1da8221132fa1ffb68a6e0a1b9f12a5cdac7734..12378f0066322da8320dc999be8d873e79fe8e21 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -932,7 +932,7 @@ static int prepare_application_metadata(grpc_call *call, size_t count,
     GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
     l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
                                                (const gpr_uint8 *)md->value,
-                                               md->value_length);
+                                               md->value_length, 1);
     if (!grpc_mdstr_is_legal_header(l->md->key)) {
       gpr_log(GPR_ERROR, "attempt to send invalid metadata key");
       return 0;
@@ -1203,7 +1203,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
 static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
                                           const char *description) {
   grpc_mdstr *details =
-      description ? grpc_mdstr_from_string(c->metadata_context, description)
+      description ? grpc_mdstr_from_string(c->metadata_context, description, 0)
                   : NULL;
 
   GPR_ASSERT(status != GRPC_STATUS_OK);
@@ -1497,7 +1497,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
             op->data.send_status_from_server.status_details != NULL
                 ? grpc_mdstr_from_string(
                       call->metadata_context,
-                      op->data.send_status_from_server.status_details)
+                      op->data.send_status_from_server.status_details, 0)
                 : NULL;
         req = &reqs[out++];
         req->op = GRPC_IOREQ_SEND_CLOSE;
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 4052c65cc67431f18d6be26d37276a8ef09e4ff3..583d350128747c6be648a5cad6a89661089e4a93 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -101,19 +101,19 @@ grpc_channel *grpc_channel_create_from_filters(
   /* decremented by grpc_channel_destroy */
   gpr_ref_init(&channel->refs, 1);
   channel->metadata_context = mdctx;
-  channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
+  channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0);
   channel->grpc_compression_algorithm_string =
-      grpc_mdstr_from_string(mdctx, "grpc-encoding");
-  channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
+      grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
+  channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0);
   for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
     char buf[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(i, buf);
     channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
         mdctx, GRPC_MDSTR_REF(channel->grpc_status_string),
-        grpc_mdstr_from_string(mdctx, buf));
+        grpc_mdstr_from_string(mdctx, buf, 0));
   }
-  channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
-  channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
+  channel->path_string = grpc_mdstr_from_string(mdctx, ":path", 0);
+  channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority", 0);
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = NULL;
 
@@ -167,10 +167,10 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
       channel, cq,
       grpc_mdelem_from_metadata_strings(
           channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
-          grpc_mdstr_from_string(channel->metadata_context, method)),
+          grpc_mdstr_from_string(channel->metadata_context, method, 0)),
       grpc_mdelem_from_metadata_strings(
           channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
-          grpc_mdstr_from_string(channel->metadata_context, host)),
+          grpc_mdstr_from_string(channel->metadata_context, host, 0)),
       deadline);
 }
 
@@ -179,10 +179,10 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
   registered_call *rc = gpr_malloc(sizeof(registered_call));
   rc->path = grpc_mdelem_from_metadata_strings(
       channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
-      grpc_mdstr_from_string(channel->metadata_context, method));
+      grpc_mdstr_from_string(channel->metadata_context, method, 0));
   rc->authority = grpc_mdelem_from_metadata_strings(
       channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
-      grpc_mdstr_from_string(channel->metadata_context, host));
+      grpc_mdstr_from_string(channel->metadata_context, host, 0));
   gpr_mu_lock(&channel->registered_call_mu);
   rc->next = channel->registered_calls;
   channel->registered_calls = rc;
@@ -284,7 +284,7 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
     gpr_ltoa(i, tmp);
     return grpc_mdelem_from_metadata_strings(
         channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string),
-        grpc_mdstr_from_string(channel->metadata_context, tmp));
+        grpc_mdstr_from_string(channel->metadata_context, tmp, 0));
   }
 }
 
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 778f7108fde0d31916f7a76dced4faba54a39481..1fd1855c28c825759afcff2d965fe964f37bc01b 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -151,8 +151,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
    Asynchronously: - resolve target
                    - connect to it (trying alternatives as presented)
                    - perform handshakes */
-grpc_channel *grpc_channel_create(const char *target,
-                                  const grpc_channel_args *args) {
+grpc_channel *grpc_insecure_channel_create(const char *target,
+                                           const grpc_channel_args *args) {
   grpc_channel *channel = NULL;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 7b3e412db0c5e5aec91a8acc020f7132103b20fb..f19bcbd090b00f5fb16d86d87ead647ce1824a64 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -688,8 +688,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
   GPR_ASSERT(!is_last);
   chand->server = NULL;
   chand->channel = NULL;
-  chand->path_key = grpc_mdstr_from_string(metadata_context, ":path");
-  chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
+  chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0);
+  chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0);
   chand->next = chand->prev = chand;
   chand->registered_methods = NULL;
   chand->connectivity_state = GRPC_CHANNEL_IDLE;
@@ -911,8 +911,8 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
     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(mdctx, rm->host) : NULL;
-      method = grpc_mdstr_from_string(mdctx, rm->method);
+      host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host, 0) : NULL;
+      method = grpc_mdstr_from_string(mdctx, rm->method, 0);
       hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
       for (probes = 0; chand->registered_methods[(hash + probes) % slots]
                            .server_registered_method != NULL;
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 65b31a5afdfc69b971fcbffd598520a5eb95235f..0f04169741af7a467390176ea9e1aa816a3739f3 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -441,7 +441,7 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
       gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
   mdelem = grpc_mdelem_from_metadata_strings(
       c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
-      grpc_mdstr_from_string(c->mdctx, timeout_str));
+      grpc_mdstr_from_string(c->mdctx, timeout_str, 0));
   mdelem = hpack_enc(c, mdelem, st);
   if (mdelem) GRPC_MDELEM_UNREF(mdelem);
 }
@@ -456,7 +456,7 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
                                        grpc_mdctx *ctx) {
   memset(c, 0, sizeof(*c));
   c->mdctx = ctx;
-  c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
+  c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout", 0);
 }
 
 void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 5f49b2ddd604b5e618e8357fb92cfae7d1d5f537..9f665a139d0fefc62ab1848ebaabf29a7a371386 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -230,7 +230,7 @@ static void init_transport(grpc_chttp2_transport *t,
   t->global.pings.next = t->global.pings.prev = &t->global.pings;
   t->parsing.is_client = is_client;
   t->parsing.str_grpc_timeout =
-      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
+      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0);
   t->parsing.deframe_state =
       is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
   t->writing.is_client = is_client;
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index e95b7a21f9aeb5d3f71ac06d13f9f5a62055b5f3..967fd4898c5be08ae21fa9a752a79b0ba9c5b0c8 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -309,7 +309,37 @@ static void slice_unref(void *p) {
   unlock(ctx);
 }
 
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) {
+  if (canonicalize_key) {
+    size_t len;
+    size_t i;
+    int canonical = 1;
+
+    for (i = 0; str[i]; i++) {
+      if (str[i] >= 'A' && str[i] <= 'Z') {
+        canonical = 0;
+        /* Keep going in loop just to get string length */
+      }
+    }
+    len = i;
+
+    if (canonical) {
+      return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, len);
+    } else {
+      char *copy = gpr_malloc(len);
+      grpc_mdstr *ret;
+      for (i = 0; i < len; i++) {
+        if (str[i] >= 'A' && str[i] <= 'Z') {
+          copy[i] = str[i] - 'A' + 'a';
+        } else {
+          copy[i] = str[i];
+        }
+      }
+      ret = grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)copy, len);
+      gpr_free(copy);
+      return ret;
+    }
+  }
   return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
 }
 
@@ -491,8 +521,8 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
 grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
                                       const char *value) {
   return grpc_mdelem_from_metadata_strings(ctx,
-                                           grpc_mdstr_from_string(ctx, key),
-                                           grpc_mdstr_from_string(ctx, value));
+                                           grpc_mdstr_from_string(ctx, key, 0),
+                                           grpc_mdstr_from_string(ctx, value, 0));
 }
 
 grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
@@ -504,9 +534,10 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
 grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
                                                 const char *key,
                                                 const gpr_uint8 *value,
-                                                size_t value_length) {
+                                                size_t value_length,
+                                                int canonicalize_key) {
   return grpc_mdelem_from_metadata_strings(
-      ctx, grpc_mdstr_from_string(ctx, key),
+      ctx, grpc_mdstr_from_string(ctx, key, canonicalize_key),
       grpc_mdstr_from_buffer(ctx, value, value_length));
 }
 
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 99b15322c39528226ddc9bab3e50eae2b595fe1f..15ef9bb555ee5aa80d598138a2b62b511519f8c2 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -95,7 +95,7 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
 
 /* Constructors for grpc_mdstr instances; take a variety of data types that
    clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str);
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization);
 /* Unrefs the slice. */
 grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
 grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
@@ -117,7 +117,8 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
 grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
                                                 const char *key,
                                                 const gpr_uint8 *value,
-                                                size_t value_length);
+                                                size_t value_length,
+                                                int canonicalize_key);
 
 /* Mutator and accessor for grpc_mdelem user data. The destructor function
    is used as a type tag and is checked during user_data fetch. */
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 5ad87845675f03ba65503d5b57b2a06f59155b4f..e802fa8034e3ff5fa9f4a7a7939dfe70e30f1695 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -49,7 +49,7 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
     grpc_channel_args channel_args;
     args.SetChannelArgs(&channel_args);
     return std::shared_ptr<ChannelInterface>(new Channel(
-        target, grpc_channel_create(target.c_str(), &channel_args)));
+        target, grpc_insecure_channel_create(target.c_str(), &channel_args)));
   }
 
   // InsecureCredentials should not be applied to a call.
diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc
index cc182f59f4e36d3555f1021765e036110d93b6cb..81c84474d838b5fec9863bcfef7344c69472c092 100644
--- a/src/cpp/server/create_default_thread_pool.cc
+++ b/src/cpp/server/create_default_thread_pool.cc
@@ -32,7 +32,7 @@
  */
 
 #include <grpc/support/cpu.h>
-#include <grpc++/fixed_size_thread_pool.h>
+#include <grpc++/dynamic_thread_pool.h>
 
 #ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL
 
@@ -41,7 +41,7 @@ namespace grpc {
 ThreadPoolInterface* CreateDefaultThreadPool() {
    int cores = gpr_cpu_num_cores();
    if (!cores) cores = 4;
-   return new FixedSizeThreadPool(cores);
+   return new DynamicThreadPool(cores);
 }
 
 }  // namespace grpc
diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f58d0420dfb026ec641766f59e2dddef621c3876
--- /dev/null
+++ b/src/cpp/server/dynamic_thread_pool.cc
@@ -0,0 +1,131 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
+#include <grpc++/dynamic_thread_pool.h>
+
+namespace grpc {
+DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool *pool):
+  pool_(pool),
+  thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, this)) {
+}
+DynamicThreadPool::DynamicThread::~DynamicThread() {
+  thd_->join();
+  thd_.reset();
+}
+
+void DynamicThreadPool::DynamicThread::ThreadFunc() {
+  pool_->ThreadFunc();
+  // Now that we have killed ourselves, we should reduce the thread count
+  grpc::unique_lock<grpc::mutex> lock(pool_->mu_);
+  pool_->nthreads_--;
+  // Move ourselves to dead list
+  pool_->dead_threads_.push_back(this);
+
+  if ((pool_->shutdown_) && (pool_->nthreads_ == 0)) {
+    pool_->shutdown_cv_.notify_one();
+  }
+}
+  
+void DynamicThreadPool::ThreadFunc() {
+  for (;;) {
+    // Wait until work is available or we are shutting down.
+    grpc::unique_lock<grpc::mutex> lock(mu_);
+    if (!shutdown_ && callbacks_.empty()) {
+      // If there are too many threads waiting, then quit this thread
+      if (threads_waiting_ >= reserve_threads_) {
+	break;
+      }
+      threads_waiting_++;
+      cv_.wait(lock);
+      threads_waiting_--;
+    }
+    // Drain callbacks before considering shutdown to ensure all work
+    // gets completed.
+    if (!callbacks_.empty()) {
+      auto cb = callbacks_.front();
+      callbacks_.pop();
+      lock.unlock();
+      cb();
+    } else if (shutdown_) {
+      break;
+    }
+  }
+}
+
+DynamicThreadPool::DynamicThreadPool(int reserve_threads) :
+  shutdown_(false), reserve_threads_(reserve_threads), nthreads_(0),
+  threads_waiting_(0) {
+  for (int i = 0; i < reserve_threads_; i++) {
+    grpc::lock_guard<grpc::mutex> lock(mu_);
+    nthreads_++;
+    new DynamicThread(this);
+  }
+}
+
+void DynamicThreadPool::ReapThreads(std::list<DynamicThread*>* tlist) {
+  for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) {
+    delete *t;    
+  }
+}
+  
+DynamicThreadPool::~DynamicThreadPool() {
+  grpc::unique_lock<grpc::mutex> lock(mu_);
+  shutdown_ = true;
+  cv_.notify_all();
+  while (nthreads_ != 0) {
+    shutdown_cv_.wait(lock);
+  }
+  ReapThreads(&dead_threads_);
+}
+
+void DynamicThreadPool::Add(const std::function<void()>& callback) {
+  grpc::lock_guard<grpc::mutex> lock(mu_);
+  // Add works to the callbacks list
+  callbacks_.push(callback);
+  // Increase pool size or notify as needed
+  if (threads_waiting_ == 0) {
+    // Kick off a new thread
+    nthreads_++;
+    new DynamicThread(this);
+  } else {
+    cv_.notify_one();
+  }
+  // Also use this chance to harvest dead threads
+  if (!dead_threads_.empty()) {
+    ReapThreads(&dead_threads_);
+  }
+}
+
+}  // namespace grpc
diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs
index 7edf19ed67aae36fd5023d3ef7fcf5ca603edb9b..9936cf583ca1de71c50a2dff447ccf7baa8843a2 100644
--- a/src/csharp/Grpc.Auth/GoogleCredential.cs
+++ b/src/csharp/Grpc.Auth/GoogleCredential.cs
@@ -89,17 +89,15 @@ namespace Grpc.Auth
                 return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer()));
             }
 
-            JObject o1 = JObject.Parse(File.ReadAllText(credsPath));
-            string clientEmail = o1.GetValue(ClientEmailFieldName).Value<string>();
-            string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value<string>();
-            var privateKey = ParsePrivateKeyFromString(privateKeyString);
+            JObject jsonCredentialParameters = JObject.Parse(File.ReadAllText(credsPath));
+            string clientEmail = jsonCredentialParameters.GetValue(ClientEmailFieldName).Value<string>();
+            string privateKeyString = jsonCredentialParameters.GetValue(PrivateKeyFieldName).Value<string>();
 
             var serviceCredential = new ServiceAccountCredential(
                 new ServiceAccountCredential.Initializer(clientEmail)
                 {
                     Scopes = scopes,
-                    Key = privateKey
-                });
+                }.FromPrivateKey(privateKeyString));
             return new GoogleCredential(serviceCredential);
         }
 
@@ -123,16 +121,5 @@ namespace Grpc.Auth
                 return credential;
             }
         }
-
-        private RSACryptoServiceProvider ParsePrivateKeyFromString(string base64PrivateKey)
-        {
-            // TODO(jtattermusch): temporary code to create RSACryptoServiceProvider.
-            base64PrivateKey = base64PrivateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("\n", "").Replace("-----END PRIVATE KEY-----", "");
-            RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(base64PrivateKey));
-            RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(key);
-            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
-            rsa.ImportParameters(rsaParameters);
-            return rsa;
-        }
     }
 }
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index fdec2e7bd7f839bb89a9806f59515ad25145a12e..5615ffd620b796fd46b4e14efc0ab9b3e99c9c9f 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -11,6 +11,7 @@
     <AssemblyName>Grpc.Auth</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
     <DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
+    <NuGetPackageImportStamp>9b408026</NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -34,14 +35,17 @@
     <Reference Include="BouncyCastle.Crypto">
       <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
     </Reference>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
+    <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
     </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices">
-      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
     </Reference>
-    <Reference Include="Google.Apis.Core">
-      <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+    <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
     </Reference>
     <Reference Include="Microsoft.Threading.Tasks">
       <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
@@ -52,18 +56,20 @@
     <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
       <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
     </Reference>
-    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.Extensions">
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+    <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
     </Reference>
-    <Reference Include="System.Net.Http.Primitives">
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+    <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
     </Reference>
     <Reference Include="System.Net.Http.WebRequest" />
   </ItemGroup>
@@ -73,7 +79,7 @@
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="GoogleCredential.cs" />
-    <Compile Include="OAuth2InterceptorFactory.cs" />
+    <Compile Include="OAuth2Interceptors.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -87,9 +93,11 @@
     <None Include="Grpc.Auth.nuspec" />
     <None Include="packages.config" />
   </ItemGroup>
-  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
-  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
-    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
-    <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
   </Target>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index 1262bdbdab89ad9826620347caf4afc75a9ee2c1..eeaa49aa92a5ae3d9715f88df494827bab37a5e2 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,8 +15,7 @@
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
 	<dependencies>
-	  <dependency id="BouncyCastle" version="1.7.0" />
-	  <dependency id="Google.Apis.Auth" version="1.9.1" />
+	  <dependency id="Google.Apis.Auth" version="1.9.2" />
 	  <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
similarity index 79%
rename from src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
rename to src/csharp/Grpc.Auth/OAuth2Interceptors.cs
index 420c4cb5371f67740223025d4428574ec0cdb0d8..c785ca5a16bcf09b4f91127dddc5e948129ff7dc 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
@@ -47,17 +47,31 @@ using Grpc.Core.Utils;
 
 namespace Grpc.Auth
 {
-    public static class OAuth2InterceptorFactory
+    public static class OAuth2Interceptors
     {
         /// <summary>
-        /// Creates OAuth2 interceptor.
+        /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
         /// </summary>
-        public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential)
+        public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
         {
             var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
             return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
         }
 
+        /// <summary>
+        /// Creates OAuth2 interceptor that will use given OAuth2 token.
+        /// </summary>
+        /// <param name="oauth2Token"></param>
+        /// <returns></returns>
+        public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
+        {
+            Preconditions.CheckNotNull(oauth2Token);
+            return new MetadataInterceptorDelegate((metadata) =>
+            {
+                metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
+            });
+        }
+
         /// <summary>
         /// Injects OAuth2 authorization header into initial metadata (= request headers).
         /// </summary>
@@ -97,8 +111,15 @@ namespace Grpc.Auth
             public void InterceptHeaders(Metadata metadata)
             {
                 var accessToken = GetAccessToken(CancellationToken.None);
-                metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken));
+                metadata.Add(CreateBearerTokenHeader(accessToken));
+            }
+
+            public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+            {
+                return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
             }
         }
+
+
     }
 }
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
index 966b777192f3d53ea95e7056f903c1bc009213f8..0a82bb4f16c05bec578209f2c8bf3ce369abdc3d 100644
--- a/src/csharp/Grpc.Auth/app.config
+++ b/src/csharp/Grpc.Auth/app.config
@@ -4,7 +4,7 @@
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
index 7d348872ba7ae685ea2bc81e8b1aa65dcf4b0101..29be953bf3e9bdf0e250476de7797ac888043fda 100644
--- a/src/csharp/Grpc.Auth/packages.config
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
-  <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" />
+  <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
   <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
-  <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
-  <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+  <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 8ba2c8a9a2b4667b32c70ab418db147eba5bd63e..e286ea519f9522d7c39a45e1aa9b52d9fb482ee6 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -45,7 +45,7 @@ namespace Grpc.Core.Tests
 {
     public class ClientServerTest
     {
-        const string Host = "localhost";
+        const string Host = "127.0.0.1";
         const string ServiceName = "/tests.Test";
 
         static readonly Method<string, string> EchoMethod = new Method<string, string>(
@@ -79,9 +79,9 @@ namespace Grpc.Core.Tests
         {
             server = new Server();
             server.AddServiceDefinition(ServiceDefinition);
-            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
             server.Start();
-            channel = new Channel(Host, port);
+            channel = new Channel(Host, port, Credentials.Insecure);
         }
 
         [TearDown]
@@ -158,59 +158,50 @@ namespace Grpc.Core.Tests
         }
 
         [Test]
-        public void AsyncUnaryCall_ServerHandlerThrows()
+        public async Task AsyncUnaryCall_ServerHandlerThrows()
         {
-            Task.Run(async () =>
+            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+            try
             {
-                var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
-                try
-                {
-                    await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
-                    Assert.Fail();
-                }
-                catch (RpcException e)
-                {
-                    Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
-                }
-            }).Wait();
+                await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
+                Assert.Fail();
+            }
+            catch (RpcException e)
+            {
+                Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+            }
         }
 
         [Test]
-        public void ClientStreamingCall()
+        public async Task ClientStreamingCall()
         {
-            Task.Run(async () => 
-            {
-                var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
-                var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
+            var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+            var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
 
-                await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
-                Assert.AreEqual("ABC", await call.ResponseAsync);
-            }).Wait();
+            await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
+            Assert.AreEqual("ABC", await call.ResponseAsync);
         }
 
         [Test]
-        public void ClientStreamingCall_CancelAfterBegin()
+        public async Task ClientStreamingCall_CancelAfterBegin()
         {
-            Task.Run(async () => 
-            {
-                var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
+            var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
 
-                var cts = new CancellationTokenSource();
-                var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
+            var cts = new CancellationTokenSource();
+            var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
 
-                // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
-                await Task.Delay(1000);
-                cts.Cancel();
+            // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
+            await Task.Delay(1000);
+            cts.Cancel();
 
-                try
-                {
-                    await call.ResponseAsync;
-                }
-                catch (RpcException e)
-                {
-                    Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); 
-                }
-            }).Wait();
+            try
+            {
+                await call.ResponseAsync;
+            }
+            catch (RpcException e)
+            {
+                Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+            }
         }
 
         [Test]
@@ -277,6 +268,14 @@ namespace Grpc.Core.Tests
             Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
         }
 
+        [Test]
+        public void PeerInfoPresent()
+        {
+            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
+            string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None);
+            Assert.IsTrue(peer.Contains(Host));
+        }
+
         private static async Task<string> EchoHandler(string request, ServerCallContext context)
         {
             foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
@@ -292,6 +291,11 @@ namespace Grpc.Core.Tests
                 return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
             }
 
+            if (request == "RETURN-PEER")
+            {
+                return context.Peer;
+            }
+
             if (request == "THROW")
             {
                 throw new Exception("This was thrown on purpose by a test");
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 9364779df9edc967ca3b612c0b38ff92f1960b79..1c4cca8b698e2ca2c47d1c4ec1f30998e3cbf61f 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -28,9 +28,25 @@
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="nunit.core">
+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="nunit.core.interfaces">
+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="nunit.framework">
       <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
     </Reference>
+    <Reference Include="nunit.util">
+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="NUnit.VisualStudio.TestAdapter">
+      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@@ -52,6 +68,7 @@
     <Compile Include="ChannelOptionsTest.cs" />
     <Compile Include="Internal\TimespecTest.cs" />
     <Compile Include="TimeoutsTest.cs" />
+    <Compile Include="NUnitVersionTest.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -61,7 +78,9 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <None Include="packages.config" />
+    <None Include="packages.config">
+      <SubType>Designer</SubType>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..600df1a18ddabbcb3091f66301eebf3cdf711a5d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+    /// <summary>
+    /// Tests if the version of nunit-console used is sufficient to run async tests.
+    /// </summary>
+    public class NUnitVersionTest
+    {
+        private int testRunCount = 0;
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            if (testRunCount != 2)
+            {
+                Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " +
+                "This test has failed to indicate that.");
+                Console.Error.Flush();
+                Environment.Exit(1);
+            }
+        }
+
+        [Test]
+        public void NUnitVersionTest1()
+        {
+            testRunCount++;
+        }
+
+        // Old version of NUnit will skip this test
+        [Test]
+        public async Task NUnitVersionTest2()
+        {
+            testRunCount ++;
+            await Task.Delay(10);
+        }
+
+
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index 1119aa370e59b5f5a275e5c1852b4cec80ea5e4c..ba9efae87130716cafa963ecaec4277f4835ea27 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -45,7 +45,7 @@ namespace Grpc.Core.Tests
         public void StartAndShutdownServer()
         {
             Server server = new Server();
-            server.AddListeningPort("localhost", Server.PickUnusedPort);
+            server.AddPort("localhost", Server.PickUnusedPort, ServerCredentials.Insecure);
             server.Start();
             server.ShutdownAsync().Wait();
             GrpcEnvironment.Shutdown();
diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
index c350391acdd7d73a7463c5ca53adabfff1d57188..010ffd898a01f2d6578d21684e53e5433e222869 100644
--- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
@@ -72,9 +72,9 @@ namespace Grpc.Core.Tests
         {
             server = new Server();
             server.AddServiceDefinition(ServiceDefinition);
-            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
             server.Start();
-            channel = new Channel(Host, port);
+            channel = new Channel(Host, port, Credentials.Insecure);
 
             stringFromServerHandlerTcs = new TaskCompletionSource<string>();
         }
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index 28af8d78c6c724d7c7e3dfe6f4eb1ad1a9f4f38f..62077f41beed246ba56daf239ce265fb6c097d1c 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -2,4 +2,5 @@
 <packages>
   <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
   <package id="NUnit" version="2.6.4" targetFramework="net45" />
+  <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e5c6abd2cb417e80b1b405b4f78374248122185d..18e6f2fda578ddc5f7b89958a8b1ff6c93a7abea 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -56,26 +56,24 @@ namespace Grpc.Core
         /// Port will default to 80 for an unsecure channel and to 443 a secure channel.
         /// </summary>
         /// <param name="host">The DNS name of IP address of the host.</param>
-        /// <param name="credentials">Optional credentials to create a secure channel.</param>
+        /// <param name="credentials">Credentials to secure the channel.</param>
         /// <param name="options">Channel options.</param>
-        public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
+        public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null)
         {
             this.environment = GrpcEnvironment.GetInstance();
             this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
 
             EnsureUserAgentChannelOption(this.options);
+            using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
             using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
             {
-                if (credentials != null)
+                if (nativeCredentials != null)
                 {
-                    using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
-                    {
-                        this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
-                    }
+                    this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs);
                 }
                 else
                 {
-                    this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
+                    this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs);
                 }
             }
             this.target = GetOverridenTarget(host, this.options);
@@ -86,9 +84,9 @@ namespace Grpc.Core
         /// </summary>
         /// <param name="host">DNS name or IP address</param>
         /// <param name="port">the port</param>
-        /// <param name="credentials">Optional credentials to create a secure channel.</param>
+        /// <param name="credentials">Credentials to secure the channel.</param>
         /// <param name="options">Channel options.</param>
-        public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) :
+        public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
             this(string.Format("{0}:{1}", host, port), credentials, options)
         {
         }
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs
index e64c1e3dc1da7ac16f4c06499fbb793396001bbf..4fcac0c4c00e97d6c5c25390ee1027c8912e8c0a 100644
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ b/src/csharp/Grpc.Core/Credentials.cs
@@ -41,39 +41,98 @@ namespace Grpc.Core
     /// </summary>
     public abstract class Credentials
     {
+        static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
+
+        /// <summary>
+        /// Returns instance of credential that provides no security and 
+        /// will result in creating an unsecure channel with no encryption whatsoever.
+        /// </summary>
+        public static Credentials Insecure
+        {
+            get
+            {
+                return InsecureInstance;
+            }
+        }
+
         /// <summary>
-        /// Creates native object for the credentials.
+        /// Creates native object for the credentials. May return null if insecure channel
+        /// should be created.
         /// </summary>
         /// <returns>The native credentials.</returns>
         internal abstract CredentialsSafeHandle ToNativeCredentials();
+
+        private sealed class InsecureCredentialsImpl : Credentials
+        {
+            internal override CredentialsSafeHandle ToNativeCredentials()
+            {
+                return null;
+            }
+        }
     }
 
     /// <summary>
     /// Client-side SSL credentials.
     /// </summary>
-    public class SslCredentials : Credentials
+    public sealed class SslCredentials : Credentials
     {
-        string pemRootCerts;
+        readonly string rootCertificates;
+        readonly KeyCertificatePair keyCertificatePair;
 
-        public SslCredentials(string pemRootCerts)
+        /// <summary>
+        /// Creates client-side SSL credentials loaded from
+        /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
+        /// If that fails, gets the roots certificates from a well known place on disk.
+        /// </summary>
+        public SslCredentials() : this(null, null)
         {
-            this.pemRootCerts = pemRootCerts;
+        }
+
+        /// <summary>
+        /// Creates client-side SSL credentials from
+        /// a string containing PEM encoded root certificates.
+        /// </summary>
+        public SslCredentials(string rootCertificates) : this(rootCertificates, null)
+        {
+        }
+            
+        /// <summary>
+        /// Creates client-side SSL credentials.
+        /// </summary>
+        /// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
+        /// <param name="keyCertificatePair">a key certificate pair.</param>
+        public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
+        {
+            this.rootCertificates = rootCertificates;
+            this.keyCertificatePair = keyCertificatePair;
         }
 
         /// <summary>
         /// PEM encoding of the server root certificates.
         /// </summary>
-        public string RootCerts
+        public string RootCertificates
+        {
+            get
+            {
+                return this.rootCertificates;
+            }
+        }
+
+        /// <summary>
+        /// Client side key and certificate pair.
+        /// If null, client will not use key and certificate pair.
+        /// </summary>
+        public KeyCertificatePair KeyCertificatePair
         {
             get
             {
-                return this.pemRootCerts;
+                return this.keyCertificatePair;
             }
         }
 
         internal override CredentialsSafeHandle ToNativeCredentials()
         {
-            return CredentialsSafeHandle.CreateSslCredentials(pemRootCerts);
+            return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index fd68b91851ec9d80db378a5ef2354702697aeeba..0d879e9b1e0f3e5362efeab4cd8edf8eccd942b5 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -47,7 +47,6 @@
     <Compile Include="IServerStreamWriter.cs" />
     <Compile Include="IAsyncStreamWriter.cs" />
     <Compile Include="IAsyncStreamReader.cs" />
-    <Compile Include="Internal\GrpcLog.cs" />
     <Compile Include="Version.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RpcException.cs" />
@@ -103,6 +102,11 @@
     <Compile Include="ChannelOptions.cs" />
     <Compile Include="AsyncUnaryCall.cs" />
     <Compile Include="VersionInfo.cs" />
+    <Compile Include="Internal\CStringSafeHandle.cs" />
+    <Compile Include="KeyCertificatePair.cs" />
+    <Compile Include="Logging\ILogger.cs" />
+    <Compile Include="Logging\ConsoleLogger.cs" />
+    <Compile Include="Internal\NativeLogRedirector.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Grpc.Core.nuspec" />
@@ -133,4 +137,7 @@
   </Target>
   <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
   <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
+  <ItemGroup>
+    <Folder Include="Logging\" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 47d1651aab86c9d41e4175ea2dd59d64047dca26..034a66be3c5ced2553622017e016d80ec7e33abc 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -35,6 +35,7 @@ using System;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core
@@ -55,6 +56,8 @@ namespace Grpc.Core
         static object staticLock = new object();
         static GrpcEnvironment instance;
 
+        static ILogger logger = new ConsoleLogger();
+
         readonly GrpcThreadPool threadPool;
         readonly CompletionRegistry completionRegistry;
         readonly DebugStats debugStats = new DebugStats();
@@ -92,18 +95,39 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary>
+        /// Gets application-wide logger used by gRPC.
+        /// </summary>
+        /// <value>The logger.</value>
+        public static ILogger Logger
+        {
+            get
+            {
+                return logger;
+            }
+        }
+
+        /// <summary>
+        /// Sets the application-wide logger that should be used by gRPC.
+        /// </summary>
+        public static void SetLogger(ILogger customLogger)
+        {
+            Preconditions.CheckNotNull(customLogger);
+            logger = customLogger;
+        }
+
         /// <summary>
         /// Creates gRPC environment.
         /// </summary>
         private GrpcEnvironment()
         {
-            GrpcLog.RedirectNativeLogs(Console.Error);
+            NativeLogRedirector.Redirect();
             grpcsharp_init();
             completionRegistry = new CompletionRegistry(this);
             threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
             threadPool.Start();
             // TODO: use proper logging here
-            Console.WriteLine("GRPC initialized.");
+            Logger.Info("gRPC initialized.");
         }
 
         /// <summary>
@@ -154,8 +178,7 @@ namespace Grpc.Core
 
             debugStats.CheckOK();
 
-            // TODO: use proper logging here
-            Console.WriteLine("GRPC shutdown.");
+            Logger.Info("gRPC shutdown.");
         }
 
         /// <summary>
@@ -171,7 +194,7 @@ namespace Grpc.Core
                 }
                 catch (Exception e)
                 {
-                    Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
+                    Logger.Error(e, "Error occured while shutting down GrpcEnvironment.");
                 }
             });
         }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 51022ac34fc1646fb2a607c542725c8e6c287164..bfcb9366a12331ec1276b867aba5c90e9ba2b36f 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
@@ -47,6 +48,8 @@ namespace Grpc.Core.Internal
     /// </summary>
     internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
+
         Channel channel;
 
         // Completion of a pending unary response if not null.
@@ -106,7 +109,7 @@ namespace Grpc.Core.Internal
                         }
                         catch (Exception e)
                         {
-                            Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+                            Logger.Error(e, "Exception occured while invoking completion delegate.");
                         }
                     }
                 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 64713c8c52c4f982070f8b10e057f70e6e363e66..38f2a5baebd0cbac4b523ada8c9c5abb94ff2293 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -38,6 +38,7 @@ using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
@@ -48,6 +49,8 @@ namespace Grpc.Core.Internal
     /// </summary>
     internal abstract class AsyncCallBase<TWrite, TRead>
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
+
         readonly Func<TWrite, byte[]> serializer;
         readonly Func<byte[], TRead> deserializer;
 
@@ -233,9 +236,9 @@ namespace Grpc.Core.Internal
                 payload = serializer(msg);
                 return true;
             }
-            catch (Exception)
+            catch (Exception e)
             {
-                Console.WriteLine("Exception occured while trying to serialize message");
+                Logger.Error(e, "Exception occured while trying to serialize message");
                 payload = null;
                 return false;
             }
@@ -248,9 +251,9 @@ namespace Grpc.Core.Internal
                 msg = deserializer(payload);
                 return true;
             } 
-            catch (Exception)
+            catch (Exception e)
             {
-                Console.WriteLine("Exception occured while trying to deserialize message");
+                Logger.Error(e, "Exception occured while trying to deserialize message.");
                 msg = default(TRead);
                 return false;
             }
@@ -264,7 +267,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+                Logger.Error(e, "Exception occured while invoking completion delegate.");
             }
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 702f1ce9e7eb2ed7e23d68302081f229c8e20abd..513902ee36484caff0da6ae019776d7dfc949682 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -131,6 +131,14 @@ namespace Grpc.Core.Internal
             }
         }
 
+        public string Peer
+        {
+            get
+            {
+                return call.GetPeer();
+            }
+        }
+
         protected override void OnReleaseResources()
         {
             environment.DebugStats.ActiveServerCalls.Decrement();
diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92fbe8cf0f1e6990aa49e9761d6da0097ede5dda
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs
@@ -0,0 +1,60 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Owned char* object.
+    /// </summary>
+    internal class CStringSafeHandle : SafeHandleZeroIsInvalid
+    {
+        [DllImport("grpc_csharp_ext.dll")]
+        static extern void gprsharp_free(IntPtr ptr);
+
+        private CStringSafeHandle()
+        {
+        }
+
+        public string GetValue()
+        {
+            return Marshal.PtrToStringAnsi(handle);
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            gprsharp_free(handle);
+            return true;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 04e35a5efdff563eaf460abc2c076b51f6520f9f..714749b171faed3fc59efd56a4d8de9e77fc56e7 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -88,6 +88,9 @@ namespace Grpc.Core.Internal
         static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call,
             BatchContextSafeHandle ctx);
 
+        [DllImport("grpc_csharp_ext.dll")]
+        static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
+
         [DllImport("grpc_csharp_ext.dll")]
         static extern void grpcsharp_call_destroy(IntPtr call);
 
@@ -180,6 +183,14 @@ namespace Grpc.Core.Internal
             grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk();
         }
 
+        public string GetPeer()
+        {
+            using (var cstring = grpcsharp_call_get_peer(this))
+            {
+                return cstring.GetValue();
+            }
+        }
+
         protected override bool ReleaseHandle()
         {
             grpcsharp_call_destroy(handle);
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 53c506c872ed8ecaa22ad57143ad80d6bd1fcf31..20815efbd356c22e3619449871019803fd76b528 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -41,7 +41,7 @@ namespace Grpc.Core.Internal
     internal class ChannelSafeHandle : SafeHandleZeroIsInvalid
     {
         [DllImport("grpc_csharp_ext.dll")]
-        static extern ChannelSafeHandle grpcsharp_channel_create(string target, ChannelArgsSafeHandle channelArgs);
+        static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
@@ -56,9 +56,9 @@ namespace Grpc.Core.Internal
         {
         }
 
-        public static ChannelSafeHandle Create(string target, ChannelArgsSafeHandle channelArgs)
+        public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs)
         {
-            return grpcsharp_channel_create(target, channelArgs);
+            return grpcsharp_insecure_channel_create(target, channelArgs);
         }
 
         public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index f6d8aa0600f57073b0724001bbe295dcd4af4993..2796c959a389c52485b3db8fd566b9ee15ccb394 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -35,6 +35,7 @@ using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
@@ -45,6 +46,8 @@ namespace Grpc.Core.Internal
 
     internal class CompletionRegistry
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
+
         readonly GrpcEnvironment environment;
         readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
 
@@ -81,7 +84,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+                Logger.Error(e, "Exception occured while invoking completion delegate.");
             }
             finally
             {
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
index f361199068eb5da2bb917f732b13bd94ba4a18c0..8b4fa85e5db38b9912ac0849990571555b401cde 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
@@ -50,9 +50,23 @@ namespace Grpc.Core.Internal
         {
         }
 
-        public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts)
+        public static CredentialsSafeHandle CreateNullCredentials()
         {
-            return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+            var creds = new CredentialsSafeHandle();
+            creds.SetHandle(IntPtr.Zero);
+            return creds;
+        }
+
+        public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
+        {
+            if (keyCertPair != null)
+            {
+                return grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey);
+            }
+            else
+            {
+                return grpcsharp_ssl_credentials_create(pemRootCerts, null, null);
+            }
         }
 
         protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index b77e89304472189665930d6819b7caeb4a13c14c..cb4c7c821e728036a7e6c47730de588e1113b68c 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -36,7 +36,7 @@ using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
-using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 
 namespace Grpc.Core.Internal
 {
@@ -45,6 +45,8 @@ namespace Grpc.Core.Internal
     /// </summary>
     internal class GrpcThreadPool
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<GrpcThreadPool>();
+
         readonly GrpcEnvironment environment;
         readonly object myLock = new object();
         readonly List<Thread> threads = new List<Thread>();
@@ -82,7 +84,7 @@ namespace Grpc.Core.Internal
             {
                 cq.Shutdown();
 
-                Console.WriteLine("Waiting for GRPC threads to finish.");
+                Logger.Info("Waiting for GRPC threads to finish.");
                 foreach (var thread in threads)
                 {
                     thread.Join();
@@ -129,12 +131,12 @@ namespace Grpc.Core.Internal
                     }
                     catch (Exception e)
                     {
-                        Console.WriteLine("Exception occured while invoking completion delegate: " + e);
+                        Logger.Error(e, "Exception occured while invoking completion delegate");
                     }
                 }
             }
             while (ev.type != GRPCCompletionType.Shutdown);
-            Console.WriteLine("Completion queue has shutdown successfully, thread " + Thread.CurrentThread.Name + " exiting.");
+            Logger.Info("Completion queue has shutdown successfully, thread {0} exiting.", Thread.CurrentThread.Name);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
similarity index 74%
rename from src/csharp/Grpc.Core/Internal/GrpcLog.cs
rename to src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
index 2f3c8ad71c1f850c24f1b2b9ec416dda408378d7..b8a55c5fe85bcd759fc26c8ec25f6dcfa5563a0b 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcLog.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
@@ -44,30 +44,26 @@ namespace Grpc.Core.Internal
 
     /// <summary>
     /// Logs from gRPC C core library can get lost if your application is not a console app.
-    /// This class allows redirection of logs to arbitrary destination.
+    /// This class allows redirection of logs to gRPC logger.
     /// </summary>
-    internal static class GrpcLog
+    internal static class NativeLogRedirector
     {
         static object staticLock = new object();
         static GprLogDelegate writeCallback;
-        static TextWriter dest;
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern void grpcsharp_redirect_log(GprLogDelegate callback);
 
         /// <summary>
-        /// Sets text writer as destination for logs from native gRPC C core library.
-        /// Only first invocation has effect.
+        /// Redirects logs from native gRPC C core library to a general logger.
         /// </summary>
-        /// <param name="textWriter"></param>
-        public static void RedirectNativeLogs(TextWriter textWriter)
+        public static void Redirect()
         {
             lock (staticLock)
             {
                 if (writeCallback == null)
                 {
                     writeCallback = new GprLogDelegate(HandleWrite);
-                    dest = textWriter;
                     grpcsharp_redirect_log(writeCallback);    
                 }
             }
@@ -77,13 +73,30 @@ namespace Grpc.Core.Internal
         {
             try
             {
-                // TODO: DateTime format used here is different than in C core.
-                dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}", 
-                    Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now,  
+                var logger = GrpcEnvironment.Logger;
+                string severityString = Marshal.PtrToStringAnsi(severityStringPtr);
+                string message = string.Format("{0} {1}:{2}: {3}",
                     threadId,
                     Marshal.PtrToStringAnsi(fileStringPtr), 
                     line, 
-                    Marshal.PtrToStringAnsi(msgPtr)));
+                    Marshal.PtrToStringAnsi(msgPtr));
+                
+                switch (severityString)
+                {
+                    case "D":
+                        logger.Debug(message);
+                        break;
+                    case "I":
+                        logger.Info(message);
+                        break;
+                    case "E":
+                        logger.Error(message);
+                        break;
+                    default:
+                        // severity not recognized, default to error.
+                        logger.Error(message);
+                        break;
+                }
             }
             catch (Exception e)
             {
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 93e1c0b29462db36d337e4e6c4ffdbedb2c1bb69..19f0e3c57f6c4043f8c94de7261ee8b2529d553a 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -37,6 +37,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
@@ -50,6 +51,8 @@ namespace Grpc.Core.Internal
         where TRequest : class
         where TResponse : class
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<UnaryServerCallHandler<TRequest, TResponse>>();
+
         readonly Method<TRequest, TResponse> method;
         readonly UnaryServerMethod<TRequest, TResponse> handler;
 
@@ -72,7 +75,7 @@ namespace Grpc.Core.Internal
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken);
+            var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
             try
             {
                 Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -85,7 +88,7 @@ namespace Grpc.Core.Internal
             } 
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured in handler: " + e);
+                Logger.Error(e, "Exception occured in handler.");
                 status = HandlerUtils.StatusFromException(e);
             }
             try
@@ -104,6 +107,8 @@ namespace Grpc.Core.Internal
         where TRequest : class
         where TResponse : class
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ServerStreamingServerCallHandler<TRequest, TResponse>>();
+
         readonly Method<TRequest, TResponse> method;
         readonly ServerStreamingServerMethod<TRequest, TResponse> handler;
 
@@ -126,7 +131,7 @@ namespace Grpc.Core.Internal
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken);
+            var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
             try
             {
                 Preconditions.CheckArgument(await requestStream.MoveNext());
@@ -138,7 +143,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured in handler: " + e);
+                Logger.Error(e, "Exception occured in handler.");
                 status = HandlerUtils.StatusFromException(e);
             }
 
@@ -158,6 +163,8 @@ namespace Grpc.Core.Internal
         where TRequest : class
         where TResponse : class
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ClientStreamingServerCallHandler<TRequest, TResponse>>();
+
         readonly Method<TRequest, TResponse> method;
         readonly ClientStreamingServerMethod<TRequest, TResponse> handler;
 
@@ -180,7 +187,7 @@ namespace Grpc.Core.Internal
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken);
+            var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
             try
             {
                 var result = await handler(requestStream, context);
@@ -196,7 +203,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured in handler: " + e);
+                Logger.Error(e, "Exception occured in handler.");
                 status = HandlerUtils.StatusFromException(e);
             }
 
@@ -216,6 +223,8 @@ namespace Grpc.Core.Internal
         where TRequest : class
         where TResponse : class
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<DuplexStreamingServerCallHandler<TRequest, TResponse>>();
+
         readonly Method<TRequest, TResponse> method;
         readonly DuplexStreamingServerMethod<TRequest, TResponse> handler;
 
@@ -238,7 +247,7 @@ namespace Grpc.Core.Internal
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken);
+            var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken);
             try
             {
                 await handler(requestStream, responseStream, context);
@@ -246,7 +255,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception occured in handler: " + e);
+                Logger.Error(e, "Exception occured in handler.");
                 status = HandlerUtils.StatusFromException(e);
             }
             try
@@ -295,12 +304,12 @@ namespace Grpc.Core.Internal
             return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
         }
 
-        public static ServerCallContext NewContext(ServerRpcNew newRpc, CancellationToken cancellationToken)
+        public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, CancellationToken cancellationToken)
         {
             DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime();
 
             return new ServerCallContext(
-                newRpc.Method, newRpc.Host, realtimeDeadline,
+                newRpc.Method, newRpc.Host, peer, realtimeDeadline,
                 newRpc.RequestMetadata, cancellationToken);
         }
     }
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
index 961180741a95202e9a89e8473afcf4668bbb1424..59238a452cf2a8fd2550999b6c93f338b018765d 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -51,10 +51,10 @@ namespace Grpc.Core.Internal
         {
         }
 
-        public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
+        public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
         {
             Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
-            return grpcsharp_ssl_server_credentials_create(null,
+            return grpcsharp_ssl_server_credentials_create(pemRootCerts,
                                                            keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
                                                            new UIntPtr((ulong)keyCertPairCertChainArray.Length));
         }
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 9e1170e6ddbf6bd340fdf3c9b41dafc33e686874..f9b44b1acfb60467b4f2d7dcc91bbced470ff2f0 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -48,7 +48,7 @@ namespace Grpc.Core.Internal
         static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args);
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
+        static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
@@ -77,12 +77,12 @@ namespace Grpc.Core.Internal
             return grpcsharp_server_create(cq, args);
         }
 
-        public int AddListeningPort(string addr)
+        public int AddInsecurePort(string addr)
         {
-            return grpcsharp_server_add_http2_port(this, addr);
+            return grpcsharp_server_add_insecure_http2_port(this, addr);
         }
 
-        public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials)
+        public int AddSecurePort(string addr, ServerCredentialsSafeHandle credentials)
         {
             return grpcsharp_server_add_secure_http2_port(this, addr, credentials);
         }
diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7cea18618ef3d403c48704e3163944ebf5f36267
--- /dev/null
+++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs
@@ -0,0 +1,84 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+    /// <summary>
+    /// Key certificate pair (in PEM encoding).
+    /// </summary>
+    public sealed class KeyCertificatePair
+    {
+        readonly string certificateChain;
+        readonly string privateKey;
+
+        /// <summary>
+        /// Creates a new certificate chain - private key pair.
+        /// </summary>
+        /// <param name="certificateChain">PEM encoded certificate chain.</param>
+        /// <param name="privateKey">PEM encoded private key.</param>
+        public KeyCertificatePair(string certificateChain, string privateKey)
+        {
+            this.certificateChain = Preconditions.CheckNotNull(certificateChain);
+            this.privateKey = Preconditions.CheckNotNull(privateKey);
+        }
+
+        /// <summary>
+        /// PEM encoded certificate chain.
+        /// </summary>
+        public string CertificateChain
+        {
+            get
+            {
+                return certificateChain;
+            }
+        }
+
+        /// <summary>
+        /// PEM encoded private key.
+        /// </summary>
+        public string PrivateKey
+        {
+            get
+            {
+                return privateKey;
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c67765c78d5164ac77fdc69deb7762ea023c930d
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -0,0 +1,103 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Grpc.Core.Logging
+{
+    /// <summary>Logger that logs to System.Console.</summary>
+    public class ConsoleLogger : ILogger
+    {
+        readonly Type forType;
+        readonly string forTypeString;
+
+        public ConsoleLogger() : this(null)
+        {
+        }
+
+        private ConsoleLogger(Type forType)
+        {
+            this.forType = forType;
+            this.forTypeString = forType != null ? forType.FullName + " " : "";
+        }
+
+        public ILogger ForType<T>()
+        {
+            if (typeof(T) == forType)
+            {
+                return this;
+            }
+            return new ConsoleLogger(typeof(T));
+        }
+
+        public void Debug(string message, params object[] formatArgs)
+        {
+            Log("D", message, formatArgs);
+        }
+
+        public void Info(string message, params object[] formatArgs)
+        {
+            Log("I", message, formatArgs);
+        }
+
+        public void Warning(string message, params object[] formatArgs)
+        {
+            Log("W", message, formatArgs);
+        }
+
+        public void Warning(Exception exception, string message, params object[] formatArgs)
+        {
+            Log("W", message + " " + exception, formatArgs);
+        }
+
+        public void Error(string message, params object[] formatArgs)
+        {
+            Log("E", message, formatArgs);
+        }
+
+        public void Error(Exception exception, string message, params object[] formatArgs)
+        {
+            Log("E", message + " " + exception, formatArgs);
+        }
+
+        private void Log(string severityString, string message, object[] formatArgs)
+        {
+            Console.Error.WriteLine("{0}{1} {2}{3}",
+                severityString,
+                DateTime.Now,
+                forTypeString,
+                string.Format(message, formatArgs));
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0d58f133e3a53fc1e17417fcf7207c74c6ef19dc
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/ILogger.cs
@@ -0,0 +1,57 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace Grpc.Core.Logging
+{
+    /// <summary>For logging messages.</summary>
+    public interface ILogger
+    {
+        /// <summary>Returns a logger associated with the specified type.</summary>
+        ILogger ForType<T>();
+
+        void Debug(string message, params object[] formatArgs);
+
+        void Info(string message, params object[] formatArgs);
+
+        void Warning(string message, params object[] formatArgs);
+
+        void Warning(Exception exception, string message, params object[] formatArgs);
+
+        void Error(string message, params object[] formatArgs);
+
+        void Error(Exception exception, string message, params object[] formatArgs);
+    }
+}
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index fd30735359fe74736d6c51a23020309dcf02f039..3217547cc472197fd8973c59bd4d74f1deef88e0 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -38,6 +38,7 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core
@@ -52,6 +53,8 @@ namespace Grpc.Core
         /// </summary>
         public const int PickUnusedPort = 0;
 
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>();
+
         readonly GrpcEnvironment environment;
         readonly List<ChannelOption> options;
         readonly ServerSafeHandle handle;
@@ -95,28 +98,31 @@ namespace Grpc.Core
         }
 
         /// <summary>
-        /// Add a non-secure port on which server should listen.
+        /// Add a port on which server should listen.
         /// Only call this before Start().
         /// </summary>
         /// <returns>The port on which server will be listening.</returns>
         /// <param name="host">the host</param>
         /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
-        public int AddListeningPort(string host, int port)
+        public int AddPort(string host, int port, ServerCredentials credentials)
         {
-            return AddListeningPortInternal(host, port, null);
-        }
-
-        /// <summary>
-        /// Add a non-secure port on which server should listen.
-        /// Only call this before Start().
-        /// </summary>
-        /// <returns>The port on which server will be listening.</returns>
-        /// <param name="host">the host</param>
-        /// <param name="port">the port. If zero, an unused port is chosen automatically.</param>
-        public int AddListeningPort(string host, int port, ServerCredentials credentials)
-        {
-            Preconditions.CheckNotNull(credentials);
-            return AddListeningPortInternal(host, port, credentials);
+            lock (myLock)
+            {
+                Preconditions.CheckNotNull(credentials);
+                Preconditions.CheckState(!startRequested);
+                var address = string.Format("{0}:{1}", host, port);
+                using (var nativeCredentials = credentials.ToNativeCredentials())
+                {
+                    if (nativeCredentials != null)
+                    {
+                        return handle.AddSecurePort(address, nativeCredentials);
+                    }
+                    else
+                    {
+                        return handle.AddInsecurePort(address);
+                    }
+                }
+            }
         }
 
         /// <summary>
@@ -183,26 +189,6 @@ namespace Grpc.Core
             handle.Dispose();
         }
 
-        private int AddListeningPortInternal(string host, int port, ServerCredentials credentials)
-        {
-            lock (myLock)
-            {
-                Preconditions.CheckState(!startRequested);    
-                var address = string.Format("{0}:{1}", host, port);
-                if (credentials != null)
-                {
-                    using (var nativeCredentials = credentials.ToNativeCredentials())
-                    {
-                        return handle.AddListeningPort(address, nativeCredentials);
-                    }
-                }
-                else
-                {
-                    return handle.AddListeningPort(address);    
-                }
-            }
-        }
-
         /// <summary>
         /// Allows one new RPC call to be received by server.
         /// </summary>
@@ -233,7 +219,7 @@ namespace Grpc.Core
             }
             catch (Exception e)
             {
-                Console.WriteLine("Exception while handling RPC: " + e);
+                Logger.Warning(e, "Exception while handling RPC.");
             }
         }
 
diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs
index 17a2eefd078b980cd1550bc21cd176324bda0007..0c48adaea52b1a569a4a31de068a8ee06c82de47 100644
--- a/src/csharp/Grpc.Core/ServerCallContext.cs
+++ b/src/csharp/Grpc.Core/ServerCallContext.cs
@@ -47,6 +47,7 @@ namespace Grpc.Core
 
         private readonly string method;
         private readonly string host;
+        private readonly string peer;
         private readonly DateTime deadline;
         private readonly Metadata requestHeaders;
         private readonly CancellationToken cancellationToken;
@@ -54,10 +55,11 @@ namespace Grpc.Core
 
         private Status status = Status.DefaultSuccess;
 
-        public ServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
+        public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
         {
             this.method = method;
             this.host = host;
+            this.peer = peer;
             this.deadline = deadline;
             this.requestHeaders = requestHeaders;
             this.cancellationToken = cancellationToken;
@@ -81,6 +83,15 @@ namespace Grpc.Core
             }
         }
 
+        /// <summary> Address of the remote endpoint in URI format. </summary>
+        public string Peer
+        {
+            get
+            {
+                return this.peer;
+            }
+        }
+
         /// <summary> Deadline for this RPC. </summary>
         public DateTime Deadline
         {
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index ab7d0b49143ed74b72ca021239171ea1aa05ba24..32ed4b78a1ff17d4b7ce73b8897b246ebad62516 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -35,6 +35,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Immutable;
 using Grpc.Core.Internal;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
@@ -43,67 +44,99 @@ namespace Grpc.Core
     /// </summary>
     public abstract class ServerCredentials
     {
+        static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl();
+
+        /// <summary>
+        /// Returns instance of credential that provides no security and 
+        /// will result in creating an unsecure server port with no encryption whatsoever.
+        /// </summary>
+        public static ServerCredentials Insecure
+        {
+            get
+            {
+                return InsecureInstance;
+            }
+        }
+
         /// <summary>
         /// Creates native object for the credentials.
         /// </summary>
         /// <returns>The native credentials.</returns>
         internal abstract ServerCredentialsSafeHandle ToNativeCredentials();
+
+        private sealed class InsecureServerCredentialsImpl : ServerCredentials
+        {
+            internal override ServerCredentialsSafeHandle ToNativeCredentials()
+            {
+                return null;
+            }
+        }
     }
 
     /// <summary>
-    /// Key certificate pair (in PEM encoding).
+    /// Server-side SSL credentials.
     /// </summary>
-    public class KeyCertificatePair
+    public class SslServerCredentials : ServerCredentials
     {
-        readonly string certChain;
-        readonly string privateKey;
+        readonly IList<KeyCertificatePair> keyCertificatePairs;
+        readonly string rootCertificates;
 
-        public KeyCertificatePair(string certChain, string privateKey)
+        /// <summary>
+        /// Creates server-side SSL credentials.
+        /// </summary>
+        /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
+        /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+        public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates)
         {
-            this.certChain = certChain;
-            this.privateKey = privateKey;
+            this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
+            Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
+                "At least one KeyCertificatePair needs to be provided");
+            this.rootCertificates = rootCertificates;
         }
 
-        public string CertChain
+        /// <summary>
+        /// Creates server-side SSL credentials.
+        /// This constructor should be use if you do not wish to autheticate client
+        /// using client root certificates.
+        /// </summary>
+        /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+        public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null)
         {
-            get
-            {
-                return certChain;
-            }
         }
 
-        public string PrivateKey
+        /// <summary>
+        /// Key-certificate pairs.
+        /// </summary>
+        public IList<KeyCertificatePair> KeyCertificatePairs
         {
             get
             {
-                return privateKey;
+                return this.keyCertificatePairs;
             }
         }
-    }
-
-    /// <summary>
-    /// Server-side SSL credentials.
-    /// </summary>
-    public class SslServerCredentials : ServerCredentials
-    {
-        ImmutableList<KeyCertificatePair> keyCertPairs;
 
-        public SslServerCredentials(ImmutableList<KeyCertificatePair> keyCertPairs)
+        /// <summary>
+        /// PEM encoded client root certificates.
+        /// </summary>
+        public string RootCertificates
         {
-            this.keyCertPairs = keyCertPairs;
+            get
+            {
+                return this.rootCertificates;
+            }
         }
 
         internal override ServerCredentialsSafeHandle ToNativeCredentials()
         {
-            int count = keyCertPairs.Count;
+            int count = keyCertificatePairs.Count;
             string[] certChains = new string[count];
             string[] keys = new string[count];
             for (int i = 0; i < count; i++)
             {
-                certChains[i] = keyCertPairs[i].CertChain;
-                keys[i] = keyCertPairs[i].PrivateKey;
+                certChains[i] = keyCertificatePairs[i].CertificateChain;
+                keys[i] = keyCertificatePairs[i].PrivateKey;
             }
-            return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys);
+            return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 4180d989385ca2069d4cb72ed0d7acadcb54de01..82653c3a1f587d12547104180cbd39072ffd3a89 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -46,13 +46,15 @@ namespace Grpc.Core.Utils
         /// </summary>
         public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action)
         {
-            Console.WriteLine("Warmup iterations: " + warmupIterations);
+            var logger = GrpcEnvironment.Logger;
+            
+            logger.Info("Warmup iterations: {0}", warmupIterations);
             for (int i = 0; i < warmupIterations; i++)
             {
                 action();
             }
 
-            Console.WriteLine("Benchmark iterations: " + benchmarkIterations);
+            logger.Info("Benchmark iterations: {0}", benchmarkIterations);
             var stopwatch = new Stopwatch();
             stopwatch.Start();
             for (int i = 0; i < benchmarkIterations; i++)
@@ -60,8 +62,8 @@ namespace Grpc.Core.Utils
                 action();
             }
             stopwatch.Stop();
-            Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms");
-            Console.WriteLine("Ops per second: " + (int)((double)benchmarkIterations  * 1000 / stopwatch.ElapsedMilliseconds));
+            logger.Info("Elapsed time: {0}ms", stopwatch.ElapsedMilliseconds);
+            logger.Info("Ops per second: {0}", (int)((double)benchmarkIterations  * 1000 / stopwatch.ElapsedMilliseconds));
         }
     }
 }
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 5d5401593d0e165e19cdcf52f78d1a426f496aea..85996a570cdb595ac11b382b327ea53808b4c82e 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -2,7 +2,7 @@
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProductVersion>10.0.0</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}</ProjectGuid>
@@ -11,7 +11,7 @@
     <AssemblyName>MathClient</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -20,16 +20,16 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index cfe2a0691607c27ed2608b91d9fa097a6c59a0c6..f9839d99f1d9bb8e2592e37efeaee323a76a8d54 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,7 +39,7 @@ namespace math
     {
         public static void Main(string[] args)
         {
-            using (Channel channel = new Channel("127.0.0.1", 23456))
+            using (Channel channel = new Channel("127.0.0.1", 23456, Credentials.Insecure))
             {
                 Math.IMathClient client = new Math.MathClient(channel);
                 MathExamples.DivExample(client);
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index 677d87da205d2e4fb01d487cf4b54c01000642f4..6c8856cc92136ea4c2e4e62581eaef74d8d90891 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -2,7 +2,7 @@
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProductVersion>10.0.0</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid>
@@ -11,7 +11,7 @@
     <AssemblyName>MathServer</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -20,16 +20,16 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
index f4409851127a2c2a36b1461381c429cf88f2adca..468eefbe3e1f8100078dd6831b8a77b74d439f78 100644
--- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -44,7 +44,7 @@ namespace math
 
             Server server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
-            int port = server.AddListeningPort(host, 23456);
+            int port = server.AddPort(host, 23456, ServerCredentials.Insecure);
             server.Start();
 
             Console.WriteLine("MathServer listening on port " + port);
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index dd56016a394b3b99e591e1fc16be4dbf7a77e671..26f332c1cf7e30a9833465e3098103cc3ba1b914 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -56,9 +56,9 @@ namespace math.Tests
         {
             server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
-            int port = server.AddListeningPort(host, Server.PickUnusedPort);
+            int port = server.AddPort(host, Server.PickUnusedPort, ServerCredentials.Insecure);
             server.Start();
-            channel = new Channel(host, port);
+            channel = new Channel(host, port, Credentials.Insecure);
             client = Math.NewClient(channel);
 
             // TODO(jtattermusch): get rid of the custom header here once we have dedicated tests
@@ -108,123 +108,105 @@ namespace math.Tests
         }
 
         [Test]
-        public void DivAsync()
+        public async Task DivAsync()
         {
-            Task.Run(async () =>
-            {
-                DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
-                Assert.AreEqual(3, response.Quotient);
-                Assert.AreEqual(1, response.Remainder);
-            }).Wait();
+            DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+            Assert.AreEqual(3, response.Quotient);
+            Assert.AreEqual(1, response.Remainder);
         }
 
         [Test]
-        public void Fib()
+        public async Task Fib()
         {
-            Task.Run(async () =>
+            using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
             {
-                using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
-                {
-                    var responses = await call.ResponseStream.ToList();
-                    CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
-                        responses.ConvertAll((n) => n.Num_));
-                }
-            }).Wait();
+                var responses = await call.ResponseStream.ToList();
+                CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
+                    responses.ConvertAll((n) => n.Num_));
+            }
         }
 
         [Test]
-        public void FibWithCancel()
+        public async Task FibWithCancel()
         {
-            Task.Run(async () =>
+            var cts = new CancellationTokenSource();
+
+            using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), 
+                cancellationToken: cts.Token))
             {
-                var cts = new CancellationTokenSource();
+                List<long> responses = new List<long>();
 
-                using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), 
-                    cancellationToken: cts.Token))
+                try
                 {
-                    List<long> responses = new List<long>();
-
-                    try
+                    while (await call.ResponseStream.MoveNext())
                     {
-                        while (await call.ResponseStream.MoveNext())
+                        if (responses.Count == 0)
                         {
-                            if (responses.Count == 0)
-                            {
-                                cts.CancelAfter(500);  // make sure we cancel soon
-                            }
-                            responses.Add(call.ResponseStream.Current.Num_);
+                            cts.CancelAfter(500);  // make sure we cancel soon
                         }
-                        Assert.Fail();
-                    }
-                    catch (RpcException e)
-                    {
-                        Assert.IsTrue(responses.Count > 0);
-                        Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+                        responses.Add(call.ResponseStream.Current.Num_);
                     }
+                    Assert.Fail();
+                }
+                catch (RpcException e)
+                {
+                    Assert.IsTrue(responses.Count > 0);
+                    Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
                 }
-            }).Wait();
+            }
         }
 
         [Test]
-        public void FibWithDeadline()
+        public async Task FibWithDeadline()
         {
-            Task.Run(async () =>
+            using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), 
+                deadline: DateTime.UtcNow.AddMilliseconds(500)))
             {
-                using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), 
-                    deadline: DateTime.UtcNow.AddMilliseconds(500)))
+                try
                 {
-                    try
-                    {
-                        await call.ResponseStream.ToList();
-                        Assert.Fail();
-                    }
-                    catch (RpcException e)
-                    {
-                        Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
-                    }
+                    await call.ResponseStream.ToList();
+                    Assert.Fail();
+                }
+                catch (RpcException e)
+                {
+                    Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode);
                 }
-            }).Wait();
+            }
         }
 
         // TODO: test Fib with limit=0 and cancellation
         [Test]
-        public void Sum()
+        public async Task Sum()
         {
-            Task.Run(async () =>
+            using (var call = client.Sum())
             {
-                using (var call = client.Sum())
-                {
-                    var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
-                             n => Num.CreateBuilder().SetNum_(n).Build());
+                var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
+                            n => Num.CreateBuilder().SetNum_(n).Build());
 
-                    await call.RequestStream.WriteAll(numbers);
-                    var result = await call.ResponseAsync;
-                    Assert.AreEqual(60, result.Num_);
-                }
-            }).Wait();
+                await call.RequestStream.WriteAll(numbers);
+                var result = await call.ResponseAsync;
+                Assert.AreEqual(60, result.Num_);
+            }
         }
 
         [Test]
-        public void DivMany()
+        public async Task DivMany()
         {
-            Task.Run(async () =>
+            var divArgsList = new List<DivArgs>
             {
-                var divArgsList = new List<DivArgs>
-                {
-                    new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
-                    new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
-                    new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
-                };
+                new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
+                new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
+                new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
+            };
 
-                using (var call = client.DivMany())
-                {
-                    await call.RequestStream.WriteAll(divArgsList);
-                    var result = await call.ResponseStream.ToList();
+            using (var call = client.DivMany())
+            {
+                await call.RequestStream.WriteAll(divArgsList);
+                var result = await call.ResponseStream.ToList();
 
-                    CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
-                    CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
-                }
-            }).Wait();
+                CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
+                CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
+            }
         }
     }
 }
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index bc14a0a62f2373f23bc096d77b8ad5d1b320b0ce..9d89698a8f0cfd852b27db413f92e36135b907d4 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -59,9 +59,9 @@ namespace Grpc.HealthCheck.Tests
 
             server = new Server();
             server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
-            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure);
             server.Start();
-            channel = new Channel(Host, port);
+            channel = new Channel(Host, port, Credentials.Insecure);
 
             client = Grpc.Health.V1Alpha.Health.NewClient(channel);
         }
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index dc1d0a44c04e46af78de7519211dc8884e51db10..37d53d61e0d950f4b780daf457340eafde545479 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -2,7 +2,7 @@
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid>
     <OutputType>Exe</OutputType>
     <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
@@ -10,7 +10,7 @@
     <StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -19,16 +19,16 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
index 966b777192f3d53ea95e7056f903c1bc009213f8..0a82bb4f16c05bec578209f2c8bf3ce369abdc3d 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config
@@ -4,7 +4,7 @@
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index f03c8f3ce3e3d95f07d5b6b6d41f319fab876768..0f3b9eb5101d0eca124248ac37355b93f4d4bb07 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -2,7 +2,7 @@
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid>
     <OutputType>Exe</OutputType>
     <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
@@ -10,7 +10,7 @@
     <StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -19,16 +19,16 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
index 966b777192f3d53ea95e7056f903c1bc009213f8..0a82bb4f16c05bec578209f2c8bf3ce369abdc3d 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config
@@ -4,7 +4,7 @@
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index d3c69ab9eb916912a95fb49898b18f0d7a950268..db2e304d373bcab7ff20946f41c6239c2b731598 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -2,16 +2,15 @@
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid>
     <OutputType>Library</OutputType>
     <RootNamespace>Grpc.IntegrationTesting</RootNamespace>
     <AssemblyName>Grpc.IntegrationTesting</AssemblyName>
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <NuGetPackageImportStamp>041c163e</NuGetPackageImportStamp>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -20,45 +19,36 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <Externalconsole>true</Externalconsole>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Google.Apis.Auth, Version=1.9.1.12395, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.1.12399, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core, Version=1.9.1.12394, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
     </Reference>
-    <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+    <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+      <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath>
     </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+      <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
     </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+    <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+      <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
     </Reference>
-    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
     <Reference Include="nunit.framework">
       <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
@@ -67,24 +57,32 @@
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
     </Reference>
-    <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
-    </Reference>
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
     </Reference>
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.Extensions, Version=2.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+    <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
     </Reference>
-    <Reference Include="System.Net.Http.Primitives, Version=4.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+    <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
     </Reference>
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="Microsoft.Threading.Tasks">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Collections.Immutable">
+      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
@@ -99,6 +97,7 @@
     <Compile Include="InteropClient.cs" />
     <Compile Include="TestCredentials.cs" />
     <Compile Include="TestGrpc.cs" />
+    <Compile Include="SslCredentialsTest.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -133,9 +132,11 @@
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
-  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
-  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
-    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
-    <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
   </Target>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index ce255f9423734b3654f9b3040152f8800831985a..7411d91d5a7ae0e6f51ae15d23db79ac4df9c5da 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -127,15 +127,15 @@ namespace Grpc.IntegrationTesting
                     {
                         credential = credential.CreateScoped(new[] { AuthScope });
                     }
-                    client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential);
+                    client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
                 }
 
-                RunTestCase(options.testCase, client);
+                RunTestCaseAsync(options.testCase, client).Wait();
             }
             GrpcEnvironment.Shutdown();
         }
 
-        private void RunTestCase(string testCase, TestService.TestServiceClient client)
+        private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client)
         {
             switch (testCase)
             {
@@ -146,16 +146,16 @@ namespace Grpc.IntegrationTesting
                     RunLargeUnary(client);
                     break;
                 case "client_streaming":
-                    RunClientStreaming(client);
+                    await RunClientStreamingAsync(client);
                     break;
                 case "server_streaming":
-                    RunServerStreaming(client);
+                    await RunServerStreamingAsync(client);
                     break;
                 case "ping_pong":
-                    RunPingPong(client);
+                    await RunPingPongAsync(client);
                     break;
                 case "empty_stream":
-                    RunEmptyStream(client);
+                    await RunEmptyStreamAsync(client);
                     break;
                 case "service_account_creds":
                     RunServiceAccountCreds(client);
@@ -170,10 +170,10 @@ namespace Grpc.IntegrationTesting
                     RunPerRpcCreds(client);
                     break;
                 case "cancel_after_begin":
-                    RunCancelAfterBegin(client);
+                    await RunCancelAfterBeginAsync(client);
                     break;
                 case "cancel_after_first_response":
-                    RunCancelAfterFirstResponse(client);
+                    await RunCancelAfterFirstResponseAsync(client);
                     break;
                 case "benchmark_empty_unary":
                     RunBenchmarkEmptyUnary(client);
@@ -207,118 +207,106 @@ namespace Grpc.IntegrationTesting
             Console.WriteLine("Passed!");
         }
 
-        public static void RunClientStreaming(TestService.ITestServiceClient client)
+        public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
-            {
-                Console.WriteLine("running client_streaming");
+            Console.WriteLine("running client_streaming");
 
-                var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build());
+            var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build());
 
-                using (var call = client.StreamingInputCall())
-                {
-                    await call.RequestStream.WriteAll(bodySizes);
+            using (var call = client.StreamingInputCall())
+            {
+                await call.RequestStream.WriteAll(bodySizes);
 
-                    var response = await call.ResponseAsync;
-                    Assert.AreEqual(74922, response.AggregatedPayloadSize);
-                }
-                Console.WriteLine("Passed!");
-            }).Wait();
+                var response = await call.ResponseAsync;
+                Assert.AreEqual(74922, response.AggregatedPayloadSize);
+            }
+            Console.WriteLine("Passed!");
         }
 
-        public static void RunServerStreaming(TestService.ITestServiceClient client)
+        public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
-            {
-                Console.WriteLine("running server_streaming");
+            Console.WriteLine("running server_streaming");
 
-                var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
+            var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
 
-                var request = StreamingOutputCallRequest.CreateBuilder()
-                .SetResponseType(PayloadType.COMPRESSABLE)
-                .AddRangeResponseParameters(bodySizes.ConvertAll(
-                    (size) => ResponseParameters.CreateBuilder().SetSize(size).Build()))
-                .Build();
+            var request = StreamingOutputCallRequest.CreateBuilder()
+            .SetResponseType(PayloadType.COMPRESSABLE)
+            .AddRangeResponseParameters(bodySizes.ConvertAll(
+                (size) => ResponseParameters.CreateBuilder().SetSize(size).Build()))
+            .Build();
 
-                using (var call = client.StreamingOutputCall(request))
+            using (var call = client.StreamingOutputCall(request))
+            {
+                var responseList = await call.ResponseStream.ToList();
+                foreach (var res in responseList)
                 {
-                    var responseList = await call.ResponseStream.ToList();
-                    foreach (var res in responseList)
-                    {
-                        Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
-                    }
-                    CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+                    Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
                 }
-                Console.WriteLine("Passed!");
-            }).Wait();
+                CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+            }
+            Console.WriteLine("Passed!");
         }
 
-        public static void RunPingPong(TestService.ITestServiceClient client)
+        public static async Task RunPingPongAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
-            {
-                Console.WriteLine("running ping_pong");
+            Console.WriteLine("running ping_pong");
 
-                using (var call = client.FullDuplexCall())
-                {
-                    await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
-                    .SetResponseType(PayloadType.COMPRESSABLE)
-                    .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
-                    .SetPayload(CreateZerosPayload(27182)).Build());
+            using (var call = client.FullDuplexCall())
+            {
+                await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+                .SetResponseType(PayloadType.COMPRESSABLE)
+                .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
+                .SetPayload(CreateZerosPayload(27182)).Build());
 
-                    Assert.IsTrue(await call.ResponseStream.MoveNext());
-                    Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
-                    Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
+                Assert.IsTrue(await call.ResponseStream.MoveNext());
+                Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+                Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
 
-                    await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
-                              .SetResponseType(PayloadType.COMPRESSABLE)
-                              .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9))
-                              .SetPayload(CreateZerosPayload(8)).Build());
+                await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+                            .SetResponseType(PayloadType.COMPRESSABLE)
+                            .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9))
+                            .SetPayload(CreateZerosPayload(8)).Build());
 
-                    Assert.IsTrue(await call.ResponseStream.MoveNext());
-                    Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
-                    Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
+                Assert.IsTrue(await call.ResponseStream.MoveNext());
+                Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+                Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
 
-                    await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
-                              .SetResponseType(PayloadType.COMPRESSABLE)
-                              .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653))
-                              .SetPayload(CreateZerosPayload(1828)).Build());
+                await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+                            .SetResponseType(PayloadType.COMPRESSABLE)
+                            .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653))
+                            .SetPayload(CreateZerosPayload(1828)).Build());
 
-                    Assert.IsTrue(await call.ResponseStream.MoveNext());
-                    Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
-                    Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
+                Assert.IsTrue(await call.ResponseStream.MoveNext());
+                Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+                Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
 
-                    await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
-                              .SetResponseType(PayloadType.COMPRESSABLE)
-                              .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
-                              .SetPayload(CreateZerosPayload(45904)).Build());
+                await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+                            .SetResponseType(PayloadType.COMPRESSABLE)
+                            .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
+                            .SetPayload(CreateZerosPayload(45904)).Build());
 
-                    Assert.IsTrue(await call.ResponseStream.MoveNext());
-                    Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
-                    Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
+                Assert.IsTrue(await call.ResponseStream.MoveNext());
+                Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+                Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
 
-                    await call.RequestStream.CompleteAsync();
+                await call.RequestStream.CompleteAsync();
 
-                    Assert.IsFalse(await call.ResponseStream.MoveNext());
-                }
-                Console.WriteLine("Passed!");
-            }).Wait();
+                Assert.IsFalse(await call.ResponseStream.MoveNext());
+            }
+            Console.WriteLine("Passed!");
         }
 
-        public static void RunEmptyStream(TestService.ITestServiceClient client)
+        public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
+            Console.WriteLine("running empty_stream");
+            using (var call = client.FullDuplexCall())
             {
-                Console.WriteLine("running empty_stream");
-                using (var call = client.FullDuplexCall())
-                {
-                    await call.RequestStream.CompleteAsync();
+                await call.RequestStream.CompleteAsync();
 
-                    var responseList = await call.ResponseStream.ToList();
-                    Assert.AreEqual(0, responseList.Count);
-                }
-                Console.WriteLine("Passed!");
-            }).Wait();
+                var responseList = await call.ResponseStream.ToList();
+                Assert.AreEqual(0, responseList.Count);
+            }
+            Console.WriteLine("Passed!");
         }
 
         public static void RunServiceAccountCreds(TestService.ITestServiceClient client)
@@ -368,11 +356,7 @@ namespace Grpc.IntegrationTesting
             Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
             string oauth2Token = credential.Token.AccessToken;
 
-            // Intercept calls with an OAuth2 token obtained out-of-band.
-            client.HeaderInterceptor = new MetadataInterceptorDelegate((metadata) =>
-            {
-                metadata.Add(new Metadata.Entry("Authorization", "Bearer " + oauth2Token));
-            });
+            client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
@@ -393,78 +377,75 @@ namespace Grpc.IntegrationTesting
             var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope });
             Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
             string oauth2Token = credential.Token.AccessToken;
+            var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
                 .SetFillOauthScope(true)
                 .Build();
 
-            var response = client.UnaryCall(request, headers: new Metadata { new Metadata.Entry("Authorization", "Bearer " + oauth2Token) });
+            var headers = new Metadata();
+            headerInterceptor(headers);
+            var response = client.UnaryCall(request, headers: headers);
 
             Assert.AreEqual(AuthScopeResponse, response.OauthScope);
             Assert.AreEqual(ServiceAccountUser, response.Username);
             Console.WriteLine("Passed!");
         }
 
-        public static void RunCancelAfterBegin(TestService.ITestServiceClient client)
+        public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
+            Console.WriteLine("running cancel_after_begin");
+
+            var cts = new CancellationTokenSource();
+            using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
             {
-                Console.WriteLine("running cancel_after_begin");
+                // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
+                await Task.Delay(1000);
+                cts.Cancel();
 
-                var cts = new CancellationTokenSource();
-                using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
+                try
                 {
-                    // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
-                    await Task.Delay(1000);
-                    cts.Cancel();
-
-                    try
-                    {
-                        var response = await call.ResponseAsync;
-                        Assert.Fail();
-                    }
-                    catch (RpcException e)
-                    {
-                        Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
-                    }
+                    var response = await call.ResponseAsync;
+                    Assert.Fail();
+                }
+                catch (RpcException e)
+                {
+                    Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
                 }
-                Console.WriteLine("Passed!");
-            }).Wait();
+            }
+            Console.WriteLine("Passed!");
         }
 
-        public static void RunCancelAfterFirstResponse(TestService.ITestServiceClient client)
+        public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client)
         {
-            Task.Run(async () =>
-            {
-                Console.WriteLine("running cancel_after_first_response");
+            Console.WriteLine("running cancel_after_first_response");
 
-                var cts = new CancellationTokenSource();
-                using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
-                {
-                    await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
-                        .SetResponseType(PayloadType.COMPRESSABLE)
-                        .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
-                        .SetPayload(CreateZerosPayload(27182)).Build());
+            var cts = new CancellationTokenSource();
+            using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
+            {
+                await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
+                    .SetResponseType(PayloadType.COMPRESSABLE)
+                    .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
+                    .SetPayload(CreateZerosPayload(27182)).Build());
 
-                    Assert.IsTrue(await call.ResponseStream.MoveNext());
-                    Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
-                    Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
+                Assert.IsTrue(await call.ResponseStream.MoveNext());
+                Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
+                Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
 
-                    cts.Cancel();
+                cts.Cancel();
 
-                    try
-                    {
-                        await call.ResponseStream.MoveNext();
-                        Assert.Fail();
-                    }
-                    catch (RpcException e)
-                    {
-                        Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
-                    }
+                try
+                {
+                    await call.ResponseStream.MoveNext();
+                    Assert.Fail();
                 }
-                Console.WriteLine("Passed!");
-            }).Wait();
+                catch (RpcException e)
+                {
+                    Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode);
+                }
+            }
+            Console.WriteLine("Passed!");
         }
 
         // This is not an official interop test, but it's useful.
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index f306289cfb5dc9031c2bfb4fdeb5a303b3ef91de..2756ce97aa32e0a4badb505c75c7869e1764fe1b 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -57,7 +57,7 @@ namespace Grpc.IntegrationTesting
         {
             server = new Server();
             server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
-            int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
+            int port = server.AddPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
             server.Start();
 
             var options = new List<ChannelOption>
@@ -89,39 +89,39 @@ namespace Grpc.IntegrationTesting
         }
 
         [Test]
-        public void ClientStreaming()
+        public async Task ClientStreaming()
         {
-            InteropClient.RunClientStreaming(client);
+            await InteropClient.RunClientStreamingAsync(client);
         }
 
         [Test]
-        public void ServerStreaming()
+        public async Task ServerStreaming()
         {
-            InteropClient.RunServerStreaming(client);
+            await InteropClient.RunServerStreamingAsync(client);
         }
 
         [Test]
-        public void PingPong()
+        public async Task PingPong()
         {
-            InteropClient.RunPingPong(client);
+            await InteropClient.RunPingPongAsync(client);
         }
 
         [Test]
-        public void EmptyStream()
+        public async Task EmptyStream()
         {
-            InteropClient.RunEmptyStream(client);
+            await InteropClient.RunEmptyStreamAsync(client);
         }
 
         [Test]
-        public void CancelAfterBegin()
+        public async Task CancelAfterBegin()
         {
-            InteropClient.RunCancelAfterBegin(client);
+            await InteropClient.RunCancelAfterBeginAsync(client);
         }
 
         [Test]
-        public void CancelAfterFirstResponse()
+        public async Task CancelAfterFirstResponse()
         {
-            InteropClient.RunCancelAfterFirstResponse(client);
+            await InteropClient.RunCancelAfterFirstResponseAsync(client);
         }
     }
 }
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 9475e66c4087f14ef0947f2309618d2497d1078a..bf6947e09dc7b3653c9166dac1bb3e3874d2079d 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -95,11 +95,11 @@ namespace Grpc.IntegrationTesting
             int port = options.port.Value;
             if (options.useTls)
             {
-                server.AddListeningPort(host, port, TestCredentials.CreateTestServerCredentials());
+                server.AddPort(host, port, TestCredentials.CreateTestServerCredentials());
             }
             else
             {
-                server.AddListeningPort(host, options.port.Value);
+                server.AddPort(host, options.port.Value, ServerCredentials.Insecure);
             }
             Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port));
             server.Start();
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1baf40eea2e439cd41a93e16daabe2f35b0912a1
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using grpc.testing;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+    /// <summary>
+    /// Test SSL credentials where server authenticates client 
+    /// and client authenticates the server.
+    /// </summary>
+    public class SslCredentialsTest
+    {
+        string host = "localhost";
+        Server server;
+        Channel channel;
+        TestService.ITestServiceClient client;
+
+        [TestFixtureSetUp]
+        public void Init()
+        {
+            var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
+            var keyCertPair = new KeyCertificatePair(
+                File.ReadAllText(TestCredentials.ServerCertChainPath),
+                File.ReadAllText(TestCredentials.ServerPrivateKeyPath));
+
+            var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert);
+            var clientCredentials = new SslCredentials(rootCert, keyCertPair);
+
+            server = new Server();
+            server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
+            int port = server.AddPort(host, Server.PickUnusedPort, serverCredentials);
+            server.Start();
+
+            var options = new List<ChannelOption>
+            {
+                new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
+            };
+
+            channel = new Channel(host, port, clientCredentials, options);
+            client = TestService.NewClient(channel);
+        }
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            channel.Dispose();
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+
+        [Test]
+        public void AuthenticatedClientAndServer()
+        {
+            var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build());
+            Assert.AreEqual(10, response.Payload.Body.Length);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index 401c50b1aeaf6ee12dcda2940c436364e7f245ba..54d8587713c309a15a86af41c0006769b2358d11 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -78,7 +78,7 @@ namespace Grpc.IntegrationTesting
             var keyCertPair = new KeyCertificatePair(
                 File.ReadAllText(ServerCertChainPath),
                 File.ReadAllText(ServerPrivateKeyPath));
-            return new SslServerCredentials(ImmutableList.Create(keyCertPair));
+            return new SslServerCredentials(new[] { keyCertPair });
         }
     }
 }
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
index 966b777192f3d53ea95e7056f903c1bc009213f8..0a82bb4f16c05bec578209f2c8bf3ce369abdc3d 100644
--- a/src/csharp/Grpc.IntegrationTesting/app.config
+++ b/src/csharp/Grpc.IntegrationTesting/app.config
@@ -4,7 +4,7 @@
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index c74ac75d79a6128b1a4f08891eb5dc620a01eb03..746133a7a5c6cf0af76c2a1450eae56743b4fb68 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,14 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
+  <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" />
   <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
   <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
-  <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
+  <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
   <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
-  <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
-  <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+  <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
   <package id="NUnit" version="2.6.4" targetFramework="net45" />
   <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 705e4fb1c215b39b826428c3efe185e30cbf5cac..0cd8aaef6d2b542e1b23ba8fa49bc39dcab45265 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -34,58 +34,58 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "G
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|x86 = Debug|x86
-		Release|x86 = Release|x86
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 	EndGlobalSection
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 7e30a84a6296546fb86bc872caf0a67c7add5023..219f6d7d7328bdbc36d4bc7693a0cca7b53edae2 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -367,8 +367,9 @@ grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
 /* Channel */
 
 GPR_EXPORT grpc_channel *GPR_CALLTYPE
-grpcsharp_channel_create(const char *target, const grpc_channel_args *args) {
-  return grpc_channel_create(target, args);
+
+grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) {
+  return grpc_insecure_channel_create(target, args);
 }
 
 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
@@ -465,6 +466,14 @@ grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status,
   return grpc_call_cancel_with_status(call, status, description);
 }
 
+GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) {
+  return grpc_call_get_peer(call);
+}
+
+GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void *p) {
+  gpr_free(p);
+}
+
 GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
   grpc_call_destroy(call);
 }
@@ -709,7 +718,7 @@ grpcsharp_server_create(grpc_completion_queue *cq,
 }
 
 GPR_EXPORT gpr_int32 GPR_CALLTYPE
-grpcsharp_server_add_http2_port(grpc_server *server, const char *addr) {
+grpcsharp_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
   return grpc_server_add_http2_port(server, addr);
 }
 
diff --git a/src/node/README.md b/src/node/README.md
index 78781dab14700904867f61bd9e8bd5feea44c401..7d3d8c7fa101addfc350bf200656c54e0d6f45a4 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -85,7 +85,7 @@ An object with factory methods for creating credential objects for clients.
 ServerCredentials
 ```
 
-An object with factory methods fro creating credential objects for servers.
+An object with factory methods for creating credential objects for servers.
 
 [homebrew]:http://brew.sh
 [linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 15c9b2d97d6df4e6f37297a0e9d9e08005ac8c8b..dc45c8d8aece4d46da3ffb141f508d525bb372b2 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -192,7 +192,7 @@ class SendMetadataOp : public Op {
   }
  protected:
   std::string GetTypeString() const {
-    return "send metadata";
+    return "send_metadata";
   }
 };
 
@@ -216,7 +216,7 @@ class SendMessageOp : public Op {
   }
  protected:
   std::string GetTypeString() const {
-    return "send message";
+    return "send_message";
   }
 };
 
@@ -232,7 +232,7 @@ class SendClientCloseOp : public Op {
   }
  protected:
   std::string GetTypeString() const {
-    return "client close";
+    return "client_close";
   }
 };
 
@@ -276,7 +276,7 @@ class SendServerStatusOp : public Op {
   }
  protected:
   std::string GetTypeString() const {
-    return "send status";
+    return "send_status";
   }
 };
 
@@ -453,6 +453,8 @@ void Call::Init(Handle<Object> exports) {
                           NanNew<FunctionTemplate>(StartBatch)->GetFunction());
   NanSetPrototypeTemplate(tpl, "cancel",
                           NanNew<FunctionTemplate>(Cancel)->GetFunction());
+  NanSetPrototypeTemplate(tpl, "getPeer",
+                          NanNew<FunctionTemplate>(GetPeer)->GetFunction());
   NanAssignPersistent(fun_tpl, tpl);
   Handle<Function> ctr = tpl->GetFunction();
   ctr->Set(NanNew("WRITE_BUFFER_HINT"),
@@ -608,5 +610,17 @@ NAN_METHOD(Call::Cancel) {
   NanReturnUndefined();
 }
 
+NAN_METHOD(Call::GetPeer) {
+  NanScope();
+  if (!HasInstance(args.This())) {
+    return NanThrowTypeError("getPeer can only be called on Call objects");
+  }
+  Call *call = ObjectWrap::Unwrap<Call>(args.This());
+  char *peer = grpc_call_get_peer(call->wrapped_call);
+  Handle<Value> peer_value = NanNew(peer);
+  gpr_free(peer);
+  NanReturnValue(peer_value);
+}
+
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 43142c7091fe6c30b434a03d413c22f844853771..6acda76197ffcac36af764ba5c83e5a6c7df510c 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -120,6 +120,7 @@ class Call : public ::node::ObjectWrap {
   static NAN_METHOD(New);
   static NAN_METHOD(StartBatch);
   static NAN_METHOD(Cancel);
+  static NAN_METHOD(GetPeer);
   static NanCallback *constructor;
   // Used for typechecking instances of this javascript class
   static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index d37bf763ddc707396783576ac2753bc6e3ef2d30..c43b55f11527ce72bbbe98d5554de2267f7246f8 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -76,6 +76,8 @@ void Channel::Init(Handle<Object> exports) {
   tpl->InstanceTemplate()->SetInternalFieldCount(1);
   NanSetPrototypeTemplate(tpl, "close",
                           NanNew<FunctionTemplate>(Close)->GetFunction());
+  NanSetPrototypeTemplate(tpl, "getTarget",
+                          NanNew<FunctionTemplate>(GetTarget)->GetFunction());
   NanAssignPersistent(fun_tpl, tpl);
   Handle<Function> ctr = tpl->GetFunction();
   constructor = new NanCallback(ctr);
@@ -103,7 +105,7 @@ NAN_METHOD(Channel::New) {
     NanUtf8String *host = new NanUtf8String(args[0]);
     NanUtf8String *host_override = NULL;
     if (args[1]->IsUndefined()) {
-      wrapped_channel = grpc_channel_create(**host, NULL);
+      wrapped_channel = grpc_insecure_channel_create(**host, NULL);
     } else if (args[1]->IsObject()) {
       grpc_credentials *creds = NULL;
       Handle<Object> args_hash(args[1]->ToObject()->Clone());
@@ -148,7 +150,7 @@ NAN_METHOD(Channel::New) {
         }
       }
       if (creds == NULL) {
-        wrapped_channel = grpc_channel_create(**host, &channel_args);
+        wrapped_channel = grpc_insecure_channel_create(**host, &channel_args);
       } else {
         wrapped_channel =
             grpc_secure_channel_create(creds, **host, &channel_args);
@@ -185,5 +187,14 @@ NAN_METHOD(Channel::Close) {
   NanReturnUndefined();
 }
 
+NAN_METHOD(Channel::GetTarget) {
+  NanScope();
+  if (!HasInstance(args.This())) {
+    return NanThrowTypeError("getTarget can only be called on Channel objects");
+  }
+  Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+  NanReturnValue(NanNew(grpc_channel_get_target(channel->wrapped_channel)));
+}
+
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h
index b3aa0f700fa98b16f47a4fa6bd4834b0f550a600..6725ebb03f008262f7a76a5d30c5efece74732d6 100644
--- a/src/node/ext/channel.h
+++ b/src/node/ext/channel.h
@@ -66,6 +66,7 @@ class Channel : public ::node::ObjectWrap {
 
   static NAN_METHOD(New);
   static NAN_METHOD(Close);
+  static NAN_METHOD(GetTarget);
   static NanCallback *constructor;
   static v8::Persistent<v8::FunctionTemplate> fun_tpl;
 
diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
index 23fe20ed78936ae69024c70dea0691c501c5f9ae..a695e3656d3c6ac2bb20cf7218f078a5e5158e35 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/credentials.cc
@@ -79,8 +79,6 @@ void Credentials::Init(Handle<Object> exports) {
            NanNew<FunctionTemplate>(CreateComposite)->GetFunction());
   ctr->Set(NanNew("createGce"),
            NanNew<FunctionTemplate>(CreateGce)->GetFunction());
-  ctr->Set(NanNew("createFake"),
-           NanNew<FunctionTemplate>(CreateFake)->GetFunction());
   ctr->Set(NanNew("createIam"),
            NanNew<FunctionTemplate>(CreateIam)->GetFunction());
   ctr->Set(NanNew("createInsecure"),
@@ -194,11 +192,6 @@ NAN_METHOD(Credentials::CreateGce) {
   NanReturnValue(WrapStruct(creds));
 }
 
-NAN_METHOD(Credentials::CreateFake) {
-  NanScope();
-  NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create()));
-}
-
 NAN_METHOD(Credentials::CreateIam) {
   NanScope();
   if (!args[0]->IsString()) {
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 34cde9ffab06dbced9893e455b412d45a986ae63..8554fce777271df1119cc488399460459c76f1ad 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -108,7 +108,7 @@ class NewCallOp : public Op {
 
  protected:
   std::string GetTypeString() const {
-    return "new call";
+    return "new_call";
   }
 };
 
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index d2b63cdc4ec26b1983164b44c39f3899209a1fac..66aaa3300fc647ded7450d338555af4542dd84e6 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -73,8 +73,6 @@ void ServerCredentials::Init(Handle<Object> exports) {
   Handle<Function> ctr = tpl->GetFunction();
   ctr->Set(NanNew("createSsl"),
            NanNew<FunctionTemplate>(CreateSsl)->GetFunction());
-  ctr->Set(NanNew("createFake"),
-           NanNew<FunctionTemplate>(CreateFake)->GetFunction());
   constructor = new NanCallback(ctr);
   exports->Set(NanNew("ServerCredentials"), ctr);
 }
@@ -144,11 +142,5 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
       grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1)));
 }
 
-NAN_METHOD(ServerCredentials::CreateFake) {
-  NanScope();
-  NanReturnValue(
-      WrapStruct(grpc_fake_transport_security_server_credentials_create()));
-}
-
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/server_credentials.h b/src/node/ext/server_credentials.h
index aaa7ef297a40cc9f4d868429b0c08e42cc52a5aa..80747504a14c592e3e1e74098df7040703e274e5 100644
--- a/src/node/ext/server_credentials.h
+++ b/src/node/ext/server_credentials.h
@@ -63,7 +63,6 @@ class ServerCredentials : public ::node::ObjectWrap {
 
   static NAN_METHOD(New);
   static NAN_METHOD(CreateSsl);
-  static NAN_METHOD(CreateFake);
   static NanCallback *constructor;
   // Used for typechecking instances of this javascript class
   static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/src/client.js b/src/node/src/client.js
index da6327b4320461f123943b8a2fabccdb0ed38f77..d89c656c07e6c7be24beb4efd814004236a1947d 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -187,6 +187,19 @@ ClientReadableStream.prototype.cancel = cancel;
 ClientWritableStream.prototype.cancel = cancel;
 ClientDuplexStream.prototype.cancel = cancel;
 
+/**
+ * Get the endpoint this call/stream is connected to.
+ * @return {string} The URI of the endpoint
+ */
+function getPeer() {
+  /* jshint validthis: true */
+  return this.call.getPeer();
+}
+
+ClientReadableStream.prototype.getPeer = getPeer;
+ClientWritableStream.prototype.getPeer = getPeer;
+ClientDuplexStream.prototype.getPeer = getPeer;
+
 /**
  * Get a function that can make unary requests to the specified method.
  * @param {string} method The name of the method to request
@@ -223,6 +236,9 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
     emitter.cancel = function cancel() {
       call.cancel();
     };
+    emitter.getPeer = function getPeer() {
+      return call.getPeer();
+    };
     this.updateMetadata(this.auth_uri, metadata, function(error, metadata) {
       if (error) {
         call.cancel();
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 0a3a0031bdfad75d47914e5688a8d0907d92555f..e876313d96cc00d9c21b4ba6137e93523ab18c61 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -373,6 +373,19 @@ ServerDuplexStream.prototype._read = _read;
 ServerDuplexStream.prototype._write = _write;
 ServerDuplexStream.prototype.sendMetadata = sendMetadata;
 
+/**
+ * Get the endpoint this call/stream is connected to.
+ * @return {string} The URI of the endpoint
+ */
+function getPeer() {
+  /* jshint validthis: true */
+  return this.call.getPeer();
+}
+
+ServerReadableStream.prototype.getPeer = getPeer;
+ServerWritableStream.prototype.getPeer = getPeer;
+ServerDuplexStream.prototype.getPeer = getPeer;
+
 /**
  * Fully handle a unary call
  * @param {grpc.Call} call The call to handle
@@ -389,6 +402,9 @@ function handleUnary(call, handler, metadata) {
       call.startBatch(batch, function() {});
     }
   };
+  emitter.getPeer = function() {
+    return call.getPeer();
+  };
   emitter.on('error', function(error) {
     handleError(call, error);
   });
@@ -544,7 +560,7 @@ function Server(options) {
       if (err) {
         return;
       }
-      var details = event['new call'];
+      var details = event.new_call;
       var call = details.call;
       var method = details.method;
       var metadata = details.metadata;
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 98158ffff357d0efed892e8c91d6c8851d7c7d4e..942c31ac688039e6a43fd66b95120731eea7c782 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -132,7 +132,7 @@ describe('call', function() {
                                                     'key2': ['value2']};
         call.startBatch(batch, function(err, resp) {
           assert.ifError(err);
-          assert.deepEqual(resp, {'send metadata': true});
+          assert.deepEqual(resp, {'send_metadata': true});
           done();
         });
       });
@@ -147,7 +147,7 @@ describe('call', function() {
         };
         call.startBatch(batch, function(err, resp) {
           assert.ifError(err);
-          assert.deepEqual(resp, {'send metadata': true});
+          assert.deepEqual(resp, {'send_metadata': true});
           done();
         });
       });
@@ -184,4 +184,10 @@ describe('call', function() {
       });
     });
   });
+  describe('getPeer', function() {
+    it('should return a string', function() {
+      var call = new grpc.Call(channel, 'method', getDeadline(1));
+      assert.strictEqual(typeof call.getPeer(), 'string');
+    });
+  });
 });
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
index 33200c99ee2d8f3305d9efa703c2cbd28ddf4ea4..3e61d3bbc62da47cad37b75e7b7ea9817c864477 100644
--- a/src/node/test/channel_test.js
+++ b/src/node/test/channel_test.js
@@ -87,4 +87,10 @@ describe('channel', function() {
       });
     });
   });
+  describe('getTarget', function() {
+    it('should return a string', function() {
+      var channel = new grpc.Channel('localhost', {});
+      assert.strictEqual(typeof channel.getTarget(), 'string');
+    });
+  });
 });
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 667852f382699ca8457af07dfb5dad11054ba323..5d3baf823da1398b76f4c0fd55d7bad5159245f4 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -85,37 +85,37 @@ describe('end-to-end', function() {
     call.startBatch(client_batch, function(err, response) {
       assert.ifError(err);
       assert.deepEqual(response, {
-        'send metadata': true,
-        'client close': true,
-        'metadata': {},
-        'status': {
-          'code': grpc.status.OK,
-          'details': status_text,
-          'metadata': {}
+        send_metadata: true,
+        client_close: true,
+        metadata: {},
+        status: {
+          code: grpc.status.OK,
+          details: status_text,
+          metadata: {}
         }
       });
       done();
     });
 
     server.requestCall(function(err, call_details) {
-      var new_call = call_details['new call'];
+      var new_call = call_details.new_call;
       assert.notEqual(new_call, null);
       var server_call = new_call.call;
       assert.notEqual(server_call, null);
       var server_batch = {};
       server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
       server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
-        'metadata': {},
-        'code': grpc.status.OK,
-        'details': status_text
+        metadata: {},
+        code: grpc.status.OK,
+        details: status_text
       };
       server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
       server_call.startBatch(server_batch, function(err, response) {
         assert.ifError(err);
         assert.deepEqual(response, {
-          'send metadata': true,
-          'send status': true,
-          'cancelled': false
+          send_metadata: true,
+          send_status: true,
+          cancelled: false
         });
        done();
       });
@@ -131,7 +131,7 @@ describe('end-to-end', function() {
                              Infinity);
     var client_batch = {};
     client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
-      'client_key': ['client_value']
+      client_key: ['client_value']
     };
     client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
     client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
@@ -139,18 +139,18 @@ describe('end-to-end', function() {
     call.startBatch(client_batch, function(err, response) {
       assert.ifError(err);
       assert.deepEqual(response,{
-        'send metadata': true,
-        'client close': true,
+        send_metadata: true,
+        client_close: true,
         metadata: {server_key: ['server_value']},
-        status: {'code': grpc.status.OK,
-                 'details': status_text,
-                 'metadata': {}}
+        status: {code: grpc.status.OK,
+                 details: status_text,
+                 metadata: {}}
       });
       done();
     });
 
     server.requestCall(function(err, call_details) {
-      var new_call = call_details['new call'];
+      var new_call = call_details.new_call;
       assert.notEqual(new_call, null);
       assert.strictEqual(new_call.metadata.client_key[0],
                          'client_value');
@@ -158,20 +158,20 @@ describe('end-to-end', function() {
       assert.notEqual(server_call, null);
       var server_batch = {};
       server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
-        'server_key': ['server_value']
+        server_key: ['server_value']
       };
       server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
-        'metadata': {},
-        'code': grpc.status.OK,
-        'details': status_text
+        metadata: {},
+        code: grpc.status.OK,
+        details: status_text
       };
       server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
       server_call.startBatch(server_batch, function(err, response) {
         assert.ifError(err);
         assert.deepEqual(response, {
-          'send metadata': true,
-          'send status': true,
-          'cancelled': false
+          send_metadata: true,
+          send_status: true,
+          cancelled: false
         });
        done();
       });
@@ -196,19 +196,19 @@ describe('end-to-end', function() {
     client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
     call.startBatch(client_batch, function(err, response) {
       assert.ifError(err);
-      assert(response['send metadata']);
-      assert(response['client close']);
+      assert(response.send_metadata);
+      assert(response.client_close);
       assert.deepEqual(response.metadata, {});
-      assert(response['send message']);
+      assert(response.send_message);
       assert.strictEqual(response.read.toString(), reply_text);
-      assert.deepEqual(response.status, {'code': grpc.status.OK,
-                                         'details': status_text,
-                                         'metadata': {}});
+      assert.deepEqual(response.status, {code: grpc.status.OK,
+                                         details: status_text,
+                                         metadata: {}});
       done();
     });
 
     server.requestCall(function(err, call_details) {
-      var new_call = call_details['new call'];
+      var new_call = call_details.new_call;
       assert.notEqual(new_call, null);
       var server_call = new_call.call;
       assert.notEqual(server_call, null);
@@ -217,18 +217,18 @@ describe('end-to-end', function() {
       server_batch[grpc.opType.RECV_MESSAGE] = true;
       server_call.startBatch(server_batch, function(err, response) {
         assert.ifError(err);
-        assert(response['send metadata']);
+        assert(response.send_metadata);
         assert.strictEqual(response.read.toString(), req_text);
         var response_batch = {};
         response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text);
         response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
-          'metadata': {},
-          'code': grpc.status.OK,
-          'details': status_text
+          metadata: {},
+          code: grpc.status.OK,
+          details: status_text
         };
         response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
         server_call.startBatch(response_batch, function(err, response) {
-          assert(response['send status']);
+          assert(response.send_status);
           assert(!response.cancelled);
           done();
         });
@@ -251,9 +251,9 @@ describe('end-to-end', function() {
     call.startBatch(client_batch, function(err, response) {
       assert.ifError(err);
       assert.deepEqual(response, {
-        'send metadata': true,
-        'send message': true,
-        'metadata': {}
+        send_metadata: true,
+        send_message: true,
+        metadata: {}
       });
       var req2_batch = {};
       req2_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[1]);
@@ -262,12 +262,12 @@ describe('end-to-end', function() {
       call.startBatch(req2_batch, function(err, resp) {
         assert.ifError(err);
         assert.deepEqual(resp, {
-          'send message': true,
-          'client close': true,
-          'status': {
-            'code': grpc.status.OK,
-            'details': status_text,
-            'metadata': {}
+          send_message: true,
+          client_close: true,
+          status: {
+            code: grpc.status.OK,
+            details: status_text,
+            metadata: {}
           }
         });
         done();
@@ -275,7 +275,7 @@ describe('end-to-end', function() {
     });
 
     server.requestCall(function(err, call_details) {
-      var new_call = call_details['new call'];
+      var new_call = call_details.new_call;
       assert.notEqual(new_call, null);
       var server_call = new_call.call;
       assert.notEqual(server_call, null);
@@ -284,7 +284,7 @@ describe('end-to-end', function() {
       server_batch[grpc.opType.RECV_MESSAGE] = true;
       server_call.startBatch(server_batch, function(err, response) {
         assert.ifError(err);
-        assert(response['send metadata']);
+        assert(response.send_metadata);
         assert.strictEqual(response.read.toString(), requests[0]);
         var snd_batch = {};
         snd_batch[grpc.opType.RECV_MESSAGE] = true;
@@ -294,13 +294,13 @@ describe('end-to-end', function() {
           var end_batch = {};
           end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
           end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
-            'metadata': {},
-            'code': grpc.status.OK,
-            'details': status_text
+            metadata: {},
+            code: grpc.status.OK,
+            details: status_text
           };
           server_call.startBatch(end_batch, function(err, response) {
             assert.ifError(err);
-            assert(response['send status']);
+            assert(response.send_status);
             assert(!response.cancelled);
             done();
           });
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 7cb34fa0cb5d24cf29918b779f3bdde9bc0149d5..9c7bb465aa3dd613654e3e4b7f2fbf6dbdeaec0b 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -34,6 +34,8 @@
 'use strict';
 
 var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
 var grpc = require('bindings')('grpc.node');
 
 describe('server', function() {
@@ -67,9 +69,13 @@ describe('server', function() {
     before(function() {
       server = new grpc.Server();
     });
-    it('should bind to an unused port with fake credentials', function() {
+    it('should bind to an unused port with ssl credentials', function() {
       var port;
-      var creds = grpc.ServerCredentials.createFake();
+      var key_path = path.join(__dirname, '../test/data/server1.key');
+      var pem_path = path.join(__dirname, '../test/data/server1.pem');
+      var key_data = fs.readFileSync(key_path);
+      var pem_data = fs.readFileSync(pem_path);
+      var creds = grpc.ServerCredentials.createSsl(null, key_data, pem_data);
       assert.doesNotThrow(function() {
         port = server.addSecureHttp2Port('0.0.0.0:0', creds);
       });
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 3cb68f8cd8389fe9b0d3b4e5ba33cb2313fce13b..9005cbd505a7fbc7532882cc3eea3b9bdaa19620 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -344,6 +344,9 @@ describe('Other conditions', function() {
   after(function() {
     server.shutdown();
   });
+  it('channel.getTarget should be available', function() {
+    assert.strictEqual(typeof client.channel.getTarget(), 'string');
+  });
   describe('Server recieving bad input', function() {
     var misbehavingClient;
     var badArg = new Buffer([0xFF]);
@@ -549,6 +552,43 @@ describe('Other conditions', function() {
       });
     });
   });
+  describe('call.getPeer should return the peer', function() {
+    it('for a unary call', function(done) {
+      var call = client.unary({error: false}, function(err, data) {
+        assert.ifError(err);
+        done();
+      });
+      assert.strictEqual(typeof call.getPeer(), 'string');
+    });
+    it('for a client stream call', function(done) {
+      var call = client.clientStream(function(err, data) {
+        assert.ifError(err);
+        done();
+      });
+      assert.strictEqual(typeof call.getPeer(), 'string');
+      call.write({error: false});
+      call.end();
+    });
+    it('for a server stream call', function(done) {
+      var call = client.serverStream({error: false});
+      assert.strictEqual(typeof call.getPeer(), 'string');
+      call.on('data', function(){});
+      call.on('status', function(status) {
+        assert.strictEqual(status.code, grpc.status.OK);
+        done();
+      });
+    });
+    it('for a bidi stream call', function(done) {
+      var call = client.bidiStream();
+      assert.strictEqual(typeof call.getPeer(), 'string');
+      call.write({error: false});
+      call.end();
+      call.on('data', function(){});
+      call.on('status', function(status) {
+        done();
+      });
+    });
+  });
 });
 describe('Cancelling surface client', function() {
   var client;
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index d27f7ca565badcd7c8230f410a4d0daca856cd4c..8518f78c5b23dd1496723632bef890a782456735 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -38,7 +38,7 @@
 @implementation GRPCUnsecuredChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_channel_create(host.UTF8String, NULL)]);
+  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
 }
 
 @end
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index b67bae75682f6b46aa0fb8abbc45ff59014f1245..1f76c7359d45bf371c415ceb4ccbdfab295431e3 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -472,6 +472,16 @@ cleanup:
   RETURN_DESTROY_ZVAL(result);
 }
 
+/**
+ * Get the endpoint this call/stream is connected to
+ * @return string The URI of the endpoint
+ */
+PHP_METHOD(Call, getPeer) {
+  wrapped_grpc_call *call =
+      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
+}
+
 /**
  * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it
  * has not already ended with another status.
@@ -485,7 +495,9 @@ PHP_METHOD(Call, cancel) {
 static zend_function_entry call_methods[] = {
     PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
     PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+    PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
+    PHP_FE_END};
 
 void grpc_init_call(TSRMLS_D) {
   zend_class_entry ce;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index b8262db162bf48350cd0d05919904d099aff6b1f..7d8a6f87ab67359e2ab465812b908be8a02d0b21 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -152,7 +152,7 @@ PHP_METHOD(Channel, __construct) {
   override = target;
   override_len = target_length;
   if (args_array == NULL) {
-    channel->wrapped = grpc_channel_create(target, NULL);
+    channel->wrapped = grpc_insecure_channel_create(target, NULL);
   } else {
     array_hash = Z_ARRVAL_P(args_array);
     if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
@@ -182,7 +182,7 @@ PHP_METHOD(Channel, __construct) {
     }
     php_grpc_read_args_array(args_array, &args);
     if (creds == NULL) {
-      channel->wrapped = grpc_channel_create(target, &args);
+      channel->wrapped = grpc_insecure_channel_create(target, &args);
     } else {
       gpr_log(GPR_DEBUG, "Initialized secure channel");
       channel->wrapped =
@@ -194,6 +194,16 @@ PHP_METHOD(Channel, __construct) {
   memcpy(channel->target, override, override_len);
 }
 
+/**
+ * Get the endpoint this call/stream is connected to
+ * @return string The URI of the endpoint
+ */
+PHP_METHOD(Channel, getTarget) {
+  wrapped_grpc_channel *channel =
+      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
+}
+
 /**
  * Close the channel
  */
@@ -208,7 +218,9 @@ PHP_METHOD(Channel, close) {
 
 static zend_function_entry channel_methods[] = {
     PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+    PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
+    PHP_FE_END};
 
 void grpc_init_channel(TSRMLS_D) {
   zend_class_entry ce;
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index a262b9981f5384cb576033a5f4ae48ea0909aafe..01cb94e3aa1d089f9a71e81bb3a8b472f04b3d5d 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -175,23 +175,12 @@ PHP_METHOD(Credentials, createGce) {
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
-/**
- * Create fake credentials. Only to be used for testing.
- * @return Credentials The new fake credentials object
- */
-PHP_METHOD(Credentials, createFake) {
-  grpc_credentials *creds = grpc_fake_transport_security_credentials_create();
-  zval *creds_object = grpc_php_wrap_credentials(creds);
-  RETURN_DESTROY_ZVAL(creds_object);
-}
-
 static zend_function_entry credentials_methods[] = {
     PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_ME(Credentials, createComposite, NULL,
            ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Credentials, createFake, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_FE_END};
 
 void grpc_init_credentials(TSRMLS_D) {
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index c4c1fabb1a51f1349bdc7da9c439412e479fb064..4c4a598cb0c904477609416ac447bb1ec3ca28bf 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -121,21 +121,8 @@ PHP_METHOD(ServerCredentials, createSsl) {
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
-/**
- * Create fake credentials. Only to be used for testing.
- * @return ServerCredentials The new fake credentials object
- */
-PHP_METHOD(ServerCredentials, createFake) {
-  grpc_server_credentials *creds =
-      grpc_fake_transport_security_server_credentials_create();
-  zval *creds_object = grpc_php_wrap_server_credentials(creds);
-  RETURN_DESTROY_ZVAL(creds_object);
-}
-
 static zend_function_entry server_credentials_methods[] = {
     PHP_ME(ServerCredentials, createSsl, NULL,
-           ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(ServerCredentials, createFake, NULL,
            ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
 
 void grpc_init_server_credentials(TSRMLS_D) {
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index 5b28417a0df479d442fd4e91f81bbdc2b5b35547..35057224f8ca021b16eaba9b702a477aaea8eca3 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -67,6 +67,13 @@ abstract class AbstractCall {
     return $this->metadata;
   }
 
+  /**
+   * @return string The URI of the endpoint.
+   */
+  public function getPeer() {
+    return $this->call->getPeer();
+  }
+
   /**
    * Cancels the call
    */
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 8c438e4bf92e6ac9a858a62f8de6d5c1e7b37d4d..a0c677908c7c4bc9714c8f5ffdc01401c1cf1d3b 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -67,6 +67,13 @@ class BaseStub {
     $this->channel = new Channel($hostname, $opts);
   }
 
+  /**
+   * @return string The URI of the endpoint.
+   */
+  public function getTarget() {
+    return $this->channel->getTarget();
+  }
+
   /**
    * Close the communication channel associated with this stub
    */
diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
index 6102aaf0a8b939041decab850cf7bf11b7ed59a6..8b7e67f57c25ffdbea4b1cec39e21ec6d1d33ed6 100644
--- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -43,7 +43,9 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
     $div_arg = new math\DivArgs();
     $div_arg->setDividend(7);
     $div_arg->setDivisor(4);
-    list($response, $status) = self::$client->Div($div_arg)->wait();
+    $call = self::$client->Div($div_arg);
+    $this->assertTrue(is_string($call->getPeer()));
+    list($response, $status) = $call->wait();
     $this->assertSame(1, $response->getQuotient());
     $this->assertSame(3, $response->getRemainder());
     $this->assertSame(\Grpc\STATUS_OK, $status->code);
@@ -53,6 +55,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
     $fib_arg = new math\FibArgs();
     $fib_arg->setLimit(7);
     $call = self::$client->Fib($fib_arg);
+    $this->assertTrue(is_string($call->getPeer()));
     $result_array = iterator_to_array($call->responses());
     $extract_num = function($num){
       return $num->getNum();
@@ -72,6 +75,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
       }
     };
     $call = self::$client->Sum($num_iter());
+    $this->assertTrue(is_string($call->getPeer()));
     list($response, $status) = $call->wait();
     $this->assertSame(21, $response->getNum());
     $this->assertSame(\Grpc\STATUS_OK, $status->code);
@@ -79,6 +83,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
 
   public function testBidiStreaming() {
     $call = self::$client->DivMany();
+    $this->assertTrue(is_string($call->getPeer()));
     for ($i = 0; $i < 7; $i++) {
       $div_arg = new math\DivArgs();
       $div_arg->setDividend(2 * $i + 1);
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 20415775574c3f1c77b68dccc3388ec30a7de71e..44e6242c299e54d079ae17ae4d3bff32fffc4332 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -332,10 +332,11 @@ if (in_array($args['test_case'], array(
   $opts['update_metadata'] = $auth->getUpdateMetadataFunc();
 }
 
-$stub = new grpc\testing\TestServiceClient(
-    new Grpc\BaseStub(
-        $server_address,
-        $opts));
+$internal_stub = new Grpc\BaseStub($server_address, $opts);
+hardAssert(is_string($internal_stub->getTarget()),
+           'Unexpected target URI value');
+
+$stub = new grpc\testing\TestServiceClient($internal_stub);
 
 echo "Connecting to $server_address\n";
 echo "Running test case $args[test_case]\n";
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 77a2d86ce4cb5896a0812126d3f8df98f175d604..caff15ee110f6ac2a0fb076d1e48af5e8de4d109 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -79,4 +79,8 @@ class CallTest extends PHPUnit_Framework_TestCase{
     $result = $this->call->startBatch($batch);
     $this->assertTrue($result->send_metadata);
   }
+
+  public function testGetPeer() {
+    $this->assertTrue(is_string($this->call->getPeer()));
+  }
 }
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 2980dca4a750cc4c3b9b5d7f2cfb054d20b10400..27e27cdfdf313f8bb757f697fb0d2900b1531956 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -34,8 +34,8 @@
 class EndToEndTest extends PHPUnit_Framework_TestCase{
   public function setUp() {
     $this->server = new Grpc\Server([]);
-    $port = $this->server->addHttp2Port('0.0.0.0:0');
-    $this->channel = new Grpc\Channel('localhost:' . $port, []);
+    $this->port = $this->server->addHttp2Port('0.0.0.0:0');
+    $this->channel = new Grpc\Channel('localhost:' . $this->port, []);
     $this->server->start();
   }
 
@@ -149,4 +149,8 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
     unset($call);
     unset($server_call);
   }
+
+  public function testGetTarget() {
+    $this->assertTrue(is_string($this->channel->getTarget()));
+  }
 }
diff --git a/src/python/src/grpc/_adapter/_c/types.h b/src/python/src/grpc/_adapter/_c/types.h
index 3449f0643f79c5964d68f1ee513e6a2f49782616..4e0da4a28a922db43cb19b675960125eed88eb3c 100644
--- a/src/python/src/grpc/_adapter/_c/types.h
+++ b/src/python/src/grpc/_adapter/_c/types.h
@@ -63,8 +63,6 @@ ClientCredentials *pygrpc_ClientCredentials_jwt(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
 ClientCredentials *pygrpc_ClientCredentials_refresh_token(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_fake_transport_security(
-    PyTypeObject *type, PyObject *ignored);
 ClientCredentials *pygrpc_ClientCredentials_iam(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
 extern PyTypeObject pygrpc_ClientCredentials_type;
@@ -81,8 +79,6 @@ typedef struct ServerCredentials {
 void pygrpc_ServerCredentials_dealloc(ServerCredentials *self);
 ServerCredentials *pygrpc_ServerCredentials_ssl(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ServerCredentials *pygrpc_ServerCredentials_fake_transport_security(
-    PyTypeObject *type, PyObject *ignored);
 extern PyTypeObject pygrpc_ServerCredentials_type;
 
 
diff --git a/src/python/src/grpc/_adapter/_c/types/channel.c b/src/python/src/grpc/_adapter/_c/types/channel.c
index c235597466c9a24a525603f8fab56fc25635a7df..feb256cf00095e147f5a529de87008f64d2d9604 100644
--- a/src/python/src/grpc/_adapter/_c/types/channel.c
+++ b/src/python/src/grpc/_adapter/_c/types/channel.c
@@ -104,7 +104,7 @@ Channel *pygrpc_Channel_new(
   if (creds) {
     self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
   } else {
-    self->c_chan = grpc_channel_create(target, &c_args);
+    self->c_chan = grpc_insecure_channel_create(target, &c_args);
   }
   pygrpc_discard_channel_args(c_args);
   return self;
diff --git a/src/python/src/grpc/_adapter/_c/types/client_credentials.c b/src/python/src/grpc/_adapter/_c/types/client_credentials.c
index 9ea2b39cad70b06ef6742683ee317cc167980bba..e314c1532473dc0c9e68b6f084831d3fec46c7b0 100644
--- a/src/python/src/grpc/_adapter/_c/types/client_credentials.c
+++ b/src/python/src/grpc/_adapter/_c/types/client_credentials.c
@@ -54,9 +54,6 @@ PyMethodDef pygrpc_ClientCredentials_methods[] = {
      METH_CLASS|METH_KEYWORDS, ""},
     {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"fake_transport_security",
-     (PyCFunction)pygrpc_ClientCredentials_fake_transport_security,
-     METH_CLASS|METH_NOARGS, ""},
     {"iam", (PyCFunction)pygrpc_ClientCredentials_iam,
      METH_CLASS|METH_KEYWORDS, ""},
     {NULL}
@@ -250,20 +247,6 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token(
   return self;
 }
 
-ClientCredentials *pygrpc_ClientCredentials_fake_transport_security(
-    PyTypeObject *type, PyObject *ignored) {
-  ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_fake_transport_security_credentials_create();
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError,
-                    "couldn't create fake credentials; "
-                    "something is horribly wrong with the universe");
-    return NULL;
-  }
-  return self;
-}
-
 ClientCredentials *pygrpc_ClientCredentials_iam(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
   ClientCredentials *self;
diff --git a/src/python/src/grpc/_adapter/_c/types/server_credentials.c b/src/python/src/grpc/_adapter/_c/types/server_credentials.c
index 2e02c8fe8161cbedf23c68e26dcf47e26e0d17fc..f22edbf18727b8ab579d0604c8e239a7942b95f6 100644
--- a/src/python/src/grpc/_adapter/_c/types/server_credentials.c
+++ b/src/python/src/grpc/_adapter/_c/types/server_credentials.c
@@ -43,9 +43,6 @@
 PyMethodDef pygrpc_ServerCredentials_methods[] = {
     {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"fake_transport_security",
-     (PyCFunction)pygrpc_ServerCredentials_fake_transport_security,
-     METH_CLASS|METH_NOARGS, ""},
     {NULL}
 };
 const char pygrpc_ServerCredentials_doc[] = "";
@@ -137,10 +134,3 @@ ServerCredentials *pygrpc_ServerCredentials_ssl(
   return self;
 }
 
-ServerCredentials *pygrpc_ServerCredentials_fake_transport_security(
-    PyTypeObject *type, PyObject *ignored) {
-  ServerCredentials *self = (ServerCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_fake_transport_security_server_credentials_create();
-  return self;
-}
-
diff --git a/src/python/src/grpc/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py
index 133b124072c99ebe7110aa880ce3d76dc1ec568f..fe020e2a9cfe915faa30859dc942634fa8c46ec8 100644
--- a/src/python/src/grpc/_adapter/_c_test.py
+++ b/src/python/src/grpc/_adapter/_c_test.py
@@ -36,14 +36,6 @@ from grpc._adapter import _types
 
 class CTypeSmokeTest(unittest.TestCase):
 
-  def testClientCredentialsUpDown(self):
-    credentials = _c.ClientCredentials.fake_transport_security()
-    del credentials
-
-  def testServerCredentialsUpDown(self):
-    credentials = _c.ServerCredentials.fake_transport_security()
-    del credentials
-
   def testCompletionQueueUpDown(self):
     completion_queue = _c.CompletionQueue()
     del completion_queue
@@ -58,10 +50,6 @@ class CTypeSmokeTest(unittest.TestCase):
     channel = _c.Channel('[::]:0', [])
     del channel
 
-  def testSecureChannelUpDown(self):
-    channel = _c.Channel('[::]:0', [], _c.ClientCredentials.fake_transport_security())
-    del channel
-
 
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index a49cd007bfa195589cf214e36ebbc645042759b1..9a8edfad0cbb4fd2650aed9a5b50bff0abf31804 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -97,7 +97,7 @@ class InsecureServerInsecureClient(unittest.TestCase):
     CLIENT_METADATA_BIN_VALUE = b'\0'*1000
     SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
     SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
-    SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought'
+    SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
     SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
     SERVER_STATUS_CODE = _types.StatusCode.OK
     SERVER_STATUS_DETAILS = 'our work is never over'
diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx
index 7bb3f798b214792e80932ac8dfc2c2b6020ee954..2d74702fbdaad899715f0d05cfb3f7043e290918 100644
--- a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx
@@ -153,12 +153,6 @@ def client_credentials_refresh_token(json_refresh_token):
   credentials.references.append(json_refresh_token)
   return credentials
 
-def client_credentials_fake_transport_security():
-  cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = (
-      grpc.grpc_fake_transport_security_credentials_create())
-  return credentials
-
 def client_credentials_iam(authorization_token, authority_selector):
   if isinstance(authorization_token, bytes):
     pass
@@ -211,8 +205,3 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs):
   )
   return credentials
 
-def server_credentials_fake_transport_security():
-  cdef ServerCredentials credentials = ServerCredentials()
-  credentials.c_credentials = (
-      grpc.grpc_fake_transport_security_server_credentials_create())
-  return credentials
diff --git a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd
index a76ddfc9e1f287be81c870e63bb348d1c87c433d..d0653835879c107e9e3a22e30579bbf16c6b79d2 100644
--- a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd
@@ -317,7 +317,6 @@ cdef extern from "grpc/grpc_security.h":
                                                 gpr_timespec token_lifetime)
   grpc_credentials *grpc_refresh_token_credentials_create(
       const char *json_refresh_token)
-  grpc_credentials *grpc_fake_transport_security_credentials_create()
   grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
                                                 const char *authority_selector)
   void grpc_credentials_release(grpc_credentials *creds)
@@ -334,7 +333,6 @@ cdef extern from "grpc/grpc_security.h":
       const char *pem_root_certs,
       grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
       size_t num_key_cert_pairs);
-  grpc_server_credentials *grpc_fake_transport_security_server_credentials_create()
   void grpc_server_credentials_release(grpc_server_credentials *creds)
 
   int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
diff --git a/src/python/src/grpc/_cython/adapter_low.py b/src/python/src/grpc/_cython/adapter_low.py
index 7546dd15992becad65b59003f798814ca2ffa0c2..2bb468eece8d7e5503284d712ca2e3ed7c7f6142 100644
--- a/src/python/src/grpc/_cython/adapter_low.py
+++ b/src/python/src/grpc/_cython/adapter_low.py
@@ -71,10 +71,6 @@ class ClientCredentials(object):
   def refresh_token():
     raise NotImplementedError()
 
-  @staticmethod
-  def fake_transport_security():
-    raise NotImplementedError()
-
   @staticmethod
   def iam():
     raise NotImplementedError()
@@ -88,10 +84,6 @@ class ServerCredentials(object):
   def ssl():
     raise NotImplementedError()
 
-  @staticmethod
-  def fake_transport_security():
-    raise NotImplementedError()
-
 
 class CompletionQueue(type_interfaces.CompletionQueue):
   def __init__(self):
diff --git a/src/python/src/grpc/_cython/cygrpc.pyx b/src/python/src/grpc/_cython/cygrpc.pyx
index dcb06f345c7c80eec38b10ccd845f10b5764b9d4..f4d9661580b5b9312390472e5a535b0fcb7c0b62 100644
--- a/src/python/src/grpc/_cython/cygrpc.pyx
+++ b/src/python/src/grpc/_cython/cygrpc.pyx
@@ -82,12 +82,8 @@ client_credentials_compute_engine = (
     credentials.client_credentials_compute_engine)
 client_credentials_jwt = credentials.client_credentials_jwt
 client_credentials_refresh_token = credentials.client_credentials_refresh_token
-client_credentials_fake_transport_security = (
-    credentials.client_credentials_fake_transport_security)
 client_credentials_iam = credentials.client_credentials_iam
 server_credentials_ssl = credentials.server_credentials_ssl
-server_credentials_fake_transport_security = (
-    credentials.server_credentials_fake_transport_security)
 
 CompletionQueue = completion_queue.CompletionQueue
 Channel = channel.Channel
diff --git a/src/python/src/grpc/_cython/cygrpc_test.py b/src/python/src/grpc/_cython/cygrpc_test.py
index 838e1e22548dc5f69d01c0939c3b75d79e2fe2aa..22d210b16b5189ba6fa690d14a546c7bc2118449 100644
--- a/src/python/src/grpc/_cython/cygrpc_test.py
+++ b/src/python/src/grpc/_cython/cygrpc_test.py
@@ -76,14 +76,6 @@ class TypeSmokeTest(unittest.TestCase):
     timespec = cygrpc.Timespec(now)
     self.assertAlmostEqual(now, float(timespec), places=8)
 
-  def testClientCredentialsUpDown(self):
-    credentials = cygrpc.client_credentials_fake_transport_security()
-    del credentials
-
-  def testServerCredentialsUpDown(self):
-    credentials = cygrpc.server_credentials_fake_transport_security()
-    del credentials
-
   def testCompletionQueueUpDown(self):
     completion_queue = cygrpc.CompletionQueue()
     del completion_queue
@@ -96,12 +88,6 @@ class TypeSmokeTest(unittest.TestCase):
     channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([]))
     del channel
 
-  def testSecureChannelUpDown(self):
-    channel = cygrpc.Channel(
-        '[::]:0', cygrpc.ChannelArgs([]),
-        cygrpc.client_credentials_fake_transport_security())
-    del channel
-
   @unittest.skip('TODO(atash): undo skip after #2229 is merged')
   def testServerStartNoExplicitShutdown(self):
     server = cygrpc.Server()
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index bfb9f6ff01bf05a818522da821d7d51501219407..a7607a83a36fc43c5c0107ce8e739acdfecb86de 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -235,8 +235,8 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
 */
 static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
   grpc_metadata_array *md_ary = NULL;
-  int array_length;
-  int i;
+  long array_length;
+  long i;
 
   /* Construct a metadata object from key and value and add it */
   TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 9bf1a9f945c11d8c45d9ac9de2ea462c155cc145..0cb6fa2f800b741e5302c5cbffaea68e4d94c024 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -146,7 +146,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
   target_chars = StringValueCStr(target);
   grpc_rb_hash_convert_to_channel_args(channel_args, &args);
   if (credentials == Qnil) {
-    ch = grpc_channel_create(target_chars, &args);
+    ch = grpc_insecure_channel_create(target_chars, &args);
   } else {
     creds = grpc_rb_get_wrapped_credentials(credentials);
     ch = grpc_secure_channel_create(creds, target_chars, &args);
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 65d9c9a237b7b3127423aaedfdb23a9c0e0ad5c2..327fd1a4fc1b82afc8f5903d9b7b337a3f251b5c 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -139,7 +139,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
           rb_raise(rb_eRangeError, "%f out of Time range",
                    RFLOAT_VALUE(time));
         }
-        t.tv_nsec = (time_t)(d * 1e9 + 0.5);
+        t.tv_nsec = (int)(d * 1e9 + 0.5);
       }
       break;
 
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 453376caec4d51f559842febd1a39e873d2990f6..77bea2ababda174651b37a3e1282b1e3f2f0c88b 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -113,7 +113,7 @@ void test_connect(const char *server_host, const char *client_host, int port,
   } else {
     gpr_join_host_port(&client_hostport, client_host, port);
   }
-  client = grpc_channel_create(client_hostport, NULL);
+  client = grpc_insecure_channel_create(client_hostport, NULL);
 
   gpr_log(GPR_INFO, "Testing with server=%s client=%s (expecting %s)",
           server_hostport, client_hostport, expect_ok ? "success" : "failure");
diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c
index 8a1530e63b05cf3949d161e6c71bfa83655c630e..6647b949ba2bbb30a547280ac720b093297a01ab 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack.c
@@ -72,7 +72,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
   GPR_ASSERT(f->client);
 }
 
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_compression.c b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
index 0a9a31229680a5e9ed0b893d64ce80e1825c8c96..f3d1fa22dcea385423a40ecd096028874f35baac 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_compression.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
@@ -82,7 +82,8 @@ void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
   }
   ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
       client_args, GRPC_COMPRESS_GZIP);
-  f->client = grpc_channel_create(ffd->localaddr, ffd->client_args_compression);
+  f->client = grpc_insecure_channel_create(ffd->localaddr,
+                                           ffd->client_args_compression);
 }
 
 void chttp2_init_server_fullstack_compression(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
index 351e1c5459b5f2335e977ed5d56fb3f5736fcfaf..89ad7b8c2d83770d1e2dcd519af345252b9c9d16 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
@@ -78,7 +78,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
index 69860d04d5e8e25ade4f852e33ce4659a18df171..93786d0943a3ad17d2296694cd7c83795d00d494 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
@@ -72,7 +72,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 79797f93751e3be0cf5b7dccd9998dc432d21cb0..6f1133c009a0aae2e986c07d16de6e552367f56c 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -61,7 +61,7 @@ int main(int argc, char **argv) {
   cqv = cq_verifier_create(cq);
 
   /* create a call, channel to a non existant server */
-  chan = grpc_channel_create("nonexistant:54321", NULL);
+  chan = grpc_insecure_channel_create("nonexistant:54321", NULL);
   call = grpc_channel_create_call(chan, cq, "/Foo", "nonexistant", deadline);
 
   op = ops;
diff --git a/test/core/end2end/tests/request_response_with_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
index ef6dfe9561f766a4e4da701ff067a9b076b9fa8d..9821d7852f3834c987d80a077c237e02b90dae28 100644
--- a/test/core/end2end/tests/request_response_with_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
@@ -111,8 +111,8 @@ static void test_request_response_with_metadata_and_payload(
   gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}},
                              {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
-  grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}},
-                             {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
+  grpc_metadata meta_s[2] = {{"KeY3", "val3", 4, {{NULL, NULL, NULL}}},
+                             {"KeY4", "val4", 4, {{NULL, NULL, NULL}}}};
   grpc_end2end_test_fixture f = begin_test(
       config, "test_request_response_with_metadata_and_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 2b196543792b232c0c828e80ab4efc48d91f2a4a..5647a16101e3f3725d9ac4d7603eaac8ac1f4990 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -183,7 +183,7 @@ int main(int argc, char **argv) {
     return 1;
   }
 
-  channel = grpc_channel_create(target, NULL);
+  channel = grpc_insecure_channel_create(target, NULL);
   cq = grpc_completion_queue_create();
   the_buffer = grpc_raw_byte_buffer_create(&slice, payload_size);
   histogram = gpr_histogram_create(0.01, 60e9);
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index a932e04f330da4cbe7246cace7568a927a842a75..4a4d4bcb8a1d2c9f63a4f4301acd4c61be2a9f96 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -63,9 +63,9 @@ static void test_create_string(void) {
   LOG_TEST("test_create_string");
 
   ctx = grpc_mdctx_create();
-  s1 = grpc_mdstr_from_string(ctx, "hello");
-  s2 = grpc_mdstr_from_string(ctx, "hello");
-  s3 = grpc_mdstr_from_string(ctx, "very much not hello");
+  s1 = grpc_mdstr_from_string(ctx, "hello", 0);
+  s2 = grpc_mdstr_from_string(ctx, "hello", 0);
+  s3 = grpc_mdstr_from_string(ctx, "very much not hello", 0);
   GPR_ASSERT(s1 == s2);
   GPR_ASSERT(s3 != s1);
   GPR_ASSERT(gpr_slice_str_cmp(s1->slice, "hello") == 0);
@@ -190,7 +190,7 @@ static void test_things_stick_around(void) {
 
   for (i = 0; i < nstrs; i++) {
     gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", i);
-    strs[i] = grpc_mdstr_from_string(ctx, buffer);
+    strs[i] = grpc_mdstr_from_string(ctx, buffer, 0);
     shuf[i] = i;
     gpr_free(buffer);
   }
@@ -212,7 +212,7 @@ static void test_things_stick_around(void) {
     GRPC_MDSTR_UNREF(strs[shuf[i]]);
     for (j = i + 1; j < nstrs; j++) {
       gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]);
-      test = grpc_mdstr_from_string(ctx, buffer);
+      test = grpc_mdstr_from_string(ctx, buffer, 0);
       GPR_ASSERT(test == strs[shuf[j]]);
       GRPC_MDSTR_UNREF(test);
       gpr_free(buffer);
@@ -235,13 +235,13 @@ static void test_slices_work(void) {
   ctx = grpc_mdctx_create();
 
   str = grpc_mdstr_from_string(
-      ctx, "123456789012345678901234567890123456789012345678901234567890");
+      ctx, "123456789012345678901234567890123456789012345678901234567890", 0);
   slice = gpr_slice_ref(str->slice);
   GRPC_MDSTR_UNREF(str);
   gpr_slice_unref(slice);
 
   str = grpc_mdstr_from_string(
-      ctx, "123456789012345678901234567890123456789012345678901234567890");
+      ctx, "123456789012345678901234567890123456789012345678901234567890", 0);
   slice = gpr_slice_ref(str->slice);
   gpr_slice_unref(slice);
   GRPC_MDSTR_UNREF(str);
@@ -258,7 +258,7 @@ static void test_base64_and_huffman_works(void) {
   LOG_TEST("test_base64_and_huffman_works");
 
   ctx = grpc_mdctx_create();
-  str = grpc_mdstr_from_string(ctx, "abcdefg");
+  str = grpc_mdstr_from_string(ctx, "abcdefg", 0);
   slice1 = grpc_mdstr_as_base64_encoded_and_huffman_compressed(str);
   slice2 = grpc_chttp2_base64_encode_and_huffman_compress(str->slice);
   GPR_ASSERT(0 == gpr_slice_cmp(slice1, slice2));
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index c433b789482e9c195dc3860ec47b01df8d22a435..d7a52bf27488efefd69bb4620b89e125635b6826 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -35,17 +35,17 @@
 #include <thread>
 
 #include "src/core/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"
 #include "test/cpp/util/echo_duplicate.grpc.pb.h"
 #include "test/cpp/util/echo.grpc.pb.h"
-#include "test/cpp/util/fake_credentials.h"
 #include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
-#include <grpc++/fixed_size_thread_pool.h>
+#include <grpc++/dynamic_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -83,13 +83,12 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
   }
 }
 
-template <typename T>
-void CheckAuthContext(T* context) {
+void CheckServerAuthContext(const ServerContext* context) {
   std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
-  std::vector<grpc::string> fake =
+  std::vector<grpc::string> ssl =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1u, fake.size());
-  EXPECT_EQ("fake", fake[0]);
+  EXPECT_EQ(1u, ssl.size());
+  EXPECT_EQ("ssl", ssl[0]);
   EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
   EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
 }
@@ -142,7 +141,7 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
       }
     }
     if (request->has_param() && request->param().check_auth_context()) {
-      CheckAuthContext(context);
+      CheckServerAuthContext(context);
     }
     if (request->has_param() &&
         request->param().response_message_length() > 0) {
@@ -240,10 +239,15 @@ class End2endTest : public ::testing::Test {
     server_address_ << "localhost:" << port;
     // Setup server
     ServerBuilder builder;
+    SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
+      test_server1_cert};
+    SslServerCredentialsOptions ssl_opts;
+    ssl_opts.pem_root_certs = "";
+    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
     builder.AddListeningPort(server_address_.str(),
-                             FakeTransportSecurityServerCredentials());
+                             SslServerCredentials(ssl_opts));
     builder.RegisterService(&service_);
-    builder.RegisterService("special", &special_service_);
+    builder.RegisterService("foo.test.youtube.com", &special_service_);
     builder.SetMaxMessageSize(
         kMaxMessageSize_);  // For testing max message size.
     builder.RegisterService(&dup_pkg_service_);
@@ -254,13 +258,16 @@ class End2endTest : public ::testing::Test {
   void TearDown() GRPC_OVERRIDE { server_->Shutdown(); }
 
   void ResetStub() {
+    SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
     ChannelArguments args;
+    args.SetSslTargetNameOverride("foo.test.google.fr");
     args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
-    std::shared_ptr<ChannelInterface> channel = CreateChannel(
-        server_address_.str(), FakeTransportSecurityCredentials(), args);
-    stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel));
+    channel_ = CreateChannel(server_address_.str(), SslCredentials(ssl_opts),
+                             args);
+    stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_));
   }
 
+  std::shared_ptr<ChannelInterface> channel_;
   std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
@@ -268,7 +275,7 @@ class End2endTest : public ::testing::Test {
   TestServiceImpl service_;
   TestServiceImpl special_service_;
   TestServiceImplDupPkg dup_pkg_service_;
-  FixedSizeThreadPool thread_pool_;
+  DynamicThreadPool thread_pool_;
 };
 
 static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
@@ -294,11 +301,11 @@ TEST_F(End2endTest, SimpleRpcWithHost) {
   request.set_message("Hello");
 
   ClientContext context;
-  context.set_authority("special");
+  context.set_authority("foo.test.youtube.com");
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(response.has_param());
-  EXPECT_EQ(response.param().host(), "special");
+  EXPECT_EQ("special", response.param().host());
   EXPECT_TRUE(s.ok());
 }
 
@@ -487,24 +494,19 @@ TEST_F(End2endTest, BidiStream) {
 // Talk to the two services with the same name but different package names.
 // The two stubs are created on the same channel.
 TEST_F(End2endTest, DiffPackageServices) {
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannel(server_address_.str(), FakeTransportSecurityCredentials(),
-                    ChannelArguments());
-
+  ResetStub();
   EchoRequest request;
   EchoResponse response;
   request.set_message("Hello");
 
-  std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub(
-      grpc::cpp::test::util::TestService::NewStub(channel));
   ClientContext context;
-  Status s = stub->Echo(&context, request, &response);
+  Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(s.ok());
 
   std::unique_ptr<grpc::cpp::test::util::duplicate::TestService::Stub>
       dup_pkg_stub(
-          grpc::cpp::test::util::duplicate::TestService::NewStub(channel));
+          grpc::cpp::test::util::duplicate::TestService::NewStub(channel_));
   ClientContext context2;
   s = dup_pkg_stub->Echo(&context2, request, &response);
   EXPECT_EQ("no package", response.message());
@@ -788,7 +790,17 @@ TEST_F(End2endTest, ClientAuthContext) {
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(s.ok());
 
-  CheckAuthContext(&context);
+  std::shared_ptr<const AuthContext> auth_ctx = context.auth_context();
+  std::vector<grpc::string> ssl =
+      auth_ctx->FindPropertyValues("transport_security_type");
+  EXPECT_EQ(1u, ssl.size());
+  EXPECT_EQ("ssl", ssl[0]);
+  EXPECT_EQ("x509_subject_alternative_name",
+            auth_ctx->GetPeerIdentityPropertyName());
+  EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size());
+  EXPECT_EQ("*.test.google.fr", auth_ctx->GetPeerIdentity()[0]);
+  EXPECT_EQ("waterzooi.test.google.be", auth_ctx->GetPeerIdentity()[1]);
+  EXPECT_EQ("*.test.youtube.com", auth_ctx->GetPeerIdentity()[2]);
 }
 
 // Make the response larger than the flow control window.
@@ -797,7 +809,7 @@ TEST_F(End2endTest, HugeResponse) {
   EchoRequest request;
   EchoResponse response;
   request.set_message("huge response");
-  const int kResponseSize = 1024 * (1024 + 10);
+  const size_t kResponseSize = 1024 * (1024 + 10);
   request.mutable_param()->set_response_message_length(kResponseSize);
 
   ClientContext context;
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 74b40d54d82fa2c4f9bc753f5ef5902fb9e1eeef..32130e24e94d0acb82dca7b9590502fc791fa81f 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -42,7 +42,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
-#include <grpc++/fixed_size_thread_pool.h>
+#include <grpc++/dynamic_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -260,7 +260,7 @@ class MockTest : public ::testing::Test {
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
   TestServiceImpl service_;
-  FixedSizeThreadPool thread_pool_;
+  DynamicThreadPool thread_pool_;
 };
 
 // Do one real rpc and one mocked one
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index e47139641b4307bbf29ec6ff827ffb2cb9ab721e..ff9c945c7c33ea7c5ac093e5700ee716989833ac 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -43,7 +43,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
-#include <grpc++/fixed_size_thread_pool.h>
+#include <grpc++/dynamic_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -208,7 +208,7 @@ class End2endTest : public ::testing::Test {
   const int kMaxMessageSize_;
   TestServiceImpl service_;
   TestServiceImplDupPkg dup_pkg_service_;
-  FixedSizeThreadPool thread_pool_;
+  DynamicThreadPool thread_pool_;
 };
 
 static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 846f8f31b0d3f40b54d1a212322e937c63fe2f01..33b6fa55c387bbc599c82469848004771b9cb2e5 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -45,7 +45,6 @@
 #include <grpc/support/host_port.h>
 #include <grpc++/async_unary_call.h>
 #include <grpc++/config.h>
-#include <grpc++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index d90ff2212bc109d8957c5bf9b2e20070971b5909..4c3c9cb497ff87358f1e703c83c938d56611bfe3 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -40,6 +40,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc++/config.h>
+#include <grpc++/dynamic_thread_pool.h>
 #include <grpc++/fixed_size_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
@@ -92,7 +93,13 @@ class TestServiceImpl GRPC_FINAL : public TestService::Service {
 class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
  public:
   SynchronousServer(const ServerConfig& config, int port)
-      : thread_pool_(config.threads()), impl_(MakeImpl(port)) {}
+      : thread_pool_(), impl_(MakeImpl(port)) {
+    if (config.threads() > 0) {
+      thread_pool_.reset(new FixedSizeThreadPool(config.threads()));
+    } else {
+      thread_pool_.reset(new DynamicThreadPool(-config.threads()));
+    }
+  }
 
  private:
   std::unique_ptr<grpc::Server> MakeImpl(int port) {
@@ -105,13 +112,13 @@ class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
 
     builder.RegisterService(&service_);
 
-    builder.SetThreadPool(&thread_pool_);
+    builder.SetThreadPool(thread_pool_.get());
 
     return builder.BuildAndStart();
   }
 
   TestServiceImpl service_;
-  FixedSizeThreadPool thread_pool_;
+  std::unique_ptr<ThreadPoolInterface> thread_pool_;
   std::unique_ptr<grpc::Server> impl_;
 };
 
diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc
index 07289f699bf554c40f26af50b2c53a2ab9ac515f..c1ba23decd961fe6b5f5ecc7958e9784175218db 100644
--- a/test/cpp/qps/timer.cc
+++ b/test/cpp/qps/timer.cc
@@ -52,7 +52,7 @@ static double time_double(struct timeval* tv) {
 Timer::Result Timer::Sample() {
   struct rusage usage;
   struct timeval tv;
-  gettimeofday(&tv, nullptr);
+  gettimeofday(&tv, NULL);
   getrusage(RUSAGE_SELF, &usage);
 
   Result r;
diff --git a/test/cpp/util/fake_credentials.cc b/test/cpp/server/dynamic_thread_pool_test.cc
similarity index 64%
rename from test/cpp/util/fake_credentials.cc
rename to test/cpp/server/dynamic_thread_pool_test.cc
index f5b83b8159f9ce3765cd90cf161eb43514f49002..63b603b8f7bf7321bc19ae2abea902247f015f88 100644
--- a/test/cpp/util/fake_credentials.cc
+++ b/test/cpp/server/dynamic_thread_pool_test.cc
@@ -31,28 +31,47 @@
  *
  */
 
-#include <grpc/grpc_security.h>
-#include <grpc++/channel_arguments.h>
-#include <grpc++/credentials.h>
-#include <grpc++/server_credentials.h>
-#include "src/cpp/client/channel.h"
-#include "src/cpp/client/secure_credentials.h"
-#include "src/cpp/server/secure_server_credentials.h"
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+
+#include <grpc++/dynamic_thread_pool.h>
+#include <gtest/gtest.h>
 
 namespace grpc {
-namespace testing {
 
-std::shared_ptr<Credentials> FakeTransportSecurityCredentials() {
-  grpc_credentials* c_creds = grpc_fake_transport_security_credentials_create();
-  return std::shared_ptr<Credentials>(new SecureCredentials(c_creds));
+class DynamicThreadPoolTest : public ::testing::Test {
+ public:
+  DynamicThreadPoolTest() : thread_pool_(0) {}
+
+ protected:
+  DynamicThreadPool thread_pool_;
+};
+
+void Callback(std::mutex* mu, std::condition_variable* cv, bool* done) {
+  std::unique_lock<std::mutex> lock(*mu);
+  *done = true;
+  cv->notify_all();
 }
 
-std::shared_ptr<ServerCredentials> FakeTransportSecurityServerCredentials() {
-  grpc_server_credentials* c_creds =
-      grpc_fake_transport_security_server_credentials_create();
-  return std::shared_ptr<ServerCredentials>(
-      new SecureServerCredentials(c_creds));
+TEST_F(DynamicThreadPoolTest, Add) {
+  std::mutex mu;
+  std::condition_variable cv;
+  bool done = false;
+  std::function<void()> callback = std::bind(Callback, &mu, &cv, &done);
+  thread_pool_.Add(callback);
+
+  // Wait for the callback to finish.
+  std::unique_lock<std::mutex> lock(mu);
+  while (!done) {
+    cv.wait(lock);
+  }
 }
 
-}  // namespace testing
 }  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  return result;
+}
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index 00bb821ae67ef5c0100ea341b810e792ddc0e1be..848a3aee577100010f10ddedea0f8455d94a231a 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -39,7 +39,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
-#include <grpc++/fixed_size_thread_pool.h>
+#include <grpc++/dynamic_thread_pool.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -102,7 +102,7 @@ class CliCallTest : public ::testing::Test {
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
   TestServiceImpl service_;
-  FixedSizeThreadPool thread_pool_;
+  DynamicThreadPool thread_pool_;
 };
 
 // Send a rpc with a normal stub and then a CliCall. Verify they match.
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 4bdd8babde52fde2aeb2c8ca6ae470919416d151..785779beb5db13dc1a83565c7f5772ee4e88af36 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -773,6 +773,7 @@ include/grpc++/config.h \
 include/grpc++/config_protobuf.h \
 include/grpc++/create_channel.h \
 include/grpc++/credentials.h \
+include/grpc++/dynamic_thread_pool.h \
 include/grpc++/fixed_size_thread_pool.h \
 include/grpc++/generic_stub.h \
 include/grpc++/impl/call.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 1c73ca6294727e680439539b0af078da4557e9a4..5cf6168388e825ff07a2a1594c47e90135e23813 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -773,6 +773,7 @@ include/grpc++/config.h \
 include/grpc++/config_protobuf.h \
 include/grpc++/create_channel.h \
 include/grpc++/credentials.h \
+include/grpc++/dynamic_thread_pool.h \
 include/grpc++/fixed_size_thread_pool.h \
 include/grpc++/generic_stub.h \
 include/grpc++/impl/call.h \
@@ -825,6 +826,7 @@ src/cpp/common/rpc_method.cc \
 src/cpp/proto/proto_utils.cc \
 src/cpp/server/async_generic_service.cc \
 src/cpp/server/create_default_thread_pool.cc \
+src/cpp/server/dynamic_thread_pool.cc \
 src/cpp/server/fixed_size_thread_pool.cc \
 src/cpp/server/insecure_server_credentials.cc \
 src/cpp/server/server.cc \
diff --git a/tools/run_tests/run_csharp.sh b/tools/run_tests/run_csharp.sh
index 752e83ef70547a7bce5e6dc258eacaf2a0accb4d..c0fedca193532abf2570a7fb2258d8b104166dbf 100755
--- a/tools/run_tests/run_csharp.sh
+++ b/tools/run_tests/run_csharp.sh
@@ -32,6 +32,8 @@ set -ex
 
 CONFIG=${CONFIG:-opt}
 
+NUNIT_CONSOLE="mono packages/NUnit.Runners.2.6.4/tools/nunit-console.exe"
+
 if [ "$CONFIG" = "dbg" ]
 then
   MSBUILD_CONFIG="Debug"
@@ -46,6 +48,7 @@ root=`pwd`
 cd src/csharp
 
 export LD_LIBRARY_PATH=$root/libs/$CONFIG
-nunit-console -labels "$1/bin/$MSBUILD_CONFIG/$1.dll"
+
+$NUNIT_CONSOLE -labels "$1/bin/$MSBUILD_CONFIG/$1.dll"
 
 
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index d6db928d2aaf343f04cb8e10194b97253c598640..84c1099a2ae2c18b14d68ad42d871c3d1d4f281e 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -1181,6 +1181,21 @@
       "test/cpp/util/time_test.cc"
     ]
   }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "dynamic_thread_pool_test", 
+    "src": [
+      "test/cpp/server/dynamic_thread_pool_test.cc"
+    ]
+  }, 
   {
     "deps": [
       "gpr", 
@@ -10652,6 +10667,7 @@
       "include/grpc++/config_protobuf.h", 
       "include/grpc++/create_channel.h", 
       "include/grpc++/credentials.h", 
+      "include/grpc++/dynamic_thread_pool.h", 
       "include/grpc++/fixed_size_thread_pool.h", 
       "include/grpc++/generic_stub.h", 
       "include/grpc++/impl/call.h", 
@@ -10701,6 +10717,7 @@
       "include/grpc++/config_protobuf.h", 
       "include/grpc++/create_channel.h", 
       "include/grpc++/credentials.h", 
+      "include/grpc++/dynamic_thread_pool.h", 
       "include/grpc++/fixed_size_thread_pool.h", 
       "include/grpc++/generic_stub.h", 
       "include/grpc++/impl/call.h", 
@@ -10751,6 +10768,7 @@
       "src/cpp/proto/proto_utils.cc", 
       "src/cpp/server/async_generic_service.cc", 
       "src/cpp/server/create_default_thread_pool.cc", 
+      "src/cpp/server/dynamic_thread_pool.cc", 
       "src/cpp/server/fixed_size_thread_pool.cc", 
       "src/cpp/server/insecure_server_credentials.cc", 
       "src/cpp/server/secure_server_credentials.cc", 
@@ -10789,7 +10807,6 @@
       "test/cpp/util/echo.pb.h", 
       "test/cpp/util/echo_duplicate.grpc.pb.h", 
       "test/cpp/util/echo_duplicate.pb.h", 
-      "test/cpp/util/fake_credentials.h", 
       "test/cpp/util/messages.grpc.pb.h", 
       "test/cpp/util/messages.pb.h", 
       "test/cpp/util/subprocess.h"
@@ -10801,8 +10818,6 @@
       "test/cpp/util/cli_call.h", 
       "test/cpp/util/create_test_channel.cc", 
       "test/cpp/util/create_test_channel.h", 
-      "test/cpp/util/fake_credentials.cc", 
-      "test/cpp/util/fake_credentials.h", 
       "test/cpp/util/subprocess.cc", 
       "test/cpp/util/subprocess.h"
     ]
@@ -10826,6 +10841,7 @@
       "include/grpc++/config_protobuf.h", 
       "include/grpc++/create_channel.h", 
       "include/grpc++/credentials.h", 
+      "include/grpc++/dynamic_thread_pool.h", 
       "include/grpc++/fixed_size_thread_pool.h", 
       "include/grpc++/generic_stub.h", 
       "include/grpc++/impl/call.h", 
@@ -10872,6 +10888,7 @@
       "include/grpc++/config_protobuf.h", 
       "include/grpc++/create_channel.h", 
       "include/grpc++/credentials.h", 
+      "include/grpc++/dynamic_thread_pool.h", 
       "include/grpc++/fixed_size_thread_pool.h", 
       "include/grpc++/generic_stub.h", 
       "include/grpc++/impl/call.h", 
@@ -10916,6 +10933,7 @@
       "src/cpp/proto/proto_utils.cc", 
       "src/cpp/server/async_generic_service.cc", 
       "src/cpp/server/create_default_thread_pool.cc", 
+      "src/cpp/server/dynamic_thread_pool.cc", 
       "src/cpp/server/fixed_size_thread_pool.cc", 
       "src/cpp/server/insecure_server_credentials.cc", 
       "src/cpp/server/server.cc", 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 98ef004c4bbb5f095545b9345e93a80d2eab61eb..b8a074534f94c022db1ec39a50d4e4723460722e 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -675,6 +675,15 @@
       "posix"
     ]
   }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
+    "name": "dynamic_thread_pool_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
   {
     "flaky": false, 
     "language": "c++", 
diff --git a/vsprojects/grpc++/grpc++.vcxproj b/vsprojects/grpc++/grpc++.vcxproj
index 2d13bf046b5e5c3c7df9c2e45c00b79ad45c77fa..51b91c643403318c78e6412b503d256469c0c89c 100644
--- a/vsprojects/grpc++/grpc++.vcxproj
+++ b/vsprojects/grpc++/grpc++.vcxproj
@@ -159,6 +159,7 @@
     <ClInclude Include="..\..\include\grpc++\config_protobuf.h" />
     <ClInclude Include="..\..\include\grpc++\create_channel.h" />
     <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\dynamic_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\call.h" />
@@ -235,6 +236,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\dynamic_thread_pool.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
diff --git a/vsprojects/grpc++/grpc++.vcxproj.filters b/vsprojects/grpc++/grpc++.vcxproj.filters
index c5d8db57aec8e3bdda2d0957f054fe5f2e3a9dd8..85b743a8fb40fa3c3e807b885aac84af1f792771 100644
--- a/vsprojects/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/grpc++/grpc++.vcxproj.filters
@@ -61,6 +61,9 @@
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\dynamic_thread_pool.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -132,6 +135,9 @@
     <ClInclude Include="..\..\include\grpc++\credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\dynamic_thread_pool.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
index f03715b353d94d47068feb3f70b36a29795fa3ad..6886bbc2a01aeece89b2677152dd3dfebdee5b05 100644
--- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -159,6 +159,7 @@
     <ClInclude Include="..\..\include\grpc++\config_protobuf.h" />
     <ClInclude Include="..\..\include\grpc++\create_channel.h" />
     <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\dynamic_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h" />
     <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\call.h" />
@@ -222,6 +223,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\dynamic_thread_pool.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 8f7f3bcd5e9da380b2d65db5495939d7b0726708..7f109a25578a7dc834e8b230c1c18cf8dc9bc12a 100644
--- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -46,6 +46,9 @@
     <ClCompile Include="..\..\src\cpp\server\create_default_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\dynamic_thread_pool.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\fixed_size_thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -117,6 +120,9 @@
     <ClInclude Include="..\..\include\grpc++\credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\dynamic_thread_pool.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\fixed_size_thread_pool.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>