aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile82
-rw-r--r--build.json32
-rw-r--r--include/grpc++/credentials.h3
-rw-r--r--include/grpc/grpc_security.h6
-rw-r--r--include/grpc/support/port_platform.h6
-rw-r--r--src/core/channel/client_channel.c5
-rw-r--r--src/core/iomgr/pollset_kick.c41
-rw-r--r--src/core/security/credentials.c6
-rw-r--r--src/core/security/security_context.c46
-rw-r--r--src/core/support/env.h60
-rw-r--r--src/core/support/env_linux.c61
-rw-r--r--src/core/support/env_posix.c56
-rw-r--r--src/core/support/env_win32.c60
-rw-r--r--src/core/support/file.c89
-rw-r--r--src/core/support/file.h61
-rw-r--r--src/core/support/file_posix.c97
-rw-r--r--src/core/support/file_win32.c78
-rw-r--r--src/core/surface/byte_buffer_queue.c12
-rw-r--r--src/core/surface/call.c24
-rw-r--r--src/core/surface/channel.c11
-rw-r--r--src/core/surface/channel.h2
-rw-r--r--src/core/surface/client.c3
-rw-r--r--src/core/surface/lame_client.c3
-rw-r--r--src/core/surface/server.c2
-rw-r--r--src/csharp/GrpcCore/Call.cs18
-rw-r--r--src/csharp/GrpcCore/GrpcCore.csproj5
-rw-r--r--src/csharp/GrpcCore/IMarshaller.cs31
-rw-r--r--src/csharp/GrpcCore/Internal/AsyncCall.cs8
-rw-r--r--src/csharp/GrpcCore/Internal/ServerSafeHandle.cs9
-rw-r--r--src/csharp/GrpcCore/Internal/ServerWritingObserver.cs38
-rw-r--r--src/csharp/GrpcCore/Internal/StreamingInputObserver.cs2
-rw-r--r--src/csharp/GrpcCore/Method.cs64
-rw-r--r--src/csharp/GrpcCore/Server.cs89
-rw-r--r--src/csharp/GrpcCore/ServerCallHandler.cs93
-rw-r--r--src/csharp/GrpcCore/ServerCalls.cs25
-rw-r--r--src/csharp/GrpcCoreTests/ClientServerTest.cs39
-rw-r--r--src/csharp/GrpcCoreTests/ServerTest.cs2
-rwxr-xr-xsrc/csharp/README.md28
-rw-r--r--test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c21
-rw-r--r--test/core/support/env_test.c64
-rw-r--r--test/core/support/file_test.c159
-rw-r--r--tools/run_tests/tests.json8
-rw-r--r--vsprojects/vs2013/build_and_run_tests.bat16
-rw-r--r--vsprojects/vs2013/gpr.vcxproj14
-rw-r--r--vsprojects/vs2013/gpr.vcxproj.filters24
45 files changed, 1495 insertions, 108 deletions
diff --git a/Makefile b/Makefile
index f31b988a35..40f98b90ca 100644
--- a/Makefile
+++ b/Makefile
@@ -338,6 +338,8 @@ gpr_cmdline_test: bins/$(CONFIG)/gpr_cmdline_test
gpr_histogram_test: bins/$(CONFIG)/gpr_histogram_test
gpr_host_port_test: bins/$(CONFIG)/gpr_host_port_test
gpr_log_test: bins/$(CONFIG)/gpr_log_test
+gpr_file_test: bins/$(CONFIG)/gpr_file_test
+gpr_env_test: bins/$(CONFIG)/gpr_env_test
gpr_slice_buffer_test: bins/$(CONFIG)/gpr_slice_buffer_test
gpr_slice_test: bins/$(CONFIG)/gpr_slice_test
gpr_string_test: bins/$(CONFIG)/gpr_string_test
@@ -571,7 +573,7 @@ privatelibs_cxx: libs/$(CONFIG)/libgrpc++_test_util.a libs/$(CONFIG)/libtips_cl
buildtests: buildtests_c buildtests_cxx
-buildtests_c: privatelibs_c bins/$(CONFIG)/alarm_heap_test bins/$(CONFIG)/alarm_list_test bins/$(CONFIG)/alarm_test bins/$(CONFIG)/alpn_test bins/$(CONFIG)/bin_encoder_test bins/$(CONFIG)/census_hash_table_test bins/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test bins/$(CONFIG)/census_statistics_multiple_writers_test bins/$(CONFIG)/census_statistics_performance_test bins/$(CONFIG)/census_statistics_quick_test bins/$(CONFIG)/census_statistics_small_log_test bins/$(CONFIG)/census_stub_test bins/$(CONFIG)/census_window_stats_test bins/$(CONFIG)/chttp2_status_conversion_test bins/$(CONFIG)/chttp2_stream_encoder_test bins/$(CONFIG)/chttp2_stream_map_test bins/$(CONFIG)/chttp2_transport_end2end_test bins/$(CONFIG)/dualstack_socket_test bins/$(CONFIG)/echo_client bins/$(CONFIG)/echo_server bins/$(CONFIG)/echo_test bins/$(CONFIG)/fd_posix_test bins/$(CONFIG)/fling_client bins/$(CONFIG)/fling_server bins/$(CONFIG)/fling_stream_test bins/$(CONFIG)/fling_test bins/$(CONFIG)/gpr_cancellable_test bins/$(CONFIG)/gpr_cmdline_test bins/$(CONFIG)/gpr_histogram_test bins/$(CONFIG)/gpr_host_port_test bins/$(CONFIG)/gpr_log_test bins/$(CONFIG)/gpr_slice_buffer_test bins/$(CONFIG)/gpr_slice_test bins/$(CONFIG)/gpr_string_test bins/$(CONFIG)/gpr_sync_test bins/$(CONFIG)/gpr_thd_test bins/$(CONFIG)/gpr_time_test bins/$(CONFIG)/gpr_useful_test bins/$(CONFIG)/grpc_base64_test bins/$(CONFIG)/grpc_byte_buffer_reader_test bins/$(CONFIG)/grpc_channel_stack_test bins/$(CONFIG)/grpc_completion_queue_test bins/$(CONFIG)/grpc_credentials_test bins/$(CONFIG)/grpc_json_token_test bins/$(CONFIG)/grpc_stream_op_test bins/$(CONFIG)/hpack_parser_test bins/$(CONFIG)/hpack_table_test bins/$(CONFIG)/httpcli_format_request_test bins/$(CONFIG)/httpcli_parser_test bins/$(CONFIG)/httpcli_test bins/$(CONFIG)/json_rewrite bins/$(CONFIG)/json_rewrite_test bins/$(CONFIG)/json_test bins/$(CONFIG)/lame_client_test bins/$(CONFIG)/message_compress_test bins/$(CONFIG)/metadata_buffer_test bins/$(CONFIG)/murmur_hash_test bins/$(CONFIG)/no_server_test bins/$(CONFIG)/poll_kick_posix_test bins/$(CONFIG)/resolve_address_test bins/$(CONFIG)/secure_endpoint_test bins/$(CONFIG)/sockaddr_utils_test bins/$(CONFIG)/tcp_client_posix_test bins/$(CONFIG)/tcp_posix_test bins/$(CONFIG)/tcp_server_posix_test bins/$(CONFIG)/time_averaged_stats_test bins/$(CONFIG)/time_test bins/$(CONFIG)/timeout_encoding_test bins/$(CONFIG)/transport_metadata_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fake_security_census_simple_request_test bins/$(CONFIG)/chttp2_fake_security_disappearing_server_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fake_security_invoke_large_request_test bins/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fake_security_no_op_test bins/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test bins/$(CONFIG)/chttp2_fake_security_simple_request_test bins/$(CONFIG)/chttp2_fake_security_thread_stress_test bins/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fullstack_no_op_test bins/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_no_op_test bins/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test
+buildtests_c: privatelibs_c bins/$(CONFIG)/alarm_heap_test bins/$(CONFIG)/alarm_list_test bins/$(CONFIG)/alarm_test bins/$(CONFIG)/alpn_test bins/$(CONFIG)/bin_encoder_test bins/$(CONFIG)/census_hash_table_test bins/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test bins/$(CONFIG)/census_statistics_multiple_writers_test bins/$(CONFIG)/census_statistics_performance_test bins/$(CONFIG)/census_statistics_quick_test bins/$(CONFIG)/census_statistics_small_log_test bins/$(CONFIG)/census_stub_test bins/$(CONFIG)/census_window_stats_test bins/$(CONFIG)/chttp2_status_conversion_test bins/$(CONFIG)/chttp2_stream_encoder_test bins/$(CONFIG)/chttp2_stream_map_test bins/$(CONFIG)/chttp2_transport_end2end_test bins/$(CONFIG)/dualstack_socket_test bins/$(CONFIG)/echo_client bins/$(CONFIG)/echo_server bins/$(CONFIG)/echo_test bins/$(CONFIG)/fd_posix_test bins/$(CONFIG)/fling_client bins/$(CONFIG)/fling_server bins/$(CONFIG)/fling_stream_test bins/$(CONFIG)/fling_test bins/$(CONFIG)/gpr_cancellable_test bins/$(CONFIG)/gpr_cmdline_test bins/$(CONFIG)/gpr_histogram_test bins/$(CONFIG)/gpr_host_port_test bins/$(CONFIG)/gpr_log_test bins/$(CONFIG)/gpr_file_test bins/$(CONFIG)/gpr_env_test bins/$(CONFIG)/gpr_slice_buffer_test bins/$(CONFIG)/gpr_slice_test bins/$(CONFIG)/gpr_string_test bins/$(CONFIG)/gpr_sync_test bins/$(CONFIG)/gpr_thd_test bins/$(CONFIG)/gpr_time_test bins/$(CONFIG)/gpr_useful_test bins/$(CONFIG)/grpc_base64_test bins/$(CONFIG)/grpc_byte_buffer_reader_test bins/$(CONFIG)/grpc_channel_stack_test bins/$(CONFIG)/grpc_completion_queue_test bins/$(CONFIG)/grpc_credentials_test bins/$(CONFIG)/grpc_json_token_test bins/$(CONFIG)/grpc_stream_op_test bins/$(CONFIG)/hpack_parser_test bins/$(CONFIG)/hpack_table_test bins/$(CONFIG)/httpcli_format_request_test bins/$(CONFIG)/httpcli_parser_test bins/$(CONFIG)/httpcli_test bins/$(CONFIG)/json_rewrite bins/$(CONFIG)/json_rewrite_test bins/$(CONFIG)/json_test bins/$(CONFIG)/lame_client_test bins/$(CONFIG)/message_compress_test bins/$(CONFIG)/metadata_buffer_test bins/$(CONFIG)/murmur_hash_test bins/$(CONFIG)/no_server_test bins/$(CONFIG)/poll_kick_posix_test bins/$(CONFIG)/resolve_address_test bins/$(CONFIG)/secure_endpoint_test bins/$(CONFIG)/sockaddr_utils_test bins/$(CONFIG)/tcp_client_posix_test bins/$(CONFIG)/tcp_posix_test bins/$(CONFIG)/tcp_server_posix_test bins/$(CONFIG)/time_averaged_stats_test bins/$(CONFIG)/time_test bins/$(CONFIG)/timeout_encoding_test bins/$(CONFIG)/transport_metadata_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fake_security_census_simple_request_test bins/$(CONFIG)/chttp2_fake_security_disappearing_server_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fake_security_invoke_large_request_test bins/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fake_security_no_op_test bins/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test bins/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test bins/$(CONFIG)/chttp2_fake_security_simple_request_test bins/$(CONFIG)/chttp2_fake_security_thread_stress_test bins/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_fullstack_no_op_test bins/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test bins/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_no_op_test bins/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test bins/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test
buildtests_cxx: privatelibs_cxx bins/$(CONFIG)/channel_arguments_test bins/$(CONFIG)/credentials_test bins/$(CONFIG)/end2end_test bins/$(CONFIG)/interop_client bins/$(CONFIG)/interop_server bins/$(CONFIG)/tips_client bins/$(CONFIG)/tips_publisher_test bins/$(CONFIG)/tips_subscriber_test bins/$(CONFIG)/qps_client bins/$(CONFIG)/qps_server bins/$(CONFIG)/status_test bins/$(CONFIG)/sync_client_async_server_test bins/$(CONFIG)/thread_pool_test
@@ -632,6 +634,10 @@ test_c: buildtests_c
$(Q) ./bins/$(CONFIG)/gpr_host_port_test || ( echo test gpr_host_port_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_log_test"
$(Q) ./bins/$(CONFIG)/gpr_log_test || ( echo test gpr_log_test failed ; exit 1 )
+ $(E) "[RUN] Testing gpr_file_test"
+ $(Q) ./bins/$(CONFIG)/gpr_file_test || ( echo test gpr_file_test failed ; exit 1 )
+ $(E) "[RUN] Testing gpr_env_test"
+ $(Q) ./bins/$(CONFIG)/gpr_env_test || ( echo test gpr_env_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_slice_buffer_test"
$(Q) ./bins/$(CONFIG)/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_slice_test"
@@ -1232,6 +1238,12 @@ LIBGPR_SRC = \
src/core/support/cmdline.c \
src/core/support/cpu_linux.c \
src/core/support/cpu_posix.c \
+ src/core/support/env_linux.c \
+ src/core/support/env_posix.c \
+ src/core/support/env_win32.c \
+ src/core/support/file.c \
+ src/core/support/file_posix.c \
+ src/core/support/file_win32.c \
src/core/support/histogram.c \
src/core/support/host_port.c \
src/core/support/log.c \
@@ -1317,6 +1329,12 @@ objs/$(CONFIG)/src/core/support/cancellable.o:
objs/$(CONFIG)/src/core/support/cmdline.o:
objs/$(CONFIG)/src/core/support/cpu_linux.o:
objs/$(CONFIG)/src/core/support/cpu_posix.o:
+objs/$(CONFIG)/src/core/support/env_linux.o:
+objs/$(CONFIG)/src/core/support/env_posix.o:
+objs/$(CONFIG)/src/core/support/env_win32.o:
+objs/$(CONFIG)/src/core/support/file.o:
+objs/$(CONFIG)/src/core/support/file_posix.o:
+objs/$(CONFIG)/src/core/support/file_win32.o:
objs/$(CONFIG)/src/core/support/histogram.o:
objs/$(CONFIG)/src/core/support/host_port.o:
objs/$(CONFIG)/src/core/support/log.o:
@@ -4321,6 +4339,68 @@ endif
endif
+GPR_FILE_TEST_SRC = \
+ test/core/support/file_test.c \
+
+GPR_FILE_TEST_OBJS = $(addprefix objs/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_FILE_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+bins/$(CONFIG)/gpr_file_test: openssl_dep_error
+
+else
+
+bins/$(CONFIG)/gpr_file_test: $(GPR_FILE_TEST_OBJS) libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(GPR_FILE_TEST_OBJS) libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o bins/$(CONFIG)/gpr_file_test
+
+endif
+
+objs/$(CONFIG)/test/core/support/file_test.o: libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+
+deps_gpr_file_test: $(GPR_FILE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_FILE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+GPR_ENV_TEST_SRC = \
+ test/core/support/env_test.c \
+
+GPR_ENV_TEST_OBJS = $(addprefix objs/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_ENV_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+bins/$(CONFIG)/gpr_env_test: openssl_dep_error
+
+else
+
+bins/$(CONFIG)/gpr_env_test: $(GPR_ENV_TEST_OBJS) libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(GPR_ENV_TEST_OBJS) libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o bins/$(CONFIG)/gpr_env_test
+
+endif
+
+objs/$(CONFIG)/test/core/support/env_test.o: libs/$(CONFIG)/libgpr_test_util.a libs/$(CONFIG)/libgpr.a
+
+deps_gpr_env_test: $(GPR_ENV_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_ENV_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
GPR_SLICE_BUFFER_TEST_SRC = \
test/core/support/slice_buffer_test.c \
diff --git a/build.json b/build.json
index 48d1a21826..170b148067 100644
--- a/build.json
+++ b/build.json
@@ -227,6 +227,8 @@
],
"headers": [
"src/core/support/cpu.h",
+ "src/core/support/env.h",
+ "src/core/support/file.h",
"src/core/support/murmur_hash.h",
"src/core/support/string.h",
"src/core/support/thd_internal.h"
@@ -237,6 +239,12 @@
"src/core/support/cmdline.c",
"src/core/support/cpu_linux.c",
"src/core/support/cpu_posix.c",
+ "src/core/support/env_linux.c",
+ "src/core/support/env_posix.c",
+ "src/core/support/env_win32.c",
+ "src/core/support/file.c",
+ "src/core/support/file_posix.c",
+ "src/core/support/file_win32.c",
"src/core/support/histogram.c",
"src/core/support/host_port.c",
"src/core/support/log.c",
@@ -924,6 +932,30 @@
]
},
{
+ "name": "gpr_file_test",
+ "build": "test",
+ "language": "c",
+ "src": [
+ "test/core/support/file_test.c"
+ ],
+ "deps": [
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
+ "name": "gpr_env_test",
+ "build": "test",
+ "language": "c",
+ "src": [
+ "test/core/support/env_test.c"
+ ],
+ "deps": [
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
"name": "gpr_slice_buffer_test",
"build": "test",
"language": "c",
diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h
index 987d890b4f..52304d7f36 100644
--- a/include/grpc++/credentials.h
+++ b/include/grpc++/credentials.h
@@ -66,14 +66,13 @@ class Credentials final {
// Options used to build SslCredentials
// pem_roots_cert is the buffer containing the PEM encoding of the server root
-// certificates. This parameter cannot be empty.
+// certificates. If this parameter is empty, the default roots will be used.
// pem_private_key is the buffer containing the PEM encoding of the client's
// private key. This parameter can be empty if the client does not have a
// private key.
// pem_cert_chain is the buffer containing the PEM encoding of the client's
// certificate chain. This parameter can be empty if the client does not have
// a certificate chain.
-// TODO(jboeuf) Change it to point to a file.
struct SslCredentialsOptions {
grpc::string pem_root_certs;
grpc::string pem_private_key;
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 0732a8f83a..731959069f 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -54,6 +54,12 @@ void grpc_credentials_release(grpc_credentials *creds);
/* Creates default credentials. */
grpc_credentials *grpc_default_credentials_create(void);
+/* Environment variable that points to the default SSL roots file. This file
+ must be a PEM encoded file with all the roots such as the one that can be
+ downloaded from https://pki.google.com/roots.pem. */
+#define GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR \
+ "GRPC_DEFAULT_SSL_ROOTS_FILE_PATH"
+
/* Object that holds a private key / certificate chain pair in PEM format. */
typedef struct {
/* private_key is the NULL-terminated string containing the PEM encoding of
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 2bf5348315..e99099c651 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -61,6 +61,8 @@
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
@@ -74,6 +76,8 @@
#define GPR_LINUX_EVENTFD 1
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
+#define GPR_LINUX_ENV 1
+#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
@@ -93,6 +97,8 @@
#define GPR_POSIX_SOCKET 1
#define GPR_POSIX_SOCKETADDR 1
#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index bcb024f2ac..507b91b8a6 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -298,6 +298,7 @@ static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
channel_data *chand = elem->channel_data;
grpc_child_channel *child_channel;
+ grpc_channel_op rop;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
switch (op->type) {
@@ -323,6 +324,10 @@ static void channel_op(grpc_channel_element *elem,
if (child_channel) {
grpc_child_channel_destroy(child_channel, 1);
}
+ /* fake a transport closed to satisfy the refcounting in client */
+ rop.type = GRPC_TRANSPORT_CLOSED;
+ rop.dir = GRPC_CALL_UP;
+ grpc_channel_next_op(elem, &rop);
break;
case GRPC_TRANSPORT_GOAWAY:
/* receiving goaway: if it's from our active child, drop the active child;
diff --git a/src/core/iomgr/pollset_kick.c b/src/core/iomgr/pollset_kick.c
index 238ec75c61..f0211b8274 100644
--- a/src/core/iomgr/pollset_kick.c
+++ b/src/core/iomgr/pollset_kick.c
@@ -48,49 +48,49 @@
/* This implementation is based on a freelist of wakeup fds, with extra logic to
* handle kicks while there is no attached fd. */
+/* TODO(klempner): Autosize this, and consider providing a way to disable the
+ * cap entirely on systems with large fd limits */
#define GRPC_MAX_CACHED_WFDS 50
-#define GRPC_WFD_LOW_WATERMARK 25
static grpc_kick_fd_info *fd_freelist = NULL;
static int fd_freelist_count = 0;
static gpr_mu fd_freelist_mu;
static grpc_kick_fd_info *allocate_wfd(void) {
- grpc_kick_fd_info *info;
+ grpc_kick_fd_info *info = NULL;
gpr_mu_lock(&fd_freelist_mu);
if (fd_freelist != NULL) {
info = fd_freelist;
fd_freelist = fd_freelist->next;
--fd_freelist_count;
- } else {
+ }
+ gpr_mu_unlock(&fd_freelist_mu);
+ if (info == NULL) {
info = gpr_malloc(sizeof(*info));
grpc_wakeup_fd_create(&info->wakeup_fd);
info->next = NULL;
}
- gpr_mu_unlock(&fd_freelist_mu);
return info;
}
-static void destroy_wfd(void) {
- /* assumes fd_freelist_mu is held */
- grpc_kick_fd_info *current = fd_freelist;
- fd_freelist = fd_freelist->next;
- fd_freelist_count--;
- grpc_wakeup_fd_destroy(&current->wakeup_fd);
- gpr_free(current);
+static void destroy_wfd(grpc_kick_fd_info* wfd) {
+ grpc_wakeup_fd_destroy(&wfd->wakeup_fd);
+ gpr_free(wfd);
}
static void free_wfd(grpc_kick_fd_info *fd_info) {
gpr_mu_lock(&fd_freelist_mu);
- fd_info->next = fd_freelist;
- fd_freelist = fd_info;
- fd_freelist_count++;
- if (fd_freelist_count > GRPC_MAX_CACHED_WFDS) {
- while (fd_freelist_count > GRPC_WFD_LOW_WATERMARK) {
- destroy_wfd();
- }
+ if (fd_freelist_count < GRPC_MAX_CACHED_WFDS) {
+ fd_info->next = fd_freelist;
+ fd_freelist = fd_info;
+ fd_freelist_count++;
+ fd_info = NULL;
}
gpr_mu_unlock(&fd_freelist_mu);
+
+ if (fd_info) {
+ destroy_wfd(fd_info);
+ }
}
void grpc_pollset_kick_init(grpc_pollset_kick_state *kick_state) {
@@ -148,6 +148,11 @@ void grpc_pollset_kick_global_init(void) {
}
void grpc_pollset_kick_global_destroy(void) {
+ while (fd_freelist != NULL) {
+ grpc_kick_fd_info *current = fd_freelist;
+ fd_freelist = fd_freelist->next;
+ destroy_wfd(current);
+ }
grpc_wakeup_fd_global_destroy();
gpr_mu_destroy(&fd_freelist_mu);
}
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 7b7d8f3211..6f0d72c0c3 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -216,14 +216,10 @@ static void ssl_copy_key_material(const char *input, unsigned char **output,
static void ssl_build_config(const char *pem_root_certs,
grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
grpc_ssl_config *config) {
- if (pem_root_certs == NULL) {
- /* TODO(jboeuf): Get them from the environment. */
- gpr_log(GPR_ERROR, "Default SSL roots not yet implemented.");
- } else {
+ if (pem_root_certs != NULL) {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
}
-
if (pem_key_cert_pair != NULL) {
GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 58cd458415..1edec29775 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -39,6 +39,8 @@
#include "src/core/channel/http_client_filter.h"
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.h"
+#include "src/core/support/env.h"
+#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include "src/core/surface/lame_client.h"
#include "src/core/transport/chttp2/alpn.h"
@@ -319,6 +321,28 @@ static grpc_security_context_vtable ssl_channel_vtable = {
static grpc_security_context_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
+static gpr_slice default_pem_root_certs;
+
+static void init_default_pem_root_certs(void) {
+ char *default_root_certs_path =
+ gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
+ if (default_root_certs_path == NULL) {
+ default_pem_root_certs = gpr_empty_slice();
+ } else {
+ default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL);
+ gpr_free(default_root_certs_path);
+ }
+}
+
+static size_t get_default_pem_roots(const unsigned char **pem_root_certs) {
+ /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
+ loading all the roots once for the lifetime of the process. */
+ static gpr_once once = GPR_ONCE_INIT;
+ gpr_once_init(&once, init_default_pem_root_certs);
+ *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
+ return GPR_SLICE_LENGTH(default_pem_root_certs);
+}
+
grpc_security_status grpc_ssl_channel_security_context_create(
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *secure_peer_name, grpc_channel_security_context **ctx) {
@@ -330,6 +354,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
tsi_result result = TSI_OK;
grpc_ssl_channel_security_context *c;
size_t i;
+ const unsigned char *pem_root_certs;
+ size_t pem_root_certs_size;
for (i = 0; i < num_alpn_protocols; i++) {
alpn_protocol_strings[i] =
@@ -338,9 +364,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
strlen(grpc_chttp2_get_alpn_version_index(i));
}
- if (config == NULL || secure_peer_name == NULL ||
- config->pem_root_certs == NULL) {
- gpr_log(GPR_ERROR, "An ssl channel needs a secure name and root certs.");
+ if (config == NULL || secure_peer_name == NULL) {
+ gpr_log(GPR_ERROR, "An ssl channel needs a config and a secure name.");
goto error;
}
if (!check_request_metadata_creds(request_metadata_creds)) {
@@ -357,11 +382,20 @@ grpc_security_status grpc_ssl_channel_security_context_create(
if (secure_peer_name != NULL) {
c->secure_peer_name = gpr_strdup(secure_peer_name);
}
+ if (config->pem_root_certs == NULL) {
+ pem_root_certs_size = get_default_pem_roots(&pem_root_certs);
+ if (pem_root_certs == NULL || pem_root_certs_size == 0) {
+ gpr_log(GPR_ERROR, "Could not get default pem root certs.");
+ goto error;
+ }
+ } else {
+ pem_root_certs = config->pem_root_certs;
+ pem_root_certs_size = config->pem_root_certs_size;
+ }
result = tsi_create_ssl_client_handshaker_factory(
config->pem_private_key, config->pem_private_key_size,
- config->pem_cert_chain, config->pem_cert_chain_size,
- config->pem_root_certs, config->pem_root_certs_size,
- GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
+ config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
+ pem_root_certs_size, GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
diff --git a/src/core/support/env.h b/src/core/support/env.h
new file mode 100644
index 0000000000..81dda7d838
--- /dev/null
+++ b/src/core/support/env.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_ENV_H__
+#define __GRPC_SUPPORT_ENV_H__
+
+#include <stdio.h>
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Env utility functions */
+
+/* Gets the environment variable value with the specified name.
+ Returns a newly allocated string. It is the responsability of the caller to
+ gpr_free the return value if not NULL (which means that the environment
+ variable exists). */
+char *gpr_getenv(const char *name);
+
+/* Sets the the environment with the specified name to the specified value. */
+void gpr_setenv(const char *name, const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRPC_SUPPORT_ENV_H__ */
diff --git a/src/core/support/env_linux.c b/src/core/support/env_linux.c
new file mode 100644
index 0000000000..28e3d1450f
--- /dev/null
+++ b/src/core/support/env_linux.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* for secure_getenv. */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX_ENV
+
+#include "src/core/support/env.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/support/string.h"
+
+char *gpr_getenv(const char *name) {
+ char *result = secure_getenv(name);
+ return result == NULL ? result : gpr_strdup(result);
+}
+
+void gpr_setenv(const char *name, const char *value) {
+ int res = setenv(name, value, 1);
+ GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_LINUX_ENV */
diff --git a/src/core/support/env_posix.c b/src/core/support/env_posix.c
new file mode 100644
index 0000000000..bcbff9a177
--- /dev/null
+++ b/src/core/support/env_posix.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_ENV
+
+#include "src/core/support/env.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/support/string.h"
+
+char *gpr_getenv(const char *name) {
+ char *result = getenv(name);
+ return result == NULL ? result : gpr_strdup(result);
+}
+
+void gpr_setenv(const char *name, const char *value) {
+ int res = setenv(name, value, 1);
+ GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_POSIX_ENV */
diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c
new file mode 100644
index 0000000000..a31fa79d68
--- /dev/null
+++ b/src/core/support/env_win32.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/support/env.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+
+char *gpr_getenv(const char *name) {
+ size_t required_size;
+ char *result = NULL;
+
+ getenv_s(&required_size, NULL, 0, name);
+ if (required_size == 0) return NULL;
+ result = gpr_malloc(required_size);
+ getenv_s(&required_size, result, required_size, name);
+ return result;
+}
+
+void gpr_setenv(const char *name, const char *value) {
+ errno_t res = _putenv_s(name, value);
+ GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/support/file.c b/src/core/support/file.c
new file mode 100644
index 0000000000..c0bb1b66a0
--- /dev/null
+++ b/src/core/support/file.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/file.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/support/string.h"
+
+gpr_slice gpr_load_file(const char *filename, int *success) {
+ unsigned char *contents = NULL;
+ size_t contents_size = 0;
+ unsigned char buf[4096];
+ char *error_msg = NULL;
+ gpr_slice result = gpr_empty_slice();
+ FILE *file = fopen(filename, "rb");
+
+ if (file == NULL) {
+ gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
+ strerror(errno));
+ GPR_ASSERT(error_msg != NULL);
+ goto end;
+ }
+
+ while (1) {
+ size_t bytes_read = fread(buf, 1, sizeof(buf), file);
+ if (bytes_read > 0) {
+ contents = gpr_realloc(contents, contents_size + bytes_read);
+ memcpy(contents + contents_size, buf, bytes_read);
+ contents_size += bytes_read;
+ }
+ if (bytes_read < sizeof(buf)) {
+ if (ferror(file)) {
+ gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
+ strerror(errno), filename);
+ GPR_ASSERT(error_msg != NULL);
+ goto end;
+ } else {
+ GPR_ASSERT(feof(file));
+ break;
+ }
+ }
+ }
+ if (success != NULL) *success = 1;
+ result = gpr_slice_new(contents, contents_size, gpr_free);
+
+end:
+ if (error_msg != NULL) {
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ gpr_free(error_msg);
+ if (success != NULL) *success = 0;
+ }
+ if (file != NULL) fclose(file);
+ return result;
+}
diff --git a/src/core/support/file.h b/src/core/support/file.h
new file mode 100644
index 0000000000..92f420e7ce
--- /dev/null
+++ b/src/core/support/file.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __GRPC_SUPPORT_FILE_H__
+#define __GRPC_SUPPORT_FILE_H__
+
+#include <stdio.h>
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* File utility functions */
+
+/* Loads the content of a file into a slice. The success parameter, if not NULL,
+ will be set to 1 in case of success and 0 in case of failure. */
+gpr_slice gpr_load_file(const char *filename, int *success);
+
+/* Creates a temporary file from a prefix.
+ If tmp_filename is not NULL, *tmp_filename is assigned the name of the
+ created file and it is the responsibility of the caller to gpr_free it
+ unless an error occurs in which case it will be set to NULL. */
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRPC_SUPPORT_FILE_H__ */
diff --git a/src/core/support/file_posix.c b/src/core/support/file_posix.c
new file mode 100644
index 0000000000..cb48b3d52f
--- /dev/null
+++ b/src/core/support/file_posix.c
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Posix code for gpr fdopen and mkstemp support. */
+
+#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 200112L
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+/* Don't know why I have to do this for mkstemp, looks like _POSIX_C_SOURCE
+ should be enough... */
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_FILE
+
+#include "src/core/support/file.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/support/string.h"
+
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
+ FILE *result = NULL;
+ char *template;
+ int fd;
+
+ if (tmp_filename != NULL) *tmp_filename = NULL;
+
+ gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix);
+ GPR_ASSERT(template != NULL);
+
+ fd = mkstemp(template);
+ if (fd == -1) {
+ gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.",
+ template, strerror(errno));
+ goto end;
+ }
+ result = fdopen(fd, "w+");
+ if (result == NULL) {
+ gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).",
+ template, fd, strerror(errno));
+ unlink(template);
+ close(fd);
+ goto end;
+ }
+
+end:
+ if (result != NULL && tmp_filename != NULL) {
+ *tmp_filename = template;
+ } else {
+ gpr_free(template);
+ }
+ return result;
+}
+
+#endif /* GPR_POSIX_FILE */
diff --git a/src/core/support/file_win32.c b/src/core/support/file_win32.c
new file mode 100644
index 0000000000..d415281e0d
--- /dev/null
+++ b/src/core/support/file_win32.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/support/file.h"
+
+#include <io.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
+ FILE *result = NULL;
+ char *template;
+
+ if (tmp_filename != NULL) *tmp_filename = NULL;
+
+ gpr_asprintf(&template, "%s_XXXXXX", prefix);
+ GPR_ASSERT(template != NULL);
+
+ /* _mktemp_s can only create a maximum of 26 file names for any combination of
+ base and template values which is kind of sad... We may revisit this
+ function later to have something better... */
+ if (_mktemp_s(template, strlen(template) + 1) != 0) {
+ gpr_log(LOG_ERROR, "Could not create tmp file.");
+ goto end;
+ }
+ if (fopen_s(&result, template, "wb+") != 0) {
+ gpr_log(GPR_ERROR, "Could not open file %s", template);
+ result = NULL;
+ goto end;
+ }
+
+end:
+ if (result != NULL && tmp_filename != NULL) {
+ *tmp_filename = template;
+ } else {
+ gpr_free(template);
+ }
+ return result;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/surface/byte_buffer_queue.c b/src/core/surface/byte_buffer_queue.c
index dc280a60c5..9709a665ba 100644
--- a/src/core/surface/byte_buffer_queue.c
+++ b/src/core/surface/byte_buffer_queue.c
@@ -35,7 +35,13 @@
#include <grpc/support/alloc.h>
#include <grpc/support/useful.h>
-static void bba_destroy(grpc_bbq_array *array) { gpr_free(array->data); }
+static void bba_destroy(grpc_bbq_array *array, size_t start_pos) {
+ size_t i;
+ for (i = start_pos; i < array->count; i++) {
+ grpc_byte_buffer_destroy(array->data[i]);
+ }
+ gpr_free(array->data);
+}
/* Append an operation to an array, expanding as needed */
static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) {
@@ -47,8 +53,8 @@ static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) {
}
void grpc_bbq_destroy(grpc_byte_buffer_queue *q) {
- bba_destroy(&q->filling);
- bba_destroy(&q->draining);
+ bba_destroy(&q->filling, 0);
+ bba_destroy(&q->draining, q->drain_pos);
}
int grpc_bbq_empty(grpc_byte_buffer_queue *q) {
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index ebd6ace962..c68ce5a6a8 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -146,10 +146,10 @@ struct grpc_call {
/* Active ioreqs.
request_set and request_data contain one element per active ioreq
operation.
-
+
request_set[op] is an integer specifying a set of operations to which
the request belongs:
- - if it is < GRPC_IOREQ_OP_COUNT, then this operation is pending
+ - if it is < GRPC_IOREQ_OP_COUNT, then this operation is pending
completion, and the integer represents to which group of operations
the ioreq belongs. Each group is represented by one master, and the
integer in request_set is an index into masters to find the master
@@ -158,7 +158,7 @@ struct grpc_call {
started
- finally, if request_set[op] is REQSET_DONE, then the operation is
complete and unavailable to be started again
-
+
request_data[op] is the request data as supplied by the initiator of
a request, and is valid iff request_set[op] <= GRPC_IOREQ_OP_COUNT.
The set fields are as per the request type specified by op.
@@ -200,12 +200,12 @@ struct grpc_call {
/* Call refcount - to keep the call alive during asynchronous operations */
gpr_refcount internal_refcount;
- /* Data that the legacy api needs to track. To be deleted at some point
+ /* Data that the legacy api needs to track. To be deleted at some point
soon */
legacy_state *legacy_state;
};
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
+#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call)+1))
#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
#define CALL_ELEM_FROM_CALL(call, idx) \
grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
@@ -273,6 +273,7 @@ static void destroy_call(void *call, int ignored_success) {
if (c->legacy_state) {
destroy_legacy_state(c->legacy_state);
}
+ grpc_bbq_destroy(&c->incoming_queue);
gpr_free(c);
}
@@ -334,7 +335,9 @@ static void unlock(grpc_call *call) {
completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
int num_completed_requests = call->num_completed_requests;
int need_more_data =
- call->need_more_data && !is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA);
+ call->need_more_data &&
+ !call->sending &&
+ call->write_state >= WRITE_STATE_STARTED;
int i;
if (need_more_data) {
@@ -853,7 +856,7 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
gpr_uint32 status;
void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data) {
- status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
+ status = ((gpr_uint32)(gpr_intptr) user_data) - STATUS_OFFSET;
} else {
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
GPR_SLICE_LENGTH(md->value->slice),
@@ -941,6 +944,8 @@ struct legacy_state {
char *details;
grpc_status_code status;
+ char *send_details;
+
size_t msg_in_read_idx;
grpc_byte_buffer *msg_in;
@@ -966,6 +971,8 @@ static void destroy_legacy_state(legacy_state *ls) {
}
gpr_free(ls->initial_md_in.metadata);
gpr_free(ls->trailing_md_in.metadata);
+ gpr_free(ls->details);
+ gpr_free(ls->send_details);
gpr_free(ls);
}
@@ -1214,8 +1221,7 @@ grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
reqs[1].op = GRPC_IOREQ_SEND_STATUS;
reqs[1].data.send_status.code = status;
- /* MEMLEAK */
- reqs[1].data.send_status.details = gpr_strdup(details);
+ reqs[1].data.send_status.details = ls->send_details = gpr_strdup(details);
reqs[2].op = GRPC_IOREQ_SEND_CLOSE;
err = start_ioreq(call, reqs, 3, finish_finish, tag);
unlock(call);
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index c33ea923e8..b33bd7b357 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -52,6 +52,9 @@ struct grpc_channel {
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
+#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) (((grpc_channel *)(channel_stack)) - 1)
+#define CHANNEL_FROM_TOP_ELEM(top_elem) \
+ CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
grpc_channel *grpc_channel_create_from_filters(
const grpc_channel_filter **filters, size_t num_filters,
@@ -60,8 +63,8 @@ grpc_channel *grpc_channel_create_from_filters(
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
grpc_channel *channel = gpr_malloc(size);
channel->is_client = is_client;
- /* decremented by grpc_channel_destroy */
- gpr_ref_init(&channel->refs, 1);
+ /* decremented by grpc_channel_destroy, and grpc_client_channel_closed if is_client */
+ gpr_ref_init(&channel->refs, 1 + is_client);
channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
@@ -158,6 +161,10 @@ void grpc_channel_destroy(grpc_channel *channel) {
grpc_channel_internal_unref(channel);
}
+void grpc_client_channel_closed(grpc_channel_element *elem) {
+ grpc_channel_internal_unref(CHANNEL_FROM_TOP_ELEM(elem));
+}
+
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index b3ea2ede40..ff9bbc237e 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -45,6 +45,8 @@ grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
+void grpc_client_channel_closed(grpc_channel_element *elem);
+
void grpc_channel_internal_ref(grpc_channel *channel);
void grpc_channel_internal_unref(grpc_channel *channel);
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
index fa63e855cc..64ee9d51e8 100644
--- a/src/core/surface/client.c
+++ b/src/core/surface/client.c
@@ -34,6 +34,7 @@
#include "src/core/surface/client.h"
#include "src/core/surface/call.h"
+#include "src/core/surface/channel.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@@ -87,7 +88,7 @@ static void channel_op(grpc_channel_element *elem,
gpr_log(GPR_ERROR, "Client cannot accept new calls");
break;
case GRPC_TRANSPORT_CLOSED:
- gpr_log(GPR_ERROR, "Transport closed");
+ grpc_client_channel_closed(elem);
break;
case GRPC_TRANSPORT_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index 2f5eff5584..411dbabfd3 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -76,6 +76,9 @@ static void channel_op(grpc_channel_element *elem,
case GRPC_CHANNEL_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
break;
+ case GRPC_CHANNEL_DISCONNECT:
+ grpc_client_channel_closed(elem);
+ break;
default:
break;
}
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index a057694f13..455bd4337f 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -258,7 +258,6 @@ static void stream_closed(grpc_call_element *elem) {
gpr_mu_lock(&chand->server->mu);
switch (calld->state) {
case ACTIVATED:
- grpc_call_stream_closed(elem);
break;
case PENDING:
call_list_remove(chand->server, calld, PENDING_START);
@@ -271,6 +270,7 @@ static void stream_closed(grpc_call_element *elem) {
break;
}
gpr_mu_unlock(&chand->server->mu);
+ grpc_call_stream_closed(elem);
}
static void read_closed(grpc_call_element *elem) {
diff --git a/src/csharp/GrpcCore/Call.cs b/src/csharp/GrpcCore/Call.cs
index bf257e5d59..d3847a8009 100644
--- a/src/csharp/GrpcCore/Call.cs
+++ b/src/csharp/GrpcCore/Call.cs
@@ -8,10 +8,8 @@ namespace Google.GRPC.Core
readonly string methodName;
readonly Func<TRequest, byte[]> requestSerializer;
readonly Func<byte[], TResponse> responseDeserializer;
- readonly TimeSpan timeout;
readonly Channel channel;
- // TODO: channel param should be removed in the future.
public Call(string methodName,
Func<TRequest, byte[]> requestSerializer,
Func<byte[], TResponse> responseDeserializer,
@@ -20,24 +18,22 @@ namespace Google.GRPC.Core
this.methodName = methodName;
this.requestSerializer = requestSerializer;
this.responseDeserializer = responseDeserializer;
- this.timeout = timeout;
this.channel = channel;
}
-
- public Channel Channel
+ public Call(Method<TRequest, TResponse> method, Channel channel)
{
- get
- {
- return this.channel;
- }
+ this.methodName = method.Name;
+ this.requestSerializer = method.RequestMarshaller.Serialize;
+ this.responseDeserializer = method.ResponseMarshaller.Deserialize;
+ this.channel = channel;
}
- public TimeSpan Timeout
+ public Channel Channel
{
get
{
- return this.timeout;
+ return this.channel;
}
}
diff --git a/src/csharp/GrpcCore/GrpcCore.csproj b/src/csharp/GrpcCore/GrpcCore.csproj
index f0c84e78ea..2ad0f9154c 100644
--- a/src/csharp/GrpcCore/GrpcCore.csproj
+++ b/src/csharp/GrpcCore/GrpcCore.csproj
@@ -54,6 +54,11 @@
<Compile Include="Internal\AsyncCall.cs" />
<Compile Include="Internal\ServerSafeHandle.cs" />
<Compile Include="Internal\StreamingInputObserver.cs" />
+ <Compile Include="Method.cs" />
+ <Compile Include="IMarshaller.cs" />
+ <Compile Include="ServerCalls.cs" />
+ <Compile Include="ServerCallHandler.cs" />
+ <Compile Include="Internal\ServerWritingObserver.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/GrpcCore/IMarshaller.cs b/src/csharp/GrpcCore/IMarshaller.cs
new file mode 100644
index 0000000000..eb08d8d386
--- /dev/null
+++ b/src/csharp/GrpcCore/IMarshaller.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Google.GRPC.Core
+{
+ /// <summary>
+ /// For serializing and deserializing messages.
+ /// </summary>
+ public interface IMarshaller<T>
+ {
+ byte[] Serialize(T value);
+
+ T Deserialize(byte[] payload);
+ }
+
+ /// <summary>
+ /// UTF-8 Marshalling for string. Useful for testing.
+ /// </summary>
+ internal class StringMarshaller : IMarshaller<string> {
+
+ public byte[] Serialize(string value)
+ {
+ return System.Text.Encoding.UTF8.GetBytes(value);
+ }
+
+ public string Deserialize(byte[] payload)
+ {
+ return System.Text.Encoding.UTF8.GetString(payload);
+ }
+ }
+}
+
diff --git a/src/csharp/GrpcCore/Internal/AsyncCall.cs b/src/csharp/GrpcCore/Internal/AsyncCall.cs
index e83ca0eaa9..c38363bb2b 100644
--- a/src/csharp/GrpcCore/Internal/AsyncCall.cs
+++ b/src/csharp/GrpcCore/Internal/AsyncCall.cs
@@ -86,6 +86,14 @@ namespace Google.GRPC.Core.Internal
return StartRead().Task;
}
+ public Task Halfclosed
+ {
+ get
+ {
+ return halfcloseTcs.Task;
+ }
+ }
+
public Task<Status> Finished
{
get
diff --git a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
index 0d38bce63e..08d4cf0192 100644
--- a/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
+++ b/src/csharp/GrpcCore/Internal/ServerSafeHandle.cs
@@ -30,8 +30,8 @@ namespace Google.GRPC.Core.Internal
[DllImport("libgrpc.so")]
static extern void grpc_server_shutdown(ServerSafeHandle server);
- [DllImport("libgrpc.so")]
- static extern void grpc_server_shutdown_and_notify(ServerSafeHandle server, IntPtr tag);
+ [DllImport("libgrpc.so", EntryPoint = "grpc_server_shutdown_and_notify")]
+ static extern void grpc_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);
[DllImport("libgrpc.so")]
static extern void grpc_server_destroy(IntPtr server);
@@ -62,6 +62,11 @@ namespace Google.GRPC.Core.Internal
grpc_server_shutdown(this);
}
+ public void ShutdownAndNotify(EventCallbackDelegate callback)
+ {
+ grpc_server_shutdown_and_notify_CALLBACK(this, callback);
+ }
+
public GRPCCallError RequestCall(EventCallbackDelegate callback)
{
return grpc_server_request_call_old_CALLBACK(this, callback);
diff --git a/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs b/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
new file mode 100644
index 0000000000..2b46e9c53d
--- /dev/null
+++ b/src/csharp/GrpcCore/Internal/ServerWritingObserver.cs
@@ -0,0 +1,38 @@
+using System;
+using Google.GRPC.Core.Internal;
+
+namespace Google.GRPC.Core.Internal
+{
+ /// <summary>
+ /// Observer that writes all arriving messages to a call abstraction (in blocking fashion)
+ /// and then halfcloses the call. Used for server-side call handling.
+ /// </summary>
+ internal class ServerWritingObserver<TWrite, TRead> : IObserver<TWrite>
+ {
+ readonly AsyncCall<TWrite, TRead> call;
+
+ public ServerWritingObserver(AsyncCall<TWrite, TRead> call)
+ {
+ this.call = call;
+ }
+
+ public void OnCompleted()
+ {
+ // TODO: how bad is the Wait here?
+ call.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
+ }
+
+ public void OnError(Exception error)
+ {
+ // TODO: handle this...
+ throw new InvalidOperationException("This should never be called.");
+ }
+
+ public void OnNext(TWrite value)
+ {
+ // TODO: how bad is the Wait here?
+ call.WriteAsync(value).Wait();
+ }
+ }
+}
+
diff --git a/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs b/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
index d483e53a2d..c5de979351 100644
--- a/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
+++ b/src/csharp/GrpcCore/Internal/StreamingInputObserver.cs
@@ -1,7 +1,7 @@
using System;
using Google.GRPC.Core.Internal;
-namespace Google.GRPC.Core
+namespace Google.GRPC.Core.Internal
{
internal class StreamingInputObserver<TWrite, TRead> : IObserver<TWrite>
{
diff --git a/src/csharp/GrpcCore/Method.cs b/src/csharp/GrpcCore/Method.cs
new file mode 100644
index 0000000000..2790115695
--- /dev/null
+++ b/src/csharp/GrpcCore/Method.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Google.GRPC.Core
+{
+ public enum MethodType
+ {
+ Unary,
+ ClientStreaming,
+ ServerStreaming,
+ DuplexStreaming
+ }
+
+ /// <summary>
+ /// A description of a service method.
+ /// </summary>
+ public class Method<TRequest, TResponse>
+ {
+ readonly MethodType type;
+ readonly string name;
+ readonly IMarshaller<TRequest> requestMarshaller;
+ readonly IMarshaller<TResponse> responseMarshaller;
+
+ public Method(MethodType type, string name, IMarshaller<TRequest> requestMarshaller, IMarshaller<TResponse> responseMarshaller)
+ {
+ this.type = type;
+ this.name = name;
+ this.requestMarshaller = requestMarshaller;
+ this.responseMarshaller = responseMarshaller;
+ }
+
+ public MethodType Type
+ {
+ get
+ {
+ return this.type;
+ }
+ }
+
+ public string Name
+ {
+ get
+ {
+ return this.name;
+ }
+ }
+
+ public IMarshaller<TRequest> RequestMarshaller
+ {
+ get
+ {
+ return this.requestMarshaller;
+ }
+ }
+
+ public IMarshaller<TResponse> ResponseMarshaller
+ {
+ get
+ {
+ return this.responseMarshaller;
+ }
+ }
+ }
+}
+
diff --git a/src/csharp/GrpcCore/Server.cs b/src/csharp/GrpcCore/Server.cs
index 68da1a8300..4e9d114f85 100644
--- a/src/csharp/GrpcCore/Server.cs
+++ b/src/csharp/GrpcCore/Server.cs
@@ -1,7 +1,9 @@
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
+using System.Threading.Tasks;
using System.Collections.Concurrent;
+using System.Collections.Generic;
using Google.GRPC.Core.Internal;
namespace Google.GRPC.Core
@@ -15,10 +17,15 @@ namespace Google.GRPC.Core
// TODO: make sure the delegate doesn't get garbage collected while
// native callbacks are in the completion queue.
readonly EventCallbackDelegate newRpcHandler;
+ readonly EventCallbackDelegate serverShutdownHandler;
readonly BlockingCollection<NewRpcInfo> newRpcQueue = new BlockingCollection<NewRpcInfo>();
readonly ServerSafeHandle handle;
+ readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
+
+ readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
+
static Server() {
GrpcEnvironment.EnsureInitialized();
}
@@ -28,8 +35,14 @@ namespace Google.GRPC.Core
// TODO: what is the tag for server shutdown?
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero);
this.newRpcHandler = HandleNewRpc;
+ this.serverShutdownHandler = HandleServerShutdown;
}
+ // only call before Start(), this will be in server builder in the future.
+ internal void AddCallHandler(string methodName, IServerCallHandler handler) {
+ callHandlers.Add(methodName, handler);
+ }
+ // only call before Start()
public int AddPort(string addr) {
return handle.AddPort(addr);
}
@@ -37,49 +50,57 @@ namespace Google.GRPC.Core
public void Start()
{
handle.Start();
+
+ // TODO: this basically means the server is single threaded....
+ StartHandlingRpcs();
}
- public void RunRpc()
+ /// <summary>
+ /// Requests and handles single RPC call.
+ /// </summary>
+ internal void RunRpc()
{
AllowOneRpc();
- try {
- var rpcInfo = newRpcQueue.Take();
-
- Console.WriteLine("Server received RPC " + rpcInfo.Method);
-
- AsyncCall<byte[], byte[]> asyncCall = new AsyncCall<byte[], byte[]>(
- (payload) => payload, (payload) => payload);
-
- asyncCall.InitializeServer(rpcInfo.Call);
+ try
+ {
+ var rpcInfo = newRpcQueue.Take();
- asyncCall.Accept(GetCompletionQueue());
+ Console.WriteLine("Server received RPC " + rpcInfo.Method);
- while(true) {
- byte[] payload = asyncCall.ReadAsync().Result;
- if (payload == null)
+ IServerCallHandler callHandler;
+ if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler))
{
- break;
- }
+ callHandler = new NoSuchMethodCallHandler();
+ }
+ callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, GetCompletionQueue());
}
-
- asyncCall.WriteAsync(new byte[] { }).Wait();
-
- // TODO: what should be the details?
- asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
-
- asyncCall.Finished.Wait();
- } catch(Exception e) {
+ catch(Exception e)
+ {
Console.WriteLine("Exception while handling RPC: " + e);
}
}
- // TODO: implement disposal properly...
- public void Shutdown() {
- handle.Shutdown();
+ /// <summary>
+ /// Requests server shutdown and when there are no more calls being serviced,
+ /// cleans up used resources.
+ /// </summary>
+ /// <returns>The async.</returns>
+ public async Task ShutdownAsync() {
+ handle.ShutdownAndNotify(serverShutdownHandler);
+ await shutdownTcs.Task;
+ handle.Dispose();
+ }
+ public void Kill() {
+ handle.Dispose();
+ }
- //handle.Dispose();
+ private async Task StartHandlingRpcs() {
+ while (true)
+ {
+ await Task.Factory.StartNew(RunRpc);
+ }
}
private void AllowOneRpc()
@@ -100,6 +121,18 @@ namespace Google.GRPC.Core
}
}
+ private void HandleServerShutdown(IntPtr eventPtr)
+ {
+ try
+ {
+ shutdownTcs.SetResult(null);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Caught exception in a native handler: " + e);
+ }
+ }
+
private static void AssertCallOk(GRPCCallError callError)
{
Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
diff --git a/src/csharp/GrpcCore/ServerCallHandler.cs b/src/csharp/GrpcCore/ServerCallHandler.cs
new file mode 100644
index 0000000000..08d527a019
--- /dev/null
+++ b/src/csharp/GrpcCore/ServerCallHandler.cs
@@ -0,0 +1,93 @@
+using System;
+using Google.GRPC.Core.Internal;
+
+namespace Google.GRPC.Core
+{
+ internal interface IServerCallHandler
+ {
+ void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq);
+ }
+
+ internal class UnaryRequestServerCallHandler<TRequest, TResponse> : IServerCallHandler
+ {
+ readonly Method<TRequest, TResponse> method;
+ readonly UnaryRequestServerMethod<TRequest, TResponse> handler;
+
+ public UnaryRequestServerCallHandler(Method<TRequest, TResponse> method, UnaryRequestServerMethod<TRequest, TResponse> handler)
+ {
+ this.method = method;
+ this.handler = handler;
+ }
+
+ public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+ {
+ var asyncCall = new AsyncCall<TResponse, TRequest>(
+ (msg) => method.ResponseMarshaller.Serialize(msg),
+ (payload) => method.RequestMarshaller.Deserialize(payload));
+
+ asyncCall.InitializeServer(call);
+ asyncCall.Accept(cq);
+
+ var request = asyncCall.ReadAsync().Result;
+
+ var responseObserver = new ServerWritingObserver<TResponse, TRequest>(asyncCall);
+ handler(request, responseObserver);
+
+ asyncCall.Halfclosed.Wait();
+ // TODO: wait until writing is finished
+
+ asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
+ asyncCall.Finished.Wait();
+ }
+ }
+
+ internal class StreamingRequestServerCallHandler<TRequest, TResponse> : IServerCallHandler
+ {
+ readonly Method<TRequest, TResponse> method;
+ readonly StreamingRequestServerMethod<TRequest, TResponse> handler;
+
+ public StreamingRequestServerCallHandler(Method<TRequest, TResponse> method, StreamingRequestServerMethod<TRequest, TResponse> handler)
+ {
+ this.method = method;
+ this.handler = handler;
+ }
+
+ public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+ {
+ var asyncCall = new AsyncCall<TResponse, TRequest>(
+ (msg) => method.ResponseMarshaller.Serialize(msg),
+ (payload) => method.RequestMarshaller.Deserialize(payload));
+
+ asyncCall.InitializeServer(call);
+ asyncCall.Accept(cq);
+
+ var responseObserver = new ServerWritingObserver<TResponse, TRequest>(asyncCall);
+ var requestObserver = handler(responseObserver);
+
+ // feed the requests
+ asyncCall.StartReadingToStream(requestObserver);
+
+ asyncCall.Halfclosed.Wait();
+
+ asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_OK, "")).Wait();
+ asyncCall.Finished.Wait();
+ }
+ }
+
+ internal class NoSuchMethodCallHandler : IServerCallHandler
+ {
+ public void StartCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+ {
+ // We don't care about the payload type here.
+ AsyncCall<byte[], byte[]> asyncCall = new AsyncCall<byte[], byte[]>(
+ (payload) => payload, (payload) => payload);
+
+ asyncCall.InitializeServer(call);
+ asyncCall.Accept(cq);
+ asyncCall.WriteStatusAsync(new Status(StatusCode.GRPC_STATUS_UNIMPLEMENTED, "No such method.")).Wait();
+
+ asyncCall.Finished.Wait();
+ }
+ }
+}
+
diff --git a/src/csharp/GrpcCore/ServerCalls.cs b/src/csharp/GrpcCore/ServerCalls.cs
new file mode 100644
index 0000000000..86c4718932
--- /dev/null
+++ b/src/csharp/GrpcCore/ServerCalls.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Google.GRPC.Core
+{
+ // TODO: perhaps add also serverSideStreaming and clientSideStreaming
+
+ public delegate void UnaryRequestServerMethod<TRequest, TResponse> (TRequest request, IObserver<TResponse> responseObserver);
+
+ public delegate IObserver<TRequest> StreamingRequestServerMethod<TRequest, TResponse> (IObserver<TResponse> responseObserver);
+
+ internal static class ServerCalls {
+
+ public static IServerCallHandler UnaryRequestCall<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryRequestServerMethod<TRequest, TResponse> handler)
+ {
+ return new UnaryRequestServerCallHandler<TRequest, TResponse>(method, handler);
+ }
+
+ public static IServerCallHandler StreamingRequestCall<TRequest, TResponse>(Method<TRequest, TResponse> method, StreamingRequestServerMethod<TRequest, TResponse> handler)
+ {
+ return new StreamingRequestServerCallHandler<TRequest, TResponse>(method, handler);
+ }
+
+ }
+}
+
diff --git a/src/csharp/GrpcCoreTests/ClientServerTest.cs b/src/csharp/GrpcCoreTests/ClientServerTest.cs
index 823ee94288..511683b003 100644
--- a/src/csharp/GrpcCoreTests/ClientServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ClientServerTest.cs
@@ -8,41 +8,48 @@ namespace Google.GRPC.Core.Tests
{
public class ClientServerTest
{
- string request = "REQUEST";
string serverAddr = "localhost:" + Utils.PickUnusedPort();
+ private Method<string, string> unaryEchoStringMethod = new Method<string, string>(
+ MethodType.Unary,
+ "/tests.Test/UnaryEchoString",
+ new StringMarshaller(),
+ new StringMarshaller());
+
[Test]
public void EmptyCall()
{
Server server = new Server();
+
+ server.AddCallHandler(unaryEchoStringMethod.Name,
+ ServerCalls.UnaryRequestCall(unaryEchoStringMethod, HandleUnaryEchoString));
+
server.AddPort(serverAddr);
server.Start();
- Task.Factory.StartNew(
- () => {
- server.RunRpc();
- }
- );
-
using (Channel channel = new Channel(serverAddr))
{
- CreateCall(channel);
- string response = Calls.BlockingUnaryCall(CreateCall(channel), request, default(CancellationToken));
- Console.WriteLine("Received response: " + response);
+ var call = CreateUnaryEchoStringCall(channel);
+
+ Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)));
+ Assert.AreEqual("abcdef", Calls.BlockingUnaryCall(call, "abcdef", default(CancellationToken)));
}
- server.Shutdown();
+ server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
- private Call<string, string> CreateCall(Channel channel)
+ private Call<string, string> CreateUnaryEchoStringCall(Channel channel)
{
- return new Call<string, string>("/tests.Test/EmptyCall",
- (s) => System.Text.Encoding.ASCII.GetBytes(s),
- (b) => System.Text.Encoding.ASCII.GetString(b),
- Timeout.InfiniteTimeSpan, channel);
+ return new Call<string, string>(unaryEchoStringMethod, channel);
+ }
+
+ private void HandleUnaryEchoString(string request, IObserver<string> responseObserver) {
+ responseObserver.OnNext(request);
+ responseObserver.OnCompleted();
}
+
}
}
diff --git a/src/csharp/GrpcCoreTests/ServerTest.cs b/src/csharp/GrpcCoreTests/ServerTest.cs
index b34101bbf5..e6de95c336 100644
--- a/src/csharp/GrpcCoreTests/ServerTest.cs
+++ b/src/csharp/GrpcCoreTests/ServerTest.cs
@@ -12,7 +12,7 @@ namespace Google.GRPC.Core.Tests
Server server = new Server();
server.AddPort("localhost:" + Utils.PickUnusedPort());
server.Start();
- server.Shutdown();
+ server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
diff --git a/src/csharp/README.md b/src/csharp/README.md
index 75bfb26252..c2f988cc5e 100755
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -14,6 +14,34 @@ EXPERIMENTAL ONLY
- It is very possible that some parts of the code will be heavily refactored or
completely rewritten.
+
+INSTALLATION AND USAGE
+----------------------
+
+- Compile and install the gRPC C Core library
+```
+make shared_c
+sudo make install
+```
+
+- Prerequisites for development: Mono framework, MonoDevelop (IDE)
+```
+sudo apt-get install mono-devel
+sudo apt-get install monodevelop monodevelop-nunit
+sudo apt-get install nunit nunit-console
+```
+
+- Use MonoDevelop to open the solution Grpc.sln (you can also run unit tests
+ from there).
+
+- After building the solution with MonoDevelop, you can use
+ nunit-console to run the unit tests (currently only running one by
+ one will make them pass.
+
+```
+nunit-console GrpcCoreTests.dll
+```
+
CONTENTS
--------
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
index a70819e47e..149ac8c07b 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -39,6 +39,9 @@
#include "src/core/channel/channel_args.h"
#include "src/core/security/credentials.h"
#include "src/core/security/security_context.h"
+#include "src/core/support/env.h"
+#include "src/core/support/file.h"
+#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
@@ -99,7 +102,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_credentials *ssl_creds =
- grpc_ssl_credentials_create(test_root_cert, NULL);
+ grpc_ssl_credentials_create(NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.com"}};
@@ -129,8 +132,20 @@ static grpc_end2end_test_config configs[] = {
int main(int argc, char **argv) {
size_t i;
+ FILE *roots_file;
+ size_t roots_size = strlen(test_root_cert);
+ char *roots_filename;
+
grpc_test_init(argc, argv);
+ /* Set the SSL roots env var. */
+ roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
+ GPR_ASSERT(roots_filename != NULL);
+ GPR_ASSERT(roots_file != NULL);
+ GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
+ fclose(roots_file);
+ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
+
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
@@ -139,5 +154,9 @@ int main(int argc, char **argv) {
grpc_shutdown();
+ /* Cleanup. */
+ remove(roots_filename);
+ gpr_free(roots_filename);
+
return 0;
}
diff --git a/test/core/support/env_test.c b/test/core/support/env_test.c
new file mode 100644
index 0000000000..36d7adf80b
--- /dev/null
+++ b/test/core/support/env_test.c
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/support/env.h"
+#include "src/core/support/string.h"
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static void test_setenv_getenv(void) {
+ const char *name = "FOO";
+ const char *value = "BAR";
+ char *retrieved_value;
+
+ LOG_TEST_NAME();
+
+ gpr_setenv(name, value);
+ retrieved_value = gpr_getenv(name);
+ GPR_ASSERT(retrieved_value != NULL);
+ GPR_ASSERT(!strcmp(value, retrieved_value));
+ gpr_free(retrieved_value);
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ test_setenv_getenv();
+ return 0;
+}
diff --git a/test/core/support/file_test.c b/test/core/support/file_test.c
new file mode 100644
index 0000000000..b089954186
--- /dev/null
+++ b/test/core/support/file_test.c
@@ -0,0 +1,159 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+
+#include "src/core/support/file.h"
+#include "src/core/support/string.h"
+#include "test/core/util/test_config.h"
+
+#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
+
+static const char prefix[] = "file_test";
+
+static void test_load_empty_file(void) {
+ FILE *tmp = NULL;
+ gpr_slice slice;
+ int success;
+ char *tmp_name;
+
+ LOG_TEST_NAME();
+
+ tmp = gpr_tmpfile(prefix, &tmp_name);
+ GPR_ASSERT(tmp_name != NULL);
+ GPR_ASSERT(tmp != NULL);
+ fclose(tmp);
+
+ slice = gpr_load_file(tmp_name, &success);
+ GPR_ASSERT(success == 1);
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
+
+ remove(tmp_name);
+ gpr_free(tmp_name);
+ gpr_slice_unref(slice);
+}
+
+static void test_load_failure(void) {
+ FILE *tmp = NULL;
+ gpr_slice slice;
+ int success;
+ char *tmp_name;
+
+ LOG_TEST_NAME();
+
+ tmp = gpr_tmpfile(prefix, &tmp_name);
+ GPR_ASSERT(tmp_name != NULL);
+ GPR_ASSERT(tmp != NULL);
+ fclose(tmp);
+ remove(tmp_name);
+
+ slice = gpr_load_file(tmp_name, &success);
+ GPR_ASSERT(success == 0);
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
+ gpr_free(tmp_name);
+ gpr_slice_unref(slice);
+}
+
+static void test_load_small_file(void) {
+ FILE *tmp = NULL;
+ gpr_slice slice;
+ int success;
+ char *tmp_name;
+ const char *blah = "blah";
+
+ LOG_TEST_NAME();
+
+ tmp = gpr_tmpfile(prefix, &tmp_name);
+ GPR_ASSERT(tmp_name != NULL);
+ GPR_ASSERT(tmp != NULL);
+ GPR_ASSERT(fwrite(blah, 1, strlen(blah), tmp) == strlen(blah));
+ fclose(tmp);
+
+ slice = gpr_load_file(tmp_name, &success);
+ GPR_ASSERT(success == 1);
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) == strlen(blah));
+ GPR_ASSERT(!memcmp(GPR_SLICE_START_PTR(slice), blah, strlen(blah)));
+
+ remove(tmp_name);
+ gpr_free(tmp_name);
+ gpr_slice_unref(slice);
+}
+
+static void test_load_big_file(void) {
+ FILE *tmp = NULL;
+ gpr_slice slice;
+ int success;
+ char *tmp_name;
+ unsigned char buffer[124631];
+ unsigned char *current;
+ size_t i;
+
+ LOG_TEST_NAME();
+
+ for (i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = 42;
+ }
+
+ tmp = gpr_tmpfile(prefix, &tmp_name);
+ GPR_ASSERT(tmp != NULL);
+ GPR_ASSERT(tmp_name != NULL);
+ GPR_ASSERT(fwrite(buffer, 1, sizeof(buffer), tmp) == sizeof(buffer));
+ fclose(tmp);
+
+ slice = gpr_load_file(tmp_name, &success);
+ GPR_ASSERT(success == 1);
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice) == sizeof(buffer));
+ current = GPR_SLICE_START_PTR(slice);
+ for (i = 0; i < sizeof(buffer); i++) {
+ GPR_ASSERT(current[i] == 42);
+ }
+
+ remove(tmp_name);
+ gpr_free(tmp_name);
+ gpr_slice_unref(slice);
+}
+
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ test_load_empty_file();
+ test_load_failure();
+ test_load_small_file();
+ test_load_big_file();
+ return 0;
+}
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 939a1a6095..facef4e0d7 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -111,6 +111,14 @@
},
{
"language": "c",
+ "name": "gpr_file_test"
+ },
+ {
+ "language": "c",
+ "name": "gpr_env_test"
+ },
+ {
+ "language": "c",
"name": "gpr_slice_buffer_test"
},
{
diff --git a/vsprojects/vs2013/build_and_run_tests.bat b/vsprojects/vs2013/build_and_run_tests.bat
index 77000739bb..88d9b2f471 100644
--- a/vsprojects/vs2013/build_and_run_tests.bat
+++ b/vsprojects/vs2013/build_and_run_tests.bat
@@ -49,6 +49,22 @@ echo Running test gpr_log_test
test_bin\gpr_log_test.exe || echo TEST FAILED: gpr_log_test && exit /b
echo(
+echo Building test gpr_file_test
+cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\file_test.c
+link.exe /OUT:"test_bin\gpr_file_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\file_test.obj
+echo(
+echo Running test gpr_file_test
+test_bin\gpr_file_test.exe || echo TEST FAILED: gpr_file_test && exit /b
+echo(
+
+echo Building test gpr_env_test
+cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\env_test.c
+link.exe /OUT:"test_bin\gpr_env_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\env_test.obj
+echo(
+echo Running test gpr_env_test
+test_bin\gpr_env_test.exe || echo TEST FAILED: gpr_env_test && exit /b
+echo(
+
echo Building test gpr_slice_buffer_test
cl.exe /c /I..\.. /I..\..\include /nologo /ZI /W3 /WX- /sdl /D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze- /Fo:test_bin\ ..\..\test\core\support\slice_buffer_test.c
link.exe /OUT:"test_bin\gpr_slice_buffer_test.exe" /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 Debug\gpr_test_util.lib Debug\gpr.lib test_bin\slice_buffer_test.obj
diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj
index 0d429ab43d..d1f7085383 100644
--- a/vsprojects/vs2013/gpr.vcxproj
+++ b/vsprojects/vs2013/gpr.vcxproj
@@ -96,6 +96,8 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\core\support\cpu.h" />
+ <ClInclude Include="..\..\src\core\support\env.h" />
+ <ClInclude Include="..\..\src\core\support\file.h" />
<ClInclude Include="..\..\src\core\support\murmur_hash.h" />
<ClInclude Include="..\..\src\core\support\string.h" />
<ClInclude Include="..\..\src\core\support\thd_internal.h" />
@@ -111,6 +113,18 @@
</ClCompile>
<ClCompile Include="..\..\src\core\support\cpu_posix.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_linux.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_posix.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_win32.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file_posix.c">
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file_win32.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\histogram.c">
</ClCompile>
<ClCompile Include="..\..\src\core\support\host_port.c">
diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters
index a992558654..13add834a8 100644
--- a/vsprojects/vs2013/gpr.vcxproj.filters
+++ b/vsprojects/vs2013/gpr.vcxproj.filters
@@ -16,6 +16,24 @@
<ClCompile Include="..\..\src\core\support\cpu_posix.c">
<Filter>src\core\support</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_linux.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_posix.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\env_win32.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file_posix.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\core\support\file_win32.c">
+ <Filter>src\core\support</Filter>
+ </ClCompile>
<ClCompile Include="..\..\src\core\support\histogram.c">
<Filter>src\core\support</Filter>
</ClCompile>
@@ -146,6 +164,12 @@
<ClInclude Include="..\..\src\core\support\cpu.h">
<Filter>src\core\support</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\core\support\env.h">
+ <Filter>src\core\support</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\core\support\file.h">
+ <Filter>src\core\support</Filter>
+ </ClInclude>
<ClInclude Include="..\..\src\core\support\murmur_hash.h">
<Filter>src\core\support</Filter>
</ClInclude>