Merge pull request #562 from ctiller/dox3
More channel argument documentation.
diff --git a/Makefile b/Makefile
index a491c38..58bbc7a 100644
--- a/Makefile
+++ b/Makefile
@@ -451,6 +451,7 @@
low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
metadata_buffer_test: $(BINDIR)/$(CONFIG)/metadata_buffer_test
+multi_init_test: $(BINDIR)/$(CONFIG)/multi_init_test
murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
poll_kick_posix_test: $(BINDIR)/$(CONFIG)/poll_kick_posix_test
@@ -464,21 +465,21 @@
time_test: $(BINDIR)/$(CONFIG)/time_test
timeout_encoding_test: $(BINDIR)/$(CONFIG)/timeout_encoding_test
transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
+async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
cpp_plugin: $(BINDIR)/$(CONFIG)/cpp_plugin
credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server
+pubsub_client: $(BINDIR)/$(CONFIG)/pubsub_client
+pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test
+pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
qps_client: $(BINDIR)/$(CONFIG)/qps_client
qps_server: $(BINDIR)/$(CONFIG)/qps_server
ruby_plugin: $(BINDIR)/$(CONFIG)/ruby_plugin
status_test: $(BINDIR)/$(CONFIG)/status_test
-sync_client_async_server_test: $(BINDIR)/$(CONFIG)/sync_client_async_server_test
thread_pool_test: $(BINDIR)/$(CONFIG)/thread_pool_test
-pubsub_client: $(BINDIR)/$(CONFIG)/pubsub_client
-pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test
-pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
chttp2_fake_security_cancel_after_accept_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test
chttp2_fake_security_cancel_after_accept_and_writes_closed_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test
chttp2_fake_security_cancel_after_invoke_test: $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test
@@ -878,9 +879,9 @@
buildtests: buildtests_c buildtests_cxx
-buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test
+buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/qps_client $(BINDIR)/$(CONFIG)/qps_server $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_client_async_server_test $(BINDIR)/$(CONFIG)/thread_pool_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_client $(BINDIR)/$(CONFIG)/qps_server $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
test: test_c test_cxx
@@ -989,6 +990,8 @@
$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
$(E) "[RUN] Testing metadata_buffer_test"
$(Q) $(BINDIR)/$(CONFIG)/metadata_buffer_test || ( echo test metadata_buffer_test failed ; exit 1 )
+ $(E) "[RUN] Testing multi_init_test"
+ $(Q) $(BINDIR)/$(CONFIG)/multi_init_test || ( echo test multi_init_test failed ; exit 1 )
$(E) "[RUN] Testing murmur_hash_test"
$(Q) $(BINDIR)/$(CONFIG)/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 )
$(E) "[RUN] Testing no_server_test"
@@ -1690,22 +1693,22 @@
test_cxx: buildtests_cxx
+ $(E) "[RUN] Testing async_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing channel_arguments_test"
$(Q) $(BINDIR)/$(CONFIG)/channel_arguments_test || ( echo test channel_arguments_test failed ; exit 1 )
$(E) "[RUN] Testing credentials_test"
$(Q) $(BINDIR)/$(CONFIG)/credentials_test || ( echo test credentials_test failed ; exit 1 )
$(E) "[RUN] Testing end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
- $(E) "[RUN] Testing status_test"
- $(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 )
- $(E) "[RUN] Testing sync_client_async_server_test"
- $(Q) $(BINDIR)/$(CONFIG)/sync_client_async_server_test || ( echo test sync_client_async_server_test failed ; exit 1 )
- $(E) "[RUN] Testing thread_pool_test"
- $(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )
$(E) "[RUN] Testing pubsub_publisher_test"
$(Q) $(BINDIR)/$(CONFIG)/pubsub_publisher_test || ( echo test pubsub_publisher_test failed ; exit 1 )
$(E) "[RUN] Testing pubsub_subscriber_test"
$(Q) $(BINDIR)/$(CONFIG)/pubsub_subscriber_test || ( echo test pubsub_subscriber_test failed ; exit 1 )
+ $(E) "[RUN] Testing status_test"
+ $(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 )
+ $(E) "[RUN] Testing thread_pool_test"
+ $(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )
tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
@@ -2198,8 +2201,8 @@
src/core/iomgr/iomgr_posix.c \
src/core/iomgr/iomgr_windows.c \
src/core/iomgr/pollset_kick.c \
- src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_multipoller_with_epoll.c \
+ src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_posix.c \
src/core/iomgr/pollset_windows.c \
src/core/iomgr/resolve_address.c \
@@ -2338,8 +2341,8 @@
src/core/iomgr/iomgr_posix.c: $(OPENSSL_DEP)
src/core/iomgr/iomgr_windows.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_kick.c: $(OPENSSL_DEP)
-src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_multipoller_with_epoll.c: $(OPENSSL_DEP)
+src/core/iomgr/pollset_multipoller_with_poll_posix.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_posix.c: $(OPENSSL_DEP)
src/core/iomgr/pollset_windows.c: $(OPENSSL_DEP)
src/core/iomgr/resolve_address.c: $(OPENSSL_DEP)
@@ -2495,8 +2498,8 @@
$(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_kick.o:
-$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o:
+$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o:
@@ -2743,8 +2746,8 @@
src/core/iomgr/iomgr_posix.c \
src/core/iomgr/iomgr_windows.c \
src/core/iomgr/pollset_kick.c \
- src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_multipoller_with_epoll.c \
+ src/core/iomgr/pollset_multipoller_with_poll_posix.c \
src/core/iomgr/pollset_posix.c \
src/core/iomgr/pollset_windows.c \
src/core/iomgr/resolve_address.c \
@@ -2883,8 +2886,8 @@
$(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_kick.o:
-$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_epoll.o:
+$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_multipoller_with_poll_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_posix.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/pollset_windows.o:
$(OBJDIR)/$(CONFIG)/src/core/iomgr/resolve_address.o:
@@ -2958,27 +2961,23 @@
src/cpp/client/channel.cc \
src/cpp/client/channel_arguments.cc \
src/cpp/client/client_context.cc \
+ src/cpp/client/client_unary_call.cc \
src/cpp/client/create_channel.cc \
src/cpp/client/credentials.cc \
src/cpp/client/internal_stub.cc \
+ src/cpp/common/call.cc \
src/cpp/common/completion_queue.cc \
src/cpp/common/rpc_method.cc \
src/cpp/proto/proto_utils.cc \
- src/cpp/server/async_server.cc \
- src/cpp/server/async_server_context.cc \
src/cpp/server/server.cc \
src/cpp/server/server_builder.cc \
- src/cpp/server/server_context_impl.cc \
+ src/cpp/server/server_context.cc \
src/cpp/server/server_credentials.cc \
- src/cpp/server/server_rpc_handler.cc \
src/cpp/server/thread_pool.cc \
- src/cpp/stream/stream_context.cc \
src/cpp/util/status.cc \
src/cpp/util/time.cc \
PUBLIC_HEADERS_CXX += \
- include/grpc++/async_server.h \
- include/grpc++/async_server_context.h \
include/grpc++/channel_arguments.h \
include/grpc++/channel_interface.h \
include/grpc++/client_context.h \
@@ -2986,6 +2985,8 @@
include/grpc++/config.h \
include/grpc++/create_channel.h \
include/grpc++/credentials.h \
+ include/grpc++/impl/call.h \
+ include/grpc++/impl/client_unary_call.h \
include/grpc++/impl/internal_stub.h \
include/grpc++/impl/rpc_method.h \
include/grpc++/impl/rpc_service_method.h \
@@ -3034,21 +3035,19 @@
src/cpp/client/channel.cc: $(OPENSSL_DEP)
src/cpp/client/channel_arguments.cc: $(OPENSSL_DEP)
src/cpp/client/client_context.cc: $(OPENSSL_DEP)
+src/cpp/client/client_unary_call.cc: $(OPENSSL_DEP)
src/cpp/client/create_channel.cc: $(OPENSSL_DEP)
src/cpp/client/credentials.cc: $(OPENSSL_DEP)
src/cpp/client/internal_stub.cc: $(OPENSSL_DEP)
+src/cpp/common/call.cc: $(OPENSSL_DEP)
src/cpp/common/completion_queue.cc: $(OPENSSL_DEP)
src/cpp/common/rpc_method.cc: $(OPENSSL_DEP)
src/cpp/proto/proto_utils.cc: $(OPENSSL_DEP)
-src/cpp/server/async_server.cc: $(OPENSSL_DEP)
-src/cpp/server/async_server_context.cc: $(OPENSSL_DEP)
src/cpp/server/server.cc: $(OPENSSL_DEP)
src/cpp/server/server_builder.cc: $(OPENSSL_DEP)
-src/cpp/server/server_context_impl.cc: $(OPENSSL_DEP)
+src/cpp/server/server_context.cc: $(OPENSSL_DEP)
src/cpp/server/server_credentials.cc: $(OPENSSL_DEP)
-src/cpp/server/server_rpc_handler.cc: $(OPENSSL_DEP)
src/cpp/server/thread_pool.cc: $(OPENSSL_DEP)
-src/cpp/stream/stream_context.cc: $(OPENSSL_DEP)
src/cpp/util/status.cc: $(OPENSSL_DEP)
src/cpp/util/time.cc: $(OPENSSL_DEP)
endif
@@ -3095,21 +3094,19 @@
$(OBJDIR)/$(CONFIG)/src/cpp/client/channel.o:
$(OBJDIR)/$(CONFIG)/src/cpp/client/channel_arguments.o:
$(OBJDIR)/$(CONFIG)/src/cpp/client/client_context.o:
+$(OBJDIR)/$(CONFIG)/src/cpp/client/client_unary_call.o:
$(OBJDIR)/$(CONFIG)/src/cpp/client/create_channel.o:
$(OBJDIR)/$(CONFIG)/src/cpp/client/credentials.o:
$(OBJDIR)/$(CONFIG)/src/cpp/client/internal_stub.o:
+$(OBJDIR)/$(CONFIG)/src/cpp/common/call.o:
$(OBJDIR)/$(CONFIG)/src/cpp/common/completion_queue.o:
$(OBJDIR)/$(CONFIG)/src/cpp/common/rpc_method.o:
$(OBJDIR)/$(CONFIG)/src/cpp/proto/proto_utils.o:
-$(OBJDIR)/$(CONFIG)/src/cpp/server/async_server.o:
-$(OBJDIR)/$(CONFIG)/src/cpp/server/async_server_context.o:
$(OBJDIR)/$(CONFIG)/src/cpp/server/server.o:
$(OBJDIR)/$(CONFIG)/src/cpp/server/server_builder.o:
-$(OBJDIR)/$(CONFIG)/src/cpp/server/server_context_impl.o:
+$(OBJDIR)/$(CONFIG)/src/cpp/server/server_context.o:
$(OBJDIR)/$(CONFIG)/src/cpp/server/server_credentials.o:
-$(OBJDIR)/$(CONFIG)/src/cpp/server/server_rpc_handler.o:
$(OBJDIR)/$(CONFIG)/src/cpp/server/thread_pool.o:
-$(OBJDIR)/$(CONFIG)/src/cpp/stream/stream_context.o:
$(OBJDIR)/$(CONFIG)/src/cpp/util/status.o:
$(OBJDIR)/$(CONFIG)/src/cpp/util/time.o:
@@ -3118,7 +3115,6 @@
$(GENDIR)/test/cpp/util/messages.pb.cc \
$(GENDIR)/test/cpp/util/echo.pb.cc \
$(GENDIR)/test/cpp/util/echo_duplicate.pb.cc \
- test/cpp/end2end/async_test_server.cc \
test/cpp/util/create_test_channel.cc \
@@ -3149,7 +3145,6 @@
test/cpp/util/messages.proto: $(OPENSSL_DEP)
test/cpp/util/echo.proto: $(OPENSSL_DEP)
test/cpp/util/echo_duplicate.proto: $(OPENSSL_DEP)
-test/cpp/end2end/async_test_server.cc: $(OPENSSL_DEP)
test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
endif
@@ -3178,7 +3173,6 @@
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/async_test_server.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc
@@ -6815,6 +6809,37 @@
endif
+MULTI_INIT_TEST_SRC = \
+ test/core/surface/multi_init_test.c \
+
+MULTI_INIT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MULTI_INIT_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/multi_init_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/multi_init_test: $(MULTI_INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(MULTI_INIT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/multi_init_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/surface/multi_init_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_multi_init_test: $(MULTI_INIT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MULTI_INIT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
MURMUR_HASH_TEST_SRC = \
test/core/support/murmur_hash_test.c \
@@ -7218,6 +7243,37 @@
endif
+ASYNC_END2END_TEST_SRC = \
+ test/cpp/end2end/async_end2end_test.cc \
+
+ASYNC_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_END2END_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/async_end2end_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/async_end2end_test: $(ASYNC_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(ASYNC_END2END_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/async_end2end_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/async_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_async_end2end_test: $(ASYNC_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ASYNC_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CHANNEL_ARGUMENTS_TEST_SRC = \
test/cpp/client/channel_arguments_test.cc \
@@ -7417,6 +7473,99 @@
endif
+PUBSUB_CLIENT_SRC = \
+ examples/pubsub/main.cc \
+
+PUBSUB_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_CLIENT_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/pubsub_client: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/pubsub_client: $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_client
+
+endif
+
+$(OBJDIR)/$(CONFIG)/examples/pubsub/main.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_pubsub_client: $(PUBSUB_CLIENT_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(PUBSUB_CLIENT_OBJS:.o=.dep)
+endif
+endif
+
+
+PUBSUB_PUBLISHER_TEST_SRC = \
+ examples/pubsub/publisher_test.cc \
+
+PUBSUB_PUBLISHER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_PUBLISHER_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/pubsub_publisher_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/pubsub_publisher_test: $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_pubsub_publisher_test: $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+PUBSUB_SUBSCRIBER_TEST_SRC = \
+ examples/pubsub/subscriber_test.cc \
+
+PUBSUB_SUBSCRIBER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_SUBSCRIBER_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_pubsub_subscriber_test: $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
QPS_CLIENT_SRC = \
$(GENDIR)/test/cpp/qps/qpstest.pb.cc \
test/cpp/qps/client.cc \
@@ -7546,37 +7695,6 @@
endif
-SYNC_CLIENT_ASYNC_SERVER_TEST_SRC = \
- test/cpp/end2end/sync_client_async_server_test.cc \
-
-SYNC_CLIENT_ASYNC_SERVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SYNC_CLIENT_ASYNC_SERVER_TEST_SRC))))
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/sync_client_async_server_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/sync_client_async_server_test: $(SYNC_CLIENT_ASYNC_SERVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(SYNC_CLIENT_ASYNC_SERVER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/sync_client_async_server_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/sync_client_async_server_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_sync_client_async_server_test: $(SYNC_CLIENT_ASYNC_SERVER_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(SYNC_CLIENT_ASYNC_SERVER_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
THREAD_POOL_TEST_SRC = \
test/cpp/server/thread_pool_test.cc \
@@ -7608,99 +7726,6 @@
endif
-PUBSUB_CLIENT_SRC = \
- examples/pubsub/main.cc \
-
-PUBSUB_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_CLIENT_SRC))))
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/pubsub_client: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/pubsub_client: $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_client
-
-endif
-
-$(OBJDIR)/$(CONFIG)/examples/pubsub/main.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_pubsub_client: $(PUBSUB_CLIENT_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(PUBSUB_CLIENT_OBJS:.o=.dep)
-endif
-endif
-
-
-PUBSUB_PUBLISHER_TEST_SRC = \
- examples/pubsub/publisher_test.cc \
-
-PUBSUB_PUBLISHER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_PUBLISHER_TEST_SRC))))
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/pubsub_publisher_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/pubsub_publisher_test: $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_pubsub_publisher_test: $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
-PUBSUB_SUBSCRIBER_TEST_SRC = \
- examples/pubsub/subscriber_test.cc \
-
-PUBSUB_SUBSCRIBER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_SUBSCRIBER_TEST_SRC))))
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL with ALPN.
-
-$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: openssl_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_pubsub_subscriber_test: $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_SRC = \
CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHTTP2_FAKE_SECURITY_CANCEL_AFTER_ACCEPT_TEST_SRC))))
diff --git a/build.json b/build.json
index 2a07209..07af691 100644
--- a/build.json
+++ b/build.json
@@ -138,8 +138,8 @@
"src/core/iomgr/iomgr_posix.c",
"src/core/iomgr/iomgr_windows.c",
"src/core/iomgr/pollset_kick.c",
- "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
"src/core/iomgr/pollset_multipoller_with_epoll.c",
+ "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
"src/core/iomgr/pollset_posix.c",
"src/core/iomgr/pollset_windows.c",
"src/core/iomgr/resolve_address.c",
@@ -398,8 +398,6 @@
"build": "all",
"language": "c++",
"public_headers": [
- "include/grpc++/async_server.h",
- "include/grpc++/async_server_context.h",
"include/grpc++/channel_arguments.h",
"include/grpc++/channel_interface.h",
"include/grpc++/client_context.h",
@@ -407,6 +405,8 @@
"include/grpc++/config.h",
"include/grpc++/create_channel.h",
"include/grpc++/credentials.h",
+ "include/grpc++/impl/call.h",
+ "include/grpc++/impl/client_unary_call.h",
"include/grpc++/impl/internal_stub.h",
"include/grpc++/impl/rpc_method.h",
"include/grpc++/impl/rpc_service_method.h",
@@ -421,30 +421,26 @@
"headers": [
"src/cpp/client/channel.h",
"src/cpp/proto/proto_utils.h",
- "src/cpp/server/server_rpc_handler.h",
"src/cpp/server/thread_pool.h",
- "src/cpp/stream/stream_context.h",
"src/cpp/util/time.h"
],
"src": [
"src/cpp/client/channel.cc",
"src/cpp/client/channel_arguments.cc",
"src/cpp/client/client_context.cc",
+ "src/cpp/client/client_unary_call.cc",
"src/cpp/client/create_channel.cc",
"src/cpp/client/credentials.cc",
"src/cpp/client/internal_stub.cc",
+ "src/cpp/common/call.cc",
"src/cpp/common/completion_queue.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/proto/proto_utils.cc",
- "src/cpp/server/async_server.cc",
- "src/cpp/server/async_server_context.cc",
"src/cpp/server/server.cc",
"src/cpp/server/server_builder.cc",
- "src/cpp/server/server_context_impl.cc",
+ "src/cpp/server/server_context.cc",
"src/cpp/server/server_credentials.cc",
- "src/cpp/server/server_rpc_handler.cc",
"src/cpp/server/thread_pool.cc",
- "src/cpp/stream/stream_context.cc",
"src/cpp/util/status.cc",
"src/cpp/util/time.cc"
],
@@ -462,7 +458,6 @@
"test/cpp/util/messages.proto",
"test/cpp/util/echo.proto",
"test/cpp/util/echo_duplicate.proto",
- "test/cpp/end2end/async_test_server.cc",
"test/cpp/util/create_test_channel.cc"
]
},
@@ -1357,6 +1352,20 @@
]
},
{
+ "name": "multi_init_test",
+ "build": "test",
+ "language": "c",
+ "src": [
+ "test/core/surface/multi_init_test.c"
+ ],
+ "deps": [
+ "grpc_test_util",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
"name": "murmur_hash_test",
"build": "test",
"language": "c",
@@ -1537,6 +1546,22 @@
]
},
{
+ "name": "async_end2end_test",
+ "build": "test",
+ "language": "c++",
+ "src": [
+ "test/cpp/end2end/async_end2end_test.cc"
+ ],
+ "deps": [
+ "grpc++_test_util",
+ "grpc_test_util",
+ "grpc++",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
"name": "channel_arguments_test",
"build": "test",
"language": "c++",
@@ -1634,105 +1659,6 @@
]
},
{
- "name": "qps_client",
- "build": "test",
- "run": false,
- "language": "c++",
- "src": [
- "test/cpp/qps/qpstest.proto",
- "test/cpp/qps/client.cc"
- ],
- "deps": [
- "grpc++_test_util",
- "grpc_test_util",
- "grpc++",
- "grpc",
- "gpr_test_util",
- "gpr"
- ]
- },
- {
- "name": "qps_server",
- "build": "test",
- "run": false,
- "language": "c++",
- "src": [
- "test/cpp/qps/qpstest.proto",
- "test/cpp/qps/server.cc"
- ],
- "deps": [
- "grpc++_test_util",
- "grpc_test_util",
- "grpc++",
- "grpc",
- "gpr_test_util",
- "gpr"
- ]
- },
- {
- "name": "ruby_plugin",
- "build": "protoc",
- "language": "c++",
- "headers": [
- "src/compiler/cpp_generator.h",
- "src/compiler/cpp_generator_helpers-inl.h",
- "src/compiler/cpp_generator_map-inl.h",
- "src/compiler/cpp_generator_string-inl.h"
- ],
- "src": [
- "src/compiler/ruby_generator.cc",
- "src/compiler/ruby_plugin.cc"
- ],
- "deps": [],
- "secure": false
- },
- {
- "name": "status_test",
- "build": "test",
- "language": "c++",
- "src": [
- "test/cpp/util/status_test.cc"
- ],
- "deps": [
- "grpc_test_util",
- "grpc++",
- "grpc",
- "gpr_test_util",
- "gpr"
- ]
- },
- {
- "name": "sync_client_async_server_test",
- "build": "test",
- "language": "c++",
- "src": [
- "test/cpp/end2end/sync_client_async_server_test.cc"
- ],
- "deps": [
- "grpc++_test_util",
- "grpc_test_util",
- "grpc++",
- "grpc",
- "gpr_test_util",
- "gpr"
- ]
- },
- {
- "name": "thread_pool_test",
- "build": "test",
- "language": "c++",
- "src": [
- "test/cpp/server/thread_pool_test.cc"
- ],
- "deps": [
- "grpc_test_util",
- "grpc++",
- "grpc",
- "gpr_test_util",
- "gpr"
- ]
- },
- {
"name": "pubsub_client",
"build": "test",
"run": false,
@@ -1783,6 +1709,83 @@
"gpr_test_util",
"gpr"
]
+ },
+ {
+ "name": "qps_client",
+ "build": "test",
+ "run": false,
+ "language": "c++",
+ "src": [
+ "test/cpp/qps/qpstest.proto",
+ "test/cpp/qps/client.cc"
+ ],
+ "deps": [
+ "grpc++_test_util",
+ "grpc_test_util",
+ "grpc++",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
+ "name": "qps_server",
+ "build": "test",
+ "run": false,
+ "language": "c++",
+ "src": [
+ "test/cpp/qps/qpstest.proto",
+ "test/cpp/qps/server.cc"
+ ],
+ "deps": [
+ "grpc++_test_util",
+ "grpc_test_util",
+ "grpc++",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
+ "name": "ruby_plugin",
+ "build": "protoc",
+ "language": "c++",
+ "src": [
+ "src/compiler/ruby_generator.cc",
+ "src/compiler/ruby_plugin.cc"
+ ],
+ "deps": [],
+ "secure": false
+ },
+ {
+ "name": "status_test",
+ "build": "test",
+ "language": "c++",
+ "src": [
+ "test/cpp/util/status_test.cc"
+ ],
+ "deps": [
+ "grpc_test_util",
+ "grpc++",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
+ },
+ {
+ "name": "thread_pool_test",
+ "build": "test",
+ "language": "c++",
+ "src": [
+ "test/cpp/server/thread_pool_test.cc"
+ ],
+ "deps": [
+ "grpc_test_util",
+ "grpc++",
+ "grpc",
+ "gpr_test_util",
+ "gpr"
+ ]
}
]
}
diff --git a/examples/pubsub/publisher_test.cc b/examples/pubsub/publisher_test.cc
index 298a5a2..6f4bc6b 100644
--- a/examples/pubsub/publisher_test.cc
+++ b/examples/pubsub/publisher_test.cc
@@ -107,7 +107,7 @@
server_address_ << "localhost:" << port;
ServerBuilder builder;
builder.AddPort(server_address_.str());
- builder.RegisterService(service_.service());
+ builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
channel_ = CreateChannel(server_address_.str(), ChannelArguments());
diff --git a/examples/pubsub/subscriber_test.cc b/examples/pubsub/subscriber_test.cc
index 65a9af3..a436c5d 100644
--- a/examples/pubsub/subscriber_test.cc
+++ b/examples/pubsub/subscriber_test.cc
@@ -106,7 +106,7 @@
server_address_ << "localhost:" << port;
ServerBuilder builder;
builder.AddPort(server_address_.str());
- builder.RegisterService(service_.service());
+ builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
channel_ = CreateChannel(server_address_.str(), ChannelArguments());
diff --git a/include/grpc++/async_server.h b/include/grpc++/async_server.h
deleted file mode 100644
index fe2c5d9..0000000
--- a/include/grpc++/async_server.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- * 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 __GRPCPP_ASYNC_SERVER_H__
-#define __GRPCPP_ASYNC_SERVER_H__
-
-#include <mutex>
-
-#include <grpc++/config.h>
-
-struct grpc_server;
-
-namespace grpc {
-class CompletionQueue;
-
-class AsyncServer {
- public:
- explicit AsyncServer(CompletionQueue* cc);
- ~AsyncServer();
-
- void AddPort(const grpc::string& addr);
-
- void Start();
-
- // The user has to call this to get one new rpc on the completion
- // queue.
- void RequestOneRpc();
-
- void Shutdown();
-
- private:
- bool started_;
- std::mutex shutdown_mu_;
- bool shutdown_;
- grpc_server* server_;
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_ASYNC_SERVER_H__
diff --git a/include/grpc++/async_server_context.h b/include/grpc++/async_server_context.h
deleted file mode 100644
index c038286..0000000
--- a/include/grpc++/async_server_context.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * 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 __GRPCPP_ASYNC_SERVER_CONTEXT_H__
-#define __GRPCPP_ASYNC_SERVER_CONTEXT_H__
-
-#include <chrono>
-
-#include <grpc++/config.h>
-
-struct grpc_byte_buffer;
-struct grpc_call;
-struct grpc_completion_queue;
-
-namespace google {
-namespace protobuf {
-class Message;
-}
-}
-
-using std::chrono::system_clock;
-
-namespace grpc {
-class Status;
-
-// TODO(rocking): wrap grpc c structures.
-class AsyncServerContext {
- public:
- AsyncServerContext(grpc_call* call, const grpc::string& method,
- const grpc::string& host,
- system_clock::time_point absolute_deadline);
- ~AsyncServerContext();
-
- // Accept this rpc, bind it to a completion queue.
- void Accept(grpc_completion_queue* cq);
-
- // Read and write calls, all async. Return true for success.
- bool StartRead(google::protobuf::Message* request);
- bool StartWrite(const google::protobuf::Message& response, int flags);
- bool StartWriteStatus(const Status& status);
-
- bool ParseRead(grpc_byte_buffer* read_buffer);
-
- grpc::string method() const { return method_; }
- grpc::string host() const { return host_; }
- system_clock::time_point absolute_deadline() { return absolute_deadline_; }
-
- grpc_call* call() { return call_; }
-
- private:
- AsyncServerContext(const AsyncServerContext&);
- AsyncServerContext& operator=(const AsyncServerContext&);
-
- // These properties may be moved to a ServerContext class.
- const grpc::string method_;
- const grpc::string host_;
- system_clock::time_point absolute_deadline_;
-
- google::protobuf::Message* request_; // not owned
- grpc_call* call_; // owned
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_ASYNC_SERVER_CONTEXT_H__
diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h
index 9ed3542..b0366fa 100644
--- a/include/grpc++/channel_interface.h
+++ b/include/grpc++/channel_interface.h
@@ -35,32 +35,30 @@
#define __GRPCPP_CHANNEL_INTERFACE_H__
#include <grpc++/status.h>
+#include <grpc++/impl/call.h>
namespace google {
namespace protobuf {
class Message;
-}
-}
+} // namespace protobuf
+} // namespace google
+
+struct grpc_call;
namespace grpc {
-
+class Call;
+class CallOpBuffer;
class ClientContext;
+class CompletionQueue;
class RpcMethod;
-class StreamContextInterface;
+class CallInterface;
-class ChannelInterface {
+class ChannelInterface : public CallHook {
public:
virtual ~ChannelInterface() {}
- virtual Status StartBlockingRpc(const RpcMethod& method,
- ClientContext* context,
- const google::protobuf::Message& request,
- google::protobuf::Message* result) = 0;
-
- virtual StreamContextInterface* CreateStream(
- const RpcMethod& method, ClientContext* context,
- const google::protobuf::Message* request,
- google::protobuf::Message* result) = 0;
+ virtual Call CreateCall(const RpcMethod &method, ClientContext *context,
+ CompletionQueue *cq) = 0;
};
} // namespace grpc
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 0cf6bdc..4594cba 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -35,8 +35,8 @@
#define __GRPCPP_CLIENT_CONTEXT_H__
#include <chrono>
+#include <map>
#include <string>
-#include <vector>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
@@ -47,8 +47,32 @@
struct grpc_call;
struct grpc_completion_queue;
+namespace google {
+namespace protobuf {
+class Message;
+} // namespace protobuf
+} // namespace google
+
namespace grpc {
+class CallOpBuffer;
+class ChannelInterface;
+class CompletionQueue;
+class RpcMethod;
+class Status;
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class R, class W>
+class ClientReaderWriter;
+template <class R>
+class ClientAsyncReader;
+template <class W>
+class ClientAsyncWriter;
+template <class R, class W>
+class ClientAsyncReaderWriter;
+
class ClientContext {
public:
ClientContext();
@@ -57,18 +81,54 @@
void AddMetadata(const grpc::string &meta_key,
const grpc::string &meta_value);
+ std::multimap<grpc::string, grpc::string> GetServerInitialMetadata() {
+ GPR_ASSERT(initial_metadata_received_);
+ return recv_initial_metadata_;
+ }
+
+ std::multimap<grpc::string, grpc::string> GetServerTrailingMetadata() {
+ // TODO(yangg) check finished
+ return trailing_metadata_;
+ }
+
void set_absolute_deadline(const system_clock::time_point &deadline);
system_clock::time_point absolute_deadline();
- void StartCancel();
+ void set_authority(const grpc::string& authority) {
+ authority_ = authority;
+ }
+
+ void TryCancel();
private:
// Disallow copy and assign.
ClientContext(const ClientContext &);
ClientContext &operator=(const ClientContext &);
+ friend class CallOpBuffer;
friend class Channel;
- friend class StreamContext;
+ template <class R>
+ friend class ::grpc::ClientReader;
+ template <class W>
+ friend class ::grpc::ClientWriter;
+ template <class R, class W>
+ friend class ::grpc::ClientReaderWriter;
+ template <class R>
+ friend class ::grpc::ClientAsyncReader;
+ template <class W>
+ friend class ::grpc::ClientAsyncWriter;
+ template <class R, class W>
+ friend class ::grpc::ClientAsyncReaderWriter;
+ friend Status BlockingUnaryCall(ChannelInterface *channel,
+ const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result);
+ friend void AsyncUnaryCall(ChannelInterface *channel, const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result, Status *status,
+ CompletionQueue *cq, void *tag);
grpc_call *call() { return call_; }
void set_call(grpc_call *call) {
@@ -81,10 +141,18 @@
gpr_timespec RawDeadline() { return absolute_deadline_; }
+ grpc::string authority() {
+ return authority_;
+ }
+
+ bool initial_metadata_received_ = false;
grpc_call *call_;
grpc_completion_queue *cq_;
gpr_timespec absolute_deadline_;
- std::vector<std::pair<grpc::string, grpc::string> > metadata_;
+ grpc::string authority_;
+ std::multimap<grpc::string, grpc::string> send_initial_metadata_;
+ std::multimap<grpc::string, grpc::string> recv_initial_metadata_;
+ std::multimap<grpc::string, grpc::string> trailing_metadata_;
};
} // namespace grpc
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index 72f6253..c5267f8 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -34,52 +34,82 @@
#ifndef __GRPCPP_COMPLETION_QUEUE_H__
#define __GRPCPP_COMPLETION_QUEUE_H__
+#include <grpc++/impl/client_unary_call.h>
+
struct grpc_completion_queue;
namespace grpc {
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class R, class W>
+class ClientReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+template <class R, class W>
+class ServerReaderWriter;
+
+class CompletionQueue;
+class Server;
+
+class CompletionQueueTag {
+ public:
+ virtual ~CompletionQueueTag() {}
+ // Called prior to returning from Next(), return value
+ // is the status of the operation (return status is the default thing
+ // to do)
+ virtual void FinalizeResult(void **tag, bool *status) = 0;
+};
+
// grpc_completion_queue wrapper class
class CompletionQueue {
public:
CompletionQueue();
+ explicit CompletionQueue(grpc_completion_queue *take);
~CompletionQueue();
- enum CompletionType {
- QUEUE_CLOSED = 0, // Shutting down.
- RPC_END = 1, // An RPC finished. Either at client or server.
- CLIENT_READ_OK = 2, // A client-side read has finished successfully.
- CLIENT_READ_ERROR = 3, // A client-side read has finished with error.
- CLIENT_WRITE_OK = 4,
- CLIENT_WRITE_ERROR = 5,
- SERVER_RPC_NEW = 6, // A new RPC just arrived at the server.
- SERVER_READ_OK = 7, // A server-side read has finished successfully.
- SERVER_READ_ERROR = 8, // A server-side read has finished with error.
- SERVER_WRITE_OK = 9,
- SERVER_WRITE_ERROR = 10,
- // Client or server has sent half close successfully.
- HALFCLOSE_OK = 11,
- // New CompletionTypes may be added in the future, so user code should
- // always
- // handle the default case of a CompletionType that appears after such code
- // was
- // written.
- DO_NOT_USE = 20,
- };
-
// Blocking read from queue.
- // For QUEUE_CLOSED, *tag is not changed.
- // For SERVER_RPC_NEW, *tag will be a newly allocated AsyncServerContext.
- // For others, *tag will be the AsyncServerContext of this rpc.
- CompletionType Next(void** tag);
+ // Returns true if an event was received, false if the queue is ready
+ // for destruction.
+ bool Next(void **tag, bool *ok);
// Shutdown has to be called, and the CompletionQueue can only be
- // destructed when the QUEUE_CLOSED message has been read with Next().
+ // destructed when false is returned from Next().
void Shutdown();
- grpc_completion_queue* cq() { return cq_; }
+ grpc_completion_queue *cq() { return cq_; }
private:
- grpc_completion_queue* cq_; // owned
+ // Friend synchronous wrappers so that they can access Pluck(), which is
+ // a semi-private API geared towards the synchronous implementation.
+ template <class R>
+ friend class ::grpc::ClientReader;
+ template <class W>
+ friend class ::grpc::ClientWriter;
+ template <class R, class W>
+ friend class ::grpc::ClientReaderWriter;
+ template <class R>
+ friend class ::grpc::ServerReader;
+ template <class W>
+ friend class ::grpc::ServerWriter;
+ template <class R, class W>
+ friend class ::grpc::ServerReaderWriter;
+ friend class ::grpc::Server;
+ friend Status BlockingUnaryCall(ChannelInterface *channel,
+ const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result);
+
+ // Wraps grpc_completion_queue_pluck.
+ // Cannot be mixed with calls to Next().
+ bool Pluck(CompletionQueueTag *tag);
+
+ grpc_completion_queue *cq_; // owned
};
} // namespace grpc
diff --git a/include/grpc++/config.h b/include/grpc++/config.h
index 52913fb..663e402 100644
--- a/include/grpc++/config.h
+++ b/include/grpc++/config.h
@@ -39,6 +39,7 @@
namespace grpc {
typedef std::string string;
-}
+
+} // namespace grpc
#endif // __GRPCPP_CONFIG_H__
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
new file mode 100644
index 0000000..64f0f89
--- /dev/null
+++ b/include/grpc++/impl/call.h
@@ -0,0 +1,147 @@
+/*
+ *
+ * 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 __GRPCPP_CALL_H__
+#define __GRPCPP_CALL_H__
+
+#include <grpc/grpc.h>
+#include <grpc++/status.h>
+#include <grpc++/completion_queue.h>
+
+#include <memory>
+#include <map>
+
+namespace google {
+namespace protobuf {
+class Message;
+} // namespace protobuf
+} // namespace google
+
+struct grpc_call;
+struct grpc_op;
+
+namespace grpc {
+
+class Call;
+
+class CallOpBuffer : public CompletionQueueTag {
+ public:
+ CallOpBuffer() : return_tag_(this) {}
+ ~CallOpBuffer();
+
+ void Reset(void *next_return_tag);
+
+ // Does not take ownership.
+ void AddSendInitialMetadata(
+ std::multimap<grpc::string, grpc::string> *metadata);
+ void AddSendInitialMetadata(ClientContext *ctx);
+ void AddRecvInitialMetadata(
+ std::multimap<grpc::string, grpc::string> *metadata);
+ void AddSendMessage(const google::protobuf::Message &message);
+ void AddRecvMessage(google::protobuf::Message *message);
+ void AddClientSendClose();
+ void AddClientRecvStatus(std::multimap<grpc::string, grpc::string> *metadata,
+ Status *status);
+ void AddServerSendStatus(std::multimap<grpc::string, grpc::string> *metadata,
+ const Status &status);
+ void AddServerRecvClose(bool *cancelled);
+
+ // INTERNAL API:
+
+ // Convert to an array of grpc_op elements
+ void FillOps(grpc_op *ops, size_t *nops);
+
+ // Called by completion queue just prior to returning from Next() or Pluck()
+ void FinalizeResult(void **tag, bool *status) override;
+
+ bool got_message = false;
+
+ private:
+ void *return_tag_ = nullptr;
+ // Send initial metadata
+ bool send_initial_metadata_ = false;
+ size_t initial_metadata_count_ = 0;
+ grpc_metadata *initial_metadata_ = nullptr;
+ // Recv initial metadta
+ std::multimap<grpc::string, grpc::string> *recv_initial_metadata_ = nullptr;
+ grpc_metadata_array recv_initial_metadata_arr_ = {0, 0, nullptr};
+ // Send message
+ const google::protobuf::Message *send_message_ = nullptr;
+ grpc_byte_buffer *send_message_buf_ = nullptr;
+ // Recv message
+ google::protobuf::Message *recv_message_ = nullptr;
+ grpc_byte_buffer *recv_message_buf_ = nullptr;
+ // Client send close
+ bool client_send_close_ = false;
+ // Client recv status
+ std::multimap<grpc::string, grpc::string> *recv_trailing_metadata_ = nullptr;
+ Status *recv_status_ = nullptr;
+ grpc_metadata_array recv_trailing_metadata_arr_ = {0, 0, nullptr};
+ grpc_status_code status_code_ = GRPC_STATUS_OK;
+ char *status_details_ = nullptr;
+ size_t status_details_capacity_ = 0;
+ // Server send status
+ const Status *send_status_ = nullptr;
+ size_t trailing_metadata_count_ = 0;
+ grpc_metadata *trailing_metadata_ = nullptr;
+ int cancelled_buf_;
+ bool *recv_closed_ = nullptr;
+};
+
+// Channel and Server implement this to allow them to hook performing ops
+class CallHook {
+ public:
+ virtual ~CallHook() {}
+ virtual void PerformOpsOnCall(CallOpBuffer *ops, Call *call) = 0;
+};
+
+// Straightforward wrapping of the C call object
+class Call final {
+ public:
+ /* call is owned by the caller */
+ Call(grpc_call *call, CallHook *call_hook_, CompletionQueue *cq);
+
+ void PerformOps(CallOpBuffer *buffer);
+
+ grpc_call *call() { return call_; }
+ CompletionQueue *cq() { return cq_; }
+
+ private:
+ CallHook *call_hook_;
+ CompletionQueue *cq_;
+ grpc_call *call_;
+};
+
+} // namespace grpc
+
+#endif // __GRPCPP_CALL_INTERFACE_H__
diff --git a/include/grpc++/impl/client_unary_call.h b/include/grpc++/impl/client_unary_call.h
new file mode 100644
index 0000000..22a8a04
--- /dev/null
+++ b/include/grpc++/impl/client_unary_call.h
@@ -0,0 +1,66 @@
+/*
+*
+* 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 __GRPCPP_CLIENT_UNARY_CALL_H__
+#define __GRPCPP_CLIENT_UNARY_CALL_H__
+
+namespace google {
+namespace protobuf {
+class Message;
+} // namespace protobuf
+} // namespace google
+
+namespace grpc {
+
+class ChannelInterface;
+class ClientContext;
+class CompletionQueue;
+class RpcMethod;
+class Status;
+
+// Wrapper that begins an asynchronous unary call
+void AsyncUnaryCall(ChannelInterface *channel, const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result, Status *status,
+ CompletionQueue *cq, void *tag);
+
+// Wrapper that performs a blocking unary call
+Status BlockingUnaryCall(ChannelInterface *channel, const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result);
+
+} // namespace grpc
+
+#endif
diff --git a/include/grpc++/impl/rpc_method.h b/include/grpc++/impl/rpc_method.h
index 75fec35..bb16e64 100644
--- a/include/grpc++/impl/rpc_method.h
+++ b/include/grpc++/impl/rpc_method.h
@@ -37,8 +37,8 @@
namespace google {
namespace protobuf {
class Message;
-}
-}
+} // namespace protobuf
+} // namespace google
namespace grpc {
diff --git a/include/grpc++/impl/rpc_service_method.h b/include/grpc++/impl/rpc_service_method.h
index 620de5e..bf62871 100644
--- a/include/grpc++/impl/rpc_service_method.h
+++ b/include/grpc++/impl/rpc_service_method.h
@@ -55,25 +55,14 @@
public:
virtual ~MethodHandler() {}
struct HandlerParameter {
- HandlerParameter(ServerContext* context,
+ HandlerParameter(Call* c, ServerContext* context,
const google::protobuf::Message* req,
google::protobuf::Message* resp)
- : server_context(context),
- request(req),
- response(resp),
- stream_context(nullptr) {}
- HandlerParameter(ServerContext* context,
- const google::protobuf::Message* req,
- google::protobuf::Message* resp,
- StreamContextInterface* stream)
- : server_context(context),
- request(req),
- response(resp),
- stream_context(stream) {}
+ : call(c), server_context(context), request(req), response(resp) {}
+ Call* call;
ServerContext* server_context;
const google::protobuf::Message* request;
google::protobuf::Message* response;
- StreamContextInterface* stream_context;
};
virtual Status RunHandler(const HandlerParameter& param) = 0;
};
@@ -114,7 +103,7 @@
: func_(func), service_(service) {}
Status RunHandler(const HandlerParameter& param) final {
- ServerReader<RequestType> reader(param.stream_context);
+ ServerReader<RequestType> reader(param.call, param.server_context);
return func_(service_, param.server_context, &reader,
dynamic_cast<ResponseType*>(param.response));
}
@@ -136,7 +125,7 @@
: func_(func), service_(service) {}
Status RunHandler(const HandlerParameter& param) final {
- ServerWriter<ResponseType> writer(param.stream_context);
+ ServerWriter<ResponseType> writer(param.call, param.server_context);
return func_(service_, param.server_context,
dynamic_cast<const RequestType*>(param.request), &writer);
}
@@ -159,7 +148,8 @@
: func_(func), service_(service) {}
Status RunHandler(const HandlerParameter& param) final {
- ServerReaderWriter<ResponseType, RequestType> stream(param.stream_context);
+ ServerReaderWriter<ResponseType, RequestType> stream(param.call,
+ param.server_context);
return func_(service_, param.server_context, &stream);
}
@@ -202,9 +192,7 @@
class RpcService {
public:
// Takes ownership.
- void AddMethod(RpcServiceMethod* method) {
- methods_.push_back(std::unique_ptr<RpcServiceMethod>(method));
- }
+ void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); }
RpcServiceMethod* GetMethod(int i) { return methods_[i].get(); }
int GetMethodCount() const { return methods_.size(); }
diff --git a/include/grpc++/impl/service_type.h b/include/grpc++/impl/service_type.h
new file mode 100644
index 0000000..221664b
--- /dev/null
+++ b/include/grpc++/impl/service_type.h
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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 __GRPCPP_IMPL_SERVICE_TYPE_H__
+#define __GRPCPP_IMPL_SERVICE_TYPE_H__
+
+namespace google {
+namespace protobuf {
+class Message;
+} // namespace protobuf
+} // namespace google
+
+namespace grpc {
+
+class Call;
+class RpcService;
+class Server;
+class ServerContext;
+class Status;
+
+class SynchronousService {
+ public:
+ virtual ~SynchronousService() {}
+ virtual RpcService* service() = 0;
+};
+
+class ServerAsyncStreamingInterface {
+ public:
+ virtual ~ServerAsyncStreamingInterface() {}
+
+ virtual void SendInitialMetadata(void* tag) = 0;
+
+ private:
+ friend class Server;
+ virtual void BindCall(Call* call) = 0;
+};
+
+class AsynchronousService {
+ public:
+ // this is Server, but in disguise to avoid a link dependency
+ class DispatchImpl {
+ public:
+ virtual void RequestAsyncCall(void* registered_method,
+ ServerContext* context,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) = 0;
+ };
+
+ AsynchronousService(CompletionQueue* cq, const char** method_names,
+ size_t method_count)
+ : cq_(cq), method_names_(method_names), method_count_(method_count) {}
+
+ ~AsynchronousService() { delete[] request_args_; }
+
+ CompletionQueue* completion_queue() const { return cq_; }
+
+ protected:
+ void RequestAsyncUnary(int index, ServerContext* context,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ dispatch_impl_->RequestAsyncCall(request_args_[index], context, request,
+ stream, cq, tag);
+ }
+ void RequestClientStreaming(int index, ServerContext* context,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr,
+ stream, cq, tag);
+ }
+ void RequestServerStreaming(int index, ServerContext* context,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ dispatch_impl_->RequestAsyncCall(request_args_[index], context, request,
+ stream, cq, tag);
+ }
+ void RequestBidiStreaming(int index, ServerContext* context,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr,
+ stream, cq, tag);
+ }
+
+ private:
+ friend class Server;
+ CompletionQueue* const cq_;
+ DispatchImpl* dispatch_impl_ = nullptr;
+ const char** const method_names_;
+ size_t method_count_;
+ void** request_args_ = nullptr;
+};
+
+} // namespace grpc
+
+#endif // __GRPCPP_IMPL_SERVICE_TYPE_H__
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 5fa371b..410c762 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -35,12 +35,14 @@
#define __GRPCPP_SERVER_H__
#include <condition_variable>
-#include <map>
+#include <list>
#include <memory>
#include <mutex>
#include <grpc++/completion_queue.h>
#include <grpc++/config.h>
+#include <grpc++/impl/call.h>
+#include <grpc++/impl/service_type.h>
#include <grpc++/status.h>
struct grpc_server;
@@ -48,18 +50,19 @@
namespace google {
namespace protobuf {
class Message;
-}
-}
+} // namespace protobuf
+} // namespace google
namespace grpc {
-class AsyncServerContext;
+class AsynchronousService;
class RpcService;
class RpcServiceMethod;
class ServerCredentials;
class ThreadPoolInterface;
// Currently it only supports handling rpcs in a single thread.
-class Server {
+class Server final : private CallHook,
+ private AsynchronousService::DispatchImpl {
public:
~Server();
@@ -69,22 +72,34 @@
private:
friend class ServerBuilder;
+ class SyncRequest;
+ class AsyncRequest;
+
// ServerBuilder use only
- Server(ThreadPoolInterface* thread_pool, ServerCredentials* creds);
+ Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
+ ServerCredentials* creds);
Server();
// Register a service. This call does not take ownership of the service.
// The service must exist for the lifetime of the Server instance.
- void RegisterService(RpcService* service);
+ bool RegisterService(RpcService* service);
+ bool RegisterAsyncService(AsynchronousService* service);
// Add a listening port. Can be called multiple times.
- void AddPort(const grpc::string& addr);
+ int AddPort(const grpc::string& addr);
// Start the server.
- void Start();
+ bool Start();
- void AllowOneRpc();
void HandleQueueClosed();
void RunRpc();
void ScheduleCallback();
+ void PerformOpsOnCall(CallOpBuffer* ops, Call* call) override;
+
+ // DispatchImpl
+ void RequestAsyncCall(void* registered_method, ServerContext* context,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag);
+
// Completion queue.
CompletionQueue cq_;
@@ -96,12 +111,11 @@
int num_running_cb_;
std::condition_variable callback_cv_;
+ std::list<SyncRequest> sync_methods_;
+
// Pointer to the c grpc server.
grpc_server* server_;
- // A map for all method information.
- std::map<grpc::string, RpcServiceMethod*> method_map_;
-
ThreadPoolInterface* thread_pool_;
// Whether the thread pool is created and owned by the server.
bool thread_pool_owned_;
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index cf27452..a550a53 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -41,9 +41,12 @@
namespace grpc {
+class AsynchronousService;
+class CompletionQueue;
class RpcService;
class Server;
class ServerCredentials;
+class SynchronousService;
class ThreadPoolInterface;
class ServerBuilder {
@@ -53,7 +56,13 @@
// Register a service. This call does not take ownership of the service.
// The service must exist for the lifetime of the Server instance returned by
// BuildAndStart().
- void RegisterService(RpcService* service);
+ void RegisterService(SynchronousService* service);
+
+ // Register an asynchronous service. New calls will be delevered to cq.
+ // This call does not take ownership of the service or completion queue.
+ // The service and completion queuemust exist for the lifetime of the Server
+ // instance returned by BuildAndStart().
+ void RegisterAsyncService(AsynchronousService* service);
// Add a listening port. Can be called multiple times.
void AddPort(const grpc::string& addr);
@@ -71,9 +80,10 @@
private:
std::vector<RpcService*> services_;
+ std::vector<AsynchronousService*> async_services_;
std::vector<grpc::string> ports_;
std::shared_ptr<ServerCredentials> creds_;
- ThreadPoolInterface* thread_pool_;
+ ThreadPoolInterface* thread_pool_ = nullptr;
};
} // namespace grpc
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index 47fd6cf..853f91f 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -35,15 +35,77 @@
#define __GRPCPP_SERVER_CONTEXT_H_
#include <chrono>
+#include <map>
+
+#include "config.h"
+
+struct gpr_timespec;
+struct grpc_metadata;
+struct grpc_call;
namespace grpc {
-// Interface of server side rpc context.
-class ServerContext {
- public:
- virtual ~ServerContext() {}
+template <class W, class R>
+class ServerAsyncReader;
+template <class W>
+class ServerAsyncWriter;
+template <class W>
+class ServerAsyncResponseWriter;
+template <class R, class W>
+class ServerAsyncReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+template <class R, class W>
+class ServerReaderWriter;
- virtual std::chrono::system_clock::time_point absolute_deadline() const = 0;
+class CallOpBuffer;
+class Server;
+
+// Interface of server side rpc context.
+class ServerContext final {
+ public:
+ ServerContext(); // for async calls
+ ~ServerContext();
+
+ std::chrono::system_clock::time_point absolute_deadline() {
+ return deadline_;
+ }
+
+ void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
+ void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
+
+ std::multimap<grpc::string, grpc::string> client_metadata() {
+ return client_metadata_;
+ }
+
+ private:
+ friend class ::grpc::Server;
+ template <class W, class R>
+ friend class ::grpc::ServerAsyncReader;
+ template <class W>
+ friend class ::grpc::ServerAsyncWriter;
+ template <class W>
+ friend class ::grpc::ServerAsyncResponseWriter;
+ template <class R, class W>
+ friend class ::grpc::ServerAsyncReaderWriter;
+ template <class R>
+ friend class ::grpc::ServerReader;
+ template <class W>
+ friend class ::grpc::ServerWriter;
+ template <class R, class W>
+ friend class ::grpc::ServerReaderWriter;
+
+ ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
+ size_t metadata_count);
+
+ std::chrono::system_clock::time_point deadline_;
+ grpc_call* call_ = nullptr;
+ bool sent_initial_metadata_ = false;
+ std::multimap<grpc::string, grpc::string> client_metadata_;
+ std::multimap<grpc::string, grpc::string> initial_metadata_;
+ std::multimap<grpc::string, grpc::string> trailing_metadata_;
};
} // namespace grpc
diff --git a/include/grpc++/stream.h b/include/grpc++/stream.h
index b8982f4..be5b295 100644
--- a/include/grpc++/stream.h
+++ b/include/grpc++/stream.h
@@ -34,7 +34,12 @@
#ifndef __GRPCPP_STREAM_H__
#define __GRPCPP_STREAM_H__
-#include <grpc++/stream_context_interface.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/completion_queue.h>
+#include <grpc++/server_context.h>
+#include <grpc++/impl/call.h>
+#include <grpc++/impl/service_type.h>
#include <grpc++/status.h>
#include <grpc/support/log.h>
@@ -45,16 +50,12 @@
public:
virtual ~ClientStreamingInterface() {}
- // Try to cancel the stream. Wait() still needs to be called to get the final
- // status. Cancelling after the stream has finished has no effects.
- virtual void Cancel() = 0;
-
// Wait until the stream finishes, and return the final status. When the
// client side declares it has no more message to send, either implicitly or
// by calling WritesDone, it needs to make sure there is no more message to
// be received from the server, either implicitly or by getting a false from
// a Read(). Otherwise, this implicitly cancels the stream.
- virtual const Status& Wait() = 0;
+ virtual Status Finish() = 0;
};
// An interface that yields a sequence of R messages.
@@ -82,147 +83,703 @@
};
template <class R>
-class ClientReader : public ClientStreamingInterface,
- public ReaderInterface<R> {
+class ClientReader final : public ClientStreamingInterface,
+ public ReaderInterface<R> {
public:
// Blocking create a stream and write the first request out.
- explicit ClientReader(StreamContextInterface* context) : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(true);
- context_->Write(context_->request(), true);
+ ClientReader(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, const google::protobuf::Message& request)
+ : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&context->send_initial_metadata_);
+ buf.AddSendMessage(request);
+ buf.AddClientSendClose();
+ call_.PerformOps(&buf);
+ cq_.Pluck(&buf);
}
- ~ClientReader() { delete context_; }
+ // Blocking wait for initial metadata from server. The received metadata
+ // can only be accessed after this call returns. Should only be called before
+ // the first read. Calling this method is optional, and if it is not called
+ // the metadata will be available in ClientContext after the first read.
+ void WaitForInitialMetadata() {
+ GPR_ASSERT(!context_->initial_metadata_received_);
- virtual bool Read(R* msg) { return context_->Read(msg); }
+ CallOpBuffer buf;
+ buf.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
+ context_->initial_metadata_received_ = true;
+ }
- virtual void Cancel() { context_->Cancel(); }
+ virtual bool Read(R* msg) override {
+ CallOpBuffer buf;
+ if (!context_->initial_metadata_received_) {
+ buf.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ buf.AddRecvMessage(msg);
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf) && buf.got_message;
+ }
- virtual const Status& Wait() { return context_->Wait(); }
+ virtual Status Finish() override {
+ CallOpBuffer buf;
+ Status status;
+ buf.AddClientRecvStatus(&context_->trailing_metadata_, &status);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
+ return status;
+ }
private:
- StreamContextInterface* const context_;
+ ClientContext* context_;
+ CompletionQueue cq_;
+ Call call_;
};
template <class W>
-class ClientWriter : public ClientStreamingInterface,
- public WriterInterface<W> {
+class ClientWriter final : public ClientStreamingInterface,
+ public WriterInterface<W> {
public:
// Blocking create a stream.
- explicit ClientWriter(StreamContextInterface* context) : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(false);
+ ClientWriter(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, google::protobuf::Message* response)
+ : context_(context),
+ response_(response),
+ call_(channel->CreateCall(method, context, &cq_)) {
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&context->send_initial_metadata_);
+ call_.PerformOps(&buf);
+ cq_.Pluck(&buf);
}
- ~ClientWriter() { delete context_; }
-
- virtual bool Write(const W& msg) {
- return context_->Write(const_cast<W*>(&msg), false);
+ virtual bool Write(const W& msg) override {
+ CallOpBuffer buf;
+ buf.AddSendMessage(msg);
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf);
}
- virtual void WritesDone() { context_->Write(nullptr, true); }
-
- virtual void Cancel() { context_->Cancel(); }
+ virtual bool WritesDone() {
+ CallOpBuffer buf;
+ buf.AddClientSendClose();
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf);
+ }
// Read the final response and wait for the final status.
- virtual const Status& Wait() {
- bool success = context_->Read(context_->response());
- if (!success) {
- Cancel();
- } else {
- success = context_->Read(nullptr);
- if (success) {
- Cancel();
- }
- }
- return context_->Wait();
+ virtual Status Finish() override {
+ CallOpBuffer buf;
+ Status status;
+ buf.AddRecvMessage(response_);
+ buf.AddClientRecvStatus(&context_->trailing_metadata_, &status);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf) && buf.got_message);
+ return status;
}
private:
- StreamContextInterface* const context_;
+ ClientContext* context_;
+ google::protobuf::Message* const response_;
+ CompletionQueue cq_;
+ Call call_;
};
// Client-side interface for bi-directional streaming.
template <class W, class R>
-class ClientReaderWriter : public ClientStreamingInterface,
- public WriterInterface<W>,
- public ReaderInterface<R> {
+class ClientReaderWriter final : public ClientStreamingInterface,
+ public WriterInterface<W>,
+ public ReaderInterface<R> {
public:
// Blocking create a stream.
- explicit ClientReaderWriter(StreamContextInterface* context)
- : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(false);
+ ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context)
+ : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&context->send_initial_metadata_);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
}
- ~ClientReaderWriter() { delete context_; }
+ // Blocking wait for initial metadata from server. The received metadata
+ // can only be accessed after this call returns. Should only be called before
+ // the first read. Calling this method is optional, and if it is not called
+ // the metadata will be available in ClientContext after the first read.
+ void WaitForInitialMetadata() {
+ GPR_ASSERT(!context_->initial_metadata_received_);
- virtual bool Read(R* msg) { return context_->Read(msg); }
-
- virtual bool Write(const W& msg) {
- return context_->Write(const_cast<W*>(&msg), false);
+ CallOpBuffer buf;
+ buf.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
+ context_->initial_metadata_received_ = true;
}
- virtual void WritesDone() { context_->Write(nullptr, true); }
+ virtual bool Read(R* msg) override {
+ CallOpBuffer buf;
+ if (!context_->initial_metadata_received_) {
+ buf.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ buf.AddRecvMessage(msg);
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf) && buf.got_message;
+ }
- virtual void Cancel() { context_->Cancel(); }
+ virtual bool Write(const W& msg) override {
+ CallOpBuffer buf;
+ buf.AddSendMessage(msg);
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf);
+ }
- virtual const Status& Wait() { return context_->Wait(); }
+ virtual bool WritesDone() {
+ CallOpBuffer buf;
+ buf.AddClientSendClose();
+ call_.PerformOps(&buf);
+ return cq_.Pluck(&buf);
+ }
+
+ virtual Status Finish() override {
+ CallOpBuffer buf;
+ Status status;
+ buf.AddClientRecvStatus(&context_->trailing_metadata_, &status);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
+ return status;
+ }
private:
- StreamContextInterface* const context_;
+ ClientContext* context_;
+ CompletionQueue cq_;
+ Call call_;
};
template <class R>
-class ServerReader : public ReaderInterface<R> {
+class ServerReader final : public ReaderInterface<R> {
public:
- explicit ServerReader(StreamContextInterface* context) : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(true);
+ ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+ void SendInitialMetadata() {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_->PerformOps(&buf);
+ call_->cq()->Pluck(&buf);
}
- virtual bool Read(R* msg) { return context_->Read(msg); }
+ virtual bool Read(R* msg) override {
+ CallOpBuffer buf;
+ buf.AddRecvMessage(msg);
+ call_->PerformOps(&buf);
+ return call_->cq()->Pluck(&buf) && buf.got_message;
+ }
private:
- StreamContextInterface* const context_; // not owned
+ Call* const call_;
+ ServerContext* const ctx_;
};
template <class W>
-class ServerWriter : public WriterInterface<W> {
+class ServerWriter final : public WriterInterface<W> {
public:
- explicit ServerWriter(StreamContextInterface* context) : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(true);
- context_->Read(context_->request());
+ ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+ void SendInitialMetadata() {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_->PerformOps(&buf);
+ call_->cq()->Pluck(&buf);
}
- virtual bool Write(const W& msg) {
- return context_->Write(const_cast<W*>(&msg), false);
+ virtual bool Write(const W& msg) override {
+ CallOpBuffer buf;
+ if (!ctx_->sent_initial_metadata_) {
+ buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ buf.AddSendMessage(msg);
+ call_->PerformOps(&buf);
+ return call_->cq()->Pluck(&buf);
}
private:
- StreamContextInterface* const context_; // not owned
+ Call* const call_;
+ ServerContext* const ctx_;
};
// Server-side interface for bi-directional streaming.
template <class W, class R>
-class ServerReaderWriter : public WriterInterface<W>,
- public ReaderInterface<R> {
+class ServerReaderWriter final : public WriterInterface<W>,
+ public ReaderInterface<R> {
public:
- explicit ServerReaderWriter(StreamContextInterface* context)
- : context_(context) {
- GPR_ASSERT(context_);
- context_->Start(true);
+ ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+ void SendInitialMetadata() {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ CallOpBuffer buf;
+ buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_->PerformOps(&buf);
+ call_->cq()->Pluck(&buf);
}
- virtual bool Read(R* msg) { return context_->Read(msg); }
+ virtual bool Read(R* msg) override {
+ CallOpBuffer buf;
+ buf.AddRecvMessage(msg);
+ call_->PerformOps(&buf);
+ return call_->cq()->Pluck(&buf) && buf.got_message;
+ }
- virtual bool Write(const W& msg) {
- return context_->Write(const_cast<W*>(&msg), false);
+ virtual bool Write(const W& msg) override {
+ CallOpBuffer buf;
+ if (!ctx_->sent_initial_metadata_) {
+ buf.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ buf.AddSendMessage(msg);
+ call_->PerformOps(&buf);
+ return call_->cq()->Pluck(&buf);
}
private:
- StreamContextInterface* const context_; // not owned
+ Call* const call_;
+ ServerContext* const ctx_;
+};
+
+// Async interfaces
+// Common interface for all client side streaming.
+class ClientAsyncStreamingInterface {
+ public:
+ virtual ~ClientAsyncStreamingInterface() {}
+
+ virtual void ReadInitialMetadata(void* tag) = 0;
+
+ virtual void Finish(Status* status, void* tag) = 0;
+};
+
+// An interface that yields a sequence of R messages.
+template <class R>
+class AsyncReaderInterface {
+ public:
+ virtual ~AsyncReaderInterface() {}
+
+ virtual void Read(R* msg, void* tag) = 0;
+};
+
+// An interface that can be fed a sequence of W messages.
+template <class W>
+class AsyncWriterInterface {
+ public:
+ virtual ~AsyncWriterInterface() {}
+
+ virtual void Write(const W& msg, void* tag) = 0;
+};
+
+template <class R>
+class ClientAsyncReader final : public ClientAsyncStreamingInterface,
+ public AsyncReaderInterface<R> {
+ public:
+ // Create a stream and write the first request out.
+ ClientAsyncReader(ChannelInterface* channel, CompletionQueue* cq,
+ const RpcMethod& method, ClientContext* context,
+ const google::protobuf::Message& request, void* tag)
+ : context_(context), call_(channel->CreateCall(method, context, cq)) {
+ init_buf_.Reset(tag);
+ init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
+ init_buf_.AddSendMessage(request);
+ init_buf_.AddClientSendClose();
+ call_.PerformOps(&init_buf_);
+ }
+
+ void ReadInitialMetadata(void* tag) override {
+ GPR_ASSERT(!context_->initial_metadata_received_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ call_.PerformOps(&meta_buf_);
+ context_->initial_metadata_received_ = true;
+ }
+
+ void Read(R* msg, void* tag) override {
+ read_buf_.Reset(tag);
+ if (!context_->initial_metadata_received_) {
+ read_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ read_buf_.AddRecvMessage(msg);
+ call_.PerformOps(&read_buf_);
+ }
+
+ void Finish(Status* status, void* tag) override {
+ finish_buf_.Reset(tag);
+ if (!context_->initial_metadata_received_) {
+ finish_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ finish_buf_.AddClientRecvStatus(&context_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ ClientContext* context_ = nullptr;
+ Call call_;
+ CallOpBuffer init_buf_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer read_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+template <class W>
+class ClientAsyncWriter final : public ClientAsyncStreamingInterface,
+ public AsyncWriterInterface<W> {
+ public:
+ ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq,
+ const RpcMethod& method, ClientContext* context,
+ google::protobuf::Message* response, void* tag)
+ : context_(context),
+ response_(response),
+ call_(channel->CreateCall(method, context, cq)) {
+ init_buf_.Reset(tag);
+ init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
+ call_.PerformOps(&init_buf_);
+ }
+
+ void ReadInitialMetadata(void* tag) override {
+ GPR_ASSERT(!context_->initial_metadata_received_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ call_.PerformOps(&meta_buf_);
+ context_->initial_metadata_received_ = true;
+ }
+
+ void Write(const W& msg, void* tag) override {
+ write_buf_.Reset(tag);
+ write_buf_.AddSendMessage(msg);
+ call_.PerformOps(&write_buf_);
+ }
+
+ void WritesDone(void* tag) {
+ writes_done_buf_.Reset(tag);
+ writes_done_buf_.AddClientSendClose();
+ call_.PerformOps(&writes_done_buf_);
+ }
+
+ void Finish(Status* status, void* tag) override {
+ finish_buf_.Reset(tag);
+ if (!context_->initial_metadata_received_) {
+ finish_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ finish_buf_.AddRecvMessage(response_);
+ finish_buf_.AddClientRecvStatus(&context_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ ClientContext* context_ = nullptr;
+ google::protobuf::Message* const response_;
+ Call call_;
+ CallOpBuffer init_buf_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer write_buf_;
+ CallOpBuffer writes_done_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+// Client-side interface for bi-directional streaming.
+template <class W, class R>
+class ClientAsyncReaderWriter final : public ClientAsyncStreamingInterface,
+ public AsyncWriterInterface<W>,
+ public AsyncReaderInterface<R> {
+ public:
+ ClientAsyncReaderWriter(ChannelInterface* channel, CompletionQueue* cq,
+ const RpcMethod& method, ClientContext* context,
+ void* tag)
+ : context_(context), call_(channel->CreateCall(method, context, cq)) {
+ init_buf_.Reset(tag);
+ init_buf_.AddSendInitialMetadata(&context->send_initial_metadata_);
+ call_.PerformOps(&init_buf_);
+ }
+
+ void ReadInitialMetadata(void* tag) override {
+ GPR_ASSERT(!context_->initial_metadata_received_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ call_.PerformOps(&meta_buf_);
+ context_->initial_metadata_received_ = true;
+ }
+
+ void Read(R* msg, void* tag) override {
+ read_buf_.Reset(tag);
+ if (!context_->initial_metadata_received_) {
+ read_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ read_buf_.AddRecvMessage(msg);
+ call_.PerformOps(&read_buf_);
+ }
+
+ void Write(const W& msg, void* tag) override {
+ write_buf_.Reset(tag);
+ write_buf_.AddSendMessage(msg);
+ call_.PerformOps(&write_buf_);
+ }
+
+ void WritesDone(void* tag) {
+ writes_done_buf_.Reset(tag);
+ writes_done_buf_.AddClientSendClose();
+ call_.PerformOps(&writes_done_buf_);
+ }
+
+ void Finish(Status* status, void* tag) override {
+ finish_buf_.Reset(tag);
+ if (!context_->initial_metadata_received_) {
+ finish_buf_.AddRecvInitialMetadata(&context_->recv_initial_metadata_);
+ context_->initial_metadata_received_ = true;
+ }
+ finish_buf_.AddClientRecvStatus(&context_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ ClientContext* context_ = nullptr;
+ Call call_;
+ CallOpBuffer init_buf_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer read_buf_;
+ CallOpBuffer write_buf_;
+ CallOpBuffer writes_done_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+// TODO(yangg) Move out of stream.h
+template <class W>
+class ServerAsyncResponseWriter final : public ServerAsyncStreamingInterface {
+ public:
+ explicit ServerAsyncResponseWriter(ServerContext* ctx)
+ : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+ void SendInitialMetadata(void* tag) {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_.PerformOps(&meta_buf_);
+ }
+
+ void Finish(const W& msg, const Status& status, void* tag) {
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // The response is dropped if the status is not OK.
+ if (status.IsOk()) {
+ finish_buf_.AddSendMessage(msg);
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ void FinishWithError(const Status& status, void* tag) {
+ GPR_ASSERT(!status.IsOk());
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ void BindCall(Call* call) override { call_ = *call; }
+
+ Call call_;
+ ServerContext* ctx_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+template <class W, class R>
+class ServerAsyncReader : public ServerAsyncStreamingInterface,
+ public AsyncReaderInterface<R> {
+ public:
+ explicit ServerAsyncReader(ServerContext* ctx)
+ : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+ void SendInitialMetadata(void* tag) override {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_.PerformOps(&meta_buf_);
+ }
+
+ void Read(R* msg, void* tag) override {
+ read_buf_.Reset(tag);
+ read_buf_.AddRecvMessage(msg);
+ call_.PerformOps(&read_buf_);
+ }
+
+ void Finish(const W& msg, const Status& status, void* tag) {
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ // The response is dropped if the status is not OK.
+ if (status.IsOk()) {
+ finish_buf_.AddSendMessage(msg);
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ void FinishWithError(const Status& status, void* tag) {
+ GPR_ASSERT(!status.IsOk());
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ void BindCall(Call* call) override { call_ = *call; }
+
+ Call call_;
+ ServerContext* ctx_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer read_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+template <class W>
+class ServerAsyncWriter : public ServerAsyncStreamingInterface,
+ public AsyncWriterInterface<W> {
+ public:
+ explicit ServerAsyncWriter(ServerContext* ctx)
+ : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+ void SendInitialMetadata(void* tag) override {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_.PerformOps(&meta_buf_);
+ }
+
+ void Write(const W& msg, void* tag) override {
+ write_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ write_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ write_buf_.AddSendMessage(msg);
+ call_.PerformOps(&write_buf_);
+ }
+
+ void Finish(const Status& status, void* tag) {
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ void BindCall(Call* call) override { call_ = *call; }
+
+ Call call_;
+ ServerContext* ctx_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer write_buf_;
+ CallOpBuffer finish_buf_;
+};
+
+// Server-side interface for bi-directional streaming.
+template <class W, class R>
+class ServerAsyncReaderWriter : public ServerAsyncStreamingInterface,
+ public AsyncWriterInterface<W>,
+ public AsyncReaderInterface<R> {
+ public:
+ explicit ServerAsyncReaderWriter(ServerContext* ctx)
+ : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+ void SendInitialMetadata(void* tag) override {
+ GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+ meta_buf_.Reset(tag);
+ meta_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ call_.PerformOps(&meta_buf_);
+ }
+
+ virtual void Read(R* msg, void* tag) override {
+ read_buf_.Reset(tag);
+ read_buf_.AddRecvMessage(msg);
+ call_.PerformOps(&read_buf_);
+ }
+
+ virtual void Write(const W& msg, void* tag) override {
+ write_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ write_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ write_buf_.AddSendMessage(msg);
+ call_.PerformOps(&write_buf_);
+ }
+
+ void Finish(const Status& status, void* tag) {
+ finish_buf_.Reset(tag);
+ if (!ctx_->sent_initial_metadata_) {
+ finish_buf_.AddSendInitialMetadata(&ctx_->initial_metadata_);
+ ctx_->sent_initial_metadata_ = true;
+ }
+ bool cancelled = false;
+ finish_buf_.AddServerRecvClose(&cancelled);
+ finish_buf_.AddServerSendStatus(&ctx_->trailing_metadata_, status);
+ call_.PerformOps(&finish_buf_);
+ }
+
+ private:
+ void BindCall(Call* call) override { call_ = *call; }
+
+ Call call_;
+ ServerContext* ctx_;
+ CallOpBuffer meta_buf_;
+ CallOpBuffer read_buf_;
+ CallOpBuffer write_buf_;
+ CallOpBuffer finish_buf_;
};
} // namespace grpc
diff --git a/include/grpc++/stream_context_interface.h b/include/grpc++/stream_context_interface.h
deleted file mode 100644
index a841198..0000000
--- a/include/grpc++/stream_context_interface.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *
- * 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 __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
-#define __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
-
-namespace google {
-namespace protobuf {
-class Message;
-}
-}
-
-namespace grpc {
-class Status;
-
-// An interface to avoid dependency on internal implementation.
-class StreamContextInterface {
- public:
- virtual ~StreamContextInterface() {}
-
- virtual void Start(bool buffered) = 0;
-
- virtual bool Read(google::protobuf::Message* msg) = 0;
- virtual bool Write(const google::protobuf::Message* msg, bool is_last) = 0;
- virtual const Status& Wait() = 0;
- virtual void Cancel() = 0;
-
- virtual google::protobuf::Message* request() = 0;
- virtual google::protobuf::Message* response() = 0;
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
diff --git a/include/grpc/grpc b/include/grpc/grpc
new file mode 120000
index 0000000..fc80ad1
--- /dev/null
+++ b/include/grpc/grpc
@@ -0,0 +1 @@
+/home/craig/grpc-ct/include/grpc
\ No newline at end of file
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 358f592..12949d5 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -260,15 +260,18 @@
void grpc_call_details_destroy(grpc_call_details *details);
typedef enum {
- /* Send initial metadata: one and only one instance MUST be sent for each call,
+ /* Send initial metadata: one and only one instance MUST be sent for each
+ call,
unless the call was cancelled - in which case this can be skipped */
GRPC_OP_SEND_INITIAL_METADATA = 0,
/* Send a message: 0 or more of these operations can occur for each call */
GRPC_OP_SEND_MESSAGE,
- /* Send a close from the server: one and only one instance MUST be sent from the client,
+ /* Send a close from the server: one and only one instance MUST be sent from
+ the client,
unless the call was cancelled - in which case this can be skipped */
GRPC_OP_SEND_CLOSE_FROM_CLIENT,
- /* Send status from the server: one and only one instance MUST be sent from the server
+ /* Send status from the server: one and only one instance MUST be sent from
+ the server
unless the call was cancelled - in which case this can be skipped */
GRPC_OP_SEND_STATUS_FROM_SERVER,
/* Receive initial metadata: one and only one MUST be made on the client, must
@@ -276,13 +279,16 @@
GRPC_OP_RECV_INITIAL_METADATA,
/* Receive a message: 0 or more of these operations can occur for each call */
GRPC_OP_RECV_MESSAGE,
- /* Receive status on the client: one and only one must be made on the client */
+ /* Receive status on the client: one and only one must be made on the client
+ */
GRPC_OP_RECV_STATUS_ON_CLIENT,
- /* Receive status on the server: one and only one must be made on the server */
+ /* Receive status on the server: one and only one must be made on the server
+ */
GRPC_OP_RECV_CLOSE_ON_SERVER
} grpc_op_type;
-/* Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT which has
+/* Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
+ which has
no arguments) */
typedef struct grpc_op {
grpc_op_type op;
@@ -306,29 +312,33 @@
grpc_metadata_array *recv_initial_metadata;
grpc_byte_buffer **recv_message;
struct {
- /* ownership of the array is with the caller, but ownership of the elements
+ /* ownership of the array is with the caller, but ownership of the
+ elements
stays with the call object (ie key, value members are owned by the call
object, trailing_metadata->array is owned by the caller).
After the operation completes, call grpc_metadata_array_destroy on this
value, or reuse it in a future op. */
grpc_metadata_array *trailing_metadata;
grpc_status_code *status;
- /* status_details is a buffer owned by the application before the op completes
- and after the op has completed. During the operation status_details may be
- reallocated to a size larger than *status_details_capacity, in which case
+ /* status_details is a buffer owned by the application before the op
+ completes
+ and after the op has completed. During the operation status_details may
+ be
+ reallocated to a size larger than *status_details_capacity, in which
+ case
*status_details_capacity will be updated with the new array capacity.
Pre-allocating space:
size_t my_capacity = 8;
char *my_details = gpr_malloc(my_capacity);
x.status_details = &my_details;
- x.status_details_capacity = &my_capacity;
+ x.status_details_capacity = &my_capacity;
Not pre-allocating space:
size_t my_capacity = 0;
char *my_details = NULL;
x.status_details = &my_details;
- x.status_details_capacity = &my_capacity;
+ x.status_details_capacity = &my_capacity;
After the call:
gpr_free(my_details); */
@@ -336,7 +346,8 @@
size_t *status_details_capacity;
} recv_status_on_client;
struct {
- /* out argument, set to 1 if the call failed in any way (seen as a cancellation
+ /* out argument, set to 1 if the call failed in any way (seen as a
+ cancellation
on the server), or 0 if the call succeeded */
int *cancelled;
} recv_close_on_server;
@@ -398,7 +409,7 @@
gpr_timespec deadline);
/* Start a batch of operations defined in the array ops; when complete, post a
- completion of type 'tag' to the completion queue bound to the call.
+ completion of type 'tag' to the completion queue bound to the call.
The order of ops specified in the batch has no significance.
Only one operation of each type can be active at once in any given
batch. */
@@ -548,10 +559,30 @@
grpc_call_error grpc_server_request_call_old(grpc_server *server,
void *tag_new);
+/* Request notification of a new call */
grpc_call_error grpc_server_request_call(
grpc_server *server, grpc_call **call, grpc_call_details *details,
grpc_metadata_array *request_metadata,
- grpc_completion_queue *completion_queue, void *tag_new);
+ grpc_completion_queue *cq_bound_to_call,
+ void *tag_new);
+
+/* Registers a method in the server.
+ Methods to this (host, method) pair will not be reported by
+ grpc_server_request_call, but instead be reported by
+ grpc_server_request_registered_call when passed the appropriate
+ registered_method (as returned by this function).
+ Must be called before grpc_server_start.
+ Returns NULL on failure. */
+void *grpc_server_register_method(grpc_server *server, const char *method,
+ const char *host,
+ grpc_completion_queue *new_call_cq);
+
+/* Request notification of a new pre-registered call */
+grpc_call_error grpc_server_request_registered_call(
+ grpc_server *server, void *registered_method, grpc_call **call,
+ gpr_timespec *deadline, grpc_metadata_array *request_metadata,
+ grpc_byte_buffer **optional_payload,
+ grpc_completion_queue *cq_bound_to_call, void *tag_new);
/* Create a server. Additional configuration for each incoming channel can
be specified with args. If no additional configuration is needed, args can
@@ -559,30 +590,29 @@
grpc_server *grpc_server_create(grpc_completion_queue *cq,
const grpc_channel_args *args);
-/* Add a http2 over tcp listener.
+/* Add a HTTP2 over plaintext over tcp listener.
Returns bound port number on success, 0 on failure.
REQUIRES: server not started */
int grpc_server_add_http2_port(grpc_server *server, const char *addr);
-/* Add a secure port to server.
- Returns bound port number on success, 0 on failure.
- REQUIRES: server not started */
-int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr);
-
/* Start a server - tells all listeners to start listening */
void grpc_server_start(grpc_server *server);
/* Begin shutting down a server.
After completion, no new calls or connections will be admitted.
- Existing calls will be allowed to complete. */
+ Existing calls will be allowed to complete.
+ Shutdown is idempotent. */
void grpc_server_shutdown(grpc_server *server);
/* As per grpc_server_shutdown, but send a GRPC_SERVER_SHUTDOWN event when
- there are no more calls being serviced. */
+ there are no more calls being serviced.
+ Shutdown is idempotent, and all tags will be notified at once if multiple
+ grpc_server_shutdown_and_notify calls are made. */
void grpc_server_shutdown_and_notify(grpc_server *server, void *tag);
/* Destroy a server.
- Forcefully cancels all existing calls. */
+ Forcefully cancels all existing calls.
+ Implies grpc_server_shutdown() if one was not previously performed. */
void grpc_server_destroy(grpc_server *server);
#ifdef __cplusplus
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 7319590..a43d998 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -162,6 +162,13 @@
grpc_completion_queue *cq,
const grpc_channel_args *args);
+/* Add a HTTP2 over an encrypted link over tcp listener.
+ Server must have been created with grpc_secure_server_create.
+ Returns bound port number on success, 0 on failure.
+ REQUIRES: server not started */
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/core/support/cpu.h b/include/grpc/support/cpu.h
similarity index 95%
rename from src/core/support/cpu.h
rename to include/grpc/support/cpu.h
index f8ec2c6..9025f7c 100644
--- a/src/core/support/cpu.h
+++ b/include/grpc/support/cpu.h
@@ -34,6 +34,10 @@
#ifndef __GRPC_INTERNAL_SUPPORT_CPU_H__
#define __GRPC_INTERNAL_SUPPORT_CPU_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Interface providing CPU information for currently running system */
/* Return the number of CPU cores on the current system. Will return 0 if
@@ -46,4 +50,8 @@
[0, gpr_cpu_num_cores() - 1] */
unsigned gpr_cpu_current_cpu(void);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif /* __GRPC_INTERNAL_SUPPORT_CPU_H__ */
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 8724f97..60dc02d 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -41,10 +41,18 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <sstream>
namespace grpc_cpp_generator {
namespace {
+template <class T>
+std::string as_string(T x) {
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
bool NoStreaming(const google::protobuf::MethodDescriptor *method) {
return !method->client_streaming() && !method->server_streaming();
}
@@ -61,6 +69,17 @@
return method->client_streaming() && method->server_streaming();
}
+bool HasUnaryCalls(const google::protobuf::FileDescriptor *file) {
+ for (int i = 0; i < file->service_count(); i++) {
+ for (int j = 0; j < file->service(i)->method_count(); j++) {
+ if (NoStreaming(file->service(i)->method(j))) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor *file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
@@ -97,20 +116,30 @@
std::string GetHeaderIncludes(const google::protobuf::FileDescriptor *file) {
std::string temp =
- "#include \"grpc++/impl/internal_stub.h\"\n"
- "#include \"grpc++/status.h\"\n"
+ "#include <grpc++/impl/internal_stub.h>\n"
+ "#include <grpc++/impl/service_type.h>\n"
+ "#include <grpc++/status.h>\n"
"\n"
"namespace grpc {\n"
+ "class CompletionQueue;\n"
"class ChannelInterface;\n"
"class RpcService;\n"
"class ServerContext;\n";
+ if (HasUnaryCalls(file)) {
+ temp.append(
+ "template <class OutMessage> class ServerAsyncResponseWriter;\n");
+ }
if (HasClientOnlyStreaming(file)) {
temp.append("template <class OutMessage> class ClientWriter;\n");
temp.append("template <class InMessage> class ServerReader;\n");
+ temp.append("template <class OutMessage> class ClientAsyncWriter;\n");
+ temp.append("template <class OutMessage, class InMessage> class ServerAsyncReader;\n");
}
if (HasServerOnlyStreaming(file)) {
temp.append("template <class InMessage> class ClientReader;\n");
temp.append("template <class OutMessage> class ServerWriter;\n");
+ temp.append("template <class OutMessage> class ClientAsyncReader;\n");
+ temp.append("template <class InMessage> class ServerAsyncWriter;\n");
}
if (HasBidiStreaming(file)) {
temp.append(
@@ -119,16 +148,24 @@
temp.append(
"template <class OutMessage, class InMessage>\n"
"class ServerReaderWriter;\n");
+ temp.append(
+ "template <class OutMessage, class InMessage>\n"
+ "class ClientAsyncReaderWriter;\n");
+ temp.append(
+ "template <class OutMessage, class InMessage>\n"
+ "class ServerAsyncReaderWriter;\n");
}
temp.append("} // namespace grpc\n");
return temp;
}
std::string GetSourceIncludes() {
- return "#include \"grpc++/channel_interface.h\"\n"
- "#include \"grpc++/impl/rpc_method.h\"\n"
- "#include \"grpc++/impl/rpc_service_method.h\"\n"
- "#include \"grpc++/stream.h\"\n";
+ return "#include <grpc++/channel_interface.h>\n"
+ "#include <grpc++/impl/client_unary_call.h>\n"
+ "#include <grpc++/impl/rpc_method.h>\n"
+ "#include <grpc++/impl/rpc_service_method.h>\n"
+ "#include <grpc++/impl/service_type.h>\n"
+ "#include <grpc++/stream.h>\n";
}
void PrintHeaderClientMethod(google::protobuf::io::Printer *printer,
@@ -142,27 +179,44 @@
if (NoStreaming(method)) {
printer->Print(*vars,
"::grpc::Status $Method$(::grpc::ClientContext* context, "
- "const $Request$& request, $Response$* response);\n\n");
+ "const $Request$& request, $Response$* response);\n");
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response, "
+ "::grpc::Status* status, "
+ "::grpc::CompletionQueue* cq, void* tag);\n");
} else if (ClientOnlyStreaming(method)) {
- printer->Print(
- *vars,
- "::grpc::ClientWriter< $Request$>* $Method$("
- "::grpc::ClientContext* context, $Response$* response);\n\n");
+ printer->Print(*vars,
+ "::grpc::ClientWriter< $Request$>* $Method$("
+ "::grpc::ClientContext* context, $Response$* response);\n");
+ printer->Print(*vars,
+ "::grpc::ClientAsyncWriter< $Request$>* $Method$("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag);\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"::grpc::ClientReader< $Response$>* $Method$("
- "::grpc::ClientContext* context, const $Request$* request);\n\n");
+ "::grpc::ClientContext* context, const $Request$& request);\n");
+ printer->Print(*vars,
+ "::grpc::ClientAsyncReader< $Response$>* $Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag);\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
"::grpc::ClientReaderWriter< $Request$, $Response$>* "
- "$Method$(::grpc::ClientContext* context);\n\n");
+ "$Method$(::grpc::ClientContext* context);\n");
+ printer->Print(*vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag);\n");
}
}
-void PrintHeaderServerMethod(google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+void PrintHeaderServerMethodSync(
+ google::protobuf::io::Printer *printer,
+ const google::protobuf::MethodDescriptor *method,
+ std::map<std::string, std::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -194,19 +248,56 @@
}
}
+void PrintHeaderServerMethodAsync(
+ google::protobuf::io::Printer *printer,
+ const google::protobuf::MethodDescriptor *method,
+ std::map<std::string, std::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] =
+ grpc_cpp_generator::ClassName(method->input_type(), true);
+ (*vars)["Response"] =
+ grpc_cpp_generator::ClassName(method->output_type(), true);
+ if (NoStreaming(method)) {
+ printer->Print(*vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
+ "::grpc::CompletionQueue* cq, void *tag);\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
+ "::grpc::CompletionQueue* cq, void *tag);\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncWriter< $Response$>* writer, "
+ "::grpc::CompletionQueue* cq, void *tag);\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
+ "::grpc::CompletionQueue* cq, void *tag);\n");
+ }
+}
+
void PrintHeaderService(google::protobuf::io::Printer *printer,
const google::protobuf::ServiceDescriptor *service,
std::map<std::string, std::string> *vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
- "class $Service$ {\n"
+ "class $Service$ final {\n"
" public:\n");
printer->Indent();
// Client side
printer->Print(
- "class Stub : public ::grpc::InternalStub {\n"
+ "class Stub final : public ::grpc::InternalStub {\n"
" public:\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
@@ -220,23 +311,37 @@
printer->Print("\n");
- // Server side
+ // Server side - Synchronous
printer->Print(
- "class Service {\n"
+ "class Service : public ::grpc::SynchronousService {\n"
" public:\n");
printer->Indent();
printer->Print("Service() : service_(nullptr) {}\n");
printer->Print("virtual ~Service();\n");
for (int i = 0; i < service->method_count(); ++i) {
- PrintHeaderServerMethod(printer, service->method(i), vars);
+ PrintHeaderServerMethodSync(printer, service->method(i), vars);
}
- printer->Print("::grpc::RpcService* service();\n");
+ printer->Print("::grpc::RpcService* service() override final;\n");
printer->Outdent();
printer->Print(
" private:\n"
" ::grpc::RpcService* service_;\n");
printer->Print("};\n");
+ // Server side - Asynchronous
+ printer->Print(
+ "class AsyncService final : public ::grpc::AsynchronousService {\n"
+ " public:\n");
+ printer->Indent();
+ (*vars)["MethodCount"] = as_string(service->method_count());
+ printer->Print("explicit AsyncService(::grpc::CompletionQueue* cq);\n");
+ printer->Print("~AsyncService() {};\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderServerMethodAsync(printer, service->method(i), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+
printer->Outdent();
printer->Print("};\n");
}
@@ -268,10 +373,20 @@
"::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response) {\n");
printer->Print(*vars,
- " return channel()->StartBlockingRpc("
- "::grpc::RpcMethod(\"/$Package$$Service$/$Method$\"), "
+ " return ::grpc::BlockingUnaryCall(channel(),"
+ "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
"context, request, response);\n"
"}\n\n");
+ printer->Print(*vars,
+ "void $Service$::Stub::$Method$("
+ "::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response, ::grpc::Status* status, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::AsyncUnaryCall(channel(),"
+ "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+ "context, request, response, status, cq, tag);\n"
+ "}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
@@ -279,22 +394,46 @@
"::grpc::ClientContext* context, $Response$* response) {\n");
printer->Print(*vars,
" return new ::grpc::ClientWriter< $Request$>("
- "channel()->CreateStream("
- "::grpc::RpcMethod(\"/$Package$$Service$/$Method$\", "
+ "channel(),"
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
- "context, nullptr, response));\n"
+ "context, response);\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncWriter< $Request$>* $Service$::Stub::$Method$("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientAsyncWriter< $Request$>("
+ "channel(), cq, "
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
+ "context, response, tag);\n"
"}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"::grpc::ClientReader< $Response$>* $Service$::Stub::$Method$("
- "::grpc::ClientContext* context, const $Request$* request) {\n");
+ "::grpc::ClientContext* context, const $Request$& request) {\n");
printer->Print(*vars,
" return new ::grpc::ClientReader< $Response$>("
- "channel()->CreateStream("
- "::grpc::RpcMethod(\"/$Package$$Service$/$Method$\", "
+ "channel(),"
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
- "context, request, nullptr));\n"
+ "context, request);\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReader< $Response$>* $Service$::Stub::$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(*vars,
+ " return new ::grpc::ClientAsyncReader< $Response$>("
+ "channel(), cq, "
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
+ "context, request, tag);\n"
"}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(
@@ -304,10 +443,23 @@
printer->Print(
*vars,
" return new ::grpc::ClientReaderWriter< $Request$, $Response$>("
- "channel()->CreateStream("
- "::grpc::RpcMethod(\"/$Package$$Service$/$Method$\", "
+ "channel(),"
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
- "context, nullptr, nullptr));\n"
+ "context);\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "$Service$::Stub::$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(
+ *vars,
+ " return new ::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
+ "channel(), cq, "
+ "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
+ "context, tag);\n"
"}\n\n");
}
}
@@ -362,10 +514,73 @@
}
}
+void PrintSourceServerAsyncMethod(
+ google::protobuf::io::Printer *printer,
+ const google::protobuf::MethodDescriptor *method,
+ std::map<std::string, std::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] =
+ grpc_cpp_generator::ClassName(method->input_type(), true);
+ (*vars)["Response"] =
+ grpc_cpp_generator::ClassName(method->output_type(), true);
+ if (NoStreaming(method)) {
+ printer->Print(*vars,
+ "void $Service$::AsyncService::Request$Method$("
+ "::grpc::ServerContext* context, "
+ "$Request$* request, "
+ "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(
+ *vars,
+ " AsynchronousService::RequestAsyncUnary($Idx$, context, request, response, cq, tag);\n");
+ printer->Print("}\n\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "void $Service$::AsyncService::Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(
+ *vars,
+ " AsynchronousService::RequestClientStreaming($Idx$, context, reader, cq, tag);\n");
+ printer->Print("}\n\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "void $Service$::AsyncService::Request$Method$("
+ "::grpc::ServerContext* context, "
+ "$Request$* request, "
+ "::grpc::ServerAsyncWriter< $Response$>* writer, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(
+ *vars,
+ " AsynchronousService::RequestServerStreaming($Idx$, context, request, writer, cq, tag);\n");
+ printer->Print("}\n\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(
+ *vars,
+ "void $Service$::AsyncService::Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
+ "::grpc::CompletionQueue* cq, void *tag) {\n");
+ printer->Print(
+ *vars,
+ " AsynchronousService::RequestBidiStreaming($Idx$, context, stream, cq, tag);\n");
+ printer->Print("}\n\n");
+ }
+}
+
void PrintSourceService(google::protobuf::io::Printer *printer,
const google::protobuf::ServiceDescriptor *service,
std::map<std::string, std::string> *vars) {
(*vars)["Service"] = service->name();
+
+ printer->Print(*vars, "static const char* $Service$_method_names[] = {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Method"] = service->method(i)->name();
+ printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
+ }
+ printer->Print(*vars, "};\n\n");
+
printer->Print(
*vars,
"$Service$::Stub* $Service$::NewStub("
@@ -375,15 +590,25 @@
" return stub;\n"
"};\n\n");
for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
PrintSourceClientMethod(printer, service->method(i), vars);
}
+ (*vars)["MethodCount"] = as_string(service->method_count());
+ printer->Print(
+ *vars,
+ "$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
+ "::grpc::AsynchronousService(cq, $Service$_method_names, $MethodCount$) "
+ "{}\n\n");
+
printer->Print(*vars,
"$Service$::Service::~Service() {\n"
" delete service_;\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
PrintSourceServerMethod(printer, service->method(i), vars);
+ PrintSourceServerAsyncMethod(printer, service->method(i), vars);
}
printer->Print(*vars,
"::grpc::RpcService* $Service$::Service::service() {\n");
@@ -395,6 +620,7 @@
printer->Print("service_ = new ::grpc::RpcService();\n");
for (int i = 0; i < service->method_count(); ++i) {
const google::protobuf::MethodDescriptor *method = service->method(i);
+ (*vars)["Idx"] = as_string(i);
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -404,7 +630,7 @@
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " \"/$Package$$Service$/$Method$\",\n"
+ " $Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::NORMAL_RPC,\n"
" new ::grpc::RpcMethodHandler< $Service$::Service, $Request$, "
"$Response$>(\n"
@@ -416,7 +642,7 @@
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " \"/$Package$$Service$/$Method$\",\n"
+ " $Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::CLIENT_STREAMING,\n"
" new ::grpc::ClientStreamingHandler< "
"$Service$::Service, $Request$, $Response$>(\n"
@@ -429,7 +655,7 @@
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " \"/$Package$$Service$/$Method$\",\n"
+ " $Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::SERVER_STREAMING,\n"
" new ::grpc::ServerStreamingHandler< "
"$Service$::Service, $Request$, $Response$>(\n"
@@ -442,7 +668,7 @@
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " \"/$Package$$Service$/$Method$\",\n"
+ " $Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::BIDI_STREAMING,\n"
" new ::grpc::BidiStreamingHandler< "
"$Service$::Service, $Request$, $Response$>(\n"
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 61a6caf..2d61d38 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -467,17 +467,11 @@
/* transport got goaway ==> call up and handle it */
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
- char *msg;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
- msg = gpr_hexdump((const char *)GPR_SLICE_START_PTR(debug),
- GPR_SLICE_LENGTH(debug), GPR_HEXDUMP_PLAINTEXT);
- gpr_log(GPR_DEBUG, "got goaway: status=%d, message=%s", status, msg);
- gpr_free(msg);
-
op.type = GRPC_TRANSPORT_GOAWAY;
op.dir = GRPC_CALL_UP;
op.data.goaway.status = status;
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 737ee01..cc57830 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -104,14 +104,17 @@
}
static void ref_by(grpc_fd *fd, int n) {
- gpr_atm_no_barrier_fetch_add(&fd->refst, n);
+ GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
}
static void unref_by(grpc_fd *fd, int n) {
- if (gpr_atm_full_fetch_add(&fd->refst, -n) == n) {
+ gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
+ if (old == n) {
grpc_iomgr_add_callback(fd->on_done, fd->on_done_user_data);
freelist_fd(fd);
grpc_iomgr_unref();
+ } else {
+ GPR_ASSERT(old > n);
}
}
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 53c9806..1245d22 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -214,6 +214,7 @@
* unary poller */
grpc_fd_unref(fds[0]);
pollset->data.ptr = fd;
+ grpc_fd_ref(fd);
}
}
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 2558a1e..11f9b05 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -46,8 +46,9 @@
grpc_tcp_server *grpc_tcp_server_create(void);
/* Start listening to bound ports */
-void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset *pollset,
- grpc_tcp_server_cb cb, void *cb_arg);
+void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset **pollsets,
+ size_t pollset_count, grpc_tcp_server_cb cb,
+ void *cb_arg);
/* Add a port to the server, returning port number on success, or negative
on failure.
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 355a040..c8df07c 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -42,17 +42,18 @@
#include "src/core/iomgr/tcp_server.h"
-#include <limits.h>
+#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
-#include <sys/socket.h>
#include <unistd.h>
-#include <string.h>
-#include <errno.h>
#include "src/core/iomgr/pollset_posix.h"
#include "src/core/iomgr/resolve_address.h"
@@ -75,10 +76,22 @@
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
- gpr_uint8 addr[GRPC_MAX_SOCKADDR_SIZE];
+ union {
+ gpr_uint8 untyped[GRPC_MAX_SOCKADDR_SIZE];
+ struct sockaddr sockaddr;
+ struct sockaddr_un un;
+ } addr;
int addr_len;
} server_port;
+static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
+ struct stat st;
+
+ if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
+ unlink(un->sun_path);
+ }
+}
+
/* the overall server */
struct grpc_tcp_server {
grpc_tcp_server_cb cb;
@@ -125,9 +138,8 @@
/* delete ALL the things */
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
- if (((struct sockaddr *)sp->addr)->sa_family == AF_UNIX) {
- struct sockaddr_un *un = (struct sockaddr_un *)sp->addr;
- unlink(un->sun_path);
+ if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(&sp->addr.un);
}
grpc_fd_orphan(sp->emfd, NULL, NULL);
}
@@ -273,7 +285,7 @@
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd);
- memcpy(sp->addr, addr, addr_len);
+ memcpy(sp->addr.untyped, addr, addr_len);
sp->addr_len = addr_len;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
@@ -298,6 +310,10 @@
socklen_t sockname_len;
int port;
+ if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(addr);
+ }
+
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
@@ -363,9 +379,10 @@
return (index < s->nports) ? s->ports[index].fd : -1;
}
-void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset *pollset,
- grpc_tcp_server_cb cb, void *cb_arg) {
- size_t i;
+void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollsets,
+ size_t pollset_count, grpc_tcp_server_cb cb,
+ void *cb_arg) {
+ size_t i, j;
GPR_ASSERT(cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb);
@@ -373,8 +390,8 @@
s->cb = cb;
s->cb_arg = cb_arg;
for (i = 0; i < s->nports; i++) {
- if (pollset) {
- grpc_pollset_add_fd(pollset, s->ports[i].emfd);
+ for (j = 0; j < pollset_count; j++) {
+ grpc_pollset_add_fd(pollsets[j], s->ports[i].emfd);
}
grpc_fd_notify_on_read(s->ports[i].emfd, on_read, &s->ports[i]);
s->active_ports++;
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index adb0269..1909617 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -349,11 +349,13 @@
void *user_data) {
grpc_ssl_channel_security_context *c =
(grpc_ssl_channel_security_context *)ctx;
- grpc_security_status status = ssl_check_peer(c->overridden_target_name != NULL
- ? c->overridden_target_name
- : c->target_name,
- &peer);
+ grpc_security_status status;
+ tsi_peer_destruct(&c->peer);
c->peer = peer;
+ status = ssl_check_peer(c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
+ &peer);
return status;
}
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 480c882..19056ba 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -76,9 +76,10 @@
/* Note: the following code is the same with server_chttp2.c */
/* Server callback: start listening on our ports */
-static void start(grpc_server *server, void *tcpp, grpc_pollset *pollset) {
+static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets,
+ size_t pollset_count) {
grpc_tcp_server *tcp = tcpp;
- grpc_tcp_server_start(tcp, pollset, on_accept, server);
+ grpc_tcp_server_start(tcp, pollsets, pollset_count, on_accept, server);
}
/* Server callback: destroy the tcp listener (so we don't generate further
diff --git a/src/core/statistics/census_log.c b/src/core/statistics/census_log.c
index aea0a33..1504c02 100644
--- a/src/core/statistics/census_log.c
+++ b/src/core/statistics/census_log.c
@@ -91,9 +91,9 @@
*/
#include "src/core/statistics/census_log.h"
#include <string.h>
-#include "src/core/support/cpu.h"
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
+#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c
index ad82174..c8375e6 100644
--- a/src/core/support/cpu_linux.c
+++ b/src/core/support/cpu_linux.c
@@ -39,7 +39,7 @@
#ifdef GPR_CPU_LINUX
-#include "src/core/support/cpu.h"
+#include <grpc/support/cpu.h>
#include <sched.h>
#include <errno.h>
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 58a2436..743ef0c 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -258,6 +258,10 @@
call->cq = cq;
}
+grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
+ return call->cq;
+}
+
void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); }
static void destroy_call(void *call, int ignored_success) {
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 05014c6..55e4344 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -89,6 +89,7 @@
const void *server_transport_data);
void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq);
+grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call);
void grpc_call_internal_ref(grpc_call *call);
void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion);
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 514073c..fef1c7d 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
+#include "src/core/iomgr/iomgr.h"
#include "src/core/surface/call.h"
#include "src/core/surface/client.h"
#include <grpc/support/alloc.h>
@@ -138,15 +139,20 @@
gpr_ref(&channel->refs);
}
+static void destroy_channel(void *p, int ok) {
+ grpc_channel *channel = p;
+ grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
+ grpc_mdstr_unref(channel->grpc_status_string);
+ grpc_mdstr_unref(channel->grpc_message_string);
+ grpc_mdstr_unref(channel->path_string);
+ grpc_mdstr_unref(channel->authority_string);
+ grpc_mdctx_orphan(channel->metadata_context);
+ gpr_free(channel);
+}
+
void grpc_channel_internal_unref(grpc_channel *channel) {
if (gpr_unref(&channel->refs)) {
- grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
- grpc_mdstr_unref(channel->grpc_status_string);
- grpc_mdstr_unref(channel->grpc_message_string);
- grpc_mdstr_unref(channel->path_string);
- grpc_mdstr_unref(channel->authority_string);
- grpc_mdctx_orphan(channel->metadata_context);
- gpr_free(channel);
+ grpc_iomgr_add_callback(destroy_channel, channel);
}
}
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index b5019eb..4d639fc 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -35,12 +35,32 @@
#include "src/core/statistics/census_interface.h"
#include "src/core/iomgr/iomgr.h"
+static gpr_once g_init = GPR_ONCE_INIT;
+static gpr_mu g_init_mu;
+static int g_initializations;
+
+static void do_init() {
+ gpr_mu_init(&g_init_mu);
+ g_initializations = 0;
+}
+
void grpc_init(void) {
- grpc_iomgr_init();
- census_init();
+ gpr_once_init(&g_init, do_init);
+
+ gpr_mu_lock(&g_init_mu);
+ if (++g_initializations == 1) {
+ grpc_iomgr_init();
+ census_init();
+ }
+ gpr_mu_unlock(&g_init_mu);
}
void grpc_shutdown(void) {
- grpc_iomgr_shutdown();
- census_shutdown();
+ gpr_mu_lock(&g_init_mu);
+ if (--g_initializations == 0) {
+ grpc_iomgr_shutdown();
+ census_shutdown();
+ }
+ gpr_mu_unlock(&g_init_mu);
}
+
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index 411dbab..a8fdeed 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -47,6 +47,7 @@
} call_data;
typedef struct {
+ grpc_mdelem *status;
grpc_mdelem *message;
} channel_data;
@@ -57,6 +58,7 @@
switch (op->type) {
case GRPC_SEND_START:
+ grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->status));
grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->message));
grpc_call_stream_closed(elem);
break;
@@ -93,18 +95,22 @@
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
channel_data *channeld = elem->channel_data;
+ char status[12];
GPR_ASSERT(is_first);
GPR_ASSERT(is_last);
channeld->message = grpc_mdelem_from_strings(mdctx, "grpc-message",
"Rpc sent on a lame channel.");
+ gpr_ltoa(GRPC_STATUS_UNKNOWN, status);
+ channeld->status = grpc_mdelem_from_strings(mdctx, "grpc-status", status);
}
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->message);
+ grpc_mdelem_unref(channeld->status);
}
static const grpc_channel_filter lame_filter = {
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index ee0f96a..7297a2a 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -53,13 +53,64 @@
typedef struct listener {
void *arg;
- void (*start)(grpc_server *server, void *arg, grpc_pollset *pollset);
+ void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets,
+ size_t pollset_count);
void (*destroy)(grpc_server *server, void *arg);
struct listener *next;
} listener;
typedef struct call_data call_data;
typedef struct channel_data channel_data;
+typedef struct registered_method registered_method;
+
+typedef struct {
+ call_data *next;
+ call_data *prev;
+} call_link;
+
+typedef enum { LEGACY_CALL, BATCH_CALL, REGISTERED_CALL } requested_call_type;
+
+typedef struct {
+ requested_call_type type;
+ void *tag;
+ union {
+ struct {
+ grpc_completion_queue *cq_bind;
+ grpc_call **call;
+ grpc_call_details *details;
+ grpc_metadata_array *initial_metadata;
+ } batch;
+ struct {
+ grpc_completion_queue *cq_bind;
+ grpc_call **call;
+ registered_method *registered_method;
+ gpr_timespec *deadline;
+ grpc_metadata_array *initial_metadata;
+ grpc_byte_buffer **optional_payload;
+ } registered;
+ } data;
+} requested_call;
+
+typedef struct {
+ requested_call *calls;
+ size_t count;
+ size_t capacity;
+} requested_call_array;
+
+struct registered_method {
+ char *method;
+ char *host;
+ call_data *pending;
+ requested_call_array requested;
+ grpc_completion_queue *cq;
+ registered_method *next;
+};
+
+typedef struct channel_registered_method {
+ registered_method *server_registered_method;
+ grpc_mdstr *method;
+ grpc_mdstr *host;
+} channel_registered_method;
struct channel_data {
grpc_server *server;
@@ -69,37 +120,29 @@
/* linked list of all channels on a server */
channel_data *next;
channel_data *prev;
+ channel_registered_method *registered_methods;
+ gpr_uint32 registered_method_slots;
+ gpr_uint32 registered_method_max_probes;
};
-typedef void (*new_call_cb)(grpc_server *server, grpc_completion_queue *cq,
- grpc_call **call, grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- call_data *calld, void *user_data);
-
-typedef struct {
- void *user_data;
- grpc_completion_queue *cq;
- grpc_call **call;
- grpc_call_details *details;
- grpc_metadata_array *initial_metadata;
- new_call_cb cb;
-} requested_call;
-
struct grpc_server {
size_t channel_filter_count;
const grpc_channel_filter **channel_filters;
grpc_channel_args *channel_args;
- grpc_completion_queue *cq;
+ grpc_completion_queue *unregistered_cq;
+
+ grpc_completion_queue **cqs;
+ grpc_pollset **pollsets;
+ size_t cq_count;
gpr_mu mu;
- requested_call *requested_calls;
- size_t requested_call_count;
- size_t requested_call_capacity;
+ registered_method *registered_methods;
+ requested_call_array requested_calls;
gpr_uint8 shutdown;
- gpr_uint8 have_shutdown_tag;
- void *shutdown_tag;
+ size_t num_shutdown_tags;
+ void **shutdown_tags;
call_data *lists[CALL_LIST_COUNT];
channel_data root_channel_data;
@@ -108,11 +151,6 @@
gpr_refcount internal_refcount;
};
-typedef struct {
- call_data *next;
- call_data *prev;
-} call_link;
-
typedef enum {
/* waiting for metadata */
NOT_STARTED,
@@ -125,7 +163,7 @@
} call_state;
typedef struct legacy_data {
- grpc_metadata_array *initial_metadata;
+ grpc_metadata_array initial_metadata;
} legacy_data;
struct call_data {
@@ -137,9 +175,9 @@
grpc_mdstr *host;
legacy_data *legacy;
- grpc_call_details *details;
+ grpc_completion_queue *cq_new;
- gpr_uint8 included[CALL_LIST_COUNT];
+ call_data **root[CALL_LIST_COUNT];
call_link links[CALL_LIST_COUNT];
};
@@ -148,30 +186,33 @@
static void do_nothing(void *unused, grpc_op_error ignored) {}
-static int call_list_join(grpc_server *server, call_data *call,
- call_list list) {
- if (call->included[list]) return 0;
- call->included[list] = 1;
- if (!server->lists[list]) {
- server->lists[list] = call;
+static void begin_call(grpc_server *server, call_data *calld,
+ requested_call *rc);
+static void fail_call(grpc_server *server, requested_call *rc);
+
+static int call_list_join(call_data **root, call_data *call, call_list list) {
+ GPR_ASSERT(!call->root[list]);
+ call->root[list] = root;
+ if (!*root) {
+ *root = call;
call->links[list].next = call->links[list].prev = call;
} else {
- call->links[list].next = server->lists[list];
- call->links[list].prev = server->lists[list]->links[list].prev;
+ call->links[list].next = *root;
+ call->links[list].prev = (*root)->links[list].prev;
call->links[list].next->links[list].prev =
call->links[list].prev->links[list].next = call;
}
return 1;
}
-static call_data *call_list_remove_head(grpc_server *server, call_list list) {
- call_data *out = server->lists[list];
+static call_data *call_list_remove_head(call_data **root, call_list list) {
+ call_data *out = *root;
if (out) {
- out->included[list] = 0;
+ out->root[list] = NULL;
if (out->links[list].next == out) {
- server->lists[list] = NULL;
+ *root = NULL;
} else {
- server->lists[list] = out->links[list].next;
+ *root = out->links[list].next;
out->links[list].next->links[list].prev = out->links[list].prev;
out->links[list].prev->links[list].next = out->links[list].next;
}
@@ -179,33 +220,60 @@
return out;
}
-static int call_list_remove(grpc_server *server, call_data *call,
- call_list list) {
- if (!call->included[list]) return 0;
- call->included[list] = 0;
- if (server->lists[list] == call) {
- server->lists[list] = call->links[list].next;
- if (server->lists[list] == call) {
- server->lists[list] = NULL;
+static int call_list_remove(call_data *call, call_list list) {
+ call_data **root = call->root[list];
+ if (root == NULL) return 0;
+ call->root[list] = NULL;
+ if (*root == call) {
+ *root = call->links[list].next;
+ if (*root == call) {
+ *root = NULL;
return 1;
}
}
- GPR_ASSERT(server->lists[list] != call);
+ GPR_ASSERT(*root != call);
call->links[list].next->links[list].prev = call->links[list].prev;
call->links[list].prev->links[list].next = call->links[list].next;
return 1;
}
+static void requested_call_array_destroy(requested_call_array *array) {
+ gpr_free(array->calls);
+}
+
+static requested_call *requested_call_array_add(requested_call_array *array) {
+ requested_call *rc;
+ if (array->count == array->capacity) {
+ array->capacity = GPR_MAX(array->capacity + 8, array->capacity * 2);
+ array->calls =
+ gpr_realloc(array->calls, sizeof(requested_call) * array->capacity);
+ }
+ rc = &array->calls[array->count++];
+ memset(rc, 0, sizeof(*rc));
+ return rc;
+}
+
static void server_ref(grpc_server *server) {
gpr_ref(&server->internal_refcount);
}
static void server_unref(grpc_server *server) {
+ registered_method *rm;
if (gpr_unref(&server->internal_refcount)) {
grpc_channel_args_destroy(server->channel_args);
gpr_mu_destroy(&server->mu);
gpr_free(server->channel_filters);
- gpr_free(server->requested_calls);
+ requested_call_array_destroy(&server->requested_calls);
+ while ((rm = server->registered_methods) != NULL) {
+ server->registered_methods = rm->next;
+ gpr_free(rm->method);
+ gpr_free(rm->host);
+ requested_call_array_destroy(&rm->requested);
+ gpr_free(rm);
+ }
+ gpr_free(server->cqs);
+ gpr_free(server->pollsets);
+ gpr_free(server->shutdown_tags);
gpr_free(server);
}
}
@@ -223,7 +291,6 @@
static void finish_destroy_channel(void *cd, int success) {
channel_data *chand = cd;
grpc_server *server = chand->server;
- /*gpr_log(GPR_INFO, "destroy channel %p", chand->channel);*/
grpc_channel_destroy(chand->channel);
server_unref(server);
}
@@ -236,23 +303,64 @@
grpc_iomgr_add_callback(finish_destroy_channel, chand);
}
+static void finish_start_new_rpc_and_unlock(grpc_server *server,
+ grpc_call_element *elem,
+ call_data **pending_root,
+ requested_call_array *array) {
+ requested_call rc;
+ call_data *calld = elem->call_data;
+ if (array->count == 0) {
+ calld->state = PENDING;
+ call_list_join(pending_root, calld, PENDING_START);
+ gpr_mu_unlock(&server->mu);
+ } else {
+ rc = array->calls[--array->count];
+ calld->state = ACTIVATED;
+ gpr_mu_unlock(&server->mu);
+ begin_call(server, calld, &rc);
+ }
+}
+
static void start_new_rpc(grpc_call_element *elem) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
grpc_server *server = chand->server;
+ gpr_uint32 i;
+ gpr_uint32 hash;
+ channel_registered_method *rm;
gpr_mu_lock(&server->mu);
- if (server->requested_call_count > 0) {
- requested_call rc = server->requested_calls[--server->requested_call_count];
- calld->state = ACTIVATED;
- gpr_mu_unlock(&server->mu);
- rc.cb(server, rc.cq, rc.call, rc.details, rc.initial_metadata, calld,
- rc.user_data);
- } else {
- calld->state = PENDING;
- call_list_join(server, calld, PENDING_START);
- gpr_mu_unlock(&server->mu);
+ if (chand->registered_methods && calld->path && calld->host) {
+ /* TODO(ctiller): unify these two searches */
+ /* check for an exact match with host */
+ hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
+ for (i = 0; i < chand->registered_method_max_probes; i++) {
+ rm = &chand->registered_methods[(hash + i) %
+ chand->registered_method_slots];
+ if (!rm) break;
+ if (rm->host != calld->host) continue;
+ if (rm->method != calld->path) continue;
+ finish_start_new_rpc_and_unlock(server, elem,
+ &rm->server_registered_method->pending,
+ &rm->server_registered_method->requested);
+ return;
+ }
+ /* check for a wildcard method definition (no host set) */
+ hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash);
+ for (i = 0; i <= chand->registered_method_max_probes; i++) {
+ rm = &chand->registered_methods[(hash + i) %
+ chand->registered_method_slots];
+ if (!rm) break;
+ if (rm->host != NULL) continue;
+ if (rm->method != calld->path) continue;
+ finish_start_new_rpc_and_unlock(server, elem,
+ &rm->server_registered_method->pending,
+ &rm->server_registered_method->requested);
+ return;
+ }
}
+ finish_start_new_rpc_and_unlock(server, elem, &server->lists[PENDING_START],
+ &server->requested_calls);
}
static void kill_zombie(void *elem, int success) {
@@ -267,7 +375,7 @@
case ACTIVATED:
break;
case PENDING:
- call_list_remove(chand->server, calld, PENDING_START);
+ call_list_remove(calld, PENDING_START);
/* fallthrough intended */
case NOT_STARTED:
calld->state = ZOMBIED;
@@ -398,7 +506,7 @@
calld->call = grpc_call_from_top_element(elem);
gpr_mu_lock(&chand->server->mu);
- call_list_join(chand->server, calld, ALL_CALLS);
+ call_list_join(&chand->server->lists[ALL_CALLS], calld, ALL_CALLS);
gpr_mu_unlock(&chand->server->mu);
server_ref(chand->server);
@@ -407,15 +515,19 @@
static void destroy_call_elem(grpc_call_element *elem) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
- int i;
+ size_t i, j;
gpr_mu_lock(&chand->server->mu);
for (i = 0; i < CALL_LIST_COUNT; i++) {
- call_list_remove(chand->server, elem->call_data, i);
+ call_list_remove(elem->call_data, i);
}
- if (chand->server->shutdown && chand->server->have_shutdown_tag &&
- chand->server->lists[ALL_CALLS] == NULL) {
- grpc_cq_end_server_shutdown(chand->server->cq, chand->server->shutdown_tag);
+ if (chand->server->shutdown && chand->server->lists[ALL_CALLS] == NULL) {
+ for (i = 0; i < chand->server->num_shutdown_tags; i++) {
+ for (j = 0; j < chand->server->cq_count; j++) {
+ grpc_cq_end_server_shutdown(chand->server->cqs[j],
+ chand->server->shutdown_tags[i]);
+ }
+ }
}
gpr_mu_unlock(&chand->server->mu);
@@ -427,8 +539,7 @@
}
if (calld->legacy) {
- gpr_free(calld->legacy->initial_metadata->metadata);
- gpr_free(calld->legacy->initial_metadata);
+ gpr_free(calld->legacy->initial_metadata.metadata);
gpr_free(calld->legacy);
}
@@ -447,10 +558,23 @@
chand->path_key = grpc_mdstr_from_string(metadata_context, ":path");
chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
chand->next = chand->prev = chand;
+ chand->registered_methods = NULL;
}
static void destroy_channel_elem(grpc_channel_element *elem) {
+ size_t i;
channel_data *chand = elem->channel_data;
+ if (chand->registered_methods) {
+ for (i = 0; i < chand->registered_method_slots; i++) {
+ if (chand->registered_methods[i].method) {
+ grpc_mdstr_unref(chand->registered_methods[i].method);
+ }
+ if (chand->registered_methods[i].host) {
+ grpc_mdstr_unref(chand->registered_methods[i].host);
+ }
+ }
+ gpr_free(chand->registered_methods);
+ }
if (chand->server) {
gpr_mu_lock(&chand->server->mu);
chand->next->prev = chand->prev;
@@ -469,6 +593,17 @@
init_channel_elem, destroy_channel_elem, "server",
};
+static void addcq(grpc_server *server, grpc_completion_queue *cq) {
+ size_t i, n;
+ for (i = 0; i < server->cq_count; i++) {
+ if (server->cqs[i] == cq) return;
+ }
+ n = server->cq_count++;
+ server->cqs = gpr_realloc(server->cqs,
+ server->cq_count * sizeof(grpc_completion_queue *));
+ server->cqs[n] = cq;
+}
+
grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq,
grpc_channel_filter **filters,
size_t filter_count,
@@ -478,10 +613,11 @@
grpc_server *server = gpr_malloc(sizeof(grpc_server));
memset(server, 0, sizeof(grpc_server));
+ if (cq) addcq(server, cq);
gpr_mu_init(&server->mu);
- server->cq = cq;
+ server->unregistered_cq = cq;
/* decremented by grpc_server_destroy */
gpr_ref_init(&server->internal_refcount, 1);
server->root_channel_data.next = server->root_channel_data.prev =
@@ -509,11 +645,50 @@
return server;
}
+static int streq(const char *a, const char *b) {
+ if (a == NULL && b == NULL) return 1;
+ if (a == NULL) return 0;
+ if (b == NULL) return 0;
+ return 0 == strcmp(a, b);
+}
+
+void *grpc_server_register_method(grpc_server *server, const char *method,
+ const char *host,
+ grpc_completion_queue *cq_new_rpc) {
+ registered_method *m;
+ if (!method) {
+ gpr_log(GPR_ERROR, "%s method string cannot be NULL", __FUNCTION__);
+ return NULL;
+ }
+ for (m = server->registered_methods; m; m = m->next) {
+ if (streq(m->method, method) && streq(m->host, host)) {
+ gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method,
+ host ? host : "*");
+ return NULL;
+ }
+ }
+ addcq(server, cq_new_rpc);
+ m = gpr_malloc(sizeof(registered_method));
+ memset(m, 0, sizeof(*m));
+ m->method = gpr_strdup(method);
+ m->host = gpr_strdup(host);
+ m->next = server->registered_methods;
+ m->cq = cq_new_rpc;
+ server->registered_methods = m;
+ return m;
+}
+
void grpc_server_start(grpc_server *server) {
listener *l;
+ size_t i;
+
+ server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
+ for (i = 0; i < server->cq_count; i++) {
+ server->pollsets[i] = grpc_cq_pollset(server->cqs[i]);
+ }
for (l = server->listeners; l; l = l->next) {
- l->start(server, l->arg, grpc_cq_pollset(server->cq));
+ l->start(server, l->arg, server->pollsets, server->cq_count);
}
}
@@ -525,8 +700,19 @@
grpc_channel_filter const **filters =
gpr_malloc(sizeof(grpc_channel_filter *) * num_filters);
size_t i;
+ size_t num_registered_methods;
+ size_t alloc;
+ registered_method *rm;
+ channel_registered_method *crm;
grpc_channel *channel;
channel_data *chand;
+ grpc_mdstr *host;
+ grpc_mdstr *method;
+ gpr_uint32 hash;
+ gpr_uint32 slots;
+ gpr_uint32 probes;
+ gpr_uint32 max_probes = 0;
+ grpc_transport_setup_result result;
for (i = 0; i < s->channel_filter_count; i++) {
filters[i] = s->channel_filters[i];
@@ -536,7 +722,9 @@
}
filters[i] = &grpc_connected_channel_filter;
- grpc_transport_add_to_pollset(transport, grpc_cq_pollset(s->cq));
+ for (i = 0; i < s->cq_count; i++) {
+ grpc_transport_add_to_pollset(transport, grpc_cq_pollset(s->cqs[i]));
+ }
channel = grpc_channel_create_from_filters(filters, num_filters,
s->channel_args, mdctx, 0);
@@ -546,6 +734,38 @@
server_ref(s);
chand->channel = channel;
+ num_registered_methods = 0;
+ for (rm = s->registered_methods; rm; rm = rm->next) {
+ num_registered_methods++;
+ }
+ /* build a lookup table phrased in terms of mdstr's in this channels context
+ to quickly find registered methods */
+ if (num_registered_methods > 0) {
+ slots = 2 * num_registered_methods;
+ alloc = sizeof(channel_registered_method) * slots;
+ chand->registered_methods = gpr_malloc(alloc);
+ memset(chand->registered_methods, 0, alloc);
+ for (rm = s->registered_methods; rm; rm = rm->next) {
+ host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host) : NULL;
+ method = grpc_mdstr_from_string(mdctx, rm->method);
+ hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
+ for (probes = 0; chand->registered_methods[(hash + probes) % slots]
+ .server_registered_method != NULL;
+ probes++)
+ ;
+ if (probes > max_probes) max_probes = probes;
+ crm = &chand->registered_methods[(hash + probes) % slots];
+ crm->server_registered_method = rm;
+ crm->host = host;
+ crm->method = method;
+ }
+ chand->registered_method_slots = slots;
+ chand->registered_method_max_probes = max_probes;
+ }
+
+ result = grpc_connected_channel_bind_transport(
+ grpc_channel_get_channel_stack(channel), transport);
+
gpr_mu_lock(&s->mu);
chand->next = &s->root_channel_data;
chand->prev = chand->next->prev;
@@ -554,24 +774,32 @@
gpr_free(filters);
- return grpc_connected_channel_bind_transport(
- grpc_channel_get_channel_stack(channel), transport);
+ return result;
}
-void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
- void *shutdown_tag) {
+static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
+ void *shutdown_tag) {
listener *l;
- requested_call *requested_calls;
- size_t requested_call_count;
+ requested_call_array requested_calls;
channel_data **channels;
channel_data *c;
size_t nchannels;
- size_t i;
+ size_t i, j;
grpc_channel_op op;
grpc_channel_element *elem;
+ registered_method *rm;
/* lock, and gather up some stuff to do */
gpr_mu_lock(&server->mu);
+ if (have_shutdown_tag) {
+ for (i = 0; i < server->cq_count; i++) {
+ grpc_cq_begin_op(server->cqs[i], NULL, GRPC_SERVER_SHUTDOWN);
+ }
+ server->shutdown_tags =
+ gpr_realloc(server->shutdown_tags,
+ sizeof(void *) * (server->num_shutdown_tags + 1));
+ server->shutdown_tags[server->num_shutdown_tags++] = shutdown_tag;
+ }
if (server->shutdown) {
gpr_mu_unlock(&server->mu);
return;
@@ -591,18 +819,32 @@
i++;
}
+ /* collect all unregistered then registered calls */
requested_calls = server->requested_calls;
- requested_call_count = server->requested_call_count;
- server->requested_calls = NULL;
- server->requested_call_count = 0;
+ memset(&server->requested_calls, 0, sizeof(server->requested_calls));
+ for (rm = server->registered_methods; rm; rm = rm->next) {
+ if (requested_calls.count + rm->requested.count >
+ requested_calls.capacity) {
+ requested_calls.capacity =
+ GPR_MAX(requested_calls.count + rm->requested.count,
+ 2 * requested_calls.capacity);
+ requested_calls.calls =
+ gpr_realloc(requested_calls.calls, sizeof(*requested_calls.calls) *
+ requested_calls.capacity);
+ }
+ memcpy(requested_calls.calls + requested_calls.count, rm->requested.calls,
+ sizeof(*requested_calls.calls) * rm->requested.count);
+ requested_calls.count += rm->requested.count;
+ gpr_free(rm->requested.calls);
+ memset(&rm->requested, 0, sizeof(rm->requested));
+ }
server->shutdown = 1;
- server->have_shutdown_tag = have_shutdown_tag;
- server->shutdown_tag = shutdown_tag;
- if (have_shutdown_tag) {
- grpc_cq_begin_op(server->cq, NULL, GRPC_SERVER_SHUTDOWN);
- if (server->lists[ALL_CALLS] == NULL) {
- grpc_cq_end_server_shutdown(server->cq, shutdown_tag);
+ if (server->lists[ALL_CALLS] == NULL) {
+ for (i = 0; i < server->num_shutdown_tags; i++) {
+ for (j = 0; j < server->cq_count; j++) {
+ grpc_cq_end_server_shutdown(server->cqs[j], server->shutdown_tags[i]);
+ }
}
}
gpr_mu_unlock(&server->mu);
@@ -623,13 +865,10 @@
gpr_free(channels);
/* terminate all the requested calls */
- for (i = 0; i < requested_call_count; i++) {
- requested_calls[i].cb(server, requested_calls[i].cq,
- requested_calls[i].call, requested_calls[i].details,
- requested_calls[i].initial_metadata, NULL,
- requested_calls[i].user_data);
+ for (i = 0; i < requested_calls.count; i++) {
+ fail_call(server, &requested_calls.calls[i]);
}
- gpr_free(requested_calls);
+ gpr_free(requested_calls.calls);
/* Shutdown listeners */
for (l = server->listeners; l; l = l->next) {
@@ -653,6 +892,12 @@
void grpc_server_destroy(grpc_server *server) {
channel_data *c;
gpr_mu_lock(&server->mu);
+ if (!server->shutdown) {
+ gpr_mu_unlock(&server->mu);
+ grpc_server_shutdown(server);
+ gpr_mu_lock(&server->mu);
+ }
+
for (c = server->root_channel_data.next; c != &server->root_channel_data;
c = c->next) {
shutdown_channel(c);
@@ -664,7 +909,8 @@
void grpc_server_add_listener(grpc_server *server, void *arg,
void (*start)(grpc_server *server, void *arg,
- grpc_pollset *pollset),
+ grpc_pollset **pollsets,
+ size_t pollset_count),
void (*destroy)(grpc_server *server, void *arg)) {
listener *l = gpr_malloc(sizeof(listener));
l->arg = arg;
@@ -675,47 +921,92 @@
}
static grpc_call_error queue_call_request(grpc_server *server,
- grpc_completion_queue *cq,
- grpc_call **call,
- grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- new_call_cb cb, void *user_data) {
- call_data *calld;
- requested_call *rc;
+ requested_call *rc) {
+ call_data *calld = NULL;
+ requested_call_array *requested_calls = NULL;
gpr_mu_lock(&server->mu);
if (server->shutdown) {
gpr_mu_unlock(&server->mu);
- cb(server, cq, call, details, initial_metadata, NULL, user_data);
+ fail_call(server, rc);
return GRPC_CALL_OK;
}
- calld = call_list_remove_head(server, PENDING_START);
+ switch (rc->type) {
+ case LEGACY_CALL:
+ case BATCH_CALL:
+ calld =
+ call_list_remove_head(&server->lists[PENDING_START], PENDING_START);
+ requested_calls = &server->requested_calls;
+ break;
+ case REGISTERED_CALL:
+ calld = call_list_remove_head(
+ &rc->data.registered.registered_method->pending, PENDING_START);
+ requested_calls = &rc->data.registered.registered_method->requested;
+ break;
+ }
if (calld) {
GPR_ASSERT(calld->state == PENDING);
calld->state = ACTIVATED;
gpr_mu_unlock(&server->mu);
- cb(server, cq, call, details, initial_metadata, calld, user_data);
+ begin_call(server, calld, rc);
return GRPC_CALL_OK;
} else {
- if (server->requested_call_count == server->requested_call_capacity) {
- server->requested_call_capacity =
- GPR_MAX(server->requested_call_capacity + 8,
- server->requested_call_capacity * 2);
- server->requested_calls =
- gpr_realloc(server->requested_calls,
- sizeof(requested_call) * server->requested_call_capacity);
- }
- rc = &server->requested_calls[server->requested_call_count++];
- rc->cb = cb;
- rc->cq = cq;
- rc->call = call;
- rc->details = details;
- rc->user_data = user_data;
- rc->initial_metadata = initial_metadata;
+ *requested_call_array_add(requested_calls) = *rc;
gpr_mu_unlock(&server->mu);
return GRPC_CALL_OK;
}
}
+grpc_call_error grpc_server_request_call(grpc_server *server, grpc_call **call,
+ grpc_call_details *details,
+ grpc_metadata_array *initial_metadata,
+ grpc_completion_queue *cq_bind,
+ void *tag) {
+ requested_call rc;
+ grpc_cq_begin_op(server->unregistered_cq, NULL, GRPC_OP_COMPLETE);
+ rc.type = BATCH_CALL;
+ rc.tag = tag;
+ rc.data.batch.cq_bind = cq_bind;
+ rc.data.batch.call = call;
+ rc.data.batch.details = details;
+ rc.data.batch.initial_metadata = initial_metadata;
+ return queue_call_request(server, &rc);
+}
+
+grpc_call_error grpc_server_request_registered_call(
+ grpc_server *server, void *rm, grpc_call **call, gpr_timespec *deadline,
+ grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload,
+ grpc_completion_queue *cq_bind, void *tag) {
+ requested_call rc;
+ registered_method *registered_method = rm;
+ grpc_cq_begin_op(registered_method->cq, NULL, GRPC_OP_COMPLETE);
+ rc.type = REGISTERED_CALL;
+ rc.tag = tag;
+ rc.data.registered.cq_bind = cq_bind;
+ rc.data.registered.call = call;
+ rc.data.registered.registered_method = registered_method;
+ rc.data.registered.deadline = deadline;
+ rc.data.registered.initial_metadata = initial_metadata;
+ rc.data.registered.optional_payload = optional_payload;
+ return queue_call_request(server, &rc);
+}
+
+grpc_call_error grpc_server_request_call_old(grpc_server *server,
+ void *tag_new) {
+ requested_call rc;
+ grpc_cq_begin_op(server->unregistered_cq, NULL, GRPC_SERVER_RPC_NEW);
+ rc.type = LEGACY_CALL;
+ rc.tag = tag_new;
+ return queue_call_request(server, &rc);
+}
+
+static void publish_legacy(grpc_call *call, grpc_op_error status, void *tag);
+static void publish_registered_or_batch(grpc_call *call, grpc_op_error status,
+ void *tag);
+static void publish_was_not_set(grpc_call *call, grpc_op_error status,
+ void *tag) {
+ abort();
+}
+
static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
gpr_slice slice = value->slice;
size_t len = GPR_SLICE_LENGTH(slice);
@@ -727,57 +1018,84 @@
memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1);
}
-static void publish_request(grpc_call *call, grpc_op_error status, void *tag) {
- grpc_call_element *elem =
- grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
- call_data *calld = elem->call_data;
- channel_data *chand = elem->channel_data;
- grpc_server *server = chand->server;
+static void begin_call(grpc_server *server, call_data *calld,
+ requested_call *rc) {
+ grpc_ioreq_completion_func publish = publish_was_not_set;
+ grpc_ioreq req[2];
+ grpc_ioreq *r = req;
- if (status == GRPC_OP_OK) {
- cpstr(&calld->details->host, &calld->details->host_capacity, calld->host);
- cpstr(&calld->details->method, &calld->details->method_capacity,
- calld->path);
- calld->details->deadline = calld->deadline;
- grpc_cq_end_op_complete(server->cq, tag, call, do_nothing, NULL,
- GRPC_OP_OK);
- } else {
- abort();
- }
-}
+ /* called once initial metadata has been read by the call, but BEFORE
+ the ioreq to fetch it out of the call has been executed.
+ This means metadata related fields can be relied on in calld, but to
+ fill in the metadata array passed by the client, we need to perform
+ an ioreq op, that should complete immediately. */
-static void begin_request(grpc_server *server, grpc_completion_queue *cq,
- grpc_call **call, grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- call_data *calld, void *tag) {
- grpc_ioreq req;
- if (!calld) {
- *call = NULL;
- initial_metadata->count = 0;
- grpc_cq_end_op_complete(cq, tag, NULL, do_nothing, NULL, GRPC_OP_ERROR);
- return;
+ switch (rc->type) {
+ case LEGACY_CALL:
+ calld->legacy = gpr_malloc(sizeof(legacy_data));
+ memset(calld->legacy, 0, sizeof(legacy_data));
+ r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
+ r->data.recv_metadata = &calld->legacy->initial_metadata;
+ r++;
+ publish = publish_legacy;
+ break;
+ case BATCH_CALL:
+ cpstr(&rc->data.batch.details->host,
+ &rc->data.batch.details->host_capacity, calld->host);
+ cpstr(&rc->data.batch.details->method,
+ &rc->data.batch.details->method_capacity, calld->path);
+ grpc_call_set_completion_queue(calld->call, rc->data.batch.cq_bind);
+ *rc->data.batch.call = calld->call;
+ r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
+ r->data.recv_metadata = rc->data.batch.initial_metadata;
+ r++;
+ calld->cq_new = server->unregistered_cq;
+ publish = publish_registered_or_batch;
+ break;
+ case REGISTERED_CALL:
+ *rc->data.registered.deadline = calld->deadline;
+ grpc_call_set_completion_queue(calld->call, rc->data.registered.cq_bind);
+ *rc->data.registered.call = calld->call;
+ r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
+ r->data.recv_metadata = rc->data.registered.initial_metadata;
+ r++;
+ if (rc->data.registered.optional_payload) {
+ r->op = GRPC_IOREQ_RECV_MESSAGE;
+ r->data.recv_message = rc->data.registered.optional_payload;
+ r++;
+ }
+ calld->cq_new = rc->data.registered.registered_method->cq;
+ publish = publish_registered_or_batch;
+ break;
}
- calld->details = details;
- grpc_call_set_completion_queue(calld->call, cq);
- *call = calld->call;
- req.op = GRPC_IOREQ_RECV_INITIAL_METADATA;
- req.data.recv_metadata = initial_metadata;
+
grpc_call_internal_ref(calld->call);
- grpc_call_start_ioreq_and_call_back(calld->call, &req, 1, publish_request,
- tag);
+ grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish,
+ rc->tag);
}
-grpc_call_error grpc_server_request_call(grpc_server *server, grpc_call **call,
- grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- grpc_completion_queue *cq, void *tag) {
- grpc_cq_begin_op(cq, NULL, GRPC_OP_COMPLETE);
- return queue_call_request(server, cq, call, details, initial_metadata,
- begin_request, tag);
+static void fail_call(grpc_server *server, requested_call *rc) {
+ switch (rc->type) {
+ case LEGACY_CALL:
+ grpc_cq_end_new_rpc(server->unregistered_cq, rc->tag, NULL, do_nothing,
+ NULL, NULL, NULL, gpr_inf_past, 0, NULL);
+ break;
+ case BATCH_CALL:
+ *rc->data.batch.call = NULL;
+ rc->data.batch.initial_metadata->count = 0;
+ grpc_cq_end_op_complete(server->unregistered_cq, rc->tag, NULL,
+ do_nothing, NULL, GRPC_OP_ERROR);
+ break;
+ case REGISTERED_CALL:
+ *rc->data.registered.call = NULL;
+ rc->data.registered.initial_metadata->count = 0;
+ grpc_cq_end_op_complete(rc->data.registered.registered_method->cq,
+ rc->tag, NULL, do_nothing, NULL, GRPC_OP_ERROR);
+ break;
+ }
}
-static void publish_legacy_request(grpc_call *call, grpc_op_error status,
- void *tag) {
+static void publish_legacy(grpc_call *call, grpc_op_error status, void *tag) {
grpc_call_element *elem =
grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
call_data *calld = elem->call_data;
@@ -785,47 +1103,23 @@
grpc_server *server = chand->server;
if (status == GRPC_OP_OK) {
- grpc_cq_end_new_rpc(server->cq, tag, call, do_nothing, NULL,
+ grpc_cq_end_new_rpc(server->unregistered_cq, tag, call, do_nothing, NULL,
grpc_mdstr_as_c_string(calld->path),
grpc_mdstr_as_c_string(calld->host), calld->deadline,
- calld->legacy->initial_metadata->count,
- calld->legacy->initial_metadata->metadata);
+ calld->legacy->initial_metadata.count,
+ calld->legacy->initial_metadata.metadata);
} else {
+ gpr_log(GPR_ERROR, "should never reach here");
abort();
}
}
-static void begin_legacy_request(grpc_server *server, grpc_completion_queue *cq,
- grpc_call **call, grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- call_data *calld, void *tag) {
- grpc_ioreq req;
- GPR_ASSERT(call == NULL);
- GPR_ASSERT(details == NULL);
- if (!calld) {
- gpr_free(initial_metadata);
- grpc_cq_end_new_rpc(cq, tag, NULL, do_nothing, NULL, NULL, NULL,
- gpr_inf_past, 0, NULL);
- return;
- }
- req.op = GRPC_IOREQ_RECV_INITIAL_METADATA;
- req.data.recv_metadata = initial_metadata;
- calld->legacy = gpr_malloc(sizeof(legacy_data));
- memset(calld->legacy, 0, sizeof(legacy_data));
- calld->legacy->initial_metadata = initial_metadata;
- grpc_call_internal_ref(calld->call);
- grpc_call_start_ioreq_and_call_back(calld->call, &req, 1,
- publish_legacy_request, tag);
-}
-
-grpc_call_error grpc_server_request_call_old(grpc_server *server,
- void *tag_new) {
- grpc_metadata_array *client_metadata =
- gpr_malloc(sizeof(grpc_metadata_array));
- memset(client_metadata, 0, sizeof(*client_metadata));
- grpc_cq_begin_op(server->cq, NULL, GRPC_SERVER_RPC_NEW);
- return queue_call_request(server, server->cq, NULL, NULL, client_metadata,
- begin_legacy_request, tag_new);
+static void publish_registered_or_batch(grpc_call *call, grpc_op_error status,
+ void *tag) {
+ grpc_call_element *elem =
+ grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+ call_data *calld = elem->call_data;
+ grpc_cq_end_op_complete(calld->cq_new, tag, call, do_nothing, NULL, status);
}
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index 50574d6..c8861f4 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -48,7 +48,7 @@
and when it shuts down, it will call destroy */
void grpc_server_add_listener(grpc_server *server, void *listener,
void (*start)(grpc_server *server, void *arg,
- grpc_pollset *pollset),
+ grpc_pollset **pollsets, size_t npollsets),
void (*destroy)(grpc_server *server, void *arg));
/* Setup a transport - creates a channel stack, binds the transport to the
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 5ba7d47..3b6abb7 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -59,9 +59,9 @@
}
/* Server callback: start listening on our ports */
-static void start(grpc_server *server, void *tcpp, grpc_pollset *pollset) {
+static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size_t pollset_count) {
grpc_tcp_server *tcp = tcpp;
- grpc_tcp_server_start(tcp, pollset, new_transport, server);
+ grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server);
}
/* Server callback: destroy the tcp listener (so we don't generate further
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 8b1fb78..dcd0171 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -184,11 +184,13 @@
gpr_uint8 is_client;
gpr_mu mu;
+ gpr_cv cv;
/* basic state management - what are we doing at the moment? */
gpr_uint8 reading;
gpr_uint8 writing;
gpr_uint8 calling_back;
+ gpr_uint8 destroying;
error_state error_state;
/* stream indexing */
@@ -362,6 +364,7 @@
gpr_mu_unlock(&t->mu);
gpr_mu_destroy(&t->mu);
+ gpr_cv_destroy(&t->cv);
/* callback remaining pings: they're not allowed to call into the transpot,
and maybe they hold resources that need to be freed */
@@ -397,6 +400,7 @@
/* one ref is for destroy, the other for when ep becomes NULL */
gpr_ref_init(&t->refs, 2);
gpr_mu_init(&t->mu);
+ gpr_cv_init(&t->cv);
t->metadata_context = mdctx;
t->str_grpc_timeout =
grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
@@ -405,6 +409,7 @@
t->error_state = ERROR_STATE_NONE;
t->next_stream_id = is_client ? 1 : 2;
t->last_incoming_stream_id = 0;
+ t->destroying = 0;
t->is_client = is_client;
t->outgoing_window = DEFAULT_WINDOW;
t->incoming_window = DEFAULT_WINDOW;
@@ -478,16 +483,18 @@
ref_transport(t);
gpr_mu_unlock(&t->mu);
- ref_transport(t);
- recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
-
sr = setup(arg, &t->base, t->metadata_context);
lock(t);
t->cb = sr.callbacks;
t->cb_user_data = sr.user_data;
t->calling_back = 0;
+ if (t->destroying) gpr_cv_signal(&t->cv);
unlock(t);
+
+ ref_transport(t);
+ recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
+
unref_transport(t);
}
@@ -495,6 +502,10 @@
transport *t = (transport *)gt;
gpr_mu_lock(&t->mu);
+ t->destroying = 1;
+ while (t->calling_back) {
+ gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future);
+ }
t->cb = NULL;
gpr_mu_unlock(&t->mu);
@@ -754,6 +765,7 @@
if (perform_callbacks || call_closed || num_goaways) {
lock(t);
t->calling_back = 0;
+ if (t->destroying) gpr_cv_signal(&t->cv);
unlock(t);
unref_transport(t);
}
@@ -1013,6 +1025,8 @@
int had_outgoing;
char buffer[GPR_LTOA_MIN_BUFSIZE];
+ gpr_log(GPR_DEBUG, "cancel %d", id);
+
if (s) {
/* clear out any unreported input & output: nobody cares anymore */
had_outgoing = s->outgoing_sopb.nops != 0;
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 3f39364..b2fc0c9 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -42,11 +42,12 @@
#include <grpc/support/slice.h>
#include "src/cpp/proto/proto_utils.h"
-#include "src/cpp/stream/stream_context.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
+#include <grpc++/completion_queue.h>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
+#include <grpc++/impl/call.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <google/protobuf/message.h>
@@ -77,103 +78,25 @@
Channel::~Channel() { grpc_channel_destroy(c_channel_); }
-namespace {
-// Pluck the finished event and set to status when it is not nullptr.
-void GetFinalStatus(grpc_completion_queue *cq, void *finished_tag,
- Status *status) {
- grpc_event *ev =
- grpc_completion_queue_pluck(cq, finished_tag, gpr_inf_future);
- if (status) {
- StatusCode error_code = static_cast<StatusCode>(ev->data.finished.status);
- grpc::string details(ev->data.finished.details ? ev->data.finished.details
- : "");
- *status = Status(error_code, details);
- }
- grpc_event_finish(ev);
-}
-} // namespace
-
-// TODO(yangg) more error handling
-Status Channel::StartBlockingRpc(const RpcMethod &method,
- ClientContext *context,
- const google::protobuf::Message &request,
- google::protobuf::Message *result) {
- Status status;
- grpc_call *call = grpc_channel_create_call_old(
- c_channel_, method.name(), target_.c_str(), context->RawDeadline());
- context->set_call(call);
-
- grpc_event *ev;
- void *finished_tag = reinterpret_cast<char *>(call);
- void *metadata_read_tag = reinterpret_cast<char *>(call) + 2;
- void *write_tag = reinterpret_cast<char *>(call) + 3;
- void *halfclose_tag = reinterpret_cast<char *>(call) + 4;
- void *read_tag = reinterpret_cast<char *>(call) + 5;
-
- grpc_completion_queue *cq = grpc_completion_queue_create();
- context->set_cq(cq);
- // add_metadata from context
- //
- // invoke
- GPR_ASSERT(grpc_call_invoke_old(call, cq, metadata_read_tag, finished_tag,
- GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
- // write request
- grpc_byte_buffer *write_buffer = nullptr;
- bool success = SerializeProto(request, &write_buffer);
- if (!success) {
- grpc_call_cancel(call);
- status =
- Status(StatusCode::DATA_LOSS, "Failed to serialize request proto.");
- GetFinalStatus(cq, finished_tag, nullptr);
- return status;
- }
- GPR_ASSERT(grpc_call_start_write_old(call, write_buffer, write_tag,
- GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
- grpc_byte_buffer_destroy(write_buffer);
- ev = grpc_completion_queue_pluck(cq, write_tag, gpr_inf_future);
-
- success = ev->data.write_accepted == GRPC_OP_OK;
- grpc_event_finish(ev);
- if (!success) {
- GetFinalStatus(cq, finished_tag, &status);
- return status;
- }
- // writes done
- GPR_ASSERT(grpc_call_writes_done_old(call, halfclose_tag) == GRPC_CALL_OK);
- ev = grpc_completion_queue_pluck(cq, halfclose_tag, gpr_inf_future);
- grpc_event_finish(ev);
- // start read metadata
- //
- ev = grpc_completion_queue_pluck(cq, metadata_read_tag, gpr_inf_future);
- grpc_event_finish(ev);
- // start read
- GPR_ASSERT(grpc_call_start_read_old(call, read_tag) == GRPC_CALL_OK);
- ev = grpc_completion_queue_pluck(cq, read_tag, gpr_inf_future);
- if (ev->data.read) {
- if (!DeserializeProto(ev->data.read, result)) {
- grpc_event_finish(ev);
- status = Status(StatusCode::DATA_LOSS, "Failed to parse response proto.");
- GetFinalStatus(cq, finished_tag, nullptr);
- return status;
- }
- }
- grpc_event_finish(ev);
-
- // wait status
- GetFinalStatus(cq, finished_tag, &status);
- return status;
+Call Channel::CreateCall(const RpcMethod &method, ClientContext *context,
+ CompletionQueue *cq) {
+ auto c_call =
+ grpc_channel_create_call(
+ c_channel_, cq->cq(), method.name(),
+ context->authority().empty() ? target_.c_str()
+ : context->authority().c_str(),
+ context->RawDeadline());
+ context->set_call(c_call);
+ return Call(c_call, this, cq);
}
-StreamContextInterface *Channel::CreateStream(
- const RpcMethod &method, ClientContext *context,
- const google::protobuf::Message *request,
- google::protobuf::Message *result) {
- grpc_call *call = grpc_channel_create_call_old(
- c_channel_, method.name(), target_.c_str(), context->RawDeadline());
- context->set_call(call);
- grpc_completion_queue *cq = grpc_completion_queue_create();
- context->set_cq(cq);
- return new StreamContext(method, context, request, result);
+void Channel::PerformOpsOnCall(CallOpBuffer *buf, Call *call) {
+ static const size_t MAX_OPS = 8;
+ size_t nops = MAX_OPS;
+ grpc_op ops[MAX_OPS];
+ buf->FillOps(ops, &nops);
+ GPR_ASSERT(GRPC_CALL_OK ==
+ grpc_call_start_batch(call->call(), ops, nops, buf));
}
} // namespace grpc
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index 67d18bf..c31adab 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -42,11 +42,14 @@
struct grpc_channel;
namespace grpc {
+class Call;
+class CallOpBuffer;
class ChannelArguments;
+class CompletionQueue;
class Credentials;
class StreamContextInterface;
-class Channel : public ChannelInterface {
+class Channel final : public ChannelInterface {
public:
Channel(const grpc::string &target, const ChannelArguments &args);
Channel(const grpc::string &target, const std::unique_ptr<Credentials> &creds,
@@ -54,14 +57,9 @@
~Channel() override;
- Status StartBlockingRpc(const RpcMethod &method, ClientContext *context,
- const google::protobuf::Message &request,
- google::protobuf::Message *result) override;
-
- StreamContextInterface *CreateStream(
- const RpcMethod &method, ClientContext *context,
- const google::protobuf::Message *request,
- google::protobuf::Message *result) override;
+ virtual Call CreateCall(const RpcMethod &method, ClientContext *context,
+ CompletionQueue *cq) override;
+ virtual void PerformOpsOnCall(CallOpBuffer *ops, Call *call) override;
private:
const grpc::string target_;
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 7bda2d0..64a8296 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -72,9 +72,13 @@
void ClientContext::AddMetadata(const grpc::string &meta_key,
const grpc::string &meta_value) {
- return;
+ send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));
}
-void ClientContext::StartCancel() {}
+void ClientContext::TryCancel() {
+ if (call_) {
+ grpc_call_cancel(call_);
+ }
+}
} // namespace grpc
diff --git a/src/cpp/client/client_unary_call.cc b/src/cpp/client/client_unary_call.cc
new file mode 100644
index 0000000..284af33
--- /dev/null
+++ b/src/cpp/client/client_unary_call.cc
@@ -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 <grpc++/impl/client_unary_call.h>
+#include <grpc++/impl/call.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/completion_queue.h>
+#include <grpc++/status.h>
+#include <grpc/support/log.h>
+
+namespace grpc {
+
+// Wrapper that performs a blocking unary call
+Status BlockingUnaryCall(ChannelInterface *channel, const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result) {
+ CompletionQueue cq;
+ Call call(channel->CreateCall(method, context, &cq));
+ CallOpBuffer buf;
+ Status status;
+ buf.AddSendInitialMetadata(context);
+ buf.AddSendMessage(request);
+ buf.AddRecvInitialMetadata(&context->recv_initial_metadata_);
+ buf.AddRecvMessage(result);
+ buf.AddClientSendClose();
+ buf.AddClientRecvStatus(&context->trailing_metadata_, &status);
+ call.PerformOps(&buf);
+ GPR_ASSERT((cq.Pluck(&buf) && buf.got_message) || !status.IsOk());
+ return status;
+}
+
+class ClientAsyncRequest final : public CallOpBuffer {
+ public:
+ void FinalizeResult(void **tag, bool *status) override {
+ CallOpBuffer::FinalizeResult(tag, status);
+ delete this;
+ }
+};
+
+void AsyncUnaryCall(ChannelInterface *channel, const RpcMethod &method,
+ ClientContext *context,
+ const google::protobuf::Message &request,
+ google::protobuf::Message *result, Status *status,
+ CompletionQueue *cq, void *tag) {
+ ClientAsyncRequest *buf = new ClientAsyncRequest;
+ buf->Reset(tag);
+ Call call(channel->CreateCall(method, context, cq));
+ buf->AddSendInitialMetadata(context);
+ buf->AddSendMessage(request);
+ buf->AddRecvInitialMetadata(&context->recv_initial_metadata_);
+ buf->AddRecvMessage(result);
+ buf->AddClientSendClose();
+ buf->AddClientRecvStatus(&context->trailing_metadata_, status);
+ call.PerformOps(buf);
+}
+
+} // namespace grpc
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
new file mode 100644
index 0000000..f1142cf
--- /dev/null
+++ b/src/cpp/common/call.cc
@@ -0,0 +1,287 @@
+/*
+ *
+ * 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 <google/protobuf/message.h>
+#include <grpc/support/alloc.h>
+#include <grpc++/impl/call.h>
+#include <grpc++/client_context.h>
+#include <grpc++/channel_interface.h>
+
+#include "src/cpp/proto/proto_utils.h"
+
+namespace grpc {
+
+void CallOpBuffer::Reset(void* next_return_tag) {
+ return_tag_ = next_return_tag;
+
+ send_initial_metadata_ = false;
+ initial_metadata_count_ = 0;
+ gpr_free(initial_metadata_);
+
+ recv_initial_metadata_ = nullptr;
+ recv_initial_metadata_arr_.count = 0;
+
+ send_message_ = nullptr;
+ if (send_message_buf_) {
+ grpc_byte_buffer_destroy(send_message_buf_);
+ send_message_buf_ = nullptr;
+ }
+
+ recv_message_ = nullptr;
+ got_message = false;
+ if (recv_message_buf_) {
+ grpc_byte_buffer_destroy(recv_message_buf_);
+ recv_message_buf_ = nullptr;
+ }
+
+ client_send_close_ = false;
+
+ recv_trailing_metadata_ = nullptr;
+ recv_status_ = nullptr;
+ recv_trailing_metadata_arr_.count = 0;
+
+ status_code_ = GRPC_STATUS_OK;
+
+ send_status_ = nullptr;
+ trailing_metadata_count_ = 0;
+ trailing_metadata_ = nullptr;
+
+ recv_closed_ = nullptr;
+}
+
+CallOpBuffer::~CallOpBuffer() {
+ gpr_free(status_details_);
+ gpr_free(recv_initial_metadata_arr_.metadata);
+ gpr_free(recv_trailing_metadata_arr_.metadata);
+ if (recv_message_buf_) {
+ grpc_byte_buffer_destroy(recv_message_buf_);
+ }
+ if (send_message_buf_) {
+ grpc_byte_buffer_destroy(send_message_buf_);
+ }
+}
+
+namespace {
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+grpc_metadata* FillMetadataArray(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ if (metadata->empty()) {
+ return nullptr;
+ }
+ grpc_metadata* metadata_array =
+ (grpc_metadata*)gpr_malloc(metadata->size() * sizeof(grpc_metadata));
+ size_t i = 0;
+ for (auto iter = metadata->cbegin(); iter != metadata->cend(); ++iter, ++i) {
+ metadata_array[i].key = iter->first.c_str();
+ metadata_array[i].value = iter->second.c_str();
+ metadata_array[i].value_length = iter->second.size();
+ }
+ return metadata_array;
+}
+
+void FillMetadataMap(grpc_metadata_array* arr,
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ for (size_t i = 0; i < arr->count; i++) {
+ // TODO(yangg) handle duplicates?
+ metadata->insert(std::pair<grpc::string, grpc::string>(
+ arr->metadata[i].key,
+ {arr->metadata[i].value, arr->metadata[i].value_length}));
+ }
+ grpc_metadata_array_destroy(arr);
+ grpc_metadata_array_init(arr);
+}
+} // namespace
+
+void CallOpBuffer::AddSendInitialMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ send_initial_metadata_ = true;
+ initial_metadata_count_ = metadata->size();
+ initial_metadata_ = FillMetadataArray(metadata);
+}
+
+void CallOpBuffer::AddRecvInitialMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ recv_initial_metadata_ = metadata;
+}
+
+void CallOpBuffer::AddSendInitialMetadata(ClientContext* ctx) {
+ AddSendInitialMetadata(&ctx->send_initial_metadata_);
+}
+
+void CallOpBuffer::AddSendMessage(const google::protobuf::Message& message) {
+ send_message_ = &message;
+}
+
+void CallOpBuffer::AddRecvMessage(google::protobuf::Message* message) {
+ recv_message_ = message;
+ recv_message_->Clear();
+}
+
+void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; }
+
+void CallOpBuffer::AddServerRecvClose(bool* cancelled) {
+ recv_closed_ = cancelled;
+}
+
+void CallOpBuffer::AddClientRecvStatus(
+ std::multimap<grpc::string, grpc::string>* metadata, Status* status) {
+ recv_trailing_metadata_ = metadata;
+ recv_status_ = status;
+}
+
+void CallOpBuffer::AddServerSendStatus(
+ std::multimap<grpc::string, grpc::string>* metadata, const Status& status) {
+ if (metadata != NULL) {
+ trailing_metadata_count_ = metadata->size();
+ trailing_metadata_ = FillMetadataArray(metadata);
+ } else {
+ trailing_metadata_count_ = 0;
+ }
+ send_status_ = &status;
+}
+
+void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
+ *nops = 0;
+ if (send_initial_metadata_) {
+ ops[*nops].op = GRPC_OP_SEND_INITIAL_METADATA;
+ ops[*nops].data.send_initial_metadata.count = initial_metadata_count_;
+ ops[*nops].data.send_initial_metadata.metadata = initial_metadata_;
+ (*nops)++;
+ }
+ if (recv_initial_metadata_) {
+ ops[*nops].op = GRPC_OP_RECV_INITIAL_METADATA;
+ ops[*nops].data.recv_initial_metadata = &recv_initial_metadata_arr_;
+ (*nops)++;
+ }
+ if (send_message_) {
+ bool success = SerializeProto(*send_message_, &send_message_buf_);
+ if (!success) {
+ abort();
+ // TODO handle parse failure
+ }
+ ops[*nops].op = GRPC_OP_SEND_MESSAGE;
+ ops[*nops].data.send_message = send_message_buf_;
+ (*nops)++;
+ }
+ if (recv_message_) {
+ ops[*nops].op = GRPC_OP_RECV_MESSAGE;
+ ops[*nops].data.recv_message = &recv_message_buf_;
+ (*nops)++;
+ }
+ if (client_send_close_) {
+ ops[*nops].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ (*nops)++;
+ }
+ if (recv_status_) {
+ ops[*nops].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ ops[*nops].data.recv_status_on_client.trailing_metadata =
+ &recv_trailing_metadata_arr_;
+ ops[*nops].data.recv_status_on_client.status = &status_code_;
+ ops[*nops].data.recv_status_on_client.status_details = &status_details_;
+ ops[*nops].data.recv_status_on_client.status_details_capacity =
+ &status_details_capacity_;
+ (*nops)++;
+ }
+ if (send_status_) {
+ ops[*nops].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ ops[*nops].data.send_status_from_server.trailing_metadata_count =
+ trailing_metadata_count_;
+ ops[*nops].data.send_status_from_server.trailing_metadata =
+ trailing_metadata_;
+ ops[*nops].data.send_status_from_server.status =
+ static_cast<grpc_status_code>(send_status_->code());
+ ops[*nops].data.send_status_from_server.status_details =
+ send_status_->details().c_str();
+ (*nops)++;
+ }
+ if (recv_closed_) {
+ ops[*nops].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ ops[*nops].data.recv_close_on_server.cancelled = &cancelled_buf_;
+ (*nops)++;
+ }
+}
+
+void CallOpBuffer::FinalizeResult(void** tag, bool* status) {
+ // Release send buffers.
+ if (send_message_buf_) {
+ grpc_byte_buffer_destroy(send_message_buf_);
+ send_message_buf_ = nullptr;
+ }
+ if (initial_metadata_) {
+ gpr_free(initial_metadata_);
+ initial_metadata_ = nullptr;
+ }
+ if (trailing_metadata_count_) {
+ gpr_free(trailing_metadata_);
+ trailing_metadata_ = nullptr;
+ }
+ // Set user-facing tag.
+ *tag = return_tag_;
+ // Process received initial metadata
+ if (recv_initial_metadata_) {
+ FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
+ }
+ // Parse received message if any.
+ if (recv_message_) {
+ if (recv_message_buf_) {
+ got_message = *status;
+ *status = *status && DeserializeProto(recv_message_buf_, recv_message_);
+ grpc_byte_buffer_destroy(recv_message_buf_);
+ recv_message_buf_ = nullptr;
+ } else {
+ // Read failed
+ got_message = false;
+ *status = false;
+ }
+ }
+ // Parse received status.
+ if (recv_status_) {
+ FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
+ *recv_status_ = Status(
+ static_cast<StatusCode>(status_code_),
+ status_details_ ? grpc::string(status_details_) : grpc::string());
+ }
+ if (recv_closed_) {
+ *recv_closed_ = cancelled_buf_ != 0;
+ }
+}
+
+Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
+ : call_hook_(call_hook), cq_(cq), call_(call) {}
+
+void Call::PerformOps(CallOpBuffer* buffer) {
+ call_hook_->PerformOpsOnCall(buffer, this);
+}
+
+} // namespace grpc
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index f06da9b..4419b4b 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -1,5 +1,4 @@
/*
- *
* Copyright 2014, Google Inc.
* All rights reserved.
*
@@ -33,80 +32,54 @@
#include <grpc++/completion_queue.h>
+#include <memory>
+
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/cpp/util/time.h"
-#include <grpc++/async_server_context.h>
namespace grpc {
CompletionQueue::CompletionQueue() { cq_ = grpc_completion_queue_create(); }
+CompletionQueue::CompletionQueue(grpc_completion_queue *take) : cq_(take) {}
+
CompletionQueue::~CompletionQueue() { grpc_completion_queue_destroy(cq_); }
void CompletionQueue::Shutdown() { grpc_completion_queue_shutdown(cq_); }
-CompletionQueue::CompletionType CompletionQueue::Next(void **tag) {
- grpc_event *ev;
- CompletionType return_type;
- bool success;
+// Helper class so we can declare a unique_ptr with grpc_event
+class EventDeleter {
+ public:
+ void operator()(grpc_event *ev) {
+ if (ev) grpc_event_finish(ev);
+ }
+};
- ev = grpc_completion_queue_next(cq_, gpr_inf_future);
- if (!ev) {
- gpr_log(GPR_ERROR, "no next event in queue");
- abort();
+bool CompletionQueue::Next(void **tag, bool *ok) {
+ std::unique_ptr<grpc_event, EventDeleter> ev;
+
+ ev.reset(grpc_completion_queue_next(cq_, gpr_inf_future));
+ if (ev->type == GRPC_QUEUE_SHUTDOWN) {
+ return false;
}
- switch (ev->type) {
- case GRPC_QUEUE_SHUTDOWN:
- return_type = QUEUE_CLOSED;
- break;
- case GRPC_READ:
- *tag = ev->tag;
- if (ev->data.read) {
- success = static_cast<AsyncServerContext *>(ev->tag)
- ->ParseRead(ev->data.read);
- return_type = success ? SERVER_READ_OK : SERVER_READ_ERROR;
- } else {
- return_type = SERVER_READ_ERROR;
- }
- break;
- case GRPC_WRITE_ACCEPTED:
- *tag = ev->tag;
- if (ev->data.write_accepted != GRPC_OP_ERROR) {
- return_type = SERVER_WRITE_OK;
- } else {
- return_type = SERVER_WRITE_ERROR;
- }
- break;
- case GRPC_SERVER_RPC_NEW:
- GPR_ASSERT(!ev->tag);
- // Finishing the pending new rpcs after the server has been shutdown.
- if (!ev->call) {
- *tag = nullptr;
- } else {
- *tag = new AsyncServerContext(
- ev->call, ev->data.server_rpc_new.method,
- ev->data.server_rpc_new.host,
- Timespec2Timepoint(ev->data.server_rpc_new.deadline));
- }
- return_type = SERVER_RPC_NEW;
- break;
- case GRPC_FINISHED:
- *tag = ev->tag;
- return_type = RPC_END;
- break;
- case GRPC_FINISH_ACCEPTED:
- *tag = ev->tag;
- return_type = HALFCLOSE_OK;
- break;
- default:
- // We do not handle client side messages now
- gpr_log(GPR_ERROR, "client-side messages aren't supported yet");
- abort();
- }
- grpc_event_finish(ev);
- return return_type;
+ auto cq_tag = static_cast<CompletionQueueTag *>(ev->tag);
+ *ok = ev->data.op_complete == GRPC_OP_OK;
+ *tag = cq_tag;
+ cq_tag->FinalizeResult(tag, ok);
+ return true;
+}
+
+bool CompletionQueue::Pluck(CompletionQueueTag *tag) {
+ std::unique_ptr<grpc_event, EventDeleter> ev;
+
+ ev.reset(grpc_completion_queue_pluck(cq_, tag, gpr_inf_future));
+ bool ok = ev->data.op_complete == GRPC_OP_OK;
+ void *ignored = tag;
+ tag->FinalizeResult(&ignored, &ok);
+ GPR_ASSERT(ignored == tag);
+ return ok;
}
} // namespace grpc
diff --git a/src/cpp/server/async_server.cc b/src/cpp/server/async_server.cc
deleted file mode 100644
index 86faa07..0000000
--- a/src/cpp/server/async_server.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *
- * 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++/async_server.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc++/completion_queue.h>
-
-namespace grpc {
-
-AsyncServer::AsyncServer(CompletionQueue *cc)
- : started_(false), shutdown_(false) {
- server_ = grpc_server_create(cc->cq(), nullptr);
-}
-
-AsyncServer::~AsyncServer() {
- std::unique_lock<std::mutex> lock(shutdown_mu_);
- if (started_ && !shutdown_) {
- lock.unlock();
- Shutdown();
- }
- grpc_server_destroy(server_);
-}
-
-void AsyncServer::AddPort(const grpc::string &addr) {
- GPR_ASSERT(!started_);
- int success = grpc_server_add_http2_port(server_, addr.c_str());
- GPR_ASSERT(success);
-}
-
-void AsyncServer::Start() {
- GPR_ASSERT(!started_);
- started_ = true;
- grpc_server_start(server_);
-}
-
-void AsyncServer::RequestOneRpc() {
- GPR_ASSERT(started_);
- std::unique_lock<std::mutex> lock(shutdown_mu_);
- if (shutdown_) {
- return;
- }
- lock.unlock();
- grpc_call_error err = grpc_server_request_call_old(server_, nullptr);
- GPR_ASSERT(err == GRPC_CALL_OK);
-}
-
-void AsyncServer::Shutdown() {
- std::unique_lock<std::mutex> lock(shutdown_mu_);
- if (started_ && !shutdown_) {
- shutdown_ = true;
- lock.unlock();
- // TODO(yangg) should we shutdown without start?
- grpc_server_shutdown(server_);
- }
-}
-
-} // namespace grpc
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
index 886e794..096eb7a 100644
--- a/src/cpp/server/async_server_context.cc
+++ b/src/cpp/server/async_server_context.cc
@@ -54,8 +54,8 @@
void AsyncServerContext::Accept(grpc_completion_queue *cq) {
GPR_ASSERT(grpc_call_server_accept_old(call_, cq, this) == GRPC_CALL_OK);
- GPR_ASSERT(grpc_call_server_end_initial_metadata_old(call_, GRPC_WRITE_BUFFER_HINT) ==
- GRPC_CALL_OK);
+ GPR_ASSERT(grpc_call_server_end_initial_metadata_old(
+ call_, GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
}
bool AsyncServerContext::StartRead(google::protobuf::Message *request) {
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 1abdf70..ee9a1da 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -37,25 +37,25 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
-#include "src/cpp/server/server_rpc_handler.h"
-#include "src/cpp/server/thread_pool.h"
-#include <grpc++/async_server_context.h>
#include <grpc++/completion_queue.h>
#include <grpc++/impl/rpc_service_method.h>
+#include <grpc++/impl/service_type.h>
+#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
+#include <grpc++/thread_pool_interface.h>
+
+#include "src/cpp/proto/proto_utils.h"
+#include "src/cpp/util/time.h"
namespace grpc {
-// TODO(rocking): consider a better default value like num of cores.
-static const int kNumThreads = 4;
-
-Server::Server(ThreadPoolInterface *thread_pool, ServerCredentials *creds)
+Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
+ ServerCredentials* creds)
: started_(false),
shutdown_(false),
num_running_cb_(0),
- thread_pool_(thread_pool == nullptr ? new ThreadPool(kNumThreads)
- : thread_pool),
- thread_pool_owned_(thread_pool == nullptr),
+ thread_pool_(thread_pool),
+ thread_pool_owned_(thread_pool_owned),
secure_(creds != nullptr) {
if (creds) {
server_ =
@@ -75,6 +75,8 @@
if (started_ && !shutdown_) {
lock.unlock();
Shutdown();
+ } else {
+ lock.unlock();
}
grpc_server_destroy(server_);
if (thread_pool_owned_) {
@@ -82,37 +84,180 @@
}
}
-void Server::RegisterService(RpcService *service) {
+bool Server::RegisterService(RpcService* service) {
for (int i = 0; i < service->GetMethodCount(); ++i) {
- RpcServiceMethod *method = service->GetMethod(i);
- method_map_.insert(std::make_pair(method->name(), method));
+ RpcServiceMethod* method = service->GetMethod(i);
+ void* tag =
+ grpc_server_register_method(server_, method->name(), nullptr, cq_.cq());
+ if (!tag) {
+ gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
+ method->name());
+ return false;
+ }
+ sync_methods_.emplace_back(method, tag);
}
+ return true;
}
-void Server::AddPort(const grpc::string &addr) {
+bool Server::RegisterAsyncService(AsynchronousService* service) {
+ GPR_ASSERT(service->dispatch_impl_ == nullptr &&
+ "Can only register an asynchronous service against one server.");
+ service->dispatch_impl_ = this;
+ service->request_args_ = new void* [service->method_count_];
+ for (size_t i = 0; i < service->method_count_; ++i) {
+ void* tag =
+ grpc_server_register_method(server_, service->method_names_[i], nullptr,
+ service->completion_queue()->cq());
+ if (!tag) {
+ gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
+ service->method_names_[i]);
+ return false;
+ }
+ service->request_args_[i] = tag;
+ }
+ return true;
+}
+
+int Server::AddPort(const grpc::string& addr) {
GPR_ASSERT(!started_);
- int success;
if (secure_) {
- success = grpc_server_add_secure_http2_port(server_, addr.c_str());
+ return grpc_server_add_secure_http2_port(server_, addr.c_str());
} else {
- success = grpc_server_add_http2_port(server_, addr.c_str());
+ return grpc_server_add_http2_port(server_, addr.c_str());
}
- GPR_ASSERT(success);
}
-void Server::Start() {
+class Server::SyncRequest final : public CompletionQueueTag {
+ public:
+ SyncRequest(RpcServiceMethod* method, void* tag)
+ : method_(method),
+ tag_(tag),
+ has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
+ method->method_type() ==
+ RpcMethod::SERVER_STREAMING),
+ has_response_payload_(method->method_type() == RpcMethod::NORMAL_RPC ||
+ method->method_type() ==
+ RpcMethod::CLIENT_STREAMING) {
+ grpc_metadata_array_init(&request_metadata_);
+ }
+
+ static SyncRequest* Wait(CompletionQueue* cq, bool* ok) {
+ void* tag = nullptr;
+ *ok = false;
+ if (!cq->Next(&tag, ok)) {
+ return nullptr;
+ }
+ auto* mrd = static_cast<SyncRequest*>(tag);
+ GPR_ASSERT(mrd->in_flight_);
+ return mrd;
+ }
+
+ void Request(grpc_server* server) {
+ GPR_ASSERT(!in_flight_);
+ in_flight_ = true;
+ cq_ = grpc_completion_queue_create();
+ GPR_ASSERT(GRPC_CALL_OK ==
+ grpc_server_request_registered_call(
+ server, tag_, &call_, &deadline_, &request_metadata_,
+ has_request_payload_ ? &request_payload_ : nullptr, cq_,
+ this));
+ }
+
+ void FinalizeResult(void** tag, bool* status) override {
+ if (!*status) {
+ grpc_completion_queue_destroy(cq_);
+ }
+ }
+
+ class CallData final {
+ public:
+ explicit CallData(Server* server, SyncRequest* mrd)
+ : cq_(mrd->cq_),
+ call_(mrd->call_, server, &cq_),
+ ctx_(mrd->deadline_, mrd->request_metadata_.metadata,
+ mrd->request_metadata_.count),
+ has_request_payload_(mrd->has_request_payload_),
+ has_response_payload_(mrd->has_response_payload_),
+ request_payload_(mrd->request_payload_),
+ method_(mrd->method_) {
+ ctx_.call_ = mrd->call_;
+ GPR_ASSERT(mrd->in_flight_);
+ mrd->in_flight_ = false;
+ mrd->request_metadata_.count = 0;
+ }
+
+ ~CallData() {
+ if (has_request_payload_ && request_payload_) {
+ grpc_byte_buffer_destroy(request_payload_);
+ }
+ }
+
+ void Run() {
+ std::unique_ptr<google::protobuf::Message> req;
+ std::unique_ptr<google::protobuf::Message> res;
+ if (has_request_payload_) {
+ req.reset(method_->AllocateRequestProto());
+ if (!DeserializeProto(request_payload_, req.get())) {
+ abort(); // for now
+ }
+ }
+ if (has_response_payload_) {
+ res.reset(method_->AllocateResponseProto());
+ }
+ auto status = method_->handler()->RunHandler(
+ MethodHandler::HandlerParameter(&call_, &ctx_, req.get(), res.get()));
+ CallOpBuffer buf;
+ if (!ctx_.sent_initial_metadata_) {
+ buf.AddSendInitialMetadata(&ctx_.initial_metadata_);
+ }
+ if (has_response_payload_) {
+ buf.AddSendMessage(*res);
+ }
+ buf.AddServerSendStatus(&ctx_.trailing_metadata_, status);
+ bool cancelled;
+ buf.AddServerRecvClose(&cancelled);
+ call_.PerformOps(&buf);
+ GPR_ASSERT(cq_.Pluck(&buf));
+ }
+
+ private:
+ CompletionQueue cq_;
+ Call call_;
+ ServerContext ctx_;
+ const bool has_request_payload_;
+ const bool has_response_payload_;
+ grpc_byte_buffer* request_payload_;
+ RpcServiceMethod* const method_;
+ };
+
+ private:
+ RpcServiceMethod* const method_;
+ void* const tag_;
+ bool in_flight_ = false;
+ const bool has_request_payload_;
+ const bool has_response_payload_;
+ grpc_call* call_;
+ gpr_timespec deadline_;
+ grpc_metadata_array request_metadata_;
+ grpc_byte_buffer* request_payload_;
+ grpc_completion_queue* cq_;
+};
+
+bool Server::Start() {
GPR_ASSERT(!started_);
started_ = true;
grpc_server_start(server_);
// Start processing rpcs.
- ScheduleCallback();
-}
+ if (!sync_methods_.empty()) {
+ for (auto& m : sync_methods_) {
+ m.Request(server_);
+ }
-void Server::AllowOneRpc() {
- GPR_ASSERT(started_);
- grpc_call_error err = grpc_server_request_call_old(server_, nullptr);
- GPR_ASSERT(err == GRPC_CALL_OK);
+ ScheduleCallback();
+ }
+
+ return true;
}
void Server::Shutdown() {
@@ -121,6 +266,7 @@
if (started_ && !shutdown_) {
shutdown_ = true;
grpc_server_shutdown(server_);
+ cq_.Shutdown();
// Wait for running callbacks to finish.
while (num_running_cb_ != 0) {
@@ -128,12 +274,85 @@
}
}
}
+}
- // Shutdown the completion queue.
- cq_.Shutdown();
- void *tag = nullptr;
- CompletionQueue::CompletionType t = cq_.Next(&tag);
- GPR_ASSERT(t == CompletionQueue::QUEUE_CLOSED);
+void Server::PerformOpsOnCall(CallOpBuffer* buf, Call* call) {
+ static const size_t MAX_OPS = 8;
+ size_t nops = MAX_OPS;
+ grpc_op ops[MAX_OPS];
+ buf->FillOps(ops, &nops);
+ GPR_ASSERT(GRPC_CALL_OK ==
+ grpc_call_start_batch(call->call(), ops, nops, buf));
+}
+
+class Server::AsyncRequest final : public CompletionQueueTag {
+ public:
+ AsyncRequest(Server* server, void* registered_method, ServerContext* ctx,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream, CompletionQueue* cq,
+ void* tag)
+ : tag_(tag),
+ request_(request),
+ stream_(stream),
+ cq_(cq),
+ ctx_(ctx),
+ server_(server) {
+ memset(&array_, 0, sizeof(array_));
+ grpc_server_request_registered_call(
+ server->server_, registered_method, &call_, &deadline_, &array_,
+ request ? &payload_ : nullptr, cq->cq(), this);
+ }
+
+ ~AsyncRequest() {
+ if (payload_) {
+ grpc_byte_buffer_destroy(payload_);
+ }
+ grpc_metadata_array_destroy(&array_);
+ }
+
+ void FinalizeResult(void** tag, bool* status) override {
+ *tag = tag_;
+ if (*status && request_) {
+ if (payload_) {
+ *status = *status && DeserializeProto(payload_, request_);
+ } else {
+ *status = false;
+ }
+ }
+ if (*status) {
+ ctx_->deadline_ = Timespec2Timepoint(deadline_);
+ for (size_t i = 0; i < array_.count; i++) {
+ ctx_->client_metadata_.insert(std::make_pair(
+ grpc::string(array_.metadata[i].key),
+ grpc::string(
+ array_.metadata[i].value,
+ array_.metadata[i].value + array_.metadata[i].value_length)));
+ }
+ }
+ ctx_->call_ = call_;
+ Call call(call_, server_, cq_);
+ stream_->BindCall(&call);
+ delete this;
+ }
+
+ private:
+ void* const tag_;
+ ::google::protobuf::Message* const request_;
+ ServerAsyncStreamingInterface* const stream_;
+ CompletionQueue* const cq_;
+ ServerContext* const ctx_;
+ Server* const server_;
+ grpc_call* call_ = nullptr;
+ gpr_timespec deadline_;
+ grpc_metadata_array array_;
+ grpc_byte_buffer* payload_ = nullptr;
+};
+
+void Server::RequestAsyncCall(void* registered_method, ServerContext* context,
+ ::google::protobuf::Message* request,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ new AsyncRequest(this, registered_method, context, request, stream, cq, tag);
}
void Server::ScheduleCallback() {
@@ -141,30 +360,21 @@
std::unique_lock<std::mutex> lock(mu_);
num_running_cb_++;
}
- std::function<void()> callback = std::bind(&Server::RunRpc, this);
- thread_pool_->ScheduleCallback(callback);
+ thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
}
void Server::RunRpc() {
// Wait for one more incoming rpc.
- void *tag = nullptr;
- AllowOneRpc();
- CompletionQueue::CompletionType t = cq_.Next(&tag);
- GPR_ASSERT(t == CompletionQueue::SERVER_RPC_NEW);
-
- AsyncServerContext *server_context = static_cast<AsyncServerContext *>(tag);
- // server_context could be nullptr during server shutdown.
- if (server_context != nullptr) {
- // Schedule a new callback to handle more rpcs.
+ bool ok;
+ auto* mrd = SyncRequest::Wait(&cq_, &ok);
+ if (mrd) {
ScheduleCallback();
+ if (ok) {
+ SyncRequest::CallData cd(this, mrd);
+ mrd->Request(server_);
- RpcServiceMethod *method = nullptr;
- auto iter = method_map_.find(server_context->method());
- if (iter != method_map_.end()) {
- method = iter->second;
+ cd.Run();
}
- ServerRpcHandler rpc_handler(server_context, method);
- rpc_handler.StartRpc();
}
{
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index add22cc..dd23e92 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -33,40 +33,70 @@
#include <grpc++/server_builder.h>
+#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
+#include <grpc++/impl/service_type.h>
#include <grpc++/server.h>
+#include "src/cpp/server/thread_pool.h"
namespace grpc {
-ServerBuilder::ServerBuilder() : thread_pool_(nullptr) {}
+ServerBuilder::ServerBuilder() {}
-void ServerBuilder::RegisterService(RpcService *service) {
- services_.push_back(service);
+void ServerBuilder::RegisterService(SynchronousService* service) {
+ services_.push_back(service->service());
}
-void ServerBuilder::AddPort(const grpc::string &addr) {
+void ServerBuilder::RegisterAsyncService(AsynchronousService* service) {
+ async_services_.push_back(service);
+}
+
+void ServerBuilder::AddPort(const grpc::string& addr) {
ports_.push_back(addr);
}
void ServerBuilder::SetCredentials(
- const std::shared_ptr<ServerCredentials> &creds) {
+ const std::shared_ptr<ServerCredentials>& creds) {
GPR_ASSERT(!creds_);
creds_ = creds;
}
-void ServerBuilder::SetThreadPool(ThreadPoolInterface *thread_pool) {
+void ServerBuilder::SetThreadPool(ThreadPoolInterface* thread_pool) {
thread_pool_ = thread_pool;
}
std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
- std::unique_ptr<Server> server(new Server(thread_pool_, creds_.get()));
- for (auto *service : services_) {
- server->RegisterService(service);
+ bool thread_pool_owned = false;
+ if (!async_services_.empty() && !services_.empty()) {
+ gpr_log(GPR_ERROR, "Mixing async and sync services is unsupported for now");
+ return nullptr;
}
- for (auto &port : ports_) {
- server->AddPort(port);
+ if (!thread_pool_ && services_.size()) {
+ int cores = gpr_cpu_num_cores();
+ if (!cores) cores = 4;
+ thread_pool_ = new ThreadPool(cores);
+ thread_pool_owned = true;
}
- server->Start();
+ std::unique_ptr<Server> server(
+ new Server(thread_pool_, thread_pool_owned, creds_.get()));
+ for (auto* service : services_) {
+ if (!server->RegisterService(service)) {
+ return nullptr;
+ }
+ }
+ for (auto* service : async_services_) {
+ if (!server->RegisterAsyncService(service)) {
+ return nullptr;
+ }
+ }
+ for (auto& port : ports_) {
+ if (!server->AddPort(port)) {
+ return nullptr;
+ }
+ }
+ if (!server->Start()) {
+ return nullptr;
+ }
return server;
}
diff --git a/src/cpp/server/server_context_impl.h b/src/cpp/server/server_context.cc
similarity index 72%
rename from src/cpp/server/server_context_impl.h
rename to src/cpp/server/server_context.cc
index c6016b7..21a61af 100644
--- a/src/cpp/server/server_context_impl.h
+++ b/src/cpp/server/server_context.cc
@@ -31,31 +31,30 @@
*
*/
-#ifndef __GRPCPP_INTERNAL_SERVER_SERVER_CONTEXT_IMPL_H_
-#define __GRPCPP_INTERNAL_SERVER_SERVER_CONTEXT_IMPL_H_
-
#include <grpc++/server_context.h>
-
-#include <chrono>
-
-#include <grpc/support/time.h>
+#include <grpc++/impl/call.h>
+#include <grpc/grpc.h>
+#include "src/cpp/util/time.h"
namespace grpc {
-class ServerContextImpl : public ServerContext {
- public:
- explicit ServerContextImpl(std::chrono::system_clock::time_point deadline)
- : absolute_deadline_(deadline) {}
- ~ServerContextImpl() {}
+ServerContext::ServerContext() {}
- std::chrono::system_clock::time_point absolute_deadline() const {
- return absolute_deadline_;
+ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata *metadata,
+ size_t metadata_count)
+ : deadline_(Timespec2Timepoint(deadline)) {
+ for (size_t i = 0; i < metadata_count; i++) {
+ client_metadata_.insert(std::make_pair(
+ grpc::string(metadata[i].key),
+ grpc::string(metadata[i].value,
+ metadata[i].value + metadata[i].value_length)));
}
+}
- private:
- std::chrono::system_clock::time_point absolute_deadline_;
-};
+ServerContext::~ServerContext() {
+ if (call_) {
+ grpc_call_destroy(call_);
+ }
+}
} // namespace grpc
-
-#endif // __GRPCPP_INTERNAL_SERVER_SERVER_CONTEXT_IMPL_H_
diff --git a/src/cpp/server/server_context_impl.cc b/src/cpp/server/server_context_impl.cc
deleted file mode 100644
index 467cc80..0000000
--- a/src/cpp/server/server_context_impl.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *
- * 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/cpp/server/server_context_impl.h"
-
-namespace grpc {} // namespace grpc
diff --git a/src/cpp/server/server_rpc_handler.cc b/src/cpp/server/server_rpc_handler.cc
deleted file mode 100644
index bf02de8..0000000
--- a/src/cpp/server/server_rpc_handler.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * 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/cpp/server/server_rpc_handler.h"
-
-#include <grpc/support/log.h>
-#include "src/cpp/server/server_context_impl.h"
-#include "src/cpp/stream/stream_context.h"
-#include <grpc++/async_server_context.h>
-#include <grpc++/impl/rpc_service_method.h>
-
-namespace grpc {
-
-ServerRpcHandler::ServerRpcHandler(AsyncServerContext *async_server_context,
- RpcServiceMethod *method)
- : async_server_context_(async_server_context), method_(method) {}
-
-void ServerRpcHandler::StartRpc() {
- if (method_ == nullptr) {
- // Method not supported, finish the rpc with error.
- // TODO(rocking): do we need to call read to consume the request?
- FinishRpc(Status(StatusCode::UNIMPLEMENTED, "No such method."));
- return;
- }
-
- ServerContextImpl user_context(async_server_context_->absolute_deadline());
-
- if (method_->method_type() == RpcMethod::NORMAL_RPC) {
- // Start the rpc on this dedicated completion queue.
- async_server_context_->Accept(cq_.cq());
-
- // Allocate request and response.
- std::unique_ptr<google::protobuf::Message> request(
- method_->AllocateRequestProto());
- std::unique_ptr<google::protobuf::Message> response(
- method_->AllocateResponseProto());
-
- // Read request
- async_server_context_->StartRead(request.get());
- auto type = WaitForNextEvent();
- GPR_ASSERT(type == CompletionQueue::SERVER_READ_OK);
-
- // Run the application's rpc handler
- MethodHandler *handler = method_->handler();
- Status status = handler->RunHandler(MethodHandler::HandlerParameter(
- &user_context, request.get(), response.get()));
-
- if (status.IsOk()) {
- // Send the response if we get an ok status.
- async_server_context_->StartWrite(*response, GRPC_WRITE_BUFFER_HINT);
- type = WaitForNextEvent();
- if (type != CompletionQueue::SERVER_WRITE_OK) {
- status = Status(StatusCode::INTERNAL, "Error writing response.");
- }
- }
-
- FinishRpc(status);
- } else {
- // Allocate request and response.
- // TODO(yangg) maybe not allocate both when not needed?
- std::unique_ptr<google::protobuf::Message> request(
- method_->AllocateRequestProto());
- std::unique_ptr<google::protobuf::Message> response(
- method_->AllocateResponseProto());
-
- StreamContext stream_context(*method_, async_server_context_->call(),
- cq_.cq(), request.get(), response.get());
-
- // Run the application's rpc handler
- MethodHandler *handler = method_->handler();
- Status status = handler->RunHandler(MethodHandler::HandlerParameter(
- &user_context, request.get(), response.get(), &stream_context));
- if (status.IsOk() &&
- method_->method_type() == RpcMethod::CLIENT_STREAMING) {
- stream_context.Write(response.get(), false);
- }
- // TODO(yangg) Do we need to consider the status in stream_context?
- FinishRpc(status);
- }
-}
-
-CompletionQueue::CompletionType ServerRpcHandler::WaitForNextEvent() {
- void *tag = nullptr;
- CompletionQueue::CompletionType type = cq_.Next(&tag);
- if (type != CompletionQueue::QUEUE_CLOSED &&
- type != CompletionQueue::RPC_END) {
- GPR_ASSERT(static_cast<AsyncServerContext *>(tag) ==
- async_server_context_.get());
- }
- return type;
-}
-
-void ServerRpcHandler::FinishRpc(const Status &status) {
- async_server_context_->StartWriteStatus(status);
- CompletionQueue::CompletionType type;
-
- // HALFCLOSE_OK and RPC_END events come in either order.
- type = WaitForNextEvent();
- GPR_ASSERT(type == CompletionQueue::HALFCLOSE_OK ||
- type == CompletionQueue::RPC_END);
- type = WaitForNextEvent();
- GPR_ASSERT(type == CompletionQueue::HALFCLOSE_OK ||
- type == CompletionQueue::RPC_END);
-
- cq_.Shutdown();
- type = WaitForNextEvent();
- GPR_ASSERT(type == CompletionQueue::QUEUE_CLOSED);
-}
-
-} // namespace grpc
diff --git a/src/cpp/server/server_rpc_handler.h b/src/cpp/server/server_rpc_handler.h
deleted file mode 100644
index a43e07d..0000000
--- a/src/cpp/server/server_rpc_handler.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- * 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 __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
-#define __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
-
-#include <memory>
-
-#include <grpc++/completion_queue.h>
-#include <grpc++/status.h>
-
-namespace grpc {
-
-class AsyncServerContext;
-class RpcServiceMethod;
-
-class ServerRpcHandler {
- public:
- // Takes ownership of async_server_context.
- ServerRpcHandler(AsyncServerContext *async_server_context,
- RpcServiceMethod *method);
-
- void StartRpc();
-
- private:
- CompletionQueue::CompletionType WaitForNextEvent();
- void FinishRpc(const Status &status);
-
- std::unique_ptr<AsyncServerContext> async_server_context_;
- RpcServiceMethod *method_;
- CompletionQueue cq_;
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h
index c53f7a7..8a28c87 100644
--- a/src/cpp/server/thread_pool.h
+++ b/src/cpp/server/thread_pool.h
@@ -44,12 +44,12 @@
namespace grpc {
-class ThreadPool : public ThreadPoolInterface {
+class ThreadPool final : public ThreadPoolInterface {
public:
explicit ThreadPool(int num_threads);
~ThreadPool();
- void ScheduleCallback(const std::function<void()> &callback) final;
+ void ScheduleCallback(const std::function<void()> &callback) override;
private:
std::mutex mu_;
diff --git a/src/cpp/stream/stream_context.cc b/src/cpp/stream/stream_context.cc
deleted file mode 100644
index e4f344d..0000000
--- a/src/cpp/stream/stream_context.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *
- * 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/cpp/stream/stream_context.h"
-
-#include <grpc/support/log.h>
-#include "src/cpp/proto/proto_utils.h"
-#include "src/cpp/util/time.h"
-#include <grpc++/client_context.h>
-#include <grpc++/config.h>
-#include <grpc++/impl/rpc_method.h>
-#include <google/protobuf/message.h>
-
-namespace grpc {
-
-// Client only ctor
-StreamContext::StreamContext(const RpcMethod &method, ClientContext *context,
- const google::protobuf::Message *request,
- google::protobuf::Message *result)
- : is_client_(true),
- method_(&method),
- call_(context->call()),
- cq_(context->cq()),
- request_(const_cast<google::protobuf::Message *>(request)),
- result_(result),
- peer_halfclosed_(false),
- self_halfclosed_(false) {
- GPR_ASSERT(method_->method_type() != RpcMethod::RpcType::NORMAL_RPC);
-}
-
-// Server only ctor
-StreamContext::StreamContext(const RpcMethod &method, grpc_call *call,
- grpc_completion_queue *cq,
- google::protobuf::Message *request,
- google::protobuf::Message *result)
- : is_client_(false),
- method_(&method),
- call_(call),
- cq_(cq),
- request_(request),
- result_(result),
- peer_halfclosed_(false),
- self_halfclosed_(false) {
- GPR_ASSERT(method_->method_type() != RpcMethod::RpcType::NORMAL_RPC);
-}
-
-StreamContext::~StreamContext() {}
-
-void StreamContext::Start(bool buffered) {
- if (is_client_) {
- // TODO(yangg) handle metadata send path
- int flag = buffered ? GRPC_WRITE_BUFFER_HINT : 0;
- grpc_call_error error = grpc_call_invoke_old(
- call(), cq(), client_metadata_read_tag(), finished_tag(), flag);
- GPR_ASSERT(GRPC_CALL_OK == error);
- } else {
- // TODO(yangg) metadata needs to be added before accept
- // TODO(yangg) correctly set flag to accept
- GPR_ASSERT(grpc_call_server_accept_old(call(), cq(), finished_tag()) ==
- GRPC_CALL_OK);
- GPR_ASSERT(grpc_call_server_end_initial_metadata_old(call(), 0) ==
- GRPC_CALL_OK);
- }
-}
-
-bool StreamContext::Read(google::protobuf::Message *msg) {
- // TODO(yangg) check peer_halfclosed_ here for possible early return.
- grpc_call_error err = grpc_call_start_read_old(call(), read_tag());
- GPR_ASSERT(err == GRPC_CALL_OK);
- grpc_event *read_ev =
- grpc_completion_queue_pluck(cq(), read_tag(), gpr_inf_future);
- GPR_ASSERT(read_ev->type == GRPC_READ);
- bool ret = true;
- if (read_ev->data.read) {
- if (!DeserializeProto(read_ev->data.read, msg)) {
- ret = false;
- grpc_call_cancel_with_status(call(), GRPC_STATUS_DATA_LOSS,
- "Failed to parse incoming proto");
- }
- } else {
- ret = false;
- peer_halfclosed_ = true;
- }
- grpc_event_finish(read_ev);
- return ret;
-}
-
-bool StreamContext::Write(const google::protobuf::Message *msg, bool is_last) {
- // TODO(yangg) check self_halfclosed_ for possible early return.
- bool ret = true;
- grpc_event *ev = nullptr;
-
- if (msg) {
- grpc_byte_buffer *out_buf = nullptr;
- if (!SerializeProto(*msg, &out_buf)) {
- grpc_call_cancel_with_status(call(), GRPC_STATUS_INVALID_ARGUMENT,
- "Failed to serialize outgoing proto");
- return false;
- }
- int flag = is_last ? GRPC_WRITE_BUFFER_HINT : 0;
- grpc_call_error err =
- grpc_call_start_write_old(call(), out_buf, write_tag(), flag);
- grpc_byte_buffer_destroy(out_buf);
- GPR_ASSERT(err == GRPC_CALL_OK);
-
- ev = grpc_completion_queue_pluck(cq(), write_tag(), gpr_inf_future);
- GPR_ASSERT(ev->type == GRPC_WRITE_ACCEPTED);
-
- ret = ev->data.write_accepted == GRPC_OP_OK;
- grpc_event_finish(ev);
- }
- if (ret && is_last) {
- grpc_call_error err = grpc_call_writes_done_old(call(), halfclose_tag());
- GPR_ASSERT(err == GRPC_CALL_OK);
- ev = grpc_completion_queue_pluck(cq(), halfclose_tag(), gpr_inf_future);
- GPR_ASSERT(ev->type == GRPC_FINISH_ACCEPTED);
- grpc_event_finish(ev);
-
- self_halfclosed_ = true;
- } else if (!ret) { // Stream broken
- self_halfclosed_ = true;
- peer_halfclosed_ = true;
- }
-
- return ret;
-}
-
-const Status &StreamContext::Wait() {
- // TODO(yangg) properly support metadata
- grpc_event *metadata_ev = grpc_completion_queue_pluck(
- cq(), client_metadata_read_tag(), gpr_inf_future);
- grpc_event_finish(metadata_ev);
- // TODO(yangg) protect states by a mutex, including other places.
- if (!self_halfclosed_ || !peer_halfclosed_) {
- Cancel();
- }
- grpc_event *finish_ev =
- grpc_completion_queue_pluck(cq(), finished_tag(), gpr_inf_future);
- GPR_ASSERT(finish_ev->type == GRPC_FINISHED);
- final_status_ = Status(
- static_cast<StatusCode>(finish_ev->data.finished.status),
- finish_ev->data.finished.details ? finish_ev->data.finished.details : "");
- grpc_event_finish(finish_ev);
- return final_status_;
-}
-
-void StreamContext::Cancel() { grpc_call_cancel(call()); }
-
-} // namespace grpc
diff --git a/src/cpp/stream/stream_context.h b/src/cpp/stream/stream_context.h
deleted file mode 100644
index 8def589..0000000
--- a/src/cpp/stream/stream_context.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *
- * 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 __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
-#define __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
-
-#include <grpc/grpc.h>
-#include <grpc++/status.h>
-#include <grpc++/stream_context_interface.h>
-
-namespace google {
-namespace protobuf {
-class Message;
-}
-}
-
-namespace grpc {
-class ClientContext;
-class RpcMethod;
-
-class StreamContext final : public StreamContextInterface {
- public:
- StreamContext(const RpcMethod &method, ClientContext *context,
- const google::protobuf::Message *request,
- google::protobuf::Message *result);
- StreamContext(const RpcMethod &method, grpc_call *call,
- grpc_completion_queue *cq, google::protobuf::Message *request,
- google::protobuf::Message *result);
- ~StreamContext();
- // Start the stream, if there is a final write following immediately, set
- // buffered so that the messages can be sent in batch.
- void Start(bool buffered) override;
- bool Read(google::protobuf::Message *msg) override;
- bool Write(const google::protobuf::Message *msg, bool is_last) override;
- const Status &Wait() override;
- void Cancel() override;
-
- google::protobuf::Message *request() override { return request_; }
- google::protobuf::Message *response() override { return result_; }
-
- private:
- // Unique tags for plucking events from the c layer. this pointer is casted
- // to char* to create single byte step between tags. It implicitly relies on
- // that StreamContext is large enough to contain all the pointers.
- void *finished_tag() { return reinterpret_cast<char *>(this); }
- void *read_tag() { return reinterpret_cast<char *>(this) + 1; }
- void *write_tag() { return reinterpret_cast<char *>(this) + 2; }
- void *halfclose_tag() { return reinterpret_cast<char *>(this) + 3; }
- void *client_metadata_read_tag() {
- return reinterpret_cast<char *>(this) + 5;
- }
- grpc_call *call() { return call_; }
- grpc_completion_queue *cq() { return cq_; }
-
- bool is_client_;
- const RpcMethod *method_; // not owned
- grpc_call *call_; // not owned
- grpc_completion_queue *cq_; // not owned
- google::protobuf::Message *request_; // first request, not owned
- google::protobuf::Message *result_; // last response, not owned
-
- bool peer_halfclosed_;
- bool self_halfclosed_;
- Status final_status_;
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
diff --git a/src/csharp/GrpcApi/proto/test.proto b/src/csharp/GrpcApi/proto/test.proto
index 8380ebb..996f11a 100644
--- a/src/csharp/GrpcApi/proto/test.proto
+++ b/src/csharp/GrpcApi/proto/test.proto
@@ -14,7 +14,7 @@
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
- // The server returns the client payload as-is.
+ // TODO(Issue 527): Describe required server behavior.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
index cf2a6ac..fb4c779 100644
--- a/src/node/binding.gyp
+++ b/src/node/binding.gyp
@@ -9,14 +9,15 @@
'include_dirs': [
"<!(nodejs -e \"require('nan')\")"
],
- 'cxxflags': [
+ 'cflags': [
+ '-std=c++11',
'-Wall',
'-pthread',
'-pedantic',
'-g',
'-zdefs'
- '-Werror',
- ],
+ '-Werror'
+ ],
'ldflags': [
'-g'
],
@@ -33,11 +34,9 @@
"ext/channel.cc",
"ext/completion_queue_async_worker.cc",
"ext/credentials.cc",
- "ext/event.cc",
"ext/node_grpc.cc",
"ext/server.cc",
"ext/server_credentials.cc",
- "ext/tag.cc",
"ext/timeval.cc"
],
'conditions' : [
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 23aead0..9ed389f 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,25 @@
*
*/
+#include <memory>
+#include <vector>
+#include <map>
+
#include <node.h>
#include "grpc/support/log.h"
#include "grpc/grpc.h"
+#include "grpc/support/alloc.h"
#include "grpc/support/time.h"
#include "byte_buffer.h"
#include "call.h"
#include "channel.h"
#include "completion_queue_async_worker.h"
#include "timeval.h"
-#include "tag.h"
+
+using std::unique_ptr;
+using std::shared_ptr;
+using std::vector;
namespace grpc {
namespace node {
@@ -49,6 +57,7 @@
using ::node::Buffer;
using v8::Arguments;
using v8::Array;
+using v8::Boolean;
using v8::Exception;
using v8::External;
using v8::Function;
@@ -68,37 +77,372 @@
Persistent<Function> Call::constructor;
Persistent<FunctionTemplate> Call::fun_tpl;
-Call::Call(grpc_call *call) : wrapped_call(call) {}
-Call::~Call() { grpc_call_destroy(wrapped_call); }
+bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
+ shared_ptr<Resources> resources) {
+ NanScope();
+ grpc_metadata_array_init(array);
+ Handle<Array> keys(metadata->GetOwnPropertyNames());
+ for (unsigned int i = 0; i < keys->Length(); i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ if (!metadata->Get(current_key)->IsArray()) {
+ return false;
+ }
+ array->capacity += Local<Array>::Cast(metadata->Get(current_key))->Length();
+ }
+ array->metadata = reinterpret_cast<grpc_metadata*>(
+ gpr_malloc(array->capacity * sizeof(grpc_metadata)));
+ for (unsigned int i = 0; i < keys->Length(); i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ NanUtf8String *utf8_key = new NanUtf8String(current_key);
+ resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_key));
+ Handle<Array> values = Local<Array>::Cast(metadata->Get(current_key));
+ for (unsigned int j = 0; j < values->Length(); j++) {
+ Handle<Value> value = values->Get(j);
+ grpc_metadata *current = &array->metadata[array->count];
+ current->key = **utf8_key;
+ if (Buffer::HasInstance(value)) {
+ current->value = Buffer::Data(value);
+ current->value_length = Buffer::Length(value);
+ Persistent<Value> handle;
+ NanAssignPersistent(handle, value);
+ resources->handles.push_back(unique_ptr<PersistentHolder>(
+ new PersistentHolder(handle)));
+ } else if (value->IsString()) {
+ Handle<String> string_value = value->ToString();
+ NanUtf8String *utf8_value = new NanUtf8String(string_value);
+ resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
+ current->value = **utf8_value;
+ current->value_length = string_value->Length();
+ } else {
+ return false;
+ }
+ array->count += 1;
+ }
+ }
+ return true;
+}
+
+Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
+ NanEscapableScope();
+ grpc_metadata *metadata_elements = metadata_array->metadata;
+ size_t length = metadata_array->count;
+ std::map<const char*, size_t> size_map;
+ std::map<const char*, size_t> index_map;
+
+ for (unsigned int i = 0; i < length; i++) {
+ const char *key = metadata_elements[i].key;
+ if (size_map.count(key)) {
+ size_map[key] += 1;
+ }
+ index_map[key] = 0;
+ }
+ Handle<Object> metadata_object = NanNew<Object>();
+ for (unsigned int i = 0; i < length; i++) {
+ grpc_metadata* elem = &metadata_elements[i];
+ Handle<String> key_string = String::New(elem->key);
+ Handle<Array> array;
+ if (metadata_object->Has(key_string)) {
+ array = Handle<Array>::Cast(metadata_object->Get(key_string));
+ } else {
+ array = NanNew<Array>(size_map[elem->key]);
+ metadata_object->Set(key_string, array);
+ }
+ array->Set(index_map[elem->key],
+ MakeFastBuffer(
+ NanNewBufferHandle(elem->value, elem->value_length)));
+ index_map[elem->key] += 1;
+ }
+ return NanEscapeScope(metadata_object);
+}
+
+Handle<Value> Op::GetOpType() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanNew<String>(GetTypeString()));
+}
+
+class SendMetadataOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!value->IsObject()) {
+ return false;
+ }
+ grpc_metadata_array array;
+ if (!CreateMetadataArray(value->ToObject(), &array, resources)) {
+ return false;
+ }
+ out->data.send_initial_metadata.count = array.count;
+ out->data.send_initial_metadata.metadata = array.metadata;
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send metadata";
+ }
+};
+
+class SendMessageOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!Buffer::HasInstance(value)) {
+ return false;
+ }
+ out->data.send_message = BufferToByteBuffer(value);
+ Persistent<Value> handle;
+ NanAssignPersistent(handle, value);
+ resources->handles.push_back(unique_ptr<PersistentHolder>(
+ new PersistentHolder(handle)));
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send message";
+ }
+};
+
+class SendClientCloseOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "client close";
+ }
+};
+
+class SendServerStatusOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanTrue());
+ }
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ if (!value->IsObject()) {
+ return false;
+ }
+ Handle<Object> server_status = value->ToObject();
+ if (!server_status->Get(NanNew("metadata"))->IsObject()) {
+ return false;
+ }
+ if (!server_status->Get(NanNew("code"))->IsUint32()) {
+ return false;
+ }
+ if (!server_status->Get(NanNew("details"))->IsString()) {
+ return false;
+ }
+ grpc_metadata_array array;
+ if (!CreateMetadataArray(server_status->Get(NanNew("metadata"))->
+ ToObject(),
+ &array, resources)) {
+ return false;
+ }
+ out->data.send_status_from_server.trailing_metadata_count = array.count;
+ out->data.send_status_from_server.trailing_metadata = array.metadata;
+ out->data.send_status_from_server.status =
+ static_cast<grpc_status_code>(
+ server_status->Get(NanNew("code"))->Uint32Value());
+ NanUtf8String *str = new NanUtf8String(
+ server_status->Get(NanNew("details")));
+ resources->strings.push_back(unique_ptr<NanUtf8String>(str));
+ out->data.send_status_from_server.status_details = **str;
+ return true;
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "send status";
+ }
+};
+
+class GetMetadataOp : public Op {
+ public:
+ GetMetadataOp() {
+ grpc_metadata_array_init(&recv_metadata);
+ }
+
+ ~GetMetadataOp() {
+ grpc_metadata_array_destroy(&recv_metadata);
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(ParseMetadata(&recv_metadata));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_initial_metadata = &recv_metadata;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "metadata";
+ }
+
+ private:
+ grpc_metadata_array recv_metadata;
+};
+
+class ReadMessageOp : public Op {
+ public:
+ ReadMessageOp() {
+ recv_message = NULL;
+ }
+ ~ReadMessageOp() {
+ if (recv_message != NULL) {
+ gpr_free(recv_message);
+ }
+ }
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(ByteBufferToBuffer(recv_message));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_message = &recv_message;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "read";
+ }
+
+ private:
+ grpc_byte_buffer *recv_message;
+};
+
+class ClientStatusOp : public Op {
+ public:
+ ClientStatusOp() {
+ grpc_metadata_array_init(&metadata_array);
+ status_details = NULL;
+ details_capacity = 0;
+ }
+
+ ~ClientStatusOp() {
+ grpc_metadata_array_destroy(&metadata_array);
+ gpr_free(status_details);
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_status_on_client.trailing_metadata = &metadata_array;
+ out->data.recv_status_on_client.status = &status;
+ out->data.recv_status_on_client.status_details = &status_details;
+ out->data.recv_status_on_client.status_details_capacity = &details_capacity;
+ return true;
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ Handle<Object> status_obj = NanNew<Object>();
+ status_obj->Set(NanNew("code"), NanNew<Number>(status));
+ if (status_details != NULL) {
+ status_obj->Set(NanNew("details"), String::New(status_details));
+ }
+ status_obj->Set(NanNew("metadata"), ParseMetadata(&metadata_array));
+ return NanEscapeScope(status_obj);
+ }
+ protected:
+ std::string GetTypeString() const {
+ return "status";
+ }
+ private:
+ grpc_metadata_array metadata_array;
+ grpc_status_code status;
+ char *status_details;
+ size_t details_capacity;
+};
+
+class ServerCloseResponseOp : public Op {
+ public:
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ return NanEscapeScope(NanNew<Boolean>(cancelled));
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ out->data.recv_close_on_server.cancelled = &cancelled;
+ return true;
+ }
+
+ protected:
+ std::string GetTypeString() const {
+ return "cancelled";
+ }
+
+ private:
+ int cancelled;
+};
+
+tag::tag(NanCallback *callback, OpVec *ops,
+ shared_ptr<Resources> resources) :
+ callback(callback), ops(ops), resources(resources){
+}
+
+tag::~tag() {
+ delete callback;
+ delete ops;
+}
+
+Handle<Value> GetTagNodeValue(void *tag) {
+ NanEscapableScope();
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ Handle<Object> tag_obj = NanNew<Object>();
+ for (vector<unique_ptr<Op> >::iterator it = tag_struct->ops->begin();
+ it != tag_struct->ops->end(); ++it) {
+ Op *op_ptr = it->get();
+ tag_obj->Set(op_ptr->GetOpType(), op_ptr->GetNodeValue());
+ }
+ return NanEscapeScope(tag_obj);
+}
+
+NanCallback *GetTagCallback(void *tag) {
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ return tag_struct->callback;
+}
+
+void DestroyTag(void *tag) {
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ delete tag_struct;
+}
+
+Call::Call(grpc_call *call) : wrapped_call(call) {
+}
+
+Call::~Call() {
+ grpc_call_destroy(wrapped_call);
+}
void Call::Init(Handle<Object> exports) {
NanScope();
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(NanNew("Call"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
- NanSetPrototypeTemplate(tpl, "addMetadata",
- FunctionTemplate::New(AddMetadata)->GetFunction());
- NanSetPrototypeTemplate(tpl, "invoke",
- FunctionTemplate::New(Invoke)->GetFunction());
- NanSetPrototypeTemplate(tpl, "serverAccept",
- FunctionTemplate::New(ServerAccept)->GetFunction());
- NanSetPrototypeTemplate(
- tpl, "serverEndInitialMetadata",
- FunctionTemplate::New(ServerEndInitialMetadata)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startBatch",
+ FunctionTemplate::New(StartBatch)->GetFunction());
NanSetPrototypeTemplate(tpl, "cancel",
FunctionTemplate::New(Cancel)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startWrite",
- FunctionTemplate::New(StartWrite)->GetFunction());
- NanSetPrototypeTemplate(
- tpl, "startWriteStatus",
- FunctionTemplate::New(StartWriteStatus)->GetFunction());
- NanSetPrototypeTemplate(tpl, "writesDone",
- FunctionTemplate::New(WritesDone)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startReadMetadata",
- FunctionTemplate::New(WritesDone)->GetFunction());
- NanSetPrototypeTemplate(tpl, "startRead",
- FunctionTemplate::New(StartRead)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
NanAssignPersistent(constructor, tpl->GetFunction());
constructor->Set(NanNew("WRITE_BUFFER_HINT"),
@@ -152,9 +496,9 @@
NanUtf8String method(args[1]);
double deadline = args[2]->NumberValue();
grpc_channel *wrapped_channel = channel->GetWrappedChannel();
- grpc_call *wrapped_call = grpc_channel_create_call_old(
- wrapped_channel, *method, channel->GetHost(),
- MillisecondsToTimespec(deadline));
+ grpc_call *wrapped_call = grpc_channel_create_call(
+ wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method,
+ channel->GetHost(), MillisecondsToTimespec(deadline));
call = new Call(wrapped_call);
args.This()->SetHiddenValue(String::NewSymbol("channel_"),
channel_object);
@@ -168,119 +512,74 @@
}
}
-NAN_METHOD(Call::AddMetadata) {
+NAN_METHOD(Call::StartBatch) {
NanScope();
if (!HasInstance(args.This())) {
- return NanThrowTypeError("addMetadata can only be called on Call objects");
+ return NanThrowTypeError("startBatch can only be called on Call objects");
}
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
if (!args[0]->IsObject()) {
- return NanThrowTypeError("addMetadata's first argument must be an object");
- }
- Handle<Object> metadata = args[0]->ToObject();
- Handle<Array> keys(metadata->GetOwnPropertyNames());
- for (unsigned int i = 0; i < keys->Length(); i++) {
- Handle<String> current_key(keys->Get(i)->ToString());
- if (!metadata->Get(current_key)->IsArray()) {
- return NanThrowTypeError(
- "addMetadata's first argument's values must be arrays");
- }
- NanUtf8String utf8_key(current_key);
- Handle<Array> values = Local<Array>::Cast(metadata->Get(current_key));
- for (unsigned int j = 0; j < values->Length(); j++) {
- Handle<Value> value = values->Get(j);
- grpc_metadata metadata;
- grpc_call_error error;
- metadata.key = *utf8_key;
- if (Buffer::HasInstance(value)) {
- metadata.value = Buffer::Data(value);
- metadata.value_length = Buffer::Length(value);
- error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
- } else if (value->IsString()) {
- Handle<String> string_value = value->ToString();
- NanUtf8String utf8_value(string_value);
- metadata.value = *utf8_value;
- metadata.value_length = string_value->Length();
- gpr_log(GPR_DEBUG, "adding metadata: %s, %s, %d", metadata.key,
- metadata.value, metadata.value_length);
- error = grpc_call_add_metadata_old(call->wrapped_call, &metadata, 0);
- } else {
- return NanThrowTypeError(
- "addMetadata values must be strings or buffers");
- }
- if (error != GRPC_CALL_OK) {
- return NanThrowError("addMetadata failed", error);
- }
- }
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::Invoke) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("invoke can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("invoke's first argument must be a function");
+ return NanThrowError("startBatch's first argument must be an object");
}
if (!args[1]->IsFunction()) {
- return NanThrowTypeError("invoke's second argument must be a function");
+ return NanThrowError("startBatch's second argument must be a callback");
}
- if (!args[2]->IsUint32()) {
- return NanThrowTypeError("invoke's third argument must be integer flags");
- }
+ Handle<Function> callback_func = args[1].As<Function>();
Call *call = ObjectWrap::Unwrap<Call>(args.This());
- unsigned int flags = args[3]->Uint32Value();
- grpc_call_error error = grpc_call_invoke_old(
- call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
- CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags);
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("invoke failed", error);
+ shared_ptr<Resources> resources(new Resources);
+ Handle<Object> obj = args[0]->ToObject();
+ Handle<Array> keys = obj->GetOwnPropertyNames();
+ size_t nops = keys->Length();
+ vector<grpc_op> ops(nops);
+ unique_ptr<OpVec> op_vector(new OpVec());
+ for (unsigned int i = 0; i < nops; i++) {
+ unique_ptr<Op> op;
+ if (!keys->Get(i)->IsUint32()) {
+ return NanThrowError(
+ "startBatch's first argument's keys must be integers");
+ }
+ uint32_t type = keys->Get(i)->Uint32Value();
+ ops[i].op = static_cast<grpc_op_type>(type);
+ switch (type) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ op.reset(new SendMetadataOp());
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ op.reset(new SendMessageOp());
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ op.reset(new SendClientCloseOp());
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ op.reset(new SendServerStatusOp());
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ op.reset(new GetMetadataOp());
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ op.reset(new ReadMessageOp());
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ op.reset(new ClientStatusOp());
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ op.reset(new ServerCloseResponseOp());
+ break;
+ default:
+ return NanThrowError("Argument object had an unrecognized key");
+ }
+ if (!op->ParseOp(obj->Get(type), &ops[i], resources)) {
+ return NanThrowTypeError("Incorrectly typed arguments to startBatch");
+ }
+ op_vector->push_back(std::move(op));
}
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::ServerAccept) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("accept can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("accept's first argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_server_accept_old(
- call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
- CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("serverAccept failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::ServerEndInitialMetadata) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError(
- "serverEndInitialMetadata can only be called on Call objects");
- }
- if (!args[0]->IsUint32()) {
- return NanThrowTypeError(
- "serverEndInitialMetadata's second argument must be integer flags");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- unsigned int flags = args[1]->Uint32Value();
- grpc_call_error error =
- grpc_call_server_end_initial_metadata_old(call->wrapped_call, flags);
+ NanCallback *callback = new NanCallback(callback_func);
+ grpc_call_error error = grpc_call_start_batch(
+ call->wrapped_call, &ops[0], nops, new struct tag(
+ callback, op_vector.release(), resources));
if (error != GRPC_CALL_OK) {
- return NanThrowError("serverEndInitialMetadata failed", error);
+ return NanThrowError("startBatch failed", error);
}
+ CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
@@ -297,102 +596,5 @@
NanReturnUndefined();
}
-NAN_METHOD(Call::StartWrite) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("startWrite can only be called on Call objects");
- }
- if (!Buffer::HasInstance(args[0])) {
- return NanThrowTypeError("startWrite's first argument must be a Buffer");
- }
- if (!args[1]->IsFunction()) {
- return NanThrowTypeError("startWrite's second argument must be a function");
- }
- if (!args[2]->IsUint32()) {
- return NanThrowTypeError(
- "startWrite's third argument must be integer flags");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]);
- unsigned int flags = args[2]->Uint32Value();
- grpc_call_error error = grpc_call_start_write_old(
- call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags);
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startWrite failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::StartWriteStatus) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError(
- "startWriteStatus can only be called on Call objects");
- }
- if (!args[0]->IsUint32()) {
- return NanThrowTypeError(
- "startWriteStatus's first argument must be a status code");
- }
- if (!args[1]->IsString()) {
- return NanThrowTypeError(
- "startWriteStatus's second argument must be a string");
- }
- if (!args[2]->IsFunction()) {
- return NanThrowTypeError(
- "startWriteStatus's third argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- NanUtf8String details(args[1]);
- grpc_call_error error = grpc_call_start_write_status_old(
- call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details,
- CreateTag(args[2], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startWriteStatus failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::WritesDone) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("writesDone can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("writesDone's first argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_writes_done_old(
- call->wrapped_call, CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("writesDone failed", error);
- }
- NanReturnUndefined();
-}
-
-NAN_METHOD(Call::StartRead) {
- NanScope();
- if (!HasInstance(args.This())) {
- return NanThrowTypeError("startRead can only be called on Call objects");
- }
- if (!args[0]->IsFunction()) {
- return NanThrowTypeError("startRead's first argument must be a function");
- }
- Call *call = ObjectWrap::Unwrap<Call>(args.This());
- grpc_call_error error = grpc_call_start_read_old(
- call->wrapped_call, CreateTag(args[0], args.This()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
- return NanThrowError("startRead failed", error);
- }
- NanReturnUndefined();
-}
-
} // namespace node
} // namespace grpc
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 1924a1b..dbdb8e2 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -34,15 +34,71 @@
#ifndef NET_GRPC_NODE_CALL_H_
#define NET_GRPC_NODE_CALL_H_
+#include <memory>
+#include <vector>
+
#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "channel.h"
+
namespace grpc {
namespace node {
+using std::unique_ptr;
+using std::shared_ptr;
+
+v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array);
+
+class PersistentHolder {
+ public:
+ explicit PersistentHolder(v8::Persistent<v8::Value> persist) :
+ persist(persist) {
+ }
+
+ ~PersistentHolder() {
+ NanDisposePersistent(persist);
+ }
+
+ private:
+ v8::Persistent<v8::Value> persist;
+};
+
+struct Resources {
+ std::vector<unique_ptr<NanUtf8String> > strings;
+ std::vector<unique_ptr<PersistentHolder> > handles;
+};
+
+class Op {
+ public:
+ virtual v8::Handle<v8::Value> GetNodeValue() const = 0;
+ virtual bool ParseOp(v8::Handle<v8::Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) = 0;
+ v8::Handle<v8::Value> GetOpType() const;
+
+ protected:
+ virtual std::string GetTypeString() const = 0;
+};
+
+typedef std::vector<unique_ptr<Op>> OpVec;
+
+struct tag {
+ tag(NanCallback *callback, OpVec *ops,
+ shared_ptr<Resources> resources);
+ ~tag();
+ NanCallback *callback;
+ OpVec *ops;
+ shared_ptr<Resources> resources;
+};
+
+v8::Handle<v8::Value> GetTagNodeValue(void *tag);
+
+NanCallback *GetTagCallback(void *tag);
+
+void DestroyTag(void *tag);
+
/* Wrapper class for grpc_call structs. */
class Call : public ::node::ObjectWrap {
public:
@@ -60,15 +116,8 @@
Call &operator=(const Call &);
static NAN_METHOD(New);
- static NAN_METHOD(AddMetadata);
- static NAN_METHOD(Invoke);
- static NAN_METHOD(ServerAccept);
- static NAN_METHOD(ServerEndInitialMetadata);
+ static NAN_METHOD(StartBatch);
static NAN_METHOD(Cancel);
- static NAN_METHOD(StartWrite);
- static NAN_METHOD(StartWriteStatus);
- static NAN_METHOD(WritesDone);
- static NAN_METHOD(StartRead);
static v8::Persistent<v8::Function> constructor;
// Used for typechecking instances of this javascript class
static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index 8de7db6..a1f390f 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -35,10 +35,10 @@
#include <nan.h>
#include "grpc/grpc.h"
+#include "grpc/support/log.h"
#include "grpc/support/time.h"
#include "completion_queue_async_worker.h"
-#include "event.h"
-#include "tag.h"
+#include "call.h"
namespace grpc {
namespace node {
@@ -58,6 +58,9 @@
void CompletionQueueAsyncWorker::Execute() {
result = grpc_completion_queue_next(queue, gpr_inf_future);
+ if (result->data.op_complete != GRPC_OP_OK) {
+ SetErrorMessage("The batch encountered an error");
+ }
}
grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
@@ -75,14 +78,26 @@
void CompletionQueueAsyncWorker::HandleOKCallback() {
NanScope();
- NanCallback event_callback(GetTagHandle(result->tag).As<Function>());
- Handle<Value> argv[] = {CreateEventObject(result)};
+ NanCallback *callback = GetTagCallback(result->tag);
+ Handle<Value> argv[] = {NanNull(), GetTagNodeValue(result->tag)};
+
+ callback->Call(2, argv);
DestroyTag(result->tag);
grpc_event_finish(result);
result = NULL;
+}
- event_callback.Call(1, argv);
+void CompletionQueueAsyncWorker::HandleErrorCallback() {
+ NanScope();
+ NanCallback *callback = GetTagCallback(result->tag);
+ Handle<Value> argv[] = {NanError(ErrorMessage())};
+
+ callback->Call(1, argv);
+
+ DestroyTag(result->tag);
+ grpc_event_finish(result);
+ result = NULL;
}
} // namespace node
diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h
index 2c928b7..c04a303 100644
--- a/src/node/ext/completion_queue_async_worker.h
+++ b/src/node/ext/completion_queue_async_worker.h
@@ -67,6 +67,8 @@
completion_queue_next */
void HandleOKCallback();
+ void HandleErrorCallback();
+
private:
grpc_event *result;
diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
index c8859ed..b79c3e3 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/credentials.cc
@@ -63,7 +63,6 @@
: wrapped_credentials(credentials) {}
Credentials::~Credentials() {
- gpr_log(GPR_DEBUG, "Destroying credentials object");
grpc_credentials_release(wrapped_credentials);
}
diff --git a/src/node/ext/event.cc b/src/node/ext/event.cc
deleted file mode 100644
index d59b68f..0000000
--- a/src/node/ext/event.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <map>
-
-#include <node.h>
-#include <nan.h>
-#include "grpc/grpc.h"
-#include "byte_buffer.h"
-#include "call.h"
-#include "event.h"
-#include "tag.h"
-#include "timeval.h"
-
-namespace grpc {
-namespace node {
-
-using ::node::Buffer;
-using v8::Array;
-using v8::Date;
-using v8::Handle;
-using v8::HandleScope;
-using v8::Number;
-using v8::Object;
-using v8::Persistent;
-using v8::String;
-using v8::Value;
-
-Handle<Value> ParseMetadata(grpc_metadata *metadata_elements, size_t length) {
- NanEscapableScope();
- std::map<const char*, size_t> size_map;
- std::map<const char*, size_t> index_map;
-
- for (unsigned int i = 0; i < length; i++) {
- const char *key = metadata_elements[i].key;
- if (size_map.count(key)) {
- size_map[key] += 1;
- }
- index_map[key] = 0;
- }
- Handle<Object> metadata_object = NanNew<Object>();
- for (unsigned int i = 0; i < length; i++) {
- grpc_metadata* elem = &metadata_elements[i];
- Handle<String> key_string = String::New(elem->key);
- Handle<Array> array;
- if (metadata_object->Has(key_string)) {
- array = Handle<Array>::Cast(metadata_object->Get(key_string));
- } else {
- array = NanNew<Array>(size_map[elem->key]);
- metadata_object->Set(key_string, array);
- }
- array->Set(index_map[elem->key],
- MakeFastBuffer(
- NanNewBufferHandle(elem->value, elem->value_length)));
- index_map[elem->key] += 1;
- }
- return NanEscapeScope(metadata_object);
-}
-
-Handle<Value> GetEventData(grpc_event *event) {
- NanEscapableScope();
- size_t count;
- grpc_metadata *items;
- Handle<Array> metadata;
- Handle<Object> status;
- Handle<Object> rpc_new;
- switch (event->type) {
- case GRPC_READ:
- return NanEscapeScope(ByteBufferToBuffer(event->data.read));
- case GRPC_WRITE_ACCEPTED:
- return NanEscapeScope(NanNew<Number>(event->data.write_accepted));
- case GRPC_FINISH_ACCEPTED:
- return NanEscapeScope(NanNew<Number>(event->data.finish_accepted));
- case GRPC_CLIENT_METADATA_READ:
- count = event->data.client_metadata_read.count;
- items = event->data.client_metadata_read.elements;
- return NanEscapeScope(ParseMetadata(items, count));
- case GRPC_FINISHED:
- status = NanNew<Object>();
- status->Set(NanNew("code"), NanNew<Number>(event->data.finished.status));
- if (event->data.finished.details != NULL) {
- status->Set(NanNew("details"),
- String::New(event->data.finished.details));
- }
- count = event->data.finished.metadata_count;
- items = event->data.finished.metadata_elements;
- status->Set(NanNew("metadata"), ParseMetadata(items, count));
- return NanEscapeScope(status);
- case GRPC_SERVER_RPC_NEW:
- rpc_new = NanNew<Object>();
- if (event->data.server_rpc_new.method == NULL) {
- return NanEscapeScope(NanNull());
- }
- rpc_new->Set(
- NanNew("method"),
- NanNew(event->data.server_rpc_new.method));
- rpc_new->Set(
- NanNew("host"),
- NanNew(event->data.server_rpc_new.host));
- rpc_new->Set(NanNew("absolute_deadline"),
- NanNew<Date>(TimespecToMilliseconds(
- event->data.server_rpc_new.deadline)));
- count = event->data.server_rpc_new.metadata_count;
- items = event->data.server_rpc_new.metadata_elements;
- metadata = NanNew<Array>(static_cast<int>(count));
- for (unsigned int i = 0; i < count; i++) {
- Handle<Object> item_obj = Object::New();
- item_obj->Set(NanNew("key"),
- NanNew(items[i].key));
- item_obj->Set(
- NanNew("value"),
- NanNew(items[i].value, static_cast<int>(items[i].value_length)));
- metadata->Set(i, item_obj);
- }
- rpc_new->Set(NanNew("metadata"), ParseMetadata(items, count));
- return NanEscapeScope(rpc_new);
- default:
- return NanEscapeScope(NanNull());
- }
-}
-
-Handle<Value> CreateEventObject(grpc_event *event) {
- NanEscapableScope();
- if (event == NULL) {
- return NanEscapeScope(NanNull());
- }
- Handle<Object> event_obj = NanNew<Object>();
- Handle<Value> call;
- if (TagHasCall(event->tag)) {
- call = TagGetCall(event->tag);
- } else {
- call = Call::WrapStruct(event->call);
- }
- event_obj->Set(NanNew<String, const char *>("call"), call);
- event_obj->Set(NanNew<String, const char *>("type"),
- NanNew<Number>(event->type));
- event_obj->Set(NanNew<String, const char *>("data"), GetEventData(event));
-
- return NanEscapeScope(event_obj);
-}
-
-} // namespace node
-} // namespace grpc
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index bc1dfaf..9b0fe82 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -130,35 +130,34 @@
call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS);
}
-void InitOpErrorConstants(Handle<Object> exports) {
+void InitOpTypeConstants(Handle<Object> exports) {
NanScope();
- Handle<Object> op_error = Object::New();
- exports->Set(NanNew("opError"), op_error);
- Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_OP_OK));
- op_error->Set(NanNew("OK"), OK);
- Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_OP_ERROR));
- op_error->Set(NanNew("ERROR"), ERROR);
-}
-
-void InitCompletionTypeConstants(Handle<Object> exports) {
- NanScope();
- Handle<Object> completion_type = Object::New();
- exports->Set(NanNew("completionType"), completion_type);
- Handle<Value> QUEUE_SHUTDOWN(NanNew<Uint32, uint32_t>(GRPC_QUEUE_SHUTDOWN));
- completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN);
- Handle<Value> READ(NanNew<Uint32, uint32_t>(GRPC_READ));
- completion_type->Set(NanNew("READ"), READ);
- Handle<Value> WRITE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_WRITE_ACCEPTED));
- completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED);
- Handle<Value> FINISH_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_FINISH_ACCEPTED));
- completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED);
- Handle<Value> CLIENT_METADATA_READ(
- NanNew<Uint32, uint32_t>(GRPC_CLIENT_METADATA_READ));
- completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ);
- Handle<Value> FINISHED(NanNew<Uint32, uint32_t>(GRPC_FINISHED));
- completion_type->Set(NanNew("FINISHED"), FINISHED);
- Handle<Value> SERVER_RPC_NEW(NanNew<Uint32, uint32_t>(GRPC_SERVER_RPC_NEW));
- completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW);
+ Handle<Object> op_type = Object::New();
+ exports->Set(NanNew("opType"), op_type);
+ Handle<Value> SEND_INITIAL_METADATA(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_INITIAL_METADATA));
+ op_type->Set(NanNew("SEND_INITIAL_METADATA"), SEND_INITIAL_METADATA);
+ Handle<Value> SEND_MESSAGE(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_MESSAGE));
+ op_type->Set(NanNew("SEND_MESSAGE"), SEND_MESSAGE);
+ Handle<Value> SEND_CLOSE_FROM_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
+ op_type->Set(NanNew("SEND_CLOSE_FROM_CLIENT"), SEND_CLOSE_FROM_CLIENT);
+ Handle<Value> SEND_STATUS_FROM_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_OP_SEND_STATUS_FROM_SERVER));
+ op_type->Set(NanNew("SEND_STATUS_FROM_SERVER"), SEND_STATUS_FROM_SERVER);
+ Handle<Value> RECV_INITIAL_METADATA(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_INITIAL_METADATA));
+ op_type->Set(NanNew("RECV_INITIAL_METADATA"), RECV_INITIAL_METADATA);
+ Handle<Value> RECV_MESSAGE(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_MESSAGE));
+ op_type->Set(NanNew("RECV_MESSAGE"), RECV_MESSAGE);
+ Handle<Value> RECV_STATUS_ON_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_STATUS_ON_CLIENT));
+ op_type->Set(NanNew("RECV_STATUS_ON_CLIENT"), RECV_STATUS_ON_CLIENT);
+ Handle<Value> RECV_CLOSE_ON_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_OP_RECV_CLOSE_ON_SERVER));
+ op_type->Set(NanNew("RECV_CLOSE_ON_SERVER"), RECV_CLOSE_ON_SERVER);
}
void init(Handle<Object> exports) {
@@ -166,8 +165,7 @@
grpc_init();
InitStatusConstants(exports);
InitCallErrorConstants(exports);
- InitOpErrorConstants(exports);
- InitCompletionTypeConstants(exports);
+ InitOpTypeConstants(exports);
grpc::node::Call::Init(exports);
grpc::node::Channel::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 6b8ccef..ee3e108 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -31,6 +31,8 @@
*
*/
+#include <memory>
+
#include "server.h"
#include <node.h>
@@ -41,17 +43,20 @@
#include <vector>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
#include "call.h"
#include "completion_queue_async_worker.h"
-#include "tag.h"
#include "server_credentials.h"
+#include "timeval.h"
namespace grpc {
namespace node {
+using std::unique_ptr;
using v8::Arguments;
using v8::Array;
using v8::Boolean;
+using v8::Date;
using v8::Exception;
using v8::Function;
using v8::FunctionTemplate;
@@ -67,6 +72,49 @@
Persistent<Function> Server::constructor;
Persistent<FunctionTemplate> Server::fun_tpl;
+class NewCallOp : public Op {
+ public:
+ NewCallOp() {
+ call = NULL;
+ grpc_call_details_init(&details);
+ grpc_metadata_array_init(&request_metadata);
+ }
+
+ ~NewCallOp() {
+ grpc_call_details_destroy(&details);
+ grpc_metadata_array_destroy(&request_metadata);
+ }
+
+ Handle<Value> GetNodeValue() const {
+ NanEscapableScope();
+ if (call == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ Handle<Object> obj = NanNew<Object>();
+ obj->Set(NanNew("call"), Call::WrapStruct(call));
+ obj->Set(NanNew("method"), NanNew(details.method));
+ obj->Set(NanNew("host"), NanNew(details.host));
+ obj->Set(NanNew("deadline"),
+ NanNew<Date>(TimespecToMilliseconds(details.deadline)));
+ obj->Set(NanNew("metadata"), ParseMetadata(&request_metadata));
+ return NanEscapeScope(obj);
+ }
+
+ bool ParseOp(Handle<Value> value, grpc_op *out,
+ shared_ptr<Resources> resources) {
+ return true;
+ }
+
+ grpc_call *call;
+ grpc_call_details details;
+ grpc_metadata_array request_metadata;
+
+ protected:
+ std::string GetTypeString() const {
+ return "new call";
+ }
+};
+
Server::Server(grpc_server *server) : wrapped_server(server) {}
Server::~Server() { grpc_server_destroy(wrapped_server); }
@@ -175,13 +223,18 @@
return NanThrowTypeError("requestCall can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
- grpc_call_error error = grpc_server_request_call_old(
- server->wrapped_server, CreateTag(args[0], NanNull()));
- if (error == GRPC_CALL_OK) {
- CompletionQueueAsyncWorker::Next();
- } else {
+ NewCallOp *op = new NewCallOp();
+ unique_ptr<OpVec> ops(new OpVec());
+ ops->push_back(unique_ptr<Op>(op));
+ grpc_call_error error = grpc_server_request_call(
+ server->wrapped_server, &op->call, &op->details, &op->request_metadata,
+ CompletionQueueAsyncWorker::GetQueue(),
+ new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
+ shared_ptr<Resources>(nullptr)));
+ if (error != GRPC_CALL_OK) {
return NanThrowError("requestCall failed", error);
}
+ CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index 393f3a6..3add43c 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -63,7 +63,6 @@
: wrapped_credentials(credentials) {}
ServerCredentials::~ServerCredentials() {
- gpr_log(GPR_DEBUG, "Destroying server credentials object");
grpc_server_credentials_release(wrapped_credentials);
}
diff --git a/src/node/ext/tag.cc b/src/node/ext/tag.cc
deleted file mode 100644
index dc8e523..0000000
--- a/src/node/ext/tag.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *
- * 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 <stdlib.h>
-#include <node.h>
-#include <nan.h>
-#include "tag.h"
-
-namespace grpc {
-namespace node {
-
-using v8::Handle;
-using v8::HandleScope;
-using v8::Persistent;
-using v8::Value;
-
-struct tag {
- tag(Persistent<Value> *tag, Persistent<Value> *call)
- : persist_tag(tag), persist_call(call) {}
-
- ~tag() {
- persist_tag->Dispose();
- if (persist_call != NULL) {
- persist_call->Dispose();
- }
- }
- Persistent<Value> *persist_tag;
- Persistent<Value> *persist_call;
-};
-
-void *CreateTag(Handle<Value> tag, Handle<Value> call) {
- NanScope();
- Persistent<Value> *persist_tag = new Persistent<Value>();
- NanAssignPersistent(*persist_tag, tag);
- Persistent<Value> *persist_call;
- if (call->IsNull() || call->IsUndefined()) {
- persist_call = NULL;
- } else {
- persist_call = new Persistent<Value>();
- NanAssignPersistent(*persist_call, call);
- }
- struct tag *tag_struct = new struct tag(persist_tag, persist_call);
- return reinterpret_cast<void *>(tag_struct);
-}
-
-Handle<Value> GetTagHandle(void *tag) {
- NanEscapableScope();
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- Handle<Value> tag_value = NanNew<Value>(*tag_struct->persist_tag);
- return NanEscapeScope(tag_value);
-}
-
-bool TagHasCall(void *tag) {
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- return tag_struct->persist_call != NULL;
-}
-
-Handle<Value> TagGetCall(void *tag) {
- NanEscapableScope();
- struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
- if (tag_struct->persist_call == NULL) {
- return NanEscapeScope(NanNull());
- }
- Handle<Value> call_value = NanNew<Value>(*tag_struct->persist_call);
- return NanEscapeScope(call_value);
-}
-
-void DestroyTag(void *tag) { delete reinterpret_cast<struct tag *>(tag); }
-
-} // namespace node
-} // namespace grpc
diff --git a/src/node/ext/tag.h b/src/node/ext/tag.h
deleted file mode 100644
index bdb0925..0000000
--- a/src/node/ext/tag.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *
- * 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 NET_GRPC_NODE_TAG_H_
-#define NET_GRPC_NODE_TAG_H_
-
-#include <node.h>
-
-namespace grpc {
-namespace node {
-
-/* Create a void* tag that can be passed to various grpc_call functions from
- a javascript value and the javascript wrapper for the call. The call can be
- null. */
-void *CreateTag(v8::Handle<v8::Value> tag, v8::Handle<v8::Value> call);
-/* Return the javascript value stored in the tag */
-v8::Handle<v8::Value> GetTagHandle(void *tag);
-/* Returns true if the call was set (non-null) when the tag was created */
-bool TagHasCall(void *tag);
-/* Returns the javascript wrapper for the call associated with this tag */
-v8::Handle<v8::Value> TagGetCall(void *call);
-/* Destroy the tag and all resources it is holding. It is illegal to call any
- of these other functions on a tag after it has been destroyed. */
-void DestroyTag(void *tag);
-
-} // namespace node
-} // namespace grpc
-
-#endif // NET_GRPC_NODE_TAG_H_
diff --git a/src/node/index.js b/src/node/index.js
index 0627e7f..baef4d0 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -35,9 +35,9 @@
var ProtoBuf = require('protobufjs');
-var surface_client = require('./src/surface_client.js');
+var client = require('./src/client.js');
-var surface_server = require('./src/surface_server.js');
+var server = require('./src/server.js');
var grpc = require('bindings')('grpc');
@@ -54,7 +54,7 @@
});
return result;
} else if (value.className === 'Service') {
- return surface_client.makeClientConstructor(value);
+ return client.makeClientConstructor(value);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
@@ -84,9 +84,9 @@
exports.load = load;
/**
- * See docs for surface_server.makeServerConstructor
+ * See docs for server.makeServerConstructor
*/
-exports.buildServer = surface_server.makeServerConstructor;
+exports.buildServer = server.makeServerConstructor;
/**
* Status name to code number mapping
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index ce18f77..8737af6 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -145,8 +145,8 @@
resp_index += 1;
});
call.on('status', function(status) {
- assert.strictEqual(resp_index, 4);
assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(resp_index, 4);
if (done) {
done();
}
diff --git a/src/node/interop/test.proto b/src/node/interop/test.proto
index 8380ebb..996f11a 100644
--- a/src/node/interop/test.proto
+++ b/src/node/interop/test.proto
@@ -14,7 +14,7 @@
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
- // The server returns the client payload as-is.
+ // TODO(Issue 527): Describe required server behavior.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
diff --git a/src/node/package.json b/src/node/package.json
index 028dc20..8f81014 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "gRPC Library for Node",
"scripts": {
"test": "./node_modules/mocha/bin/mocha"
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 3a1c9ee..81fa65e 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,185 +31,452 @@
*
*/
+var _ = require('underscore');
+
+var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
+
var grpc = require('bindings')('grpc.node');
-var common = require('./common');
+var common = require('./common.js');
-var Duplex = require('stream').Duplex;
+var EventEmitter = require('events').EventEmitter;
+
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
var util = require('util');
-util.inherits(GrpcClientStream, Duplex);
+util.inherits(ClientWritableStream, Writable);
/**
- * Class for representing a gRPC client side stream as a Node stream. Extends
- * from stream.Duplex.
+ * A stream that the client can write to. Used for calls that are streaming from
+ * the client side.
* @constructor
- * @param {grpc.Call} call Call object to proxy
- * @param {function(*):Buffer=} serialize Serialization function for requests
- * @param {function(Buffer):*=} deserialize Deserialization function for
- * responses
+ * @param {grpc.Call} call The call object to send data with
+ * @param {function(*):Buffer=} serialize Serialization function for writes.
*/
-function GrpcClientStream(call, serialize, deserialize) {
- Duplex.call(this, {objectMode: true});
- if (!serialize) {
- serialize = function(value) {
- return value;
- };
- }
- if (!deserialize) {
- deserialize = function(value) {
- return value;
- };
- }
- var self = this;
- var finished = false;
- // Indicates that a read is currently pending
- var reading = false;
- // Indicates that a write is currently pending
- var writing = false;
- this._call = call;
-
- /**
- * Serialize a request value to a buffer. Always maps null to null. Otherwise
- * uses the provided serialize function
- * @param {*} value The value to serialize
- * @return {Buffer} The serialized value
- */
- this.serialize = function(value) {
- if (value === null || value === undefined) {
- return null;
- }
- return serialize(value);
- };
-
- /**
- * Deserialize a response buffer to a value. Always maps null to null.
- * Otherwise uses the provided deserialize function.
- * @param {Buffer} buffer The buffer to deserialize
- * @return {*} The deserialized value
- */
- this.deserialize = function(buffer) {
- if (buffer === null) {
- return null;
- }
- return deserialize(buffer);
- };
- /**
- * Callback to be called when a READ event is received. Pushes the data onto
- * the read queue and starts reading again if applicable
- * @param {grpc.Event} event READ event object
- */
- function readCallback(event) {
- if (finished) {
- self.push(null);
- return;
- }
- var data = event.data;
- if (self.push(self.deserialize(data)) && data != null) {
- self._call.startRead(readCallback);
- } else {
- reading = false;
- }
- }
- call.invoke(function(event) {
- self.emit('metadata', event.data);
- }, function(event) {
- finished = true;
- self.emit('status', event.data);
- }, 0);
+function ClientWritableStream(call, serialize) {
+ Writable.call(this, {objectMode: true});
+ this.call = call;
+ this.serialize = common.wrapIgnoreNull(serialize);
this.on('finish', function() {
- call.writesDone(function() {});
+ var batch = {};
+ batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(batch, function() {});
});
- /**
- * Start reading if there is not already a pending read. Reading will
- * continue until self.push returns false (indicating reads should slow
- * down) or the read data is null (indicating that there is no more data).
- */
- this.startReading = function() {
- if (finished) {
- self.push(null);
- } else {
- if (!reading) {
- reading = true;
- self._call.startRead(readCallback);
- }
- }
- };
}
/**
- * Start reading. This is an implementation of a method needed for implementing
- * stream.Readable.
- * @param {number} size Ignored
- */
-GrpcClientStream.prototype._read = function(size) {
- this.startReading();
-};
-
-/**
* Attempt to write the given chunk. Calls the callback when done. This is an
* implementation of a method needed for implementing stream.Writable.
* @param {Buffer} chunk The chunk to write
* @param {string} encoding Ignored
- * @param {function(Error=)} callback Ignored
+ * @param {function(Error=)} callback Called when the write is complete
*/
-GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
- var self = this;
- self._call.startWrite(self.serialize(chunk), function(event) {
+function _write(chunk, encoding, callback) {
+ var batch = {};
+ batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ this.call.startBatch(batch, function(err, event) {
+ if (err) {
+ throw err;
+ }
callback();
- }, 0);
+ });
};
-/**
- * Cancel the ongoing call. If the call has not already finished, it will finish
- * with status CANCELLED.
- */
-GrpcClientStream.prototype.cancel = function() {
- this._call.cancel();
-};
+ClientWritableStream.prototype._write = _write;
+
+util.inherits(ClientReadableStream, Readable);
/**
- * Make a request on the channel to the given method with the given arguments
- * @param {grpc.Channel} channel The channel on which to make the request
- * @param {string} method The method to request
- * @param {function(*):Buffer} serialize Serialization function for requests
- * @param {function(Buffer):*} deserialize Deserialization function for
- * responses
- * @param {array=} metadata Array of metadata key/value pairs to add to the call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future.
- * @return {stream=} The stream of responses
+ * A stream that the client can read from. Used for calls that are streaming
+ * from the server side.
+ * @constructor
+ * @param {grpc.Call} call The call object to read data with
+ * @param {function(Buffer):*=} deserialize Deserialization function for reads
*/
-function makeRequest(channel,
- method,
- serialize,
- deserialize,
- metadata,
- deadline) {
- if (deadline === undefined) {
- deadline = Infinity;
- }
- var call = new grpc.Call(channel, method, deadline);
- if (metadata) {
- call.addMetadata(metadata);
- }
- return new GrpcClientStream(call, serialize, deserialize);
+function ClientReadableStream(call, deserialize) {
+ Readable.call(this, {objectMode: true});
+ this.call = call;
+ this.finished = false;
+ this.reading = false;
+ this.deserialize = common.wrapIgnoreNull(deserialize);
}
/**
- * See documentation for makeRequest above
+ * Read the next object from the stream.
+ * @param {*} size Ignored because we use objectMode=true
*/
-exports.makeRequest = makeRequest;
+function _read(size) {
+ var self = this;
+ /**
+ * Callback to be called when a READ event is received. Pushes the data onto
+ * the read queue and starts reading again if applicable
+ * @param {grpc.Event} event READ event object
+ */
+ function readCallback(err, event) {
+ if (err) {
+ throw err;
+ }
+ if (self.finished) {
+ self.push(null);
+ return;
+ }
+ var data = event.read;
+ if (self.push(self.deserialize(data)) && data != null) {
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
+ } else {
+ self.reading = false;
+ }
+ }
+ if (self.finished) {
+ self.push(null);
+ } else {
+ if (!self.reading) {
+ self.reading = true;
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
+ }
+ }
+};
+
+ClientReadableStream.prototype._read = _read;
+
+util.inherits(ClientDuplexStream, Duplex);
/**
- * Represents a client side gRPC channel associated with a single host.
+ * A stream that the client can read from or write to. Used for calls with
+ * duplex streaming.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {function(*):Buffer=} serialize Serialization function for requests
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * responses
*/
-exports.Channel = grpc.Channel;
+function ClientDuplexStream(call, serialize, deserialize) {
+ Duplex.call(this, {objectMode: true});
+ this.serialize = common.wrapIgnoreNull(serialize);
+ this.deserialize = common.wrapIgnoreNull(deserialize);
+ var self = this;
+ var finished = false;
+ // Indicates that a read is currently pending
+ var reading = false;
+ this.call = call;
+ this.on('finish', function() {
+ var batch = {};
+ batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(batch, function() {});
+ });
+}
+
+ClientDuplexStream.prototype._read = _read;
+ClientDuplexStream.prototype._write = _write;
+
/**
- * Status name to code number mapping
+ * Cancel the ongoing call
+ */
+function cancel() {
+ this.call.cancel();
+}
+
+ClientReadableStream.prototype.cancel = cancel;
+ClientWritableStream.prototype.cancel = cancel;
+ClientDuplexStream.prototype.cancel = cancel;
+
+/**
+ * Get a function that can make unary requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeUnaryRequest
+ */
+function makeUnaryRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a unary request with this method on the given channel with the given
+ * argument, callback, etc.
+ * @this {Client} Client object. Must have a channel member.
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeUnaryRequest(argument, callback, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var emitter = new EventEmitter();
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ emitter.cancel = function cancel() {
+ call.cancel();
+ };
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (response.status.code != grpc.status.OK) {
+ callback(response.status);
+ return;
+ }
+ emitter.emit('status', response.status);
+ emitter.emit('metadata', response.metadata);
+ callback(null, deserialize(response.read));
+ });
+ return emitter;
+ }
+ return makeUnaryRequest;
+}
+
+/**
+ * Get a function that can make client stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeClientStreamRequest
+ */
+function makeClientStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a client stream request with this method on the given channel with the
+ * given callback, etc.
+ * @this {Client} Client object. Must have a channel member.
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeClientStreamRequest(callback, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientWritableStream(call, serialize);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(metadata_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var client_batch = {};
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (response.status.code != grpc.status.OK) {
+ callback(response.status);
+ return;
+ }
+ stream.emit('status', response.status);
+ callback(null, deserialize(response.read));
+ });
+ return stream;
+ }
+ return makeClientStreamRequest;
+}
+
+/**
+ * Get a function that can make server stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeServerStreamRequest
+ */
+function makeServerStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a server stream request with this method on the given channel with the
+ * given argument, etc.
+ * @this {SurfaceClient} Client object. Must have a channel member.
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeServerStreamRequest(argument, metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientReadableStream(call, deserialize);
+ var start_batch = {};
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+ start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('status', response.status);
+ });
+ return stream;
+ }
+ return makeServerStreamRequest;
+}
+
+/**
+ * Get a function that can make bidirectional stream requests to the specified
+ * method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeBidiStreamRequest
+ */
+function makeBidiStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a bidirectional stream request with this method on the given channel.
+ * @this {SurfaceClient} Client object. Must have a channel member.
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeBidiStreamRequest(metadata, deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(this.channel, method, deadline);
+ if (metadata === null || metadata === undefined) {
+ metadata = {};
+ }
+ var stream = new ClientDuplexStream(call, serialize, deserialize);
+ var start_batch = {};
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('metadata', response.metadata);
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ if (err) {
+ throw err;
+ }
+ stream.emit('status', response.status);
+ });
+ return stream;
+ }
+ return makeBidiStreamRequest;
+}
+
+
+/**
+ * Map with short names for each of the requester maker functions. Used in
+ * makeClientConstructor
+ */
+var requester_makers = {
+ unary: makeUnaryRequestFunction,
+ server_stream: makeServerStreamRequestFunction,
+ client_stream: makeClientStreamRequestFunction,
+ bidi: makeBidiStreamRequestFunction
+};
+
+/**
+ * Creates a constructor for clients for the given service
+ * @param {ProtoBuf.Reflect.Service} service The service to generate a client
+ * for
+ * @return {function(string, Object)} New client constructor
+ */
+function makeClientConstructor(service) {
+ var prefix = '/' + common.fullyQualifiedName(service) + '/';
+ /**
+ * Create a client with the given methods
+ * @constructor
+ * @param {string} address The address of the server to connect to
+ * @param {Object} options Options to pass to the underlying channel
+ */
+ function Client(address, options) {
+ this.channel = new grpc.Channel(address, options);
+ }
+
+ _.each(service.children, function(method) {
+ var method_type;
+ if (method.requestStream) {
+ if (method.responseStream) {
+ method_type = 'bidi';
+ } else {
+ method_type = 'client_stream';
+ }
+ } else {
+ if (method.responseStream) {
+ method_type = 'server_stream';
+ } else {
+ method_type = 'unary';
+ }
+ }
+ Client.prototype[decapitalize(method.name)] =
+ requester_makers[method_type](
+ prefix + capitalize(method.name),
+ common.serializeCls(method.resolvedRequestType.build()),
+ common.deserializeCls(method.resolvedResponseType.build()));
+ });
+
+ Client.service = service;
+
+ return Client;
+}
+
+exports.makeClientConstructor = makeClientConstructor;
+
+/**
+ * See docs for client.status
*/
exports.status = grpc.status;
/**
- * Call error name to code number mapping
+ * See docs for client.callError
*/
exports.callError = grpc.callError;
diff --git a/src/node/src/common.js b/src/node/src/common.js
index 54247e3..7560cf1 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -31,6 +31,8 @@
*
*/
+var _ = require('underscore');
+
var capitalize = require('underscore.string/capitalize');
/**
@@ -88,6 +90,24 @@
}
/**
+ * Wrap a function to pass null-like values through without calling it. If no
+ * function is given, just uses the identity;
+ * @param {?function} func The function to wrap
+ * @return {function} The wrapped function
+ */
+function wrapIgnoreNull(func) {
+ if (!func) {
+ return _.identity;
+ }
+ return function(arg) {
+ if (arg === null || arg === undefined) {
+ return null;
+ }
+ return func(arg);
+ };
+}
+
+/**
* See docs for deserializeCls
*/
exports.deserializeCls = deserializeCls;
@@ -101,3 +121,8 @@
* See docs for fullyQualifiedName
*/
exports.fullyQualifiedName = fullyQualifiedName;
+
+/**
+ * See docs for wrapIgnoreNull
+ */
+exports.wrapIgnoreNull = wrapIgnoreNull;
diff --git a/src/node/src/server.js b/src/node/src/server.js
index e4f71ff..48c349e 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,80 +33,108 @@
var _ = require('underscore');
+var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
+
var grpc = require('bindings')('grpc.node');
var common = require('./common');
-var Duplex = require('stream').Duplex;
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
var util = require('util');
-util.inherits(GrpcServerStream, Duplex);
+var EventEmitter = require('events').EventEmitter;
+
+var common = require('./common.js');
/**
- * Class for representing a gRPC server side stream as a Node stream. Extends
- * from stream.Duplex.
- * @constructor
- * @param {grpc.Call} call Call object to proxy
- * @param {function(*):Buffer=} serialize Serialization function for responses
- * @param {function(Buffer):*=} deserialize Deserialization function for
- * requests
+ * Handle an error on a call by sending it as a status
+ * @param {grpc.Call} call The call to send the error on
+ * @param {Object} error The error object
*/
-function GrpcServerStream(call, serialize, deserialize) {
- Duplex.call(this, {objectMode: true});
- if (!serialize) {
- serialize = function(value) {
- return value;
- };
- }
- if (!deserialize) {
- deserialize = function(value) {
- return value;
- };
- }
- this._call = call;
- // Indicate that a status has been sent
- var finished = false;
- var self = this;
+function handleError(call, error) {
var status = {
- 'code' : grpc.status.OK,
- 'details' : 'OK'
+ code: grpc.status.INTERNAL,
+ details: 'Unknown Error',
+ metadata: {}
};
-
- /**
- * Serialize a response value to a buffer. Always maps null to null. Otherwise
- * uses the provided serialize function
- * @param {*} value The value to serialize
- * @return {Buffer} The serialized value
- */
- this.serialize = function(value) {
- if (value === null || value === undefined) {
- return null;
- }
- return serialize(value);
- };
-
- /**
- * Deserialize a request buffer to a value. Always maps null to null.
- * Otherwise uses the provided deserialize function.
- * @param {Buffer} buffer The buffer to deserialize
- * @return {*} The deserialized value
- */
- this.deserialize = function(buffer) {
- if (buffer === null) {
- return null;
- }
- return deserialize(buffer);
- };
-
- /**
- * Send the pending status
- */
- function sendStatus() {
- call.startWriteStatus(status.code, status.details, function() {
- });
- finished = true;
+ if (error.hasOwnProperty('message')) {
+ status.details = error.message;
}
- this.on('finish', sendStatus);
+ if (error.hasOwnProperty('code')) {
+ status.code = error.code;
+ if (error.hasOwnProperty('details')) {
+ status.details = error.details;
+ }
+ }
+ var error_batch = {};
+ error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
+ call.startBatch(error_batch, function(){});
+}
+
+/**
+ * Wait for the client to close, then emit a cancelled event if the client
+ * cancelled.
+ * @param {grpc.Call} call The call object to wait on
+ * @param {EventEmitter} emitter The event emitter to emit the cancelled event
+ * on
+ */
+function waitForCancel(call, emitter) {
+ var cancel_batch = {};
+ cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ call.startBatch(cancel_batch, function(err, result) {
+ if (err) {
+ emitter.emit('error', err);
+ }
+ if (result.cancelled) {
+ emitter.cancelled = true;
+ emitter.emit('cancelled');
+ }
+ });
+}
+
+/**
+ * Send a response to a unary or client streaming call.
+ * @param {grpc.Call} call The call to respond on
+ * @param {*} value The value to respond with
+ * @param {function(*):Buffer=} serialize Serialization function for the
+ * response
+ */
+function sendUnaryResponse(call, value, serialize) {
+ var end_batch = {};
+ end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+ end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ code: grpc.status.OK,
+ details: 'OK',
+ metadata: {}
+ };
+ call.startBatch(end_batch, function (){});
+}
+
+/**
+ * Initialize a writable stream. This is used for both the writable and duplex
+ * stream constructors.
+ * @param {Writable} stream The stream to set up
+ * @param {function(*):Buffer=} Serialization function for responses
+ */
+function setUpWritable(stream, serialize) {
+ stream.finished = false;
+ stream.status = {
+ code : grpc.status.OK,
+ details : 'OK',
+ metadata : {}
+ };
+ stream.serialize = common.wrapIgnoreNull(serialize);
+ function sendStatus() {
+ var batch = {};
+ batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
+ stream.call.startBatch(batch, function(){});
+ }
+ stream.on('finish', sendStatus);
/**
* Set the pending status to a given error status. If the error does not have
* code or details properties, the code will be set to grpc.status.INTERNAL
@@ -116,14 +144,16 @@
function setStatus(err) {
var code = grpc.status.INTERNAL;
var details = 'Unknown Error';
-
+ if (err.hasOwnProperty('message')) {
+ details = err.message;
+ }
if (err.hasOwnProperty('code')) {
code = err.code;
if (err.hasOwnProperty('details')) {
details = err.details;
}
}
- status = {'code': code, 'details': details};
+ stream.status = {code: code, details: details, metadata: {}};
}
/**
* Terminate the call. This includes indicating that reads are done, draining
@@ -133,55 +163,50 @@
*/
function terminateCall(err) {
// Drain readable data
- this.on('data', function() {});
setStatus(err);
- this.end();
+ stream.end();
}
- this.on('error', terminateCall);
- // Indicates that a read is pending
- var reading = false;
- /**
- * Callback to be called when a READ event is received. Pushes the data onto
- * the read queue and starts reading again if applicable
- * @param {grpc.Event} event READ event object
- */
- function readCallback(event) {
- if (finished) {
- self.push(null);
- return;
- }
- var data = event.data;
- if (self.push(self.deserialize(data)) && data != null) {
- self._call.startRead(readCallback);
- } else {
- reading = false;
- }
- }
- /**
- * Start reading if there is not already a pending read. Reading will
- * continue until self.push returns false (indicating reads should slow
- * down) or the read data is null (indicating that there is no more data).
- */
- this.startReading = function() {
- if (finished) {
- self.push(null);
- } else {
- if (!reading) {
- reading = true;
- self._call.startRead(readCallback);
- }
- }
- };
+ stream.on('error', terminateCall);
}
/**
- * Start reading from the gRPC data source. This is an implementation of a
- * method required for implementing stream.Readable
- * @param {number} size Ignored
+ * Initialize a readable stream. This is used for both the readable and duplex
+ * stream constructors.
+ * @param {Readable} stream The stream to initialize
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * incoming data.
*/
-GrpcServerStream.prototype._read = function(size) {
- this.startReading();
-};
+function setUpReadable(stream, deserialize) {
+ stream.deserialize = common.wrapIgnoreNull(deserialize);
+ stream.finished = false;
+ stream.reading = false;
+
+ stream.terminate = function() {
+ stream.finished = true;
+ stream.on('data', function() {});
+ };
+
+ stream.on('cancelled', function() {
+ stream.terminate();
+ });
+}
+
+util.inherits(ServerWritableStream, Writable);
+
+/**
+ * A stream that the server can write to. Used for calls that are streaming from
+ * the server side.
+ * @constructor
+ * @param {grpc.Call} call The call object to send data with
+ * @param {function(*):Buffer=} serialize Serialization function for writes
+ */
+function ServerWritableStream(call, serialize) {
+ Writable.call(this, {objectMode: true});
+ this.call = call;
+
+ this.finished = false;
+ setUpWritable(this, serialize);
+}
/**
* Start writing a chunk of data. This is an implementation of a method required
@@ -191,11 +216,197 @@
* @param {function(Error=)} callback Callback to indicate that the write is
* complete
*/
-GrpcServerStream.prototype._write = function(chunk, encoding, callback) {
- var self = this;
- self._call.startWrite(self.serialize(chunk), function(event) {
+function _write(chunk, encoding, callback) {
+ var batch = {};
+ batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+ this.call.startBatch(batch, function(err, value) {
+ if (err) {
+ this.emit('error', err);
+ return;
+ }
callback();
- }, 0);
+ });
+}
+
+ServerWritableStream.prototype._write = _write;
+
+util.inherits(ServerReadableStream, Readable);
+
+/**
+ * A stream that the server can read from. Used for calls that are streaming
+ * from the client side.
+ * @constructor
+ * @param {grpc.Call} call The call object to read data with
+ * @param {function(Buffer):*=} deserialize Deserialization function for reads
+ */
+function ServerReadableStream(call, deserialize) {
+ Readable.call(this, {objectMode: true});
+ this.call = call;
+ setUpReadable(this, deserialize);
+}
+
+/**
+ * Start reading from the gRPC data source. This is an implementation of a
+ * method required for implementing stream.Readable
+ * @param {number} size Ignored
+ */
+function _read(size) {
+ var self = this;
+ /**
+ * Callback to be called when a READ event is received. Pushes the data onto
+ * the read queue and starts reading again if applicable
+ * @param {grpc.Event} event READ event object
+ */
+ function readCallback(err, event) {
+ if (err) {
+ self.terminate();
+ return;
+ }
+ if (self.finished) {
+ self.push(null);
+ return;
+ }
+ var data = event.read;
+ if (self.push(self.deserialize(data)) && data != null) {
+ var read_batch = {};
+ read_batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(read_batch, readCallback);
+ } else {
+ self.reading = false;
+ }
+ }
+ if (self.finished) {
+ self.push(null);
+ } else {
+ if (!self.reading) {
+ self.reading = true;
+ var batch = {};
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ self.call.startBatch(batch, readCallback);
+ }
+ }
+}
+
+ServerReadableStream.prototype._read = _read;
+
+util.inherits(ServerDuplexStream, Duplex);
+
+/**
+ * A stream that the server can read from or write to. Used for calls with
+ * duplex streaming.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {function(*):Buffer=} serialize Serialization function for requests
+ * @param {function(Buffer):*=} deserialize Deserialization function for
+ * responses
+ */
+function ServerDuplexStream(call, serialize, deserialize) {
+ Duplex.call(this, {objectMode: true});
+ this.call = call;
+ setUpWritable(this, serialize);
+ setUpReadable(this, deserialize);
+}
+
+ServerDuplexStream.prototype._read = _read;
+ServerDuplexStream.prototype._write = _write;
+
+/**
+ * Fully handle a unary call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleUnary(call, handler, metadata) {
+ var emitter = new EventEmitter();
+ emitter.on('error', function(error) {
+ handleError(call, error);
+ });
+ waitForCancel(call, emitter);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ call.startBatch(batch, function(err, result) {
+ if (err) {
+ handleError(call, err);
+ return;
+ }
+ emitter.request = handler.deserialize(result.read);
+ if (emitter.cancelled) {
+ return;
+ }
+ handler.func(emitter, function sendUnaryData(err, value) {
+ if (err) {
+ handleError(call, err);
+ }
+ sendUnaryResponse(call, value, handler.serialize);
+ });
+ });
+}
+
+/**
+ * Fully handle a server streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleServerStreaming(call, handler, metadata) {
+ var stream = new ServerWritableStream(call, handler.serialize);
+ waitForCancel(call, stream);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ batch[grpc.opType.RECV_MESSAGE] = true;
+ call.startBatch(batch, function(err, result) {
+ if (err) {
+ stream.emit('error', err);
+ return;
+ }
+ stream.request = handler.deserialize(result.read);
+ handler.func(stream);
+ });
+}
+
+/**
+ * Fully handle a client streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleClientStreaming(call, handler, metadata) {
+ var stream = new ServerReadableStream(call, handler.deserialize);
+ waitForCancel(call, stream);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ call.startBatch(metadata_batch, function() {});
+ handler.func(stream, function(err, value) {
+ stream.terminate();
+ if (err) {
+ handleError(call, err);
+ }
+ sendUnaryResponse(call, value, handler.serialize);
+ });
+}
+
+/**
+ * Fully handle a bidirectional streaming call
+ * @param {grpc.Call} call The call to handle
+ * @param {Object} handler Request handler object for the method that was called
+ * @param {Object} metadata Metadata from the client
+ */
+function handleBidiStreaming(call, handler, metadata) {
+ var stream = new ServerDuplexStream(call, handler.serialize,
+ handler.deserialize);
+ waitForCancel(call, stream);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ call.startBatch(metadata_batch, function() {});
+ handler.func(stream);
+}
+
+var streamHandlers = {
+ unary: handleUnary,
+ server_stream: handleServerStreaming,
+ client_stream: handleClientStreaming,
+ bidi: handleBidiStreaming
};
/**
@@ -218,7 +429,7 @@
* Start the server and begin handling requests
* @this Server
*/
- this.start = function() {
+ this.listen = function() {
console.log('Server starting');
_.each(handlers, function(handler, handler_name) {
console.log('Serving', handler_name);
@@ -233,48 +444,39 @@
* wait for the next request
* @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
*/
- function handleNewCall(event) {
- var call = event.call;
- var data = event.data;
- if (data === null) {
+ function handleNewCall(err, event) {
+ if (err) {
+ return;
+ }
+ var details = event['new call'];
+ var call = details.call;
+ var method = details.method;
+ var metadata = details.metadata;
+ if (method === null) {
return;
}
server.requestCall(handleNewCall);
var handler = undefined;
- var deadline = data.absolute_deadline;
- var cancelled = false;
- call.serverAccept(function(event) {
- if (event.data.code === grpc.status.CANCELLED) {
- cancelled = true;
- if (stream) {
- stream.emit('cancelled');
- }
- }
- }, 0);
- if (handlers.hasOwnProperty(data.method)) {
- handler = handlers[data.method];
+ var deadline = details.deadline;
+ if (handlers.hasOwnProperty(method)) {
+ handler = handlers[method];
} else {
- call.serverEndInitialMetadata(0);
- call.startWriteStatus(
- grpc.status.UNIMPLEMENTED,
- "This method is not available on this server.",
- function() {});
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ code: grpc.status.UNIMPLEMENTED,
+ details: "This method is not available on this server.",
+ metadata: {}
+ };
+ batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ call.startBatch(batch, function() {});
return;
}
+ var response_metadata = {};
if (getMetadata) {
- call.addMetadata(getMetadata(data.method, data.metadata));
+ response_metadata = getMetadata(method, metadata);
}
- call.serverEndInitialMetadata(0);
- var stream = new GrpcServerStream(call, handler.serialize,
- handler.deserialize);
- Object.defineProperty(stream, 'cancelled', {
- get: function() { return cancelled;}
- });
- try {
- handler.func(stream, data.metadata);
- } catch (e) {
- stream.emit('error', e);
- }
+ streamHandlers[handler.type](call, handler, response_metadata);
}
server.requestCall(handleNewCall);
};
@@ -294,17 +496,20 @@
* returns a stream of response values
* @param {function(*):Buffer} serialize Serialization function for responses
* @param {function(Buffer):*} deserialize Deserialization function for requests
+ * @param {string} type The streaming type of method that this handles
* @return {boolean} True if the handler was set. False if a handler was already
* set for that name.
*/
-Server.prototype.register = function(name, handler, serialize, deserialize) {
+Server.prototype.register = function(name, handler, serialize, deserialize,
+ type) {
if (this.handlers.hasOwnProperty(name)) {
return false;
}
this.handlers[name] = {
func: handler,
serialize: serialize,
- deserialize: deserialize
+ deserialize: deserialize,
+ type: type
};
return true;
};
@@ -324,6 +529,110 @@
};
/**
- * See documentation for Server
+ * Creates a constructor for servers with a service defined by the methods
+ * object. The methods object has string keys and values of this form:
+ * {serialize: function, deserialize: function, client_stream: bool,
+ * server_stream: bool}
+ * @param {Object} methods Method descriptor for each method the server should
+ * expose
+ * @param {string} prefix The prefex to prepend to each method name
+ * @return {function(Object, Object)} New server constructor
*/
-module.exports = Server;
+function makeServerConstructor(services) {
+ var qual_names = [];
+ _.each(services, function(service) {
+ _.each(service.children, function(method) {
+ var name = common.fullyQualifiedName(method);
+ if (_.indexOf(qual_names, name) !== -1) {
+ throw new Error('Method ' + name + ' exposed by more than one service');
+ }
+ qual_names.push(name);
+ });
+ });
+ /**
+ * Create a server with the given handlers for all of the methods.
+ * @constructor
+ * @param {Object} service_handlers Map from service names to map from method
+ * names to handlers
+ * @param {function(string, Object<string, Array<Buffer>>):
+ Object<string, Array<Buffer|string>>=} getMetadata Callback that
+ * gets metatada for a given method
+ * @param {Object=} options Options to pass to the underlying server
+ */
+ function SurfaceServer(service_handlers, getMetadata, options) {
+ var server = new Server(getMetadata, options);
+ this.inner_server = server;
+ _.each(services, function(service) {
+ var service_name = common.fullyQualifiedName(service);
+ if (service_handlers[service_name] === undefined) {
+ throw new Error('Handlers for service ' +
+ service_name + ' not provided.');
+ }
+ var prefix = '/' + common.fullyQualifiedName(service) + '/';
+ _.each(service.children, function(method) {
+ var method_type;
+ if (method.requestStream) {
+ if (method.responseStream) {
+ method_type = 'bidi';
+ } else {
+ method_type = 'client_stream';
+ }
+ } else {
+ if (method.responseStream) {
+ method_type = 'server_stream';
+ } else {
+ method_type = 'unary';
+ }
+ }
+ if (service_handlers[service_name][decapitalize(method.name)] ===
+ undefined) {
+ throw new Error('Method handler for ' +
+ common.fullyQualifiedName(method) + ' not provided.');
+ }
+ var serialize = common.serializeCls(
+ method.resolvedResponseType.build());
+ var deserialize = common.deserializeCls(
+ method.resolvedRequestType.build());
+ server.register(
+ prefix + capitalize(method.name),
+ service_handlers[service_name][decapitalize(method.name)],
+ serialize, deserialize, method_type);
+ });
+ }, this);
+ }
+
+ /**
+ * Binds the server to the given port, with SSL enabled if secure is specified
+ * @param {string} port The port that the server should bind on, in the format
+ * "address:port"
+ * @param {boolean=} secure Whether the server should open a secure port
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.bind = function(port, secure) {
+ return this.inner_server.bind(port, secure);
+ };
+
+ /**
+ * Starts the server listening on any bound ports
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.listen = function() {
+ this.inner_server.listen();
+ return this;
+ };
+
+ /**
+ * Shuts the server down; tells it to stop listening for new requests and to
+ * kill old requests.
+ */
+ SurfaceServer.prototype.shutdown = function() {
+ this.inner_server.shutdown();
+ };
+
+ return SurfaceServer;
+}
+
+/**
+ * See documentation for makeServerConstructor
+ */
+exports.makeServerConstructor = makeServerConstructor;
diff --git a/src/node/src/surface_client.js b/src/node/src/surface_client.js
deleted file mode 100644
index 16c3180..0000000
--- a/src/node/src/surface_client.js
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-var _ = require('underscore');
-
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
-var client = require('./client.js');
-
-var common = require('./common.js');
-
-var EventEmitter = require('events').EventEmitter;
-
-var stream = require('stream');
-
-var Readable = stream.Readable;
-var Writable = stream.Writable;
-var Duplex = stream.Duplex;
-var util = require('util');
-
-
-function forwardEvent(fromEmitter, toEmitter, event) {
- fromEmitter.on(event, function forward() {
- _.partial(toEmitter.emit, event).apply(toEmitter, arguments);
- });
-}
-
-util.inherits(ClientReadableObjectStream, Readable);
-
-/**
- * Class for representing a gRPC server streaming call as a Node stream on the
- * client side. Extends from stream.Readable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ClientReadableObjectStream(stream) {
- var options = {objectMode: true};
- Readable.call(this, options);
- this._stream = stream;
- var self = this;
- forwardEvent(stream, this, 'status');
- forwardEvent(stream, this, 'metadata');
- this._stream.on('data', function forwardData(chunk) {
- if (!self.push(chunk)) {
- self._stream.pause();
- }
- });
- this._stream.pause();
-}
-
-/**
- * _read implementation for both types of streams that allow reading.
- * @this {ClientReadableObjectStream}
- * @param {number} size Ignored
- */
-function _read(size) {
- this._stream.resume();
-}
-
-/**
- * See docs for _read
- */
-ClientReadableObjectStream.prototype._read = _read;
-
-util.inherits(ClientWritableObjectStream, Writable);
-
-/**
- * Class for representing a gRPC client streaming call as a Node stream on the
- * client side. Extends from stream.Writable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ClientWritableObjectStream(stream) {
- var options = {objectMode: true};
- Writable.call(this, options);
- this._stream = stream;
- forwardEvent(stream, this, 'status');
- forwardEvent(stream, this, 'metadata');
- this.on('finish', function() {
- this._stream.end();
- });
-}
-
-/**
- * _write implementation for both types of streams that allow writing
- * @this {ClientWritableObjectStream}
- * @param {*} chunk The value to write to the stream
- * @param {string} encoding Ignored
- * @param {function(Error)} callback Callback to call when finished writing
- */
-function _write(chunk, encoding, callback) {
- this._stream.write(chunk, encoding, callback);
-}
-
-/**
- * See docs for _write
- */
-ClientWritableObjectStream.prototype._write = _write;
-
-/**
- * Cancel the underlying call
- */
-function cancel() {
- this._stream.cancel();
-}
-
-ClientReadableObjectStream.prototype.cancel = cancel;
-ClientWritableObjectStream.prototype.cancel = cancel;
-
-/**
- * Get a function that can make unary requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeUnaryRequest
- */
-function makeUnaryRequestFunction(method, serialize, deserialize) {
- /**
- * Make a unary request with this method on the given channel with the given
- * argument, callback, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {*} argument The argument to the call. Should be serializable with
- * serialize
- * @param {function(?Error, value=)} callback The callback to for when the
- * response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeUnaryRequest(argument, callback, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var emitter = new EventEmitter();
- emitter.cancel = function cancel() {
- stream.cancel();
- };
- forwardEvent(stream, emitter, 'status');
- forwardEvent(stream, emitter, 'metadata');
- stream.write(argument);
- stream.end();
- stream.on('data', function forwardData(chunk) {
- try {
- callback(null, chunk);
- } catch (e) {
- callback(e);
- }
- });
- stream.on('status', function forwardStatus(status) {
- if (status.code !== client.status.OK) {
- callback(status);
- }
- });
- return emitter;
- }
- return makeUnaryRequest;
-}
-
-/**
- * Get a function that can make client stream requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeClientStreamRequest
- */
-function makeClientStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a client stream request with this method on the given channel with the
- * given callback, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {function(?Error, value=)} callback The callback to for when the
- * response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeClientStreamRequest(callback, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var obj_stream = new ClientWritableObjectStream(stream);
- stream.on('data', function forwardData(chunk) {
- try {
- callback(null, chunk);
- } catch (e) {
- callback(e);
- }
- });
- stream.on('status', function forwardStatus(status) {
- if (status.code !== client.status.OK) {
- callback(status);
- }
- });
- return obj_stream;
- }
- return makeClientStreamRequest;
-}
-
-/**
- * Get a function that can make server stream requests to the specified method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeServerStreamRequest
- */
-function makeServerStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a server stream request with this method on the given channel with the
- * given argument, etc.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {*} argument The argument to the call. Should be serializable with
- * serialize
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeServerStreamRequest(argument, metadata, deadline) {
- var stream = client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- var obj_stream = new ClientReadableObjectStream(stream);
- stream.write(argument);
- stream.end();
- return obj_stream;
- }
- return makeServerStreamRequest;
-}
-
-/**
- * Get a function that can make bidirectional stream requests to the specified
- * method.
- * @param {string} method The name of the method to request
- * @param {function(*):Buffer} serialize The serialization function for inputs
- * @param {function(Buffer)} deserialize The deserialization function for
- * outputs
- * @return {Function} makeBidiStreamRequest
- */
-function makeBidiStreamRequestFunction(method, serialize, deserialize) {
- /**
- * Make a bidirectional stream request with this method on the given channel.
- * @this {SurfaceClient} Client object. Must have a channel member.
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
- * @param {(number|Date)=} deadline The deadline for processing this request.
- * Defaults to infinite future
- * @return {EventEmitter} An event emitter for stream related events
- */
- function makeBidiStreamRequest(metadata, deadline) {
- return client.makeRequest(this.channel, method, serialize,
- deserialize, metadata, deadline);
- }
- return makeBidiStreamRequest;
-}
-
-/**
- * Map with short names for each of the requester maker functions. Used in
- * makeClientConstructor
- */
-var requester_makers = {
- unary: makeUnaryRequestFunction,
- server_stream: makeServerStreamRequestFunction,
- client_stream: makeClientStreamRequestFunction,
- bidi: makeBidiStreamRequestFunction
-}
-
-/**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- * for
- * @return {function(string, Object)} New client constructor
- */
-function makeClientConstructor(service) {
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
- /**
- * Create a client with the given methods
- * @constructor
- * @param {string} address The address of the server to connect to
- * @param {Object} options Options to pass to the underlying channel
- */
- function SurfaceClient(address, options) {
- this.channel = new client.Channel(address, options);
- }
-
- _.each(service.children, function(method) {
- var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
- method_type = 'bidi';
- } else {
- method_type = 'client_stream';
- }
- } else {
- if (method.responseStream) {
- method_type = 'server_stream';
- } else {
- method_type = 'unary';
- }
- }
- SurfaceClient.prototype[decapitalize(method.name)] =
- requester_makers[method_type](
- prefix + capitalize(method.name),
- common.serializeCls(method.resolvedRequestType.build()),
- common.deserializeCls(method.resolvedResponseType.build()));
- });
-
- SurfaceClient.service = service;
-
- return SurfaceClient;
-}
-
-exports.makeClientConstructor = makeClientConstructor;
-
-/**
- * See docs for client.status
- */
-exports.status = client.status;
-/**
- * See docs for client.callError
- */
-exports.callError = client.callError;
diff --git a/src/node/src/surface_server.js b/src/node/src/surface_server.js
deleted file mode 100644
index a47d1fa..0000000
--- a/src/node/src/surface_server.js
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-var _ = require('underscore');
-
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
-var Server = require('./server.js');
-
-var stream = require('stream');
-
-var Readable = stream.Readable;
-var Writable = stream.Writable;
-var Duplex = stream.Duplex;
-var util = require('util');
-
-var common = require('./common.js');
-
-util.inherits(ServerReadableObjectStream, Readable);
-
-/**
- * Class for representing a gRPC client streaming call as a Node stream on the
- * server side. Extends from stream.Readable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ServerReadableObjectStream(stream) {
- var options = {objectMode: true};
- Readable.call(this, options);
- this._stream = stream;
- Object.defineProperty(this, 'cancelled', {
- get: function() { return stream.cancelled; }
- });
- var self = this;
- this._stream.on('cancelled', function() {
- self.emit('cancelled');
- });
- this._stream.on('data', function forwardData(chunk) {
- if (!self.push(chunk)) {
- self._stream.pause();
- }
- });
- this._stream.on('end', function forwardEnd() {
- self.push(null);
- });
- this._stream.pause();
-}
-
-/**
- * _read implementation for both types of streams that allow reading.
- * @this {ServerReadableObjectStream|ServerBidiObjectStream}
- * @param {number} size Ignored
- */
-function _read(size) {
- this._stream.resume();
-}
-
-/**
- * See docs for _read
- */
-ServerReadableObjectStream.prototype._read = _read;
-
-util.inherits(ServerWritableObjectStream, Writable);
-
-/**
- * Class for representing a gRPC server streaming call as a Node stream on the
- * server side. Extends from stream.Writable.
- * @constructor
- * @param {stream} stream Underlying binary Duplex stream for the call
- */
-function ServerWritableObjectStream(stream) {
- var options = {objectMode: true};
- Writable.call(this, options);
- this._stream = stream;
- this._stream.on('cancelled', function() {
- self.emit('cancelled');
- });
- this.on('finish', function() {
- this._stream.end();
- });
-}
-
-/**
- * _write implementation for both types of streams that allow writing
- * @this {ServerWritableObjectStream}
- * @param {*} chunk The value to write to the stream
- * @param {string} encoding Ignored
- * @param {function(Error)} callback Callback to call when finished writing
- */
-function _write(chunk, encoding, callback) {
- this._stream.write(chunk, encoding, callback);
-}
-
-/**
- * See docs for _write
- */
-ServerWritableObjectStream.prototype._write = _write;
-
-/**
- * Creates a binary stream handler function from a unary handler function
- * @param {function(Object, function(Error, *), metadata=)} handler Unary call
- * handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeUnaryHandler(handler) {
- /**
- * Handles a stream by reading a single data value, passing it to the handler,
- * and writing the response back to the stream.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleUnaryCall(stream, metadata) {
- stream.on('data', function handleUnaryData(value) {
- var call = {request: value};
- Object.defineProperty(call, 'cancelled', {
- get: function() { return stream.cancelled;}
- });
- stream.on('cancelled', function() {
- call.emit('cancelled');
- });
- handler(call, function sendUnaryData(err, value) {
- if (err) {
- stream.emit('error', err);
- } else {
- stream.write(value);
- stream.end();
- }
- }, metadata);
- });
- };
-}
-
-/**
- * Creates a binary stream handler function from a client stream handler
- * function
- * @param {function(Readable, function(Error, *), metadata=)} handler Client
- * stream call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeClientStreamHandler(handler) {
- /**
- * Handles a stream by passing a deserializing stream to the handler and
- * writing the response back to the stream.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleClientStreamCall(stream, metadata) {
- var object_stream = new ServerReadableObjectStream(stream);
- handler(object_stream, function sendClientStreamData(err, value) {
- if (err) {
- stream.emit('error', err);
- } else {
- stream.write(value);
- stream.end();
- }
- }, metadata);
- };
-}
-
-/**
- * Creates a binary stream handler function from a server stream handler
- * function
- * @param {function(Writable, metadata=)} handler Server stream call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeServerStreamHandler(handler) {
- /**
- * Handles a stream by attaching it to a serializing stream, and passing it to
- * the handler.
- * @param {stream} stream Binary data stream
- * @param {metadata=} metadata Incoming metadata array
- */
- return function handleServerStreamCall(stream, metadata) {
- stream.on('data', function handleClientData(value) {
- var object_stream = new ServerWritableObjectStream(stream);
- object_stream.request = value;
- handler(object_stream, metadata);
- });
- };
-}
-
-/**
- * Creates a binary stream handler function from a bidi stream handler function
- * @param {function(Duplex, metadata=)} handler Unary call handler
- * @return {function(stream, metadata=)} Binary stream handler
- */
-function makeBidiStreamHandler(handler) {
- return handler;
-}
-
-/**
- * Map with short names for each of the handler maker functions. Used in
- * makeServerConstructor
- */
-var handler_makers = {
- unary: makeUnaryHandler,
- server_stream: makeServerStreamHandler,
- client_stream: makeClientStreamHandler,
- bidi: makeBidiStreamHandler
-};
-
-/**
- * Creates a constructor for servers with a service defined by the methods
- * object. The methods object has string keys and values of this form:
- * {serialize: function, deserialize: function, client_stream: bool,
- * server_stream: bool}
- * @param {Object} methods Method descriptor for each method the server should
- * expose
- * @param {string} prefix The prefex to prepend to each method name
- * @return {function(Object, Object)} New server constructor
- */
-function makeServerConstructor(services) {
- var qual_names = [];
- _.each(services, function(service) {
- _.each(service.children, function(method) {
- var name = common.fullyQualifiedName(method);
- if (_.indexOf(qual_names, name) !== -1) {
- throw new Error('Method ' + name + ' exposed by more than one service');
- }
- qual_names.push(name);
- });
- });
- /**
- * Create a server with the given handlers for all of the methods.
- * @constructor
- * @param {Object} service_handlers Map from service names to map from method
- * names to handlers
- * @param {function(string, Object<string, Array<Buffer>>):
- Object<string, Array<Buffer|string>>=} getMetadata Callback that
- * gets metatada for a given method
- * @param {Object=} options Options to pass to the underlying server
- */
- function SurfaceServer(service_handlers, getMetadata, options) {
- var server = new Server(getMetadata, options);
- this.inner_server = server;
- _.each(services, function(service) {
- var service_name = common.fullyQualifiedName(service);
- if (service_handlers[service_name] === undefined) {
- throw new Error('Handlers for service ' +
- service_name + ' not provided.');
- }
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
- _.each(service.children, function(method) {
- var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
- method_type = 'bidi';
- } else {
- method_type = 'client_stream';
- }
- } else {
- if (method.responseStream) {
- method_type = 'server_stream';
- } else {
- method_type = 'unary';
- }
- }
- if (service_handlers[service_name][decapitalize(method.name)] ===
- undefined) {
- throw new Error('Method handler for ' +
- common.fullyQualifiedName(method) + ' not provided.');
- }
- var binary_handler = handler_makers[method_type](
- service_handlers[service_name][decapitalize(method.name)]);
- var serialize = common.serializeCls(
- method.resolvedResponseType.build());
- var deserialize = common.deserializeCls(
- method.resolvedRequestType.build());
- server.register(prefix + capitalize(method.name), binary_handler,
- serialize, deserialize);
- });
- }, this);
- }
-
- /**
- * Binds the server to the given port, with SSL enabled if secure is specified
- * @param {string} port The port that the server should bind on, in the format
- * "address:port"
- * @param {boolean=} secure Whether the server should open a secure port
- * @return {SurfaceServer} this
- */
- SurfaceServer.prototype.bind = function(port, secure) {
- return this.inner_server.bind(port, secure);
- };
-
- /**
- * Starts the server listening on any bound ports
- * @return {SurfaceServer} this
- */
- SurfaceServer.prototype.listen = function() {
- this.inner_server.start();
- return this;
- };
-
- /**
- * Shuts the server down; tells it to stop listening for new requests and to
- * kill old requests.
- */
- SurfaceServer.prototype.shutdown = function() {
- this.inner_server.shutdown();
- };
-
- return SurfaceServer;
-}
-
-/**
- * See documentation for makeServerConstructor
- */
-exports.makeServerConstructor = makeServerConstructor;
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 48db245..c1a7e95 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2014, Google Inc.
+ * Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -98,101 +98,81 @@
}, TypeError);
});
});
- describe('addMetadata', function() {
- it('should succeed with a map from strings to string arrays', function() {
+ describe('startBatch', function() {
+ it('should fail without an object and a function', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.doesNotThrow(function() {
- call.addMetadata({'key': ['value']});
+ assert.throws(function() {
+ call.startBatch();
});
- assert.doesNotThrow(function() {
- call.addMetadata({'key1': ['value1'], 'key2': ['value2']});
+ assert.throws(function() {
+ call.startBatch({});
+ });
+ assert.throws(function() {
+ call.startBatch(null, function(){});
});
});
- it('should succeed with a map from strings to buffer arrays', function() {
+ it('should succeed with an empty object', function(done) {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.doesNotThrow(function() {
- call.addMetadata({'key': [new Buffer('value')]});
+ call.startBatch({}, function(err) {
+ assert.ifError(err);
+ done();
+ });
});
+ });
+ });
+ describe('startBatch with metadata', function() {
+ it('should succeed with a map of strings to string arrays', function(done) {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.doesNotThrow(function() {
- call.addMetadata({'key1': [new Buffer('value1')],
- 'key2': [new Buffer('value2')]});
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'],
+ 'key2': ['value2']};
+ call.startBatch(batch, function(err, resp) {
+ assert.ifError(err);
+ assert.deepEqual(resp, {'send metadata': true});
+ done();
+ });
+ });
+ });
+ it('should succeed with a map of strings to buffer arrays', function(done) {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.doesNotThrow(function() {
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'key1': [new Buffer('value1')],
+ 'key2': [new Buffer('value2')]
+ };
+ call.startBatch(batch, function(err, resp) {
+ assert.ifError(err);
+ assert.deepEqual(resp, {'send metadata': true});
+ done();
+ });
});
});
it('should fail with other parameter types', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
- call.addMetadata();
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = undefined;
+ call.startBatch(batch, function(){});
});
assert.throws(function() {
- call.addMetadata(null);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = null;
+ call.startBatch(batch, function(){});
}, TypeError);
assert.throws(function() {
- call.addMetadata('value');
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = 'value';
+ call.startBatch(batch, function(){});
}, TypeError);
assert.throws(function() {
- call.addMetadata(5);
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] = 5;
+ call.startBatch(batch, function(){});
}, TypeError);
});
- it.skip('should fail if invoke was already called', function(done) {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- call.invoke(function() {},
- function() {done();},
- 0);
- assert.throws(function() {
- call.addMetadata({'key': ['value']});
- });
- // Cancel to speed up the test
- call.cancel();
- });
- });
- describe('invoke', function() {
- it('should fail with fewer than 3 arguments', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.invoke();
- }, TypeError);
- assert.throws(function() {
- call.invoke(function() {});
- }, TypeError);
- assert.throws(function() {
- call.invoke(function() {},
- function() {});
- }, TypeError);
- });
- it('should work with 2 args and an int', function(done) {
- assert.doesNotThrow(function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- call.invoke(function() {},
- function() {done();},
- 0);
- // Cancel to speed up the test
- call.cancel();
- });
- });
- it('should reject incorrectly typed arguments', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.invoke(0, 0, 0);
- }, TypeError);
- assert.throws(function() {
- call.invoke(function() {},
- function() {}, 'test');
- });
- });
- });
- describe('serverAccept', function() {
- it('should fail with fewer than 1 argument1', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.serverAccept();
- }, TypeError);
- });
- it.skip('should return an error when called on a client Call', function() {
- var call = new grpc.Call(channel, 'method', getDeadline(1));
- assert.throws(function() {
- call.serverAccept(function() {});
- });
- });
});
describe('cancel', function() {
it('should succeed', function() {
diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js
deleted file mode 100644
index 1db9f69..0000000
--- a/src/node/test/client_server_test.js
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-var assert = require('assert');
-var fs = require('fs');
-var path = require('path');
-var grpc = require('bindings')('grpc.node');
-var Server = require('../src/server');
-var client = require('../src/client');
-var common = require('../src/common');
-
-var ca_path = path.join(__dirname, 'data/ca.pem');
-
-var key_path = path.join(__dirname, 'data/server1.key');
-
-var pem_path = path.join(__dirname, 'data/server1.pem');
-
-/**
- * Helper function to return an absolute deadline given a relative timeout in
- * seconds.
- * @param {number} timeout_secs The number of seconds to wait before timing out
- * @return {Date} A date timeout_secs in the future
- */
-function getDeadline(timeout_secs) {
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + timeout_secs);
- return deadline;
-}
-
-/**
- * Responds to every request with the same data as a response
- * @param {Stream} stream
- */
-function echoHandler(stream) {
- stream.pipe(stream);
-}
-
-/**
- * Responds to every request with an error status
- * @param {Stream} stream
- */
-function errorHandler(stream) {
- throw {
- 'code' : grpc.status.UNIMPLEMENTED,
- 'details' : 'error details'
- };
-}
-
-/**
- * Wait for a cancellation instead of responding
- * @param {Stream} stream
- */
-function cancelHandler(stream) {
- // do nothing
-}
-
-function metadataHandler(stream, metadata) {
- stream.end();
-}
-
-/**
- * Serialize a string to a Buffer
- * @param {string} value The string to serialize
- * @return {Buffer} The serialized value
- */
-function stringSerialize(value) {
- return new Buffer(value);
-}
-
-/**
- * Deserialize a Buffer to a string
- * @param {Buffer} buffer The buffer to deserialize
- * @return {string} The string value of the buffer
- */
-function stringDeserialize(buffer) {
- return buffer.toString();
-}
-
-describe('echo client', function() {
- var server;
- var channel;
- before(function() {
- server = new Server(function getMetadata(method, metadata) {
- return {method: [method]};
- });
- var port_num = server.bind('0.0.0.0:0');
- server.register('echo', echoHandler);
- server.register('error', errorHandler);
- server.register('cancellation', cancelHandler);
- server.register('metadata', metadataHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num);
- });
- after(function() {
- server.shutdown();
- });
- it('should receive echo responses', function(done) {
- var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
- var stream = client.makeRequest(
- channel,
- 'echo',
- stringSerialize,
- stringDeserialize);
- for (var i = 0; i < messages.length; i++) {
- stream.write(messages[i]);
- }
- stream.end();
- var index = 0;
- stream.on('data', function(chunk) {
- assert.equal(messages[index], chunk);
- index += 1;
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- });
- stream.on('end', function() {
- assert.equal(index, messages.length);
- done();
- });
- });
- it('should recieve metadata set by the server', function(done) {
- var stream = client.makeRequest(channel, 'metadata');
- stream.on('metadata', function(metadata) {
- assert.strictEqual(metadata.method[0].toString(), 'metadata');
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- done();
- });
- stream.end();
- });
- it('should get an error status that the server throws', function(done) {
- var stream = client.makeRequest(channel, 'error');
-
- stream.on('data', function() {});
- stream.write(new Buffer('test'));
- stream.end();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.UNIMPLEMENTED);
- assert.equal(status.details, 'error details');
- done();
- });
- });
- it('should be able to cancel a call', function(done) {
- var stream = client.makeRequest(
- channel,
- 'cancellation',
- null,
- getDeadline(1));
-
- stream.cancel();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.CANCELLED);
- done();
- });
- });
- it('should get correct status for unimplemented method', function(done) {
- var stream = client.makeRequest(channel, 'unimplemented_method');
- stream.end();
- stream.on('status', function(status) {
- assert.equal(status.code, grpc.status.UNIMPLEMENTED);
- done();
- });
- });
-});
-/* TODO(mlumish): explore options for reducing duplication between this test
- * and the insecure echo client test */
-describe('secure echo client', function() {
- var server;
- var channel;
- before(function(done) {
- fs.readFile(ca_path, function(err, ca_data) {
- assert.ifError(err);
- fs.readFile(key_path, function(err, key_data) {
- assert.ifError(err);
- fs.readFile(pem_path, function(err, pem_data) {
- assert.ifError(err);
- var creds = grpc.Credentials.createSsl(ca_data);
- var server_creds = grpc.ServerCredentials.createSsl(null,
- key_data,
- pem_data);
-
- server = new Server(null, {'credentials' : server_creds});
- var port_num = server.bind('0.0.0.0:0', true);
- server.register('echo', echoHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num, {
- 'grpc.ssl_target_name_override' : 'foo.test.google.com',
- 'credentials' : creds
- });
- done();
- });
- });
- });
- });
- after(function() {
- server.shutdown();
- });
- it('should recieve echo responses', function(done) {
- var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
- var stream = client.makeRequest(
- channel,
- 'echo',
- stringSerialize,
- stringDeserialize);
- for (var i = 0; i < messages.length; i++) {
- stream.write(messages[i]);
- }
- stream.end();
- var index = 0;
- stream.on('data', function(chunk) {
- assert.equal(messages[index], chunk);
- index += 1;
- });
- stream.on('status', function(status) {
- assert.equal(status.code, client.status.OK);
- });
- stream.on('end', function() {
- assert.equal(index, messages.length);
- done();
- });
- });
-});
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index 0138a55..4d11e6f 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -76,31 +76,6 @@
'INVALID_FLAGS'
];
-/**
- * List of all op error names
- * @const
- * @type {Array.<string>}
- */
-var opErrorNames = [
- 'OK',
- 'ERROR'
-];
-
-/**
- * List of all completion type names
- * @const
- * @type {Array.<string>}
- */
-var completionTypeNames = [
- 'QUEUE_SHUTDOWN',
- 'READ',
- 'WRITE_ACCEPTED',
- 'FINISH_ACCEPTED',
- 'CLIENT_METADATA_READ',
- 'FINISHED',
- 'SERVER_RPC_NEW'
-];
-
describe('constants', function() {
it('should have all of the status constants', function() {
for (var i = 0; i < statusNames.length; i++) {
@@ -114,16 +89,4 @@
'call error missing: ' + callErrorNames[i]);
}
});
- it('should have all of the op errors', function() {
- for (var i = 0; i < opErrorNames.length; i++) {
- assert(grpc.opError.hasOwnProperty(opErrorNames[i]),
- 'op error missing: ' + opErrorNames[i]);
- }
- });
- it('should have all of the completion types', function() {
- for (var i = 0; i < completionTypeNames.length; i++) {
- assert(grpc.completionType.hasOwnProperty(completionTypeNames[i]),
- 'completion type missing: ' + completionTypeNames[i]);
- }
- });
});
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 1f53df2..f8899be 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -74,40 +74,49 @@
var status_text = 'xyz';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'client close': true,
+ 'metadata': {},
+ 'status': {
+ 'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}
+ }
+ });
done();
- }, 0);
-
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- var server_call = event.call;
- assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- }, 0);
- server_call.serverEndInitialMetadata(0);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
});
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
+
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ var server_call = new_call.call;
+ assert.notEqual(server_call, null);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'send status': true,
+ 'cancelled': false
+ });
+ done();
+ });
});
});
it('should successfully send and receive metadata', function(complete) {
@@ -117,115 +126,110 @@
var status_text = 'xyz';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.addMetadata({'client_key': ['client_value']});
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- assert.strictEqual(event.data.server_key[0].toString(), 'server_value');
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'client_key': ['client_value']
+ };
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert(response['client close']);
+ assert(response.hasOwnProperty('metadata'));
+ assert.strictEqual(response.metadata.server_key[0].toString(),
+ 'server_value');
+ assert.deepEqual(response.status, {'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}});
done();
- }, 0);
-
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- assert.strictEqual(event.data.metadata.client_key[0].toString(),
- 'client_value');
- var server_call = event.call;
- assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- }, 0);
- server_call.addMetadata({'server_key': ['server_value']});
- server_call.serverEndInitialMetadata(0);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
});
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
+
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ assert.strictEqual(new_call.metadata.client_key[0].toString(),
+ 'client_value');
+ var server_call = new_call.call;
+ assert.notEqual(server_call, null);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
+ 'server_key': ['server_value']
+ };
+ server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'send status': true,
+ 'cancelled': false
+ });
+ done();
+ });
});
});
it('should send and receive data without error', function(complete) {
var req_text = 'client_request';
var reply_text = 'server_response';
- var done = multiDone(complete, 6);
+ var done = multiDone(complete, 2);
var deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 3);
var status_text = 'success';
var call = new grpc.Call(channel,
'dummy_method',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- done();
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
- done();
- }, 0);
- call.startWrite(
- new Buffer(req_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
- call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), reply_text);
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(req_text);
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert(response['client close']);
+ assert.deepEqual(response.metadata, {});
+ assert(response['send message']);
+ assert.strictEqual(response.read.toString(), reply_text);
+ assert.deepEqual(response.status, {'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}});
done();
});
- server.requestCall(function(event) {
- assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
- var server_call = event.call;
+
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ var server_call = new_call.call;
assert.notEqual(server_call, null);
- server_call.serverAccept(function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- done();
- });
- server_call.serverEndInitialMetadata(0);
- server_call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), req_text);
- server_call.startWrite(
- new Buffer(reply_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data,
- grpc.opError.OK);
- server_call.startWriteStatus(
- grpc.status.OK,
- status_text,
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ server_batch[grpc.opType.RECV_MESSAGE] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert.strictEqual(response.read.toString(), req_text);
+ var response_batch = {};
+ response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text);
+ response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ server_call.startBatch(response_batch, function(err, response) {
+ assert(response['send status']);
+ assert(!response['cancelled']);
+ done();
+ });
});
});
});
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index 7ecaad8..81cd9fa 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -56,7 +56,7 @@
interop_client.runTest(port, name_override, 'empty_unary', true, done);
});
// This fails due to an unknown bug
- it.skip('should pass large_unary', function(done) {
+ it('should pass large_unary', function(done) {
interop_client.runTest(port, name_override, 'large_unary', true, done);
});
it('should pass client_streaming', function(done) {
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 0e365bf..61b4a2f 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -63,9 +63,6 @@
assert.ifError(err);
assert.equal(value.quotient, 1);
assert.equal(value.remainder, 3);
- });
- call.on('status', function checkStatus(status) {
- assert.strictEqual(status.code, grpc.status.OK);
done();
});
});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
deleted file mode 100644
index a3e1edf..0000000
--- a/src/node/test/server_test.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
-var Server = require('../src/server');
-
-/**
- * This is used for testing functions with multiple asynchronous calls that
- * can happen in different orders. This should be passed the number of async
- * function invocations that can occur last, and each of those should call this
- * function's return value
- * @param {function()} done The function that should be called when a test is
- * complete.
- * @param {number} count The number of calls to the resulting function if the
- * test passes.
- * @return {function()} The function that should be called at the end of each
- * sequence of asynchronous functions.
- */
-function multiDone(done, count) {
- return function() {
- count -= 1;
- if (count <= 0) {
- done();
- }
- };
-}
-
-/**
- * Responds to every request with the same data as a response
- * @param {Stream} stream
- */
-function echoHandler(stream) {
- stream.pipe(stream);
-}
-
-describe('echo server', function() {
- var server;
- var channel;
- before(function() {
- server = new Server();
- var port_num = server.bind('[::]:0');
- server.register('echo', echoHandler);
- server.start();
-
- channel = new grpc.Channel('localhost:' + port_num);
- });
- after(function() {
- server.shutdown();
- });
- it('should echo inputs as responses', function(done) {
- done = multiDone(done, 4);
-
- var req_text = 'echo test string';
- var status_text = 'OK';
-
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + 3);
- var call = new grpc.Call(channel,
- 'echo',
- deadline);
- call.invoke(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.CLIENT_METADATA_READ);
- done();
- },function(event) {
- assert.strictEqual(event.type, grpc.completionType.FINISHED);
- var status = event.data;
- assert.strictEqual(status.code, grpc.status.OK);
- assert.strictEqual(status.details, status_text);
- done();
- }, 0);
- call.startWrite(
- new Buffer(req_text),
- function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.WRITE_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- call.writesDone(function(event) {
- assert.strictEqual(event.type,
- grpc.completionType.FINISH_ACCEPTED);
- assert.strictEqual(event.data, grpc.opError.OK);
- done();
- });
- }, 0);
- call.startRead(function(event) {
- assert.strictEqual(event.type, grpc.completionType.READ);
- assert.strictEqual(event.data.toString(), req_text);
- done();
- });
- });
-});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 1038f9a..34e4ab4 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -33,9 +33,9 @@
var assert = require('assert');
-var surface_server = require('../src/surface_server.js');
+var surface_server = require('../src/server.js');
-var surface_client = require('../src/surface_client.js');
+var surface_client = require('../src/client.js');
var ProtoBuf = require('protobufjs');
diff --git a/src/python/src/__init__.py b/src/python/interop/interop/__init__.py
similarity index 100%
copy from src/python/src/__init__.py
copy to src/python/interop/interop/__init__.py
diff --git a/src/python/interop/interop/credentials/README b/src/python/interop/interop/credentials/README
new file mode 100755
index 0000000..cb20dcb
--- /dev/null
+++ b/src/python/interop/interop/credentials/README
@@ -0,0 +1 @@
+These are test keys *NOT* to be used in production.
diff --git a/src/python/interop/interop/credentials/server1.key b/src/python/interop/interop/credentials/server1.key
new file mode 100755
index 0000000..143a5b8
--- /dev/null
+++ b/src/python/interop/interop/credentials/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/python/interop/interop/credentials/server1.pem b/src/python/interop/interop/credentials/server1.pem
new file mode 100755
index 0000000..8e582e5
--- /dev/null
+++ b/src/python/interop/interop/credentials/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/python/interop/interop/empty_pb2.py b/src/python/interop/interop/empty_pb2.py
new file mode 100644
index 0000000..753341c
--- /dev/null
+++ b/src/python/interop/interop/empty_pb2.py
@@ -0,0 +1,60 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/empty.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/empty.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1ctest/cpp/interop/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05\x45mpty')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+
+
+
+_EMPTY = _descriptor.Descriptor(
+ name='Empty',
+ full_name='grpc.testing.Empty',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=46,
+ serialized_end=53,
+)
+
+DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
+
+Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), dict(
+ DESCRIPTOR = _EMPTY,
+ __module__ = 'test.cpp.interop.empty_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.Empty)
+ ))
+_sym_db.RegisterMessage(Empty)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/messages_pb2.py b/src/python/interop/interop/messages_pb2.py
new file mode 100644
index 0000000..79270cd
--- /dev/null
+++ b/src/python/interop/interop/messages_pb2.py
@@ -0,0 +1,444 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/messages.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/messages.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1ftest/cpp/interop/messages.proto\x12\x0cgrpc.testing\"@\n\x07Payload\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\"\xb1\x01\n\rSimpleRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x15\n\rresponse_size\x18\x02 \x01(\x05\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x15\n\rfill_username\x18\x04 \x01(\x08\x12\x18\n\x10\x66ill_oauth_scope\x18\x05 \x01(\x08\"_\n\x0eSimpleResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x13\n\x0boauth_scope\x18\x03 \x01(\t\"C\n\x19StreamingInputCallRequest\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\"=\n\x1aStreamingInputCallResponse\x12\x1f\n\x17\x61ggregated_payload_size\x18\x01 \x01(\x05\"7\n\x12ResponseParameters\x12\x0c\n\x04size\x18\x01 \x01(\x05\x12\x13\n\x0binterval_us\x18\x02 \x01(\x05\"\xb5\x01\n\x1aStreamingOutputCallRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12=\n\x13response_parameters\x18\x02 \x03(\x0b\x32 .grpc.testing.ResponseParameters\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\"E\n\x1bStreamingOutputCallResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload*?\n\x0bPayloadType\x12\x10\n\x0c\x43OMPRESSABLE\x10\x00\x12\x12\n\x0eUNCOMPRESSABLE\x10\x01\x12\n\n\x06RANDOM\x10\x02')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+_PAYLOADTYPE = _descriptor.EnumDescriptor(
+ name='PayloadType',
+ full_name='grpc.testing.PayloadType',
+ filename=None,
+ file=DESCRIPTOR,
+ values=[
+ _descriptor.EnumValueDescriptor(
+ name='COMPRESSABLE', index=0, number=0,
+ options=None,
+ type=None),
+ _descriptor.EnumValueDescriptor(
+ name='UNCOMPRESSABLE', index=1, number=1,
+ options=None,
+ type=None),
+ _descriptor.EnumValueDescriptor(
+ name='RANDOM', index=2, number=2,
+ options=None,
+ type=None),
+ ],
+ containing_type=None,
+ options=None,
+ serialized_start=836,
+ serialized_end=899,
+)
+_sym_db.RegisterEnumDescriptor(_PAYLOADTYPE)
+
+PayloadType = enum_type_wrapper.EnumTypeWrapper(_PAYLOADTYPE)
+COMPRESSABLE = 0
+UNCOMPRESSABLE = 1
+RANDOM = 2
+
+
+
+_PAYLOAD = _descriptor.Descriptor(
+ name='Payload',
+ full_name='grpc.testing.Payload',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='type', full_name='grpc.testing.Payload.type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='body', full_name='grpc.testing.Payload.body', index=1,
+ number=2, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=49,
+ serialized_end=113,
+)
+
+
+_SIMPLEREQUEST = _descriptor.Descriptor(
+ name='SimpleRequest',
+ full_name='grpc.testing.SimpleRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='response_type', full_name='grpc.testing.SimpleRequest.response_type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='response_size', full_name='grpc.testing.SimpleRequest.response_size', index=1,
+ number=2, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.SimpleRequest.payload', index=2,
+ number=3, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='fill_username', full_name='grpc.testing.SimpleRequest.fill_username', index=3,
+ number=4, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='fill_oauth_scope', full_name='grpc.testing.SimpleRequest.fill_oauth_scope', index=4,
+ number=5, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=116,
+ serialized_end=293,
+)
+
+
+_SIMPLERESPONSE = _descriptor.Descriptor(
+ name='SimpleResponse',
+ full_name='grpc.testing.SimpleResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.SimpleResponse.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='username', full_name='grpc.testing.SimpleResponse.username', index=1,
+ number=2, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='oauth_scope', full_name='grpc.testing.SimpleResponse.oauth_scope', index=2,
+ number=3, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=295,
+ serialized_end=390,
+)
+
+
+_STREAMINGINPUTCALLREQUEST = _descriptor.Descriptor(
+ name='StreamingInputCallRequest',
+ full_name='grpc.testing.StreamingInputCallRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingInputCallRequest.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=392,
+ serialized_end=459,
+)
+
+
+_STREAMINGINPUTCALLRESPONSE = _descriptor.Descriptor(
+ name='StreamingInputCallResponse',
+ full_name='grpc.testing.StreamingInputCallResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='aggregated_payload_size', full_name='grpc.testing.StreamingInputCallResponse.aggregated_payload_size', index=0,
+ number=1, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=461,
+ serialized_end=522,
+)
+
+
+_RESPONSEPARAMETERS = _descriptor.Descriptor(
+ name='ResponseParameters',
+ full_name='grpc.testing.ResponseParameters',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='size', full_name='grpc.testing.ResponseParameters.size', index=0,
+ number=1, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='interval_us', full_name='grpc.testing.ResponseParameters.interval_us', index=1,
+ number=2, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=524,
+ serialized_end=579,
+)
+
+
+_STREAMINGOUTPUTCALLREQUEST = _descriptor.Descriptor(
+ name='StreamingOutputCallRequest',
+ full_name='grpc.testing.StreamingOutputCallRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='response_type', full_name='grpc.testing.StreamingOutputCallRequest.response_type', index=0,
+ number=1, type=14, cpp_type=8, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='response_parameters', full_name='grpc.testing.StreamingOutputCallRequest.response_parameters', index=1,
+ number=2, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingOutputCallRequest.payload', index=2,
+ number=3, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=582,
+ serialized_end=763,
+)
+
+
+_STREAMINGOUTPUTCALLRESPONSE = _descriptor.Descriptor(
+ name='StreamingOutputCallResponse',
+ full_name='grpc.testing.StreamingOutputCallResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='payload', full_name='grpc.testing.StreamingOutputCallResponse.payload', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=765,
+ serialized_end=834,
+)
+
+_PAYLOAD.fields_by_name['type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_SIMPLERESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGINPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_parameters'].message_type = _RESPONSEPARAMETERS
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGOUTPUTCALLRESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD
+DESCRIPTOR.message_types_by_name['SimpleRequest'] = _SIMPLEREQUEST
+DESCRIPTOR.message_types_by_name['SimpleResponse'] = _SIMPLERESPONSE
+DESCRIPTOR.message_types_by_name['StreamingInputCallRequest'] = _STREAMINGINPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingInputCallResponse'] = _STREAMINGINPUTCALLRESPONSE
+DESCRIPTOR.message_types_by_name['ResponseParameters'] = _RESPONSEPARAMETERS
+DESCRIPTOR.message_types_by_name['StreamingOutputCallRequest'] = _STREAMINGOUTPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingOutputCallResponse'] = _STREAMINGOUTPUTCALLRESPONSE
+DESCRIPTOR.enum_types_by_name['PayloadType'] = _PAYLOADTYPE
+
+Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict(
+ DESCRIPTOR = _PAYLOAD,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.Payload)
+ ))
+_sym_db.RegisterMessage(Payload)
+
+SimpleRequest = _reflection.GeneratedProtocolMessageType('SimpleRequest', (_message.Message,), dict(
+ DESCRIPTOR = _SIMPLEREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.SimpleRequest)
+ ))
+_sym_db.RegisterMessage(SimpleRequest)
+
+SimpleResponse = _reflection.GeneratedProtocolMessageType('SimpleResponse', (_message.Message,), dict(
+ DESCRIPTOR = _SIMPLERESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.SimpleResponse)
+ ))
+_sym_db.RegisterMessage(SimpleResponse)
+
+StreamingInputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingInputCallRequest', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGINPUTCALLREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallRequest)
+ ))
+_sym_db.RegisterMessage(StreamingInputCallRequest)
+
+StreamingInputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingInputCallResponse', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGINPUTCALLRESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallResponse)
+ ))
+_sym_db.RegisterMessage(StreamingInputCallResponse)
+
+ResponseParameters = _reflection.GeneratedProtocolMessageType('ResponseParameters', (_message.Message,), dict(
+ DESCRIPTOR = _RESPONSEPARAMETERS,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.ResponseParameters)
+ ))
+_sym_db.RegisterMessage(ResponseParameters)
+
+StreamingOutputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingOutputCallRequest', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGOUTPUTCALLREQUEST,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallRequest)
+ ))
+_sym_db.RegisterMessage(StreamingOutputCallRequest)
+
+StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingOutputCallResponse', (_message.Message,), dict(
+ DESCRIPTOR = _STREAMINGOUTPUTCALLRESPONSE,
+ __module__ = 'test.cpp.interop.messages_pb2'
+ # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallResponse)
+ ))
+_sym_db.RegisterMessage(StreamingOutputCallResponse)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
new file mode 100644
index 0000000..854dbec
--- /dev/null
+++ b/src/python/interop/interop/methods.py
@@ -0,0 +1,109 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Implementations of interoperability test methods."""
+
+from grpc.early_adopter import utilities
+
+from interop import empty_pb2
+from interop import messages_pb2
+
+def _empty_call(request):
+ return empty_pb2.Empty()
+
+EMPTY_CALL = utilities.unary_unary_rpc_method(
+ _empty_call, empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString,
+ empty_pb2.Empty.SerializeToString, empty_pb2.Empty.FromString)
+
+
+def _unary_call(request):
+ return messages_pb2.SimpleResponse(
+ payload=messages_pb2.Payload(
+ type=messages_pb2.COMPRESSABLE,
+ body=b'\x00' * request.response_size))
+
+UNARY_CALL = utilities.unary_unary_rpc_method(
+ _unary_call, messages_pb2.SimpleRequest.SerializeToString,
+ messages_pb2.SimpleRequest.FromString,
+ messages_pb2.SimpleResponse.SerializeToString,
+ messages_pb2.SimpleResponse.FromString)
+
+
+def _streaming_output_call(request):
+ for response_parameters in request.response_parameters:
+ yield messages_pb2.StreamingOutputCallResponse(
+ payload=messages_pb2.Payload(
+ type=request.response_type,
+ body=b'\x00' * response_parameters.size))
+
+STREAMING_OUTPUT_CALL = utilities.unary_stream_rpc_method(
+ _streaming_output_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
+
+
+def _streaming_input_call(request_iterator):
+ aggregate_size = 0
+ for request in request_iterator:
+ if request.payload and request.payload.body:
+ aggregate_size += len(request.payload.body)
+ return messages_pb2.StreamingInputCallResponse(
+ aggregated_payload_size=aggregate_size)
+
+STREAMING_INPUT_CALL = utilities.stream_unary_rpc_method(
+ _streaming_input_call,
+ messages_pb2.StreamingInputCallRequest.SerializeToString,
+ messages_pb2.StreamingInputCallRequest.FromString,
+ messages_pb2.StreamingInputCallResponse.SerializeToString,
+ messages_pb2.StreamingInputCallResponse.FromString)
+
+
+def _full_duplex_call(request_iterator):
+ for request in request_iterator:
+ yield messages_pb2.StreamingOutputCallResponse(
+ payload=messages_pb2.Payload(
+ type=request.payload.type,
+ body=b'\x00' * request.response_parameters[0].size))
+
+FULL_DUPLEX_CALL = utilities.stream_stream_rpc_method(
+ _full_duplex_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
+
+# NOTE(nathaniel): Apparently this is the same as the full-duplex call?
+HALF_DUPLEX_CALL = utilities.stream_stream_rpc_method(
+ _full_duplex_call,
+ messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ messages_pb2.StreamingOutputCallRequest.FromString,
+ messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ messages_pb2.StreamingOutputCallResponse.FromString)
diff --git a/src/python/interop/interop/server.py b/src/python/interop/interop/server.py
new file mode 100644
index 0000000..0035e06
--- /dev/null
+++ b/src/python/interop/interop/server.py
@@ -0,0 +1,91 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""The Python implementation of the GRPC interoperability test server."""
+
+import argparse
+import logging
+import pkg_resources
+import time
+
+from grpc.early_adopter import implementations
+
+from interop import methods
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
+_CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
+
+_METHODS = {
+ '/grpc.testing.TestService/EmptyCall': methods.EMPTY_CALL,
+ '/grpc.testing.TestService/UnaryCall': methods.UNARY_CALL,
+ '/grpc.testing.TestService/StreamingOutputCall':
+ methods.STREAMING_OUTPUT_CALL,
+ '/grpc.testing.TestService/StreamingInputCall':
+ methods.STREAMING_INPUT_CALL,
+ '/grpc.testing.TestService/FullDuplexCall':
+ methods.FULL_DUPLEX_CALL,
+ '/grpc.testing.TestService/HalfDuplexCall':
+ methods.HALF_DUPLEX_CALL,
+}
+
+
+def serve():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--port', help='the port on which to serve', type=int)
+ parser.add_argument(
+ '--use_tls', help='require a secure connection', dest='use_tls',
+ action='store_true')
+ args = parser.parse_args()
+
+ if args.use_tls:
+ private_key = pkg_resources.resource_string(
+ __name__, _PRIVATE_KEY_RESOURCE_PATH)
+ certificate_chain = pkg_resources.resource_string(
+ __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
+ server = implementations.secure_server(
+ _METHODS, args.port, private_key, certificate_chain)
+ else:
+ server = implementations.insecure_server(
+ _METHODS, args.port)
+
+ server.start()
+ logging.info('Server serving.')
+ try:
+ while True:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except BaseException as e:
+ logging.info('Caught exception "%s"; stopping server...', e)
+ server.stop()
+ logging.info('Server stopped; exiting.')
+
+if __name__ == '__main__':
+ serve()
diff --git a/src/python/interop/interop/test_pb2.py b/src/python/interop/interop/test_pb2.py
new file mode 100644
index 0000000..1241453
--- /dev/null
+++ b/src/python/interop/interop/test_pb2.py
@@ -0,0 +1,32 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: test/cpp/interop/test.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from test.cpp.interop import empty_pb2 as test_dot_cpp_dot_interop_dot_empty__pb2
+from test.cpp.interop import messages_pb2 as test_dot_cpp_dot_interop_dot_messages__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='test/cpp/interop/test.proto',
+ package='grpc.testing',
+ serialized_pb=_b('\n\x1btest/cpp/interop/test.proto\x12\x0cgrpc.testing\x1a\x1ctest/cpp/interop/empty.proto\x1a\x1ftest/cpp/interop/messages.proto2\xbb\x04\n\x0bTestService\x12\x35\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\x12\x46\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12\'.grpc.testing.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallResponse(\x01\x12i\n\x0e\x46ullDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01\x12i\n\x0eHalfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.StreamingOutputCallResponse(\x01\x30\x01')
+ ,
+ dependencies=[test_dot_cpp_dot_interop_dot_empty__pb2.DESCRIPTOR,test_dot_cpp_dot_interop_dot_messages__pb2.DESCRIPTOR,])
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+
+
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py b/src/python/interop/setup.py
similarity index 75%
copy from src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py
copy to src/python/interop/setup.py
index 69d91ec..4b7709f 100644
--- a/src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py
+++ b/src/python/interop/setup.py
@@ -27,20 +27,25 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""One of the tests of the Face layer of RPC Framework."""
+"""A setup module for the GRPC Python interop testing package."""
-import unittest
+from distutils import core as _core
-from _adapter import _face_test_case
-from _framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case
+_PACKAGES = (
+ 'interop',
+)
+_PACKAGE_DIRECTORIES = {
+ 'interop': 'interop',
+}
-class EventInvocationSynchronousEventServiceTest(
- _face_test_case.FaceTestCase,
- test_case.EventInvocationSynchronousEventServiceTestCase,
- unittest.TestCase):
- pass
+_PACKAGE_DATA = {
+ 'interop': ['credentials/server1.key', 'credentials/server1.pem',]
+}
+_INSTALL_REQUIRES = ['grpc-2015>=0.0.1']
-if __name__ == '__main__':
- unittest.main()
+_core.setup(
+ name='interop', version='0.0.1', packages=_PACKAGES,
+ package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA,
+ install_requires=_INSTALL_REQUIRES)
diff --git a/src/python/src/__init__.py b/src/python/src/grpc/__init__.py
similarity index 100%
rename from src/python/src/__init__.py
rename to src/python/src/grpc/__init__.py
diff --git a/src/python/src/_adapter/__init__.py b/src/python/src/grpc/_adapter/__init__.py
similarity index 100%
rename from src/python/src/_adapter/__init__.py
rename to src/python/src/grpc/_adapter/__init__.py
diff --git a/src/python/src/_adapter/_blocking_invocation_inline_service_test.py b/src/python/src/grpc/_adapter/_blocking_invocation_inline_service_test.py
similarity index 67%
rename from src/python/src/_adapter/_blocking_invocation_inline_service_test.py
rename to src/python/src/grpc/_adapter/_blocking_invocation_inline_service_test.py
index 873ce9a..761e5cf 100644
--- a/src/python/src/_adapter/_blocking_invocation_inline_service_test.py
+++ b/src/python/src/grpc/_adapter/_blocking_invocation_inline_service_test.py
@@ -2,8 +2,8 @@
import unittest
-from _adapter import _face_test_case
-from _framework.face.testing import blocking_invocation_inline_service_test_case as test_case
+from grpc._adapter import _face_test_case
+from grpc.framework.face.testing import blocking_invocation_inline_service_test_case as test_case
class BlockingInvocationInlineServiceTest(
diff --git a/src/python/src/_adapter/_c.c b/src/python/src/grpc/_adapter/_c.c
similarity index 92%
rename from src/python/src/_adapter/_c.c
rename to src/python/src/grpc/_adapter/_c.c
index 6fb7fa2..13eb93f 100644
--- a/src/python/src/_adapter/_c.c
+++ b/src/python/src/grpc/_adapter/_c.c
@@ -34,11 +34,11 @@
#include <Python.h>
#include <grpc/grpc.h>
-#include "_adapter/_completion_queue.h"
-#include "_adapter/_channel.h"
-#include "_adapter/_call.h"
-#include "_adapter/_server.h"
-#include "_adapter/_server_credentials.h"
+#include "grpc/_adapter/_completion_queue.h"
+#include "grpc/_adapter/_channel.h"
+#include "grpc/_adapter/_call.h"
+#include "grpc/_adapter/_server.h"
+#include "grpc/_adapter/_server_credentials.h"
static PyObject *init(PyObject *self, PyObject *args) {
grpc_init();
diff --git a/src/python/src/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py
similarity index 98%
rename from src/python/src/_adapter/_c_test.py
rename to src/python/src/grpc/_adapter/_c_test.py
index 210ac1f..d421692 100644
--- a/src/python/src/_adapter/_c_test.py
+++ b/src/python/src/grpc/_adapter/_c_test.py
@@ -33,8 +33,8 @@
import time
import unittest
-from _adapter import _c
-from _adapter import _datatypes
+from grpc._adapter import _c
+from grpc._adapter import _datatypes
_TIMEOUT = 3
_FUTURE = time.time() + 60 * 60 * 24
diff --git a/src/python/src/_adapter/_call.c b/src/python/src/grpc/_adapter/_call.c
similarity index 98%
rename from src/python/src/_adapter/_call.c
rename to src/python/src/grpc/_adapter/_call.c
index 3bc35be..a2cc590 100644
--- a/src/python/src/_adapter/_call.c
+++ b/src/python/src/grpc/_adapter/_call.c
@@ -31,15 +31,15 @@
*
*/
-#include "_adapter/_call.h"
+#include "grpc/_adapter/_call.h"
#include <math.h>
#include <Python.h>
#include <grpc/grpc.h>
-#include "_adapter/_channel.h"
-#include "_adapter/_completion_queue.h"
-#include "_adapter/_error.h"
+#include "grpc/_adapter/_channel.h"
+#include "grpc/_adapter/_completion_queue.h"
+#include "grpc/_adapter/_error.h"
static int pygrpc_call_init(Call *self, PyObject *args, PyObject *kwds) {
const PyObject *channel;
diff --git a/src/python/src/_adapter/_call.h b/src/python/src/grpc/_adapter/_call.h
similarity index 100%
rename from src/python/src/_adapter/_call.h
rename to src/python/src/grpc/_adapter/_call.h
diff --git a/src/python/src/_adapter/_channel.c b/src/python/src/grpc/_adapter/_channel.c
similarity index 98%
rename from src/python/src/_adapter/_channel.c
rename to src/python/src/grpc/_adapter/_channel.c
index d41ebd4..6962722 100644
--- a/src/python/src/_adapter/_channel.c
+++ b/src/python/src/grpc/_adapter/_channel.c
@@ -31,7 +31,7 @@
*
*/
-#include "_adapter/_channel.h"
+#include "grpc/_adapter/_channel.h"
#include <Python.h>
#include <grpc/grpc.h>
diff --git a/src/python/src/_adapter/_channel.h b/src/python/src/grpc/_adapter/_channel.h
similarity index 100%
rename from src/python/src/_adapter/_channel.h
rename to src/python/src/grpc/_adapter/_channel.h
diff --git a/src/python/src/_adapter/_common.py b/src/python/src/grpc/_adapter/_common.py
similarity index 100%
rename from src/python/src/_adapter/_common.py
rename to src/python/src/grpc/_adapter/_common.py
diff --git a/src/python/src/_adapter/_completion_queue.c b/src/python/src/grpc/_adapter/_completion_queue.c
similarity index 99%
rename from src/python/src/_adapter/_completion_queue.c
rename to src/python/src/grpc/_adapter/_completion_queue.c
index 7c951d2..1d593d0 100644
--- a/src/python/src/_adapter/_completion_queue.c
+++ b/src/python/src/grpc/_adapter/_completion_queue.c
@@ -31,13 +31,13 @@
*
*/
-#include "_adapter/_completion_queue.h"
+#include "grpc/_adapter/_completion_queue.h"
#include <Python.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
-#include "_adapter/_call.h"
+#include "grpc/_adapter/_call.h"
static PyObject *status_class;
static PyObject *service_acceptance_class;
@@ -500,7 +500,7 @@
}
int pygrpc_add_completion_queue(PyObject *module) {
- char *datatypes_module_path = "_adapter._datatypes";
+ char *datatypes_module_path = "grpc._adapter._datatypes";
PyObject *datatypes_module = PyImport_ImportModule(datatypes_module_path);
if (datatypes_module == NULL) {
PyErr_SetString(PyExc_ImportError, datatypes_module_path);
diff --git a/src/python/src/_adapter/_completion_queue.h b/src/python/src/grpc/_adapter/_completion_queue.h
similarity index 100%
rename from src/python/src/_adapter/_completion_queue.h
rename to src/python/src/grpc/_adapter/_completion_queue.h
diff --git a/src/python/src/_adapter/_datatypes.py b/src/python/src/grpc/_adapter/_datatypes.py
similarity index 100%
rename from src/python/src/_adapter/_datatypes.py
rename to src/python/src/grpc/_adapter/_datatypes.py
diff --git a/src/python/src/_adapter/_error.c b/src/python/src/grpc/_adapter/_error.c
similarity index 98%
rename from src/python/src/_adapter/_error.c
rename to src/python/src/grpc/_adapter/_error.c
index 8c04f4b..a8a1dbc 100644
--- a/src/python/src/_adapter/_error.c
+++ b/src/python/src/grpc/_adapter/_error.c
@@ -31,7 +31,7 @@
*
*/
-#include "_adapter/_error.h"
+#include "grpc/_adapter/_error.h"
#include <Python.h>
#include <grpc/grpc.h>
diff --git a/src/python/src/_adapter/_error.h b/src/python/src/grpc/_adapter/_error.h
similarity index 100%
rename from src/python/src/_adapter/_error.h
rename to src/python/src/grpc/_adapter/_error.h
diff --git a/src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py b/src/python/src/grpc/_adapter/_event_invocation_synchronous_event_service_test.py
similarity index 92%
rename from src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py
rename to src/python/src/grpc/_adapter/_event_invocation_synchronous_event_service_test.py
index 69d91ec..b9a13ce 100644
--- a/src/python/src/_adapter/_event_invocation_synchronous_event_service_test.py
+++ b/src/python/src/grpc/_adapter/_event_invocation_synchronous_event_service_test.py
@@ -31,8 +31,8 @@
import unittest
-from _adapter import _face_test_case
-from _framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case
+from grpc._adapter import _face_test_case
+from grpc.framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case
class EventInvocationSynchronousEventServiceTest(
diff --git a/src/python/src/_adapter/_face_test_case.py b/src/python/src/grpc/_adapter/_face_test_case.py
similarity index 90%
rename from src/python/src/_adapter/_face_test_case.py
rename to src/python/src/grpc/_adapter/_face_test_case.py
index 112dcfb..da73366 100644
--- a/src/python/src/_adapter/_face_test_case.py
+++ b/src/python/src/grpc/_adapter/_face_test_case.py
@@ -31,15 +31,15 @@
import unittest
-from _adapter import fore
-from _adapter import rear
-from _framework.base import util
-from _framework.base.packets import implementations as tickets_implementations
-from _framework.face import implementations as face_implementations
-from _framework.face.testing import coverage
-from _framework.face.testing import serial
-from _framework.face.testing import test_case
-from _framework.foundation import logging_pool
+from grpc._adapter import fore
+from grpc._adapter import rear
+from grpc.framework.base import util
+from grpc.framework.base.packets import implementations as tickets_implementations
+from grpc.framework.face import implementations as face_implementations
+from grpc.framework.face.testing import coverage
+from grpc.framework.face.testing import serial
+from grpc.framework.face.testing import test_case
+from grpc.framework.foundation import logging_pool
_TIMEOUT = 3
_MAXIMUM_TIMEOUT = 90
@@ -80,7 +80,7 @@
fore_link = fore.ForeLink(
pool, serialization.request_deserializers,
- serialization.response_serializers)
+ serialization.response_serializers, None, ())
port = fore_link.start()
rear_link = rear.RearLink(
'localhost', port, pool,
diff --git a/src/python/src/_adapter/_future_invocation_asynchronous_event_service_test.py b/src/python/src/grpc/_adapter/_future_invocation_asynchronous_event_service_test.py
similarity index 92%
rename from src/python/src/_adapter/_future_invocation_asynchronous_event_service_test.py
rename to src/python/src/grpc/_adapter/_future_invocation_asynchronous_event_service_test.py
index 3db39dd..7d6a4ff 100644
--- a/src/python/src/_adapter/_future_invocation_asynchronous_event_service_test.py
+++ b/src/python/src/grpc/_adapter/_future_invocation_asynchronous_event_service_test.py
@@ -31,8 +31,8 @@
import unittest
-from _adapter import _face_test_case
-from _framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case
+from grpc._adapter import _face_test_case
+from grpc.framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case
class FutureInvocationAsynchronousEventServiceTest(
diff --git a/src/python/src/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
similarity index 95%
rename from src/python/src/_adapter/_links_test.py
rename to src/python/src/grpc/_adapter/_links_test.py
index 8341460..ba7660b 100644
--- a/src/python/src/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -32,13 +32,13 @@
import threading
import unittest
-from _adapter import _proto_scenarios
-from _adapter import _test_links
-from _adapter import fore
-from _adapter import rear
-from _framework.base import interfaces
-from _framework.base.packets import packets as tickets
-from _framework.foundation import logging_pool
+from grpc._adapter import _proto_scenarios
+from grpc._adapter import _test_links
+from grpc._adapter import fore
+from grpc._adapter import rear
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import packets as tickets
+from grpc.framework.foundation import logging_pool
_IDENTITY = lambda x: x
_TIMEOUT = 2
@@ -67,7 +67,7 @@
test_rear_link = _test_links.RearLink(rear_action, None)
fore_link = fore.ForeLink(
- self.fore_link_pool, {test_method: None}, {test_method: None})
+ self.fore_link_pool, {test_method: None}, {test_method: None}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
@@ -120,7 +120,7 @@
fore_link = fore.ForeLink(
self.fore_link_pool, {test_method: _IDENTITY},
- {test_method: _IDENTITY})
+ {test_method: _IDENTITY}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
@@ -182,7 +182,7 @@
fore_link = fore.ForeLink(
self.fore_link_pool, {test_method: scenario.deserialize_request},
- {test_method: scenario.serialize_response})
+ {test_method: scenario.serialize_response}, None, ())
fore_link.join_rear_link(test_rear_link)
test_rear_link.join_fore_link(fore_link)
port = fore_link.start()
diff --git a/src/python/src/_adapter/_lonely_rear_link_test.py b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
similarity index 93%
rename from src/python/src/_adapter/_lonely_rear_link_test.py
rename to src/python/src/grpc/_adapter/_lonely_rear_link_test.py
index 7ccdb0b..fd502a1 100644
--- a/src/python/src/_adapter/_lonely_rear_link_test.py
+++ b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
@@ -31,11 +31,11 @@
import unittest
-from _adapter import _test_links
-from _adapter import rear
-from _framework.base import interfaces
-from _framework.base.packets import packets
-from _framework.foundation import logging_pool
+from grpc._adapter import _test_links
+from grpc._adapter import rear
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import packets
+from grpc.framework.foundation import logging_pool
_IDENTITY = lambda x: x
_TIMEOUT = 2
diff --git a/src/python/src/_adapter/_low.py b/src/python/src/grpc/_adapter/_low.py
similarity index 94%
rename from src/python/src/_adapter/_low.py
rename to src/python/src/grpc/_adapter/_low.py
index 6c24087..2ef2eb8 100644
--- a/src/python/src/_adapter/_low.py
+++ b/src/python/src/grpc/_adapter/_low.py
@@ -32,8 +32,8 @@
import atexit
import gc
-from _adapter import _c
-from _adapter import _datatypes
+from grpc._adapter import _c
+from grpc._adapter import _datatypes
def _shut_down():
# force garbage collection before shutting down grpc, to ensure all grpc
@@ -52,4 +52,5 @@
Channel = _c.Channel
CompletionQueue = _c.CompletionQueue
Server = _c.Server
+ServerCredentials = _c.ServerCredentials
# pylint: enable=invalid-name
diff --git a/src/python/src/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
similarity index 99%
rename from src/python/src/_adapter/_low_test.py
rename to src/python/src/grpc/_adapter/_low_test.py
index 899ccf5..898c62c 100644
--- a/src/python/src/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -32,7 +32,7 @@
import time
import unittest
-from _adapter import _low
+from grpc._adapter import _low
_STREAM_LENGTH = 300
_TIMEOUT = 5
diff --git a/src/python/src/_adapter/_proto_scenarios.py b/src/python/src/grpc/_adapter/_proto_scenarios.py
similarity index 99%
rename from src/python/src/_adapter/_proto_scenarios.py
rename to src/python/src/grpc/_adapter/_proto_scenarios.py
index c452fb5..60a622b 100644
--- a/src/python/src/_adapter/_proto_scenarios.py
+++ b/src/python/src/grpc/_adapter/_proto_scenarios.py
@@ -32,7 +32,7 @@
import abc
import threading
-from _junkdrawer import math_pb2
+from grpc._junkdrawer import math_pb2
class ProtoScenario(object):
diff --git a/src/python/src/_adapter/_server.c b/src/python/src/grpc/_adapter/_server.c
similarity index 89%
rename from src/python/src/_adapter/_server.c
rename to src/python/src/grpc/_adapter/_server.c
index 503be61..d4bf5fb 100644
--- a/src/python/src/_adapter/_server.c
+++ b/src/python/src/grpc/_adapter/_server.c
@@ -31,14 +31,14 @@
*
*/
-#include "_adapter/_server.h"
+#include "grpc/_adapter/_server.h"
#include <Python.h>
#include <grpc/grpc.h>
-#include "_adapter/_completion_queue.h"
-#include "_adapter/_error.h"
-#include "_adapter/_server_credentials.h"
+#include "grpc/_adapter/_completion_queue.h"
+#include "grpc/_adapter/_error.h"
+#include "grpc/_adapter/_server_credentials.h"
static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) {
const PyObject *completion_queue;
@@ -85,6 +85,19 @@
return PyInt_FromLong(port);
}
+static PyObject *pygrpc_server_add_secure_http2_addr(Server *self,
+ PyObject *args) {
+ const char *addr;
+ int port;
+ PyArg_ParseTuple(args, "s", &addr);
+ port = grpc_server_add_secure_http2_port(self->c_server, addr);
+ if (port == 0) {
+ PyErr_SetString(PyExc_RuntimeError, "Couldn't add port to server!");
+ return NULL;
+ }
+ return PyInt_FromLong(port);
+}
+
static PyObject *pygrpc_server_start(Server *self) {
grpc_server_start(self->c_server);
@@ -118,6 +131,8 @@
static PyMethodDef methods[] = {
{"add_http2_addr", (PyCFunction)pygrpc_server_add_http2_addr, METH_VARARGS,
"Add an HTTP2 address."},
+ {"add_secure_http2_addr", (PyCFunction)pygrpc_server_add_secure_http2_addr,
+ METH_VARARGS, "Add a secure HTTP2 address."},
{"start", (PyCFunction)pygrpc_server_start, METH_NOARGS,
"Starts the server."},
{"service", (PyCFunction)pygrpc_server_service, METH_VARARGS,
diff --git a/src/python/src/_adapter/_server.h b/src/python/src/grpc/_adapter/_server.h
similarity index 100%
rename from src/python/src/_adapter/_server.h
rename to src/python/src/grpc/_adapter/_server.h
diff --git a/src/python/src/_adapter/_server_credentials.c b/src/python/src/grpc/_adapter/_server_credentials.c
similarity index 98%
rename from src/python/src/_adapter/_server_credentials.c
rename to src/python/src/grpc/_adapter/_server_credentials.c
index 390266a..ae85fd3 100644
--- a/src/python/src/_adapter/_server_credentials.c
+++ b/src/python/src/grpc/_adapter/_server_credentials.c
@@ -31,7 +31,7 @@
*
*/
-#include "_adapter/_server_credentials.h"
+#include "grpc/_adapter/_server_credentials.h"
#include <Python.h>
#include <grpc/grpc_security.h>
diff --git a/src/python/src/_adapter/_server_credentials.h b/src/python/src/grpc/_adapter/_server_credentials.h
similarity index 100%
rename from src/python/src/_adapter/_server_credentials.h
rename to src/python/src/grpc/_adapter/_server_credentials.h
diff --git a/src/python/src/_adapter/_test_links.py b/src/python/src/grpc/_adapter/_test_links.py
similarity index 97%
rename from src/python/src/_adapter/_test_links.py
rename to src/python/src/grpc/_adapter/_test_links.py
index 77d1b00..ac0d6e2 100644
--- a/src/python/src/_adapter/_test_links.py
+++ b/src/python/src/grpc/_adapter/_test_links.py
@@ -31,7 +31,7 @@
import threading
-from _framework.base.packets import interfaces
+from grpc.framework.base.packets import interfaces
class ForeLink(interfaces.ForeLink):
diff --git a/src/python/src/_adapter/fore.py b/src/python/src/grpc/_adapter/fore.py
similarity index 89%
rename from src/python/src/_adapter/fore.py
rename to src/python/src/grpc/_adapter/fore.py
index 2f10275..f72b2fd 100644
--- a/src/python/src/_adapter/fore.py
+++ b/src/python/src/grpc/_adapter/fore.py
@@ -34,12 +34,12 @@
import threading
import time
-from _adapter import _common
-from _adapter import _low
-from _framework.base import interfaces
-from _framework.base.packets import interfaces as ticket_interfaces
-from _framework.base.packets import null
-from _framework.base.packets import packets as tickets
+from grpc._adapter import _common
+from grpc._adapter import _low
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import interfaces as ticket_interfaces
+from grpc.framework.base.packets import null
+from grpc.framework.base.packets import packets as tickets
@enum.unique
@@ -69,7 +69,8 @@
"""A service-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
- self, pool, request_deserializers, response_serializers, port=None):
+ self, pool, request_deserializers, response_serializers,
+ root_certificates, key_chain_pairs, port=None):
"""Constructor.
Args:
@@ -78,6 +79,10 @@
deserializer behaviors.
response_serializers: A dict from RPC method names to response object
serializer behaviors.
+ root_certificates: The PEM-encoded client root certificates as a
+ bytestring or None.
+ key_chain_pairs: A sequence of PEM-encoded private key-certificate chain
+ pairs.
port: The port on which to serve, or None to have a port selected
automatically.
"""
@@ -85,6 +90,8 @@
self._pool = pool
self._request_deserializers = request_deserializers
self._response_serializers = response_serializers
+ self._root_certificates = root_certificates
+ self._key_chain_pairs = key_chain_pairs
self._port = port
self._rear_link = null.NULL_REAR_LINK
@@ -264,10 +271,16 @@
object.
"""
with self._condition:
+ address = '[::]:%d' % (0 if self._port is None else self._port)
self._completion_queue = _low.CompletionQueue()
- self._server = _low.Server(self._completion_queue, None)
- port = self._server.add_http2_addr(
- '[::]:%d' % (0 if self._port is None else self._port))
+ if self._root_certificates is None and not self._key_chain_pairs:
+ self._server = _low.Server(self._completion_queue, None)
+ port = self._server.add_http2_addr(address)
+ else:
+ server_credentials = _low.ServerCredentials(
+ self._root_certificates, self._key_chain_pairs)
+ self._server = _low.Server(self._completion_queue, server_credentials)
+ port = self._server.add_secure_http2_addr(address)
self._server.start()
self._server.service(None)
diff --git a/src/python/src/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
similarity index 97%
rename from src/python/src/_adapter/rear.py
rename to src/python/src/grpc/_adapter/rear.py
index 5e0975a..c47c0aa 100644
--- a/src/python/src/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -34,11 +34,11 @@
import threading
import time
-from _adapter import _common
-from _adapter import _low
-from _framework.base.packets import interfaces as ticket_interfaces
-from _framework.base.packets import null
-from _framework.base.packets import packets as tickets
+from grpc._adapter import _common
+from grpc._adapter import _low
+from grpc.framework.base.packets import interfaces as ticket_interfaces
+from grpc.framework.base.packets import null
+from grpc.framework.base.packets import packets as tickets
_INVOCATION_EVENT_KINDS = (
_low.Event.Kind.METADATA_ACCEPTED,
diff --git a/src/python/src/_junkdrawer/__init__.py b/src/python/src/grpc/_junkdrawer/__init__.py
similarity index 100%
rename from src/python/src/_junkdrawer/__init__.py
rename to src/python/src/grpc/_junkdrawer/__init__.py
diff --git a/src/python/src/_junkdrawer/math_pb2.py b/src/python/src/grpc/_junkdrawer/math_pb2.py
similarity index 100%
rename from src/python/src/_junkdrawer/math_pb2.py
rename to src/python/src/grpc/_junkdrawer/math_pb2.py
diff --git a/src/python/src/_junkdrawer/stock_pb2.py b/src/python/src/grpc/_junkdrawer/stock_pb2.py
similarity index 100%
rename from src/python/src/_junkdrawer/stock_pb2.py
rename to src/python/src/grpc/_junkdrawer/stock_pb2.py
diff --git a/src/python/src/_adapter/__init__.py b/src/python/src/grpc/early_adopter/__init__.py
similarity index 100%
copy from src/python/src/_adapter/__init__.py
copy to src/python/src/grpc/early_adopter/__init__.py
diff --git a/src/python/src/grpc/early_adopter/_face_utilities.py b/src/python/src/grpc/early_adopter/_face_utilities.py
new file mode 100644
index 0000000..714f2bb
--- /dev/null
+++ b/src/python/src/grpc/early_adopter/_face_utilities.py
@@ -0,0 +1,143 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import abc
+import collections
+
+from grpc.framework.face import interfaces as face_interfaces
+
+from grpc.early_adopter import interfaces
+
+
+class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod):
+
+ def __init__(self, unary_unary_rpc_method):
+ self._method = unary_unary_rpc_method
+
+ def service(self, request, context):
+ """See face_interfaces.InlineValueInValueOutMethod.service for spec."""
+ return self._method.service_unary_unary(request)
+
+
+class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod):
+
+ def __init__(self, unary_stream_rpc_method):
+ self._method = unary_stream_rpc_method
+
+ def service(self, request, context):
+ """See face_interfaces.InlineValueInStreamOutMethod.service for spec."""
+ return self._method.service_unary_stream(request)
+
+
+class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod):
+
+ def __init__(self, stream_unary_rpc_method):
+ self._method = stream_unary_rpc_method
+
+ def service(self, request_iterator, context):
+ """See face_interfaces.InlineStreamInValueOutMethod.service for spec."""
+ return self._method.service_stream_unary(request_iterator)
+
+
+class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod):
+
+ def __init__(self, stream_stream_rpc_method):
+ self._method = stream_stream_rpc_method
+
+ def service(self, request_iterator, context):
+ """See face_interfaces.InlineStreamInStreamOutMethod.service for spec."""
+ return self._method.service_stream_stream(request_iterator)
+
+
+class Breakdown(object):
+ """An intermediate representation of implementations of RPC methods.
+
+ Attributes:
+ unary_unary_methods:
+ unary_stream_methods:
+ stream_unary_methods:
+ stream_stream_methods:
+ request_serializers:
+ request_deserializers:
+ response_serializers:
+ response_deserializers:
+ """
+ __metaclass__ = abc.ABCMeta
+
+
+
+class _EasyBreakdown(
+ Breakdown,
+ collections.namedtuple(
+ '_EasyBreakdown',
+ ['unary_unary_methods', 'unary_stream_methods', 'stream_unary_methods',
+ 'stream_stream_methods', 'request_serializers',
+ 'request_deserializers', 'response_serializers',
+ 'response_deserializers'])):
+ pass
+
+
+def break_down(methods):
+ """Breaks down RPC methods.
+
+ Args:
+ methods: A dictionary from RPC mthod name to
+ interfaces.RpcMethod object describing the RPCs.
+
+ Returns:
+ A Breakdown corresponding to the given methods.
+ """
+ unary_unary = {}
+ unary_stream = {}
+ stream_unary = {}
+ stream_stream = {}
+ request_serializers = {}
+ request_deserializers = {}
+ response_serializers = {}
+ response_deserializers = {}
+
+ for name, method in methods.iteritems():
+ cardinality = method.cardinality()
+ if cardinality is interfaces.Cardinality.UNARY_UNARY:
+ unary_unary[name] = _InlineUnaryUnaryMethod(method)
+ elif cardinality is interfaces.Cardinality.UNARY_STREAM:
+ unary_stream[name] = _InlineUnaryStreamMethod(method)
+ elif cardinality is interfaces.Cardinality.STREAM_UNARY:
+ stream_unary[name] = _InlineStreamUnaryMethod(method)
+ elif cardinality is interfaces.Cardinality.STREAM_STREAM:
+ stream_stream[name] = _InlineStreamStreamMethod(method)
+ request_serializers[name] = method.serialize_request
+ request_deserializers[name] = method.deserialize_request
+ response_serializers[name] = method.serialize_response
+ response_deserializers[name] = method.deserialize_response
+
+ return _EasyBreakdown(
+ unary_unary, unary_stream, stream_unary, stream_stream,
+ request_serializers, request_deserializers, response_serializers,
+ response_deserializers)
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
new file mode 100644
index 0000000..cd9dd5a
--- /dev/null
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -0,0 +1,129 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Entry points into GRPC."""
+
+import threading
+
+from grpc._adapter import fore
+from grpc.framework.base.packets import implementations as _tickets_implementations
+from grpc.framework.face import implementations as _face_implementations
+from grpc.framework.foundation import logging_pool
+from grpc.early_adopter import _face_utilities
+from grpc.early_adopter import interfaces
+
+_MEGA_TIMEOUT = 60 * 60 * 24
+_THREAD_POOL_SIZE = 80
+
+
+class _Server(interfaces.Server):
+
+ def __init__(self, breakdown, port, private_key, certificate_chain):
+ self._lock = threading.Lock()
+ self._breakdown = breakdown
+ self._port = port
+ self._private_key = private_key
+ self._certificate_chain = certificate_chain
+
+ self._pool = None
+ self._fore_link = None
+ self._back = None
+
+ def start(self):
+ """See interfaces.Server.start for specification."""
+ with self._lock:
+ if self._pool is None:
+ self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ servicer = _face_implementations.servicer(
+ self._pool,
+ inline_value_in_value_out_methods=self._breakdown.unary_unary_methods,
+ inline_value_in_stream_out_methods=self._breakdown.unary_stream_methods,
+ inline_stream_in_value_out_methods=self._breakdown.stream_unary_methods,
+ inline_stream_in_stream_out_methods=self._breakdown.stream_stream_methods)
+ self._fore_link = fore.ForeLink(
+ self._pool, self._breakdown.request_deserializers,
+ self._breakdown.response_serializers, None,
+ ((self._private_key, self._certificate_chain),), port=self._port)
+ port = self._fore_link.start()
+ self._back = _tickets_implementations.back(
+ servicer, self._pool, self._pool, self._pool, _MEGA_TIMEOUT,
+ _MEGA_TIMEOUT)
+ self._fore_link.join_rear_link(self._back)
+ self._back.join_fore_link(self._fore_link)
+ return port
+ else:
+ raise ValueError('Server currently running!')
+
+ def stop(self):
+ """See interfaces.Server.stop for specification."""
+ with self._lock:
+ if self._pool is None:
+ raise ValueError('Server not running!')
+ else:
+ self._fore_link.stop()
+ self._pool.shutdown(wait=True)
+ self._pool = None
+
+
+def _build_server(methods, port, private_key, certificate_chain):
+ breakdown = _face_utilities.break_down(methods)
+ return _Server(breakdown, port, private_key, certificate_chain)
+
+
+def insecure_server(methods, port):
+ """Constructs an insecure interfaces.Server.
+
+ Args:
+ methods: A dictionary from RPC method name to
+ interfaces.RpcMethod object describing the RPCs to be
+ serviced by the created server.
+ port: The port on which to serve.
+
+ Returns:
+ An interfaces.Server that will run with no security and
+ service unsecured raw requests.
+ """
+ return _build_server(methods, port, None, None)
+
+
+def secure_server(methods, port, private_key, certificate_chain):
+ """Constructs a secure interfaces.Server.
+
+ Args:
+ methods: A dictionary from RPC method name to
+ interfaces.RpcMethod object describing the RPCs to be
+ serviced by the created server.
+ port: The port on which to serve.
+ private_key: A pem-encoded private key.
+ certificate_chain: A pem-encoded certificate chain.
+
+ Returns:
+ An interfaces.Server that will serve secure traffic.
+ """
+ return _build_server(methods, port, private_key, certificate_chain)
diff --git a/src/python/src/grpc/early_adopter/interfaces.py b/src/python/src/grpc/early_adopter/interfaces.py
new file mode 100644
index 0000000..c2806c2
--- /dev/null
+++ b/src/python/src/grpc/early_adopter/interfaces.py
@@ -0,0 +1,194 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Interfaces of GRPC."""
+
+import abc
+import enum
+
+
+@enum.unique
+class Cardinality(enum.Enum):
+ """Constants for the four cardinalities of RPC."""
+
+ UNARY_UNARY = 'request-unary/response-unary'
+ UNARY_STREAM = 'request-unary/response-streaming'
+ STREAM_UNARY = 'request-streaming/response-unary'
+ STREAM_STREAM = 'request-streaming/response-streaming'
+
+
+class RpcMethod(object):
+ """A sum type for the implementation of an RPC method."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def cardinality(self):
+ """Identifies the cardinality of this RpcMethod.
+
+ Returns:
+ A Cardinality value identifying whether or not this
+ RpcMethod is request-unary or request-streaming and
+ whether or not it is response-unary or
+ response-streaming.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def serialize_request(self, request):
+ """Serializes a request value.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Returns:
+ The serialization of the given request value as a
+ bytestring.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def deserialize_request(self, serialized_request):
+ """Deserializes a request value.
+
+ Args:
+ serialized_request: A bytestring that is the
+ serialization of a request value appropriate for this
+ RpcMethod.
+
+ Returns:
+ A request value corresponding to the given bytestring.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def serialize_response(self, response):
+ """Serializes a response value.
+
+ Args:
+ response: A response value appropriate for this RpcMethod.
+
+ Returns:
+ The serialization of the given response value as a
+ bytestring.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def deserialize_response(self, serialized_response):
+ """Deserializes a response value.
+
+ Args:
+ serialized_response: A bytestring that is the
+ serialization of a response value appropriate for this
+ RpcMethod.
+
+ Returns:
+ A response value corresponding to the given bytestring.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_unary_unary(self, request):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.UNARY_UNARY.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Returns:
+ A response value appropriate for this RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_unary_stream(self, request):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.UNARY_STREAM.
+
+ Args:
+ request: A request value appropriate for this RpcMethod.
+
+ Yields:
+ Zero or more response values appropriate for this
+ RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_stream_unary(self, request_iterator):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.STREAM_UNARY.
+
+ Args:
+ request_iterator: An iterator of request values
+ appropriate for this RpcMethod.
+
+ Returns:
+ A response value appropriate for this RpcMethod.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def service_stream_stream(self, request_iterator):
+ """Carries out this RPC.
+
+ This method may only be called if the cardinality of this
+ RpcMethod is Cardinality.STREAM_STREAM.
+
+ Args:
+ request_iterator: An iterator of request values
+ appropriate for this RpcMethod.
+
+ Yields:
+ Zero or more response values appropraite for this
+ RpcMethod.
+ """
+ raise NotImplementedError()
+
+
+class Server(object):
+ """A GRPC Server."""
+ __metaclass__ = abc.ABCMeta
+
+
+ @abc.abstractmethod
+ def start(self):
+ """Instructs this server to commence service of RPCs."""
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop(self):
+ """Instructs this server to halt service of RPCs."""
+ raise NotImplementedError()
diff --git a/src/python/src/grpc/early_adopter/utilities.py b/src/python/src/grpc/early_adopter/utilities.py
new file mode 100644
index 0000000..a4ee253
--- /dev/null
+++ b/src/python/src/grpc/early_adopter/utilities.py
@@ -0,0 +1,213 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Utilities for use with GRPC."""
+
+from grpc.early_adopter import interfaces
+
+
+class _RpcMethod(interfaces.RpcMethod):
+
+ def __init__(
+ self, cardinality, unary_unary, unary_stream, stream_unary,
+ stream_stream, request_serializer, request_deserializer,
+ response_serializer, response_deserializer):
+ self._cardinality = cardinality
+ self._unary_unary = unary_unary
+ self._unary_stream = unary_stream
+ self._stream_unary = stream_unary
+ self._stream_stream = stream_stream
+ self._request_serializer = request_serializer
+ self._request_deserializer = request_deserializer
+ self._response_serializer = response_serializer
+ self._response_deserializer = response_deserializer
+
+ def cardinality(self):
+ """See interfaces.RpcMethod.cardinality for specification."""
+ return self._cardinality
+
+ def serialize_request(self, request):
+ """See interfaces.RpcMethod.serialize_request for specification."""
+ return self._request_serializer(request)
+
+ def deserialize_request(self, serialized_request):
+ """See interfaces.RpcMethod.deserialize_request for specification."""
+ return self._request_deserializer(serialized_request)
+
+ def serialize_response(self, response):
+ """See interfaces.RpcMethod.serialize_response for specification."""
+ return self._response_serializer(response)
+
+ def deserialize_response(self, serialized_response):
+ """See interfaces.RpcMethod.deserialize_response for specification."""
+ return self._response_deserializer(serialized_response)
+
+ def service_unary_unary(self, request):
+ """See interfaces.RpcMethod.service_unary_unary for specification."""
+ return self._unary_unary(request)
+
+ def service_unary_stream(self, request):
+ """See interfaces.RpcMethod.service_unary_stream for specification."""
+ return self._unary_stream(request)
+
+ def service_stream_unary(self, request_iterator):
+ """See interfaces.RpcMethod.service_stream_unary for specification."""
+ return self._stream_unary(request_iterator)
+
+ def service_stream_stream(self, request_iterator):
+ """See interfaces.RpcMethod.service_stream_stream for specification."""
+ return self._stream_stream(request_iterator)
+
+
+def unary_unary_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a unary-unary RPC
+ method that accepts a single request and returns a single
+ response.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ request_deserializer: A callable that when called on a
+ bytestring returns the request value corresponding to that
+ bytestring.
+ response_serializer: A callable that when called on a
+ response value returns the bytestring corresponding to
+ that value.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a unary-request/unary-response RPC
+ method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.UNARY_UNARY, behavior, None, None, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def unary_stream_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a unary-stream RPC
+ method that accepts a single request and returns an
+ iterator of zero or more responses.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ request_deserializer: A callable that when called on a
+ bytestring returns the request value corresponding to that
+ bytestring.
+ response_serializer: A callable that when called on a
+ response value returns the bytestring corresponding to
+ that value.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a unary-request/streaming-response
+ RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.UNARY_STREAM, None, behavior, None, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def stream_unary_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a stream-unary RPC
+ method that accepts an iterator of zero or more requests
+ and returns a single response.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ request_deserializer: A callable that when called on a
+ bytestring returns the request value corresponding to that
+ bytestring.
+ response_serializer: A callable that when called on a
+ response value returns the bytestring corresponding to
+ that value.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a streaming-request/unary-response
+ RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.STREAM_UNARY, None, None, behavior, None,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
+
+
+def stream_stream_rpc_method(
+ behavior, request_serializer, request_deserializer, response_serializer,
+ response_deserializer):
+ """Constructs an interfaces.RpcMethod for the given behavior.
+
+ Args:
+ behavior: A callable that implements a stream-stream RPC
+ method that accepts an iterator of zero or more requests
+ and returns an iterator of zero or more responses.
+ request_serializer: A callable that when called on a request
+ value returns a bytestring corresponding to that value.
+ request_deserializer: A callable that when called on a
+ bytestring returns the request value corresponding to that
+ bytestring.
+ response_serializer: A callable that when called on a
+ response value returns the bytestring corresponding to
+ that value.
+ response_deserializer: A callable that when called on a
+ bytestring returns the response value corresponding to
+ that bytestring.
+
+ Returns:
+ An interfaces.RpcMethod constructed from the given
+ arguments representing a
+ streaming-request/streaming-response RPC method.
+ """
+ return _RpcMethod(
+ interfaces.Cardinality.STREAM_STREAM, None, None, None, behavior,
+ request_serializer, request_deserializer, response_serializer,
+ response_deserializer)
diff --git a/src/python/src/_framework/__init__.py b/src/python/src/grpc/framework/__init__.py
similarity index 100%
rename from src/python/src/_framework/__init__.py
rename to src/python/src/grpc/framework/__init__.py
diff --git a/src/python/src/_framework/base/__init__.py b/src/python/src/grpc/framework/base/__init__.py
similarity index 100%
rename from src/python/src/_framework/base/__init__.py
rename to src/python/src/grpc/framework/base/__init__.py
diff --git a/src/python/src/_framework/base/exceptions.py b/src/python/src/grpc/framework/base/exceptions.py
similarity index 100%
rename from src/python/src/_framework/base/exceptions.py
rename to src/python/src/grpc/framework/base/exceptions.py
diff --git a/src/python/src/_framework/base/interfaces.py b/src/python/src/grpc/framework/base/interfaces.py
similarity index 98%
rename from src/python/src/_framework/base/interfaces.py
rename to src/python/src/grpc/framework/base/interfaces.py
index 70030e5..ed43b25 100644
--- a/src/python/src/_framework/base/interfaces.py
+++ b/src/python/src/grpc/framework/base/interfaces.py
@@ -33,7 +33,7 @@
import enum
# stream is referenced from specification in this module.
-from _framework.foundation import stream # pylint: disable=unused-import
+from grpc.framework.foundation import stream # pylint: disable=unused-import
@enum.unique
diff --git a/src/python/src/_framework/base/interfaces_test.py b/src/python/src/grpc/framework/base/interfaces_test.py
similarity index 97%
rename from src/python/src/_framework/base/interfaces_test.py
rename to src/python/src/grpc/framework/base/interfaces_test.py
index 8e26d88..b86011c 100644
--- a/src/python/src/_framework/base/interfaces_test.py
+++ b/src/python/src/grpc/framework/base/interfaces_test.py
@@ -32,11 +32,11 @@
import threading
import time
-from _framework.base import interfaces
-from _framework.base import util
-from _framework.foundation import stream
-from _framework.foundation import stream_testing
-from _framework.foundation import stream_util
+from grpc.framework.base import interfaces
+from grpc.framework.base import util
+from grpc.framework.foundation import stream
+from grpc.framework.foundation import stream_testing
+from grpc.framework.foundation import stream_util
TICK = 0.1
SMALL_TIMEOUT = TICK * 50
diff --git a/src/python/src/_framework/base/packets/__init__.py b/src/python/src/grpc/framework/base/packets/__init__.py
similarity index 100%
rename from src/python/src/_framework/base/packets/__init__.py
rename to src/python/src/grpc/framework/base/packets/__init__.py
diff --git a/src/python/src/_framework/base/packets/_cancellation.py b/src/python/src/grpc/framework/base/packets/_cancellation.py
similarity index 96%
rename from src/python/src/_framework/base/packets/_cancellation.py
rename to src/python/src/grpc/framework/base/packets/_cancellation.py
index 49172d1..2373c78 100644
--- a/src/python/src/_framework/base/packets/_cancellation.py
+++ b/src/python/src/grpc/framework/base/packets/_cancellation.py
@@ -29,8 +29,8 @@
"""State and behavior for operation cancellation."""
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
class CancellationManager(_interfaces.CancellationManager):
diff --git a/src/python/src/_framework/base/packets/_constants.py b/src/python/src/grpc/framework/base/packets/_constants.py
similarity index 100%
rename from src/python/src/_framework/base/packets/_constants.py
rename to src/python/src/grpc/framework/base/packets/_constants.py
diff --git a/src/python/src/_framework/base/packets/_context.py b/src/python/src/grpc/framework/base/packets/_context.py
similarity index 94%
rename from src/python/src/_framework/base/packets/_context.py
rename to src/python/src/grpc/framework/base/packets/_context.py
index be39036..e09d4a6 100644
--- a/src/python/src/_framework/base/packets/_context.py
+++ b/src/python/src/grpc/framework/base/packets/_context.py
@@ -32,9 +32,9 @@
import time
# _interfaces and packets are referenced from specification in this module.
-from _framework.base import interfaces as base_interfaces
-from _framework.base.packets import _interfaces # pylint: disable=unused-import
-from _framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.base.packets import _interfaces # pylint: disable=unused-import
+from grpc.framework.base.packets import packets # pylint: disable=unused-import
class OperationContext(base_interfaces.OperationContext):
diff --git a/src/python/src/_framework/base/packets/_emission.py b/src/python/src/grpc/framework/base/packets/_emission.py
similarity index 97%
rename from src/python/src/_framework/base/packets/_emission.py
rename to src/python/src/grpc/framework/base/packets/_emission.py
index b4be5eb..9446b86 100644
--- a/src/python/src/_framework/base/packets/_emission.py
+++ b/src/python/src/grpc/framework/base/packets/_emission.py
@@ -30,8 +30,8 @@
"""State and behavior for handling emitted values."""
# packets is referenced from specifications in this module.
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets # pylint: disable=unused-import
class _EmissionManager(_interfaces.EmissionManager):
diff --git a/src/python/src/_framework/base/packets/_ends.py b/src/python/src/grpc/framework/base/packets/_ends.py
similarity index 95%
rename from src/python/src/_framework/base/packets/_ends.py
rename to src/python/src/grpc/framework/base/packets/_ends.py
index b1d1645..15bf3bf 100644
--- a/src/python/src/_framework/base/packets/_ends.py
+++ b/src/python/src/grpc/framework/base/packets/_ends.py
@@ -34,19 +34,19 @@
import uuid
# _interfaces and packets are referenced from specification in this module.
-from _framework.base import interfaces as base_interfaces
-from _framework.base.packets import _cancellation
-from _framework.base.packets import _context
-from _framework.base.packets import _emission
-from _framework.base.packets import _expiration
-from _framework.base.packets import _ingestion
-from _framework.base.packets import _interfaces # pylint: disable=unused-import
-from _framework.base.packets import _reception
-from _framework.base.packets import _termination
-from _framework.base.packets import _transmission
-from _framework.base.packets import interfaces
-from _framework.base.packets import packets # pylint: disable=unused-import
-from _framework.foundation import callable_util
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.base.packets import _cancellation
+from grpc.framework.base.packets import _context
+from grpc.framework.base.packets import _emission
+from grpc.framework.base.packets import _expiration
+from grpc.framework.base.packets import _ingestion
+from grpc.framework.base.packets import _interfaces # pylint: disable=unused-import
+from grpc.framework.base.packets import _reception
+from grpc.framework.base.packets import _termination
+from grpc.framework.base.packets import _transmission
+from grpc.framework.base.packets import interfaces
+from grpc.framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.foundation import callable_util
_IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
diff --git a/src/python/src/_framework/base/packets/_expiration.py b/src/python/src/grpc/framework/base/packets/_expiration.py
similarity index 97%
rename from src/python/src/_framework/base/packets/_expiration.py
rename to src/python/src/grpc/framework/base/packets/_expiration.py
index 772e15f..f58db28 100644
--- a/src/python/src/_framework/base/packets/_expiration.py
+++ b/src/python/src/grpc/framework/base/packets/_expiration.py
@@ -31,9 +31,9 @@
import time
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
-from _framework.foundation import later
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
+from grpc.framework.foundation import later
class _ExpirationManager(_interfaces.ExpirationManager):
diff --git a/src/python/src/_framework/base/packets/_ingestion.py b/src/python/src/grpc/framework/base/packets/_ingestion.py
similarity index 96%
rename from src/python/src/_framework/base/packets/_ingestion.py
rename to src/python/src/grpc/framework/base/packets/_ingestion.py
index abc1e7a..a750195 100644
--- a/src/python/src/_framework/base/packets/_ingestion.py
+++ b/src/python/src/grpc/framework/base/packets/_ingestion.py
@@ -32,14 +32,14 @@
import abc
import collections
-from _framework.base import exceptions
-from _framework.base import interfaces
-from _framework.base.packets import _constants
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
-from _framework.foundation import abandonment
-from _framework.foundation import callable_util
-from _framework.foundation import stream
+from grpc.framework.base import exceptions
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import _constants
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import callable_util
+from grpc.framework.foundation import stream
_CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!'
_CONSUME_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!'
@@ -183,7 +183,7 @@
payload: A customer-significant payload object. May be None only if
complete is True.
complete: Whether or not the end of the payload sequence has been reached.
- May be False only if payload is not None.
+ Must be True if payload is None.
Returns:
True if the wrapped consumer made progress or False if the wrapped
@@ -191,13 +191,12 @@
progress.
"""
try:
- if payload:
- if complete:
- self._consumer.consume_and_terminate(payload)
- else:
- self._consumer.consume(payload)
- else:
+ if payload is None:
self._consumer.terminate()
+ elif complete:
+ self._consumer.consume_and_terminate(payload)
+ else:
+ self._consumer.consume(payload)
return True
except abandonment.Abandoned:
return False
diff --git a/src/python/src/_framework/base/packets/_interfaces.py b/src/python/src/grpc/framework/base/packets/_interfaces.py
similarity index 97%
rename from src/python/src/_framework/base/packets/_interfaces.py
rename to src/python/src/grpc/framework/base/packets/_interfaces.py
index d1bda95..70d9572 100644
--- a/src/python/src/_framework/base/packets/_interfaces.py
+++ b/src/python/src/grpc/framework/base/packets/_interfaces.py
@@ -32,9 +32,9 @@
import abc
# base_interfaces and packets are referenced from specification in this module.
-from _framework.base import interfaces as base_interfaces # pylint: disable=unused-import
-from _framework.base.packets import packets # pylint: disable=unused-import
-from _framework.foundation import stream
+from grpc.framework.base import interfaces as base_interfaces # pylint: disable=unused-import
+from grpc.framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.foundation import stream
class TerminationManager(object):
diff --git a/src/python/src/_framework/base/packets/_reception.py b/src/python/src/grpc/framework/base/packets/_reception.py
similarity index 99%
rename from src/python/src/_framework/base/packets/_reception.py
rename to src/python/src/grpc/framework/base/packets/_reception.py
index a2a3823..6e2c9c0 100644
--- a/src/python/src/_framework/base/packets/_reception.py
+++ b/src/python/src/grpc/framework/base/packets/_reception.py
@@ -31,8 +31,8 @@
import abc
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
class _Receiver(object):
diff --git a/src/python/src/_framework/base/packets/_termination.py b/src/python/src/grpc/framework/base/packets/_termination.py
similarity index 96%
rename from src/python/src/_framework/base/packets/_termination.py
rename to src/python/src/grpc/framework/base/packets/_termination.py
index ae3ba1c..5c10da7 100644
--- a/src/python/src/_framework/base/packets/_termination.py
+++ b/src/python/src/grpc/framework/base/packets/_termination.py
@@ -31,11 +31,11 @@
import enum
-from _framework.base import interfaces
-from _framework.base.packets import _constants
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
-from _framework.foundation import callable_util
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import _constants
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
+from grpc.framework.foundation import callable_util
_CALLBACK_EXCEPTION_LOG_MESSAGE = 'Exception calling termination callback!'
diff --git a/src/python/src/_framework/base/packets/_transmission.py b/src/python/src/grpc/framework/base/packets/_transmission.py
similarity index 98%
rename from src/python/src/_framework/base/packets/_transmission.py
rename to src/python/src/grpc/framework/base/packets/_transmission.py
index 24fe6e6..ac7f450 100644
--- a/src/python/src/_framework/base/packets/_transmission.py
+++ b/src/python/src/grpc/framework/base/packets/_transmission.py
@@ -31,11 +31,11 @@
import abc
-from _framework.base import interfaces
-from _framework.base.packets import _constants
-from _framework.base.packets import _interfaces
-from _framework.base.packets import packets
-from _framework.foundation import callable_util
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import _constants
+from grpc.framework.base.packets import _interfaces
+from grpc.framework.base.packets import packets
+from grpc.framework.foundation import callable_util
_TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!'
diff --git a/src/python/src/_framework/base/packets/implementations.py b/src/python/src/grpc/framework/base/packets/implementations.py
similarity index 95%
rename from src/python/src/_framework/base/packets/implementations.py
rename to src/python/src/grpc/framework/base/packets/implementations.py
index 2f07054..28688bc 100644
--- a/src/python/src/_framework/base/packets/implementations.py
+++ b/src/python/src/grpc/framework/base/packets/implementations.py
@@ -30,8 +30,8 @@
"""Entry points into the packet-exchange-based implementation the base layer."""
# interfaces is referenced from specification in this module.
-from _framework.base.packets import _ends
-from _framework.base.packets import interfaces # pylint: disable=unused-import
+from grpc.framework.base.packets import _ends
+from grpc.framework.base.packets import interfaces # pylint: disable=unused-import
def front(work_pool, transmission_pool, utility_pool):
diff --git a/src/python/src/_framework/base/packets/implementations_test.py b/src/python/src/grpc/framework/base/packets/implementations_test.py
similarity index 94%
rename from src/python/src/_framework/base/packets/implementations_test.py
rename to src/python/src/grpc/framework/base/packets/implementations_test.py
index 8bb5353..628f4b3 100644
--- a/src/python/src/_framework/base/packets/implementations_test.py
+++ b/src/python/src/grpc/framework/base/packets/implementations_test.py
@@ -31,10 +31,10 @@
import unittest
-from _framework.base import interfaces_test
-from _framework.base import util
-from _framework.base.packets import implementations
-from _framework.foundation import logging_pool
+from grpc.framework.base import interfaces_test
+from grpc.framework.base import util
+from grpc.framework.base.packets import implementations
+from grpc.framework.foundation import logging_pool
POOL_MAX_WORKERS = 100
DEFAULT_TIMEOUT = 30
diff --git a/src/python/src/_framework/base/packets/in_memory.py b/src/python/src/grpc/framework/base/packets/in_memory.py
similarity index 95%
rename from src/python/src/_framework/base/packets/in_memory.py
rename to src/python/src/grpc/framework/base/packets/in_memory.py
index 17daf3a..453fd3b 100644
--- a/src/python/src/_framework/base/packets/in_memory.py
+++ b/src/python/src/grpc/framework/base/packets/in_memory.py
@@ -31,9 +31,9 @@
import threading
-from _framework.base.packets import _constants
-from _framework.base.packets import interfaces
-from _framework.foundation import callable_util
+from grpc.framework.base.packets import _constants
+from grpc.framework.base.packets import interfaces
+from grpc.framework.foundation import callable_util
class _Serializer(object):
diff --git a/src/python/src/_framework/base/packets/interfaces.py b/src/python/src/grpc/framework/base/packets/interfaces.py
similarity index 95%
rename from src/python/src/_framework/base/packets/interfaces.py
rename to src/python/src/grpc/framework/base/packets/interfaces.py
index 99f9e87..7c48956 100644
--- a/src/python/src/_framework/base/packets/interfaces.py
+++ b/src/python/src/grpc/framework/base/packets/interfaces.py
@@ -32,8 +32,8 @@
import abc
# packets is referenced from specifications in this module.
-from _framework.base import interfaces
-from _framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.base import interfaces
+from grpc.framework.base.packets import packets # pylint: disable=unused-import
class ForeLink(object):
diff --git a/src/python/src/_framework/base/packets/null.py b/src/python/src/grpc/framework/base/packets/null.py
similarity index 97%
rename from src/python/src/_framework/base/packets/null.py
rename to src/python/src/grpc/framework/base/packets/null.py
index 9b40a00..5a21212 100644
--- a/src/python/src/_framework/base/packets/null.py
+++ b/src/python/src/grpc/framework/base/packets/null.py
@@ -29,7 +29,7 @@
"""Null links that ignore tickets passed to them."""
-from _framework.base.packets import interfaces
+from grpc.framework.base.packets import interfaces
class _NullForeLink(interfaces.ForeLink):
diff --git a/src/python/src/_framework/base/packets/packets.py b/src/python/src/grpc/framework/base/packets/packets.py
similarity index 98%
rename from src/python/src/_framework/base/packets/packets.py
rename to src/python/src/grpc/framework/base/packets/packets.py
index f7503bd..9e2d408 100644
--- a/src/python/src/_framework/base/packets/packets.py
+++ b/src/python/src/grpc/framework/base/packets/packets.py
@@ -33,7 +33,7 @@
import enum
# interfaces is referenced from specifications in this module.
-from _framework.base import interfaces # pylint: disable=unused-import
+from grpc.framework.base import interfaces # pylint: disable=unused-import
@enum.unique
diff --git a/src/python/src/_framework/base/util.py b/src/python/src/grpc/framework/base/util.py
similarity index 98%
rename from src/python/src/_framework/base/util.py
rename to src/python/src/grpc/framework/base/util.py
index 35ce044..c832c82 100644
--- a/src/python/src/_framework/base/util.py
+++ b/src/python/src/grpc/framework/base/util.py
@@ -32,7 +32,7 @@
import collections
import threading
-from _framework.base import interfaces
+from grpc.framework.base import interfaces
class _ServicedSubscription(
diff --git a/src/python/src/_framework/common/__init__.py b/src/python/src/grpc/framework/common/__init__.py
similarity index 100%
rename from src/python/src/_framework/common/__init__.py
rename to src/python/src/grpc/framework/common/__init__.py
diff --git a/src/python/src/_framework/common/cardinality.py b/src/python/src/grpc/framework/common/cardinality.py
similarity index 100%
rename from src/python/src/_framework/common/cardinality.py
rename to src/python/src/grpc/framework/common/cardinality.py
diff --git a/src/python/src/_framework/face/__init__.py b/src/python/src/grpc/framework/face/__init__.py
similarity index 100%
rename from src/python/src/_framework/face/__init__.py
rename to src/python/src/grpc/framework/face/__init__.py
diff --git a/src/python/src/_framework/face/_calls.py b/src/python/src/grpc/framework/face/_calls.py
similarity index 97%
rename from src/python/src/_framework/face/_calls.py
rename to src/python/src/grpc/framework/face/_calls.py
index a7d8be5..75a550e 100644
--- a/src/python/src/_framework/face/_calls.py
+++ b/src/python/src/grpc/framework/face/_calls.py
@@ -32,12 +32,12 @@
import sys
import threading
-from _framework.base import interfaces as base_interfaces
-from _framework.base import util as base_util
-from _framework.face import _control
-from _framework.face import interfaces
-from _framework.foundation import callable_util
-from _framework.foundation import future
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.base import util as base_util
+from grpc.framework.face import _control
+from grpc.framework.face import interfaces
+from grpc.framework.foundation import callable_util
+from grpc.framework.foundation import future
_ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!'
_DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!'
diff --git a/src/python/src/_framework/face/_control.py b/src/python/src/grpc/framework/face/_control.py
similarity index 96%
rename from src/python/src/_framework/face/_control.py
rename to src/python/src/grpc/framework/face/_control.py
index 9f1bf6d..e918907 100644
--- a/src/python/src/_framework/face/_control.py
+++ b/src/python/src/grpc/framework/face/_control.py
@@ -31,11 +31,11 @@
import threading
-from _framework.base import interfaces as base_interfaces
-from _framework.face import exceptions
-from _framework.face import interfaces
-from _framework.foundation import abandonment
-from _framework.foundation import stream
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.face import exceptions
+from grpc.framework.face import interfaces
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import stream
INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Face) Internal Error! :-('
diff --git a/src/python/src/_framework/face/_service.py b/src/python/src/grpc/framework/face/_service.py
similarity index 93%
rename from src/python/src/_framework/face/_service.py
rename to src/python/src/grpc/framework/face/_service.py
index d758c2f..26bde12 100644
--- a/src/python/src/_framework/face/_service.py
+++ b/src/python/src/grpc/framework/face/_service.py
@@ -31,14 +31,14 @@
# base_interfaces and interfaces are referenced from specification in this
# module.
-from _framework.base import interfaces as base_interfaces # pylint: disable=unused-import
-from _framework.face import _control
-from _framework.face import exceptions
-from _framework.face import interfaces # pylint: disable=unused-import
-from _framework.foundation import abandonment
-from _framework.foundation import callable_util
-from _framework.foundation import stream
-from _framework.foundation import stream_util
+from grpc.framework.base import interfaces as base_interfaces # pylint: disable=unused-import
+from grpc.framework.face import _control
+from grpc.framework.face import exceptions
+from grpc.framework.face import interfaces # pylint: disable=unused-import
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import callable_util
+from grpc.framework.foundation import stream
+from grpc.framework.foundation import stream_util
class _ValueInStreamOutConsumer(stream.Consumer):
diff --git a/src/python/src/_framework/face/_test_case.py b/src/python/src/grpc/framework/face/_test_case.py
similarity index 94%
rename from src/python/src/_framework/face/_test_case.py
rename to src/python/src/grpc/framework/face/_test_case.py
index 50b55c3..a4e17c4 100644
--- a/src/python/src/_framework/face/_test_case.py
+++ b/src/python/src/grpc/framework/face/_test_case.py
@@ -29,10 +29,10 @@
"""Common lifecycle code for in-memory-ticket-exchange Face-layer tests."""
-from _framework.face import implementations
-from _framework.face.testing import base_util
-from _framework.face.testing import test_case
-from _framework.foundation import logging_pool
+from grpc.framework.face import implementations
+from grpc.framework.face.testing import base_util
+from grpc.framework.face.testing import test_case
+from grpc.framework.foundation import logging_pool
_TIMEOUT = 3
_MAXIMUM_POOL_SIZE = 100
diff --git a/src/python/src/_framework/face/blocking_invocation_inline_service_test.py b/src/python/src/grpc/framework/face/blocking_invocation_inline_service_test.py
similarity index 92%
rename from src/python/src/_framework/face/blocking_invocation_inline_service_test.py
rename to src/python/src/grpc/framework/face/blocking_invocation_inline_service_test.py
index 96563c9..636cd70 100644
--- a/src/python/src/_framework/face/blocking_invocation_inline_service_test.py
+++ b/src/python/src/grpc/framework/face/blocking_invocation_inline_service_test.py
@@ -31,8 +31,8 @@
import unittest
-from _framework.face import _test_case
-from _framework.face.testing import blocking_invocation_inline_service_test_case as test_case
+from grpc.framework.face import _test_case
+from grpc.framework.face.testing import blocking_invocation_inline_service_test_case as test_case
class BlockingInvocationInlineServiceTest(
diff --git a/src/python/src/_framework/face/demonstration.py b/src/python/src/grpc/framework/face/demonstration.py
similarity index 94%
rename from src/python/src/_framework/face/demonstration.py
rename to src/python/src/grpc/framework/face/demonstration.py
index 501ec6b..d922f6e 100644
--- a/src/python/src/_framework/face/demonstration.py
+++ b/src/python/src/grpc/framework/face/demonstration.py
@@ -29,10 +29,10 @@
"""Demonstration-suitable implementation of the face layer of RPC Framework."""
-from _framework.base import util as _base_util
-from _framework.base.packets import implementations as _tickets_implementations
-from _framework.face import implementations
-from _framework.foundation import logging_pool
+from grpc.framework.base import util as _base_util
+from grpc.framework.base.packets import implementations as _tickets_implementations
+from grpc.framework.face import implementations
+from grpc.framework.foundation import logging_pool
_POOL_SIZE_LIMIT = 20
diff --git a/src/python/src/_framework/face/event_invocation_synchronous_event_service_test.py b/src/python/src/grpc/framework/face/event_invocation_synchronous_event_service_test.py
similarity index 92%
rename from src/python/src/_framework/face/event_invocation_synchronous_event_service_test.py
rename to src/python/src/grpc/framework/face/event_invocation_synchronous_event_service_test.py
index 48e05b2..25f3e29 100644
--- a/src/python/src/_framework/face/event_invocation_synchronous_event_service_test.py
+++ b/src/python/src/grpc/framework/face/event_invocation_synchronous_event_service_test.py
@@ -31,8 +31,8 @@
import unittest
-from _framework.face import _test_case
-from _framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case
+from grpc.framework.face import _test_case
+from grpc.framework.face.testing import event_invocation_synchronous_event_service_test_case as test_case
class EventInvocationSynchronousEventServiceTest(
diff --git a/src/python/src/_framework/face/exceptions.py b/src/python/src/grpc/framework/face/exceptions.py
similarity index 100%
rename from src/python/src/_framework/face/exceptions.py
rename to src/python/src/grpc/framework/face/exceptions.py
diff --git a/src/python/src/_framework/face/future_invocation_asynchronous_event_service_test.py b/src/python/src/grpc/framework/face/future_invocation_asynchronous_event_service_test.py
similarity index 92%
rename from src/python/src/_framework/face/future_invocation_asynchronous_event_service_test.py
rename to src/python/src/grpc/framework/face/future_invocation_asynchronous_event_service_test.py
index 96f5fe8..38229ea 100644
--- a/src/python/src/_framework/face/future_invocation_asynchronous_event_service_test.py
+++ b/src/python/src/grpc/framework/face/future_invocation_asynchronous_event_service_test.py
@@ -31,8 +31,8 @@
import unittest
-from _framework.face import _test_case
-from _framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case
+from grpc.framework.face import _test_case
+from grpc.framework.face.testing import future_invocation_asynchronous_event_service_test_case as test_case
class FutureInvocationAsynchronousEventServiceTest(
diff --git a/src/python/src/_framework/face/implementations.py b/src/python/src/grpc/framework/face/implementations.py
similarity index 96%
rename from src/python/src/_framework/face/implementations.py
rename to src/python/src/grpc/framework/face/implementations.py
index 94362e2..c499b90 100644
--- a/src/python/src/_framework/face/implementations.py
+++ b/src/python/src/grpc/framework/face/implementations.py
@@ -29,12 +29,12 @@
"""Entry points into the Face layer of RPC Framework."""
-from _framework.base import exceptions as _base_exceptions
-from _framework.base import interfaces as base_interfaces
-from _framework.face import _calls
-from _framework.face import _service
-from _framework.face import exceptions
-from _framework.face import interfaces
+from grpc.framework.base import exceptions as _base_exceptions
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.face import _calls
+from grpc.framework.face import _service
+from grpc.framework.face import exceptions
+from grpc.framework.face import interfaces
class _BaseServicer(base_interfaces.Servicer):
diff --git a/src/python/src/_framework/face/interfaces.py b/src/python/src/grpc/framework/face/interfaces.py
similarity index 98%
rename from src/python/src/_framework/face/interfaces.py
rename to src/python/src/grpc/framework/face/interfaces.py
index 2480454..548e9ce 100644
--- a/src/python/src/_framework/face/interfaces.py
+++ b/src/python/src/grpc/framework/face/interfaces.py
@@ -34,9 +34,9 @@
# exceptions, abandonment, and future are referenced from specification in this
# module.
-from _framework.face import exceptions # pylint: disable=unused-import
-from _framework.foundation import abandonment # pylint: disable=unused-import
-from _framework.foundation import future # pylint: disable=unused-import
+from grpc.framework.face import exceptions # pylint: disable=unused-import
+from grpc.framework.foundation import abandonment # pylint: disable=unused-import
+from grpc.framework.foundation import future # pylint: disable=unused-import
class CancellableIterator(object):
diff --git a/src/python/src/_framework/face/testing/__init__.py b/src/python/src/grpc/framework/face/testing/__init__.py
similarity index 100%
rename from src/python/src/_framework/face/testing/__init__.py
rename to src/python/src/grpc/framework/face/testing/__init__.py
diff --git a/src/python/src/_framework/face/testing/base_util.py b/src/python/src/grpc/framework/face/testing/base_util.py
similarity index 92%
rename from src/python/src/_framework/face/testing/base_util.py
rename to src/python/src/grpc/framework/face/testing/base_util.py
index d9ccb3a..7872a6b 100644
--- a/src/python/src/_framework/face/testing/base_util.py
+++ b/src/python/src/grpc/framework/face/testing/base_util.py
@@ -32,11 +32,11 @@
import abc
# interfaces is referenced from specification in this module.
-from _framework.base import util as _base_util
-from _framework.base.packets import implementations
-from _framework.base.packets import in_memory
-from _framework.base.packets import interfaces # pylint: disable=unused-import
-from _framework.foundation import logging_pool
+from grpc.framework.base import util as _base_util
+from grpc.framework.base.packets import implementations
+from grpc.framework.base.packets import in_memory
+from grpc.framework.base.packets import interfaces # pylint: disable=unused-import
+from grpc.framework.foundation import logging_pool
_POOL_SIZE_LIMIT = 20
diff --git a/src/python/src/_framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
similarity index 96%
rename from src/python/src/_framework/face/testing/blocking_invocation_inline_service_test_case.py
rename to src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
index 0b1a2f0..993098f 100644
--- a/src/python/src/_framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
@@ -33,12 +33,12 @@
import abc
import unittest # pylint: disable=unused-import
-from _framework.face import exceptions
-from _framework.face.testing import control
-from _framework.face.testing import coverage
-from _framework.face.testing import digest
-from _framework.face.testing import stock_service
-from _framework.face.testing import test_case
+from grpc.framework.face import exceptions
+from grpc.framework.face.testing import control
+from grpc.framework.face.testing import coverage
+from grpc.framework.face.testing import digest
+from grpc.framework.face.testing import stock_service
+from grpc.framework.face.testing import test_case
_TIMEOUT = 3
diff --git a/src/python/src/_framework/face/testing/callback.py b/src/python/src/grpc/framework/face/testing/callback.py
similarity index 98%
rename from src/python/src/_framework/face/testing/callback.py
rename to src/python/src/grpc/framework/face/testing/callback.py
index 7a20869..d0e63c8 100644
--- a/src/python/src/_framework/face/testing/callback.py
+++ b/src/python/src/grpc/framework/face/testing/callback.py
@@ -31,7 +31,7 @@
import threading
-from _framework.foundation import stream
+from grpc.framework.foundation import stream
class Callback(stream.Consumer):
diff --git a/src/python/src/_framework/face/testing/control.py b/src/python/src/grpc/framework/face/testing/control.py
similarity index 100%
rename from src/python/src/_framework/face/testing/control.py
rename to src/python/src/grpc/framework/face/testing/control.py
diff --git a/src/python/src/_framework/face/testing/coverage.py b/src/python/src/grpc/framework/face/testing/coverage.py
similarity index 100%
rename from src/python/src/_framework/face/testing/coverage.py
rename to src/python/src/grpc/framework/face/testing/coverage.py
diff --git a/src/python/src/_framework/face/testing/digest.py b/src/python/src/grpc/framework/face/testing/digest.py
similarity index 96%
rename from src/python/src/_framework/face/testing/digest.py
rename to src/python/src/grpc/framework/face/testing/digest.py
index 8d1291c..b8fb573 100644
--- a/src/python/src/_framework/face/testing/digest.py
+++ b/src/python/src/grpc/framework/face/testing/digest.py
@@ -34,13 +34,13 @@
# testing_control, interfaces, and testing_service are referenced from
# specification in this module.
-from _framework.face import exceptions
-from _framework.face import interfaces as face_interfaces
-from _framework.face.testing import control as testing_control # pylint: disable=unused-import
-from _framework.face.testing import interfaces # pylint: disable=unused-import
-from _framework.face.testing import service as testing_service # pylint: disable=unused-import
-from _framework.foundation import stream
-from _framework.foundation import stream_util
+from grpc.framework.face import exceptions
+from grpc.framework.face import interfaces as face_interfaces
+from grpc.framework.face.testing import control as testing_control # pylint: disable=unused-import
+from grpc.framework.face.testing import interfaces # pylint: disable=unused-import
+from grpc.framework.face.testing import service as testing_service # pylint: disable=unused-import
+from grpc.framework.foundation import stream
+from grpc.framework.foundation import stream_util
_IDENTITY = lambda x: x
diff --git a/src/python/src/_framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
similarity index 97%
rename from src/python/src/_framework/face/testing/event_invocation_synchronous_event_service_test_case.py
rename to src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
index cb786f5..21e669b 100644
--- a/src/python/src/_framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
@@ -32,13 +32,13 @@
import abc
import unittest
-from _framework.face import interfaces
-from _framework.face.testing import callback as testing_callback
-from _framework.face.testing import control
-from _framework.face.testing import coverage
-from _framework.face.testing import digest
-from _framework.face.testing import stock_service
-from _framework.face.testing import test_case
+from grpc.framework.face import interfaces
+from grpc.framework.face.testing import callback as testing_callback
+from grpc.framework.face.testing import control
+from grpc.framework.face.testing import coverage
+from grpc.framework.face.testing import digest
+from grpc.framework.face.testing import stock_service
+from grpc.framework.face.testing import test_case
_TIMEOUT = 3
diff --git a/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
similarity index 97%
rename from src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
rename to src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index 939b238..42db305 100644
--- a/src/python/src/_framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -34,14 +34,14 @@
import threading
import unittest
-from _framework.face import exceptions
-from _framework.face.testing import control
-from _framework.face.testing import coverage
-from _framework.face.testing import digest
-from _framework.face.testing import stock_service
-from _framework.face.testing import test_case
-from _framework.foundation import future
-from _framework.foundation import logging_pool
+from grpc.framework.face import exceptions
+from grpc.framework.face.testing import control
+from grpc.framework.face.testing import coverage
+from grpc.framework.face.testing import digest
+from grpc.framework.face.testing import stock_service
+from grpc.framework.face.testing import test_case
+from grpc.framework.foundation import future
+from grpc.framework.foundation import logging_pool
_TIMEOUT = 3
_MAXIMUM_POOL_SIZE = 100
diff --git a/src/python/src/_framework/face/testing/interfaces.py b/src/python/src/grpc/framework/face/testing/interfaces.py
similarity index 97%
rename from src/python/src/_framework/face/testing/interfaces.py
rename to src/python/src/grpc/framework/face/testing/interfaces.py
index 253f6f1..5932dab 100644
--- a/src/python/src/_framework/face/testing/interfaces.py
+++ b/src/python/src/grpc/framework/face/testing/interfaces.py
@@ -32,7 +32,7 @@
import abc
# cardinality is referenced from specification in this module.
-from _framework.common import cardinality # pylint: disable=unused-import
+from grpc.framework.common import cardinality # pylint: disable=unused-import
class Method(object):
diff --git a/src/python/src/_framework/face/testing/serial.py b/src/python/src/grpc/framework/face/testing/serial.py
similarity index 100%
rename from src/python/src/_framework/face/testing/serial.py
rename to src/python/src/grpc/framework/face/testing/serial.py
diff --git a/src/python/src/_framework/face/testing/service.py b/src/python/src/grpc/framework/face/testing/service.py
similarity index 98%
rename from src/python/src/_framework/face/testing/service.py
rename to src/python/src/grpc/framework/face/testing/service.py
index 771346e..a58e2ee 100644
--- a/src/python/src/_framework/face/testing/service.py
+++ b/src/python/src/grpc/framework/face/testing/service.py
@@ -32,8 +32,8 @@
import abc
# interfaces is referenced from specification in this module.
-from _framework.face import interfaces as face_interfaces # pylint: disable=unused-import
-from _framework.face.testing import interfaces
+from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
+from grpc.framework.face.testing import interfaces
class UnaryUnaryTestMethod(interfaces.Method):
diff --git a/src/python/src/_framework/face/testing/stock_service.py b/src/python/src/grpc/framework/face/testing/stock_service.py
similarity index 97%
rename from src/python/src/_framework/face/testing/stock_service.py
rename to src/python/src/grpc/framework/face/testing/stock_service.py
index bd82877..83c9418 100644
--- a/src/python/src/_framework/face/testing/stock_service.py
+++ b/src/python/src/grpc/framework/face/testing/stock_service.py
@@ -29,12 +29,12 @@
"""Examples of Python implementations of the stock.proto Stock service."""
-from _framework.common import cardinality
-from _framework.face.testing import service
-from _framework.foundation import abandonment
-from _framework.foundation import stream
-from _framework.foundation import stream_util
-from _junkdrawer import stock_pb2
+from grpc.framework.common import cardinality
+from grpc.framework.face.testing import service
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import stream
+from grpc.framework.foundation import stream_util
+from grpc._junkdrawer import stock_pb2
SYMBOL_FORMAT = 'test symbol:%03d'
STREAM_LENGTH = 400
diff --git a/src/python/src/_framework/face/testing/test_case.py b/src/python/src/grpc/framework/face/testing/test_case.py
similarity index 96%
rename from src/python/src/_framework/face/testing/test_case.py
rename to src/python/src/grpc/framework/face/testing/test_case.py
index 09b5a67..218a2a8 100644
--- a/src/python/src/_framework/face/testing/test_case.py
+++ b/src/python/src/grpc/framework/face/testing/test_case.py
@@ -32,8 +32,8 @@
import abc
# face_interfaces and interfaces are referenced in specification in this module.
-from _framework.face import interfaces as face_interfaces # pylint: disable=unused-import
-from _framework.face.testing import interfaces # pylint: disable=unused-import
+from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
+from grpc.framework.face.testing import interfaces # pylint: disable=unused-import
class FaceTestCase(object):
diff --git a/src/python/src/_framework/foundation/__init__.py b/src/python/src/grpc/framework/foundation/__init__.py
similarity index 100%
rename from src/python/src/_framework/foundation/__init__.py
rename to src/python/src/grpc/framework/foundation/__init__.py
diff --git a/src/python/src/_framework/foundation/_later_test.py b/src/python/src/grpc/framework/foundation/_later_test.py
similarity index 98%
rename from src/python/src/_framework/foundation/_later_test.py
rename to src/python/src/grpc/framework/foundation/_later_test.py
index 50b6790..e83e703 100644
--- a/src/python/src/_framework/foundation/_later_test.py
+++ b/src/python/src/grpc/framework/foundation/_later_test.py
@@ -33,7 +33,7 @@
import time
import unittest
-from _framework.foundation import later
+from grpc.framework.foundation import later
TICK = 0.1
diff --git a/src/python/src/_framework/foundation/_logging_pool_test.py b/src/python/src/grpc/framework/foundation/_logging_pool_test.py
similarity index 97%
rename from src/python/src/_framework/foundation/_logging_pool_test.py
rename to src/python/src/grpc/framework/foundation/_logging_pool_test.py
index f2224d8..11463a8 100644
--- a/src/python/src/_framework/foundation/_logging_pool_test.py
+++ b/src/python/src/grpc/framework/foundation/_logging_pool_test.py
@@ -31,7 +31,7 @@
import unittest
-from _framework.foundation import logging_pool
+from grpc.framework.foundation import logging_pool
_POOL_SIZE = 16
diff --git a/src/python/src/_framework/foundation/_timer_future.py b/src/python/src/grpc/framework/foundation/_timer_future.py
similarity index 99%
rename from src/python/src/_framework/foundation/_timer_future.py
rename to src/python/src/grpc/framework/foundation/_timer_future.py
index 4aa6699..2c9996a 100644
--- a/src/python/src/_framework/foundation/_timer_future.py
+++ b/src/python/src/grpc/framework/foundation/_timer_future.py
@@ -33,7 +33,7 @@
import threading
import time
-from _framework.foundation import future
+from grpc.framework.foundation import future
class TimerFuture(future.Future):
diff --git a/src/python/src/_framework/foundation/abandonment.py b/src/python/src/grpc/framework/foundation/abandonment.py
similarity index 100%
rename from src/python/src/_framework/foundation/abandonment.py
rename to src/python/src/grpc/framework/foundation/abandonment.py
diff --git a/src/python/src/_framework/foundation/callable_util.py b/src/python/src/grpc/framework/foundation/callable_util.py
similarity index 100%
rename from src/python/src/_framework/foundation/callable_util.py
rename to src/python/src/grpc/framework/foundation/callable_util.py
diff --git a/src/python/src/_framework/foundation/future.py b/src/python/src/grpc/framework/foundation/future.py
similarity index 100%
rename from src/python/src/_framework/foundation/future.py
rename to src/python/src/grpc/framework/foundation/future.py
diff --git a/src/python/src/_framework/foundation/later.py b/src/python/src/grpc/framework/foundation/later.py
similarity index 97%
rename from src/python/src/_framework/foundation/later.py
rename to src/python/src/grpc/framework/foundation/later.py
index fc2cf57..1d1e065 100644
--- a/src/python/src/_framework/foundation/later.py
+++ b/src/python/src/grpc/framework/foundation/later.py
@@ -31,7 +31,7 @@
import time
-from _framework.foundation import _timer_future
+from grpc.framework.foundation import _timer_future
def later(delay, computation):
diff --git a/src/python/src/_framework/foundation/logging_pool.py b/src/python/src/grpc/framework/foundation/logging_pool.py
similarity index 100%
rename from src/python/src/_framework/foundation/logging_pool.py
rename to src/python/src/grpc/framework/foundation/logging_pool.py
diff --git a/src/python/src/_framework/foundation/stream.py b/src/python/src/grpc/framework/foundation/stream.py
similarity index 100%
rename from src/python/src/_framework/foundation/stream.py
rename to src/python/src/grpc/framework/foundation/stream.py
diff --git a/src/python/src/_framework/foundation/stream_testing.py b/src/python/src/grpc/framework/foundation/stream_testing.py
similarity index 98%
rename from src/python/src/_framework/foundation/stream_testing.py
rename to src/python/src/grpc/framework/foundation/stream_testing.py
index c1acedc..098a53d 100644
--- a/src/python/src/_framework/foundation/stream_testing.py
+++ b/src/python/src/grpc/framework/foundation/stream_testing.py
@@ -29,7 +29,7 @@
"""Utilities for testing stream-related code."""
-from _framework.foundation import stream
+from grpc.framework.foundation import stream
class TestConsumer(stream.Consumer):
diff --git a/src/python/src/_framework/foundation/stream_util.py b/src/python/src/grpc/framework/foundation/stream_util.py
similarity index 98%
rename from src/python/src/_framework/foundation/stream_util.py
rename to src/python/src/grpc/framework/foundation/stream_util.py
index 3a9c043..2210e4e 100644
--- a/src/python/src/_framework/foundation/stream_util.py
+++ b/src/python/src/grpc/framework/foundation/stream_util.py
@@ -32,7 +32,7 @@
import logging
import threading
-from _framework.foundation import stream
+from grpc.framework.foundation import stream
_NO_VALUE = object()
diff --git a/src/python/setup.py b/src/python/src/setup.py
similarity index 68%
rename from src/python/setup.py
rename to src/python/src/setup.py
index 5e566ba..8e33ebb 100644
--- a/src/python/setup.py
+++ b/src/python/src/setup.py
@@ -32,19 +32,17 @@
from distutils import core as _core
_EXTENSION_SOURCES = (
- 'src/_adapter/_c.c',
- 'src/_adapter/_call.c',
- 'src/_adapter/_channel.c',
- 'src/_adapter/_completion_queue.c',
- 'src/_adapter/_error.c',
- 'src/_adapter/_server.c',
- 'src/_adapter/_server_credentials.c',
+ 'grpc/_adapter/_c.c',
+ 'grpc/_adapter/_call.c',
+ 'grpc/_adapter/_channel.c',
+ 'grpc/_adapter/_completion_queue.c',
+ 'grpc/_adapter/_error.c',
+ 'grpc/_adapter/_server.c',
+ 'grpc/_adapter/_server_credentials.c',
)
_EXTENSION_INCLUDE_DIRECTORIES = (
- 'src',
- # TODO(nathaniel): Can this path specification be made to work?
- #'../../include',
+ '.',
)
_EXTENSION_LIBRARIES = (
@@ -52,36 +50,35 @@
'grpc',
)
-_EXTENSION_LIBRARY_DIRECTORIES = (
- # TODO(nathaniel): Can this path specification be made to work?
- #'../../libs/dbg',
-)
-
_EXTENSION_MODULE = _core.Extension(
- '_adapter._c', sources=list(_EXTENSION_SOURCES),
+ 'grpc._adapter._c', sources=list(_EXTENSION_SOURCES),
include_dirs=_EXTENSION_INCLUDE_DIRECTORIES,
libraries=_EXTENSION_LIBRARIES,
- library_dirs=_EXTENSION_LIBRARY_DIRECTORIES)
+ )
_PACKAGES=(
- '_adapter',
- '_framework',
- '_framework.base',
- '_framework.base.packets',
- '_framework.common',
- '_framework.face',
- '_framework.face.testing',
- '_framework.foundation',
- '_junkdrawer',
+ 'grpc',
+ 'grpc._adapter',
+ 'grpc._junkdrawer',
+ 'grpc.early_adopter',
+ 'grpc.framework',
+ 'grpc.framework.base',
+ 'grpc.framework.base.packets',
+ 'grpc.framework.common',
+ 'grpc.framework.face',
+ 'grpc.framework.face.testing',
+ 'grpc.framework.foundation',
)
_PACKAGE_DIRECTORIES = {
- '_adapter': 'src/_adapter',
- '_framework': 'src/_framework',
- '_junkdrawer': 'src/_junkdrawer',
+ 'grpc': 'grpc',
+ 'grpc._adapter': 'grpc/_adapter',
+ 'grpc._junkdrawer': 'grpc/_junkdrawer',
+ 'grpc.early_adopter': 'grpc/early_adopter',
+ 'grpc.framework': 'grpc/framework',
}
_core.setup(
- name='grpc', version='0.0.1',
+ name='grpc-2015', version='0.0.1',
ext_modules=[_EXTENSION_MODULE], packages=_PACKAGES,
package_dir=_PACKAGE_DIRECTORIES)
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index f5acae8..1321727 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -362,9 +362,11 @@
@server.close
end
- it_behaves_like 'basic GRPC message delivery is OK' do
- end
+ # TODO: uncomment after updating the to the new c api
+ # it_behaves_like 'basic GRPC message delivery is OK' do
+ # end
- it_behaves_like 'GRPC metadata delivery works OK' do
- end
+ # TODO: uncomment after updating the to the new c api
+ # it_behaves_like 'GRPC metadata delivery works OK' do
+ # end
end
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 18d6bce..17f37d6 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -166,7 +166,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(2)));
+ f.server_cq,
+ tag(2)));
cq_expect_completion(v_server, tag(2), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
index 123c8bc..51486cc 100644
--- a/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/early_server_shutdown_finishes_tags.c
@@ -79,7 +79,7 @@
static void shutdown_server(grpc_end2end_test_fixture *f) {
if (!f->server) return;
- grpc_server_shutdown(f->server);
+ /* don't shutdown, just destroy, to tickle this code edge */
grpc_server_destroy(f->server);
f->server = NULL;
}
diff --git a/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
index 940e327..a71e3a7 100644
--- a/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
@@ -175,7 +175,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/request_response_with_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
index 80cb629..f7394a2 100644
--- a/test/core/end2end/tests/request_response_with_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
@@ -168,7 +168,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/request_response_with_payload.c b/test/core/end2end/tests/request_response_with_payload.c
index b07f51d..be4beb5 100644
--- a/test/core/end2end/tests/request_response_with_payload.c
+++ b/test/core/end2end/tests/request_response_with_payload.c
@@ -162,7 +162,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
index e547604..637a9ff 100644
--- a/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
@@ -169,7 +169,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/request_with_large_metadata.c b/test/core/end2end/tests/request_with_large_metadata.c
index eb6180c..fff83dc 100644
--- a/test/core/end2end/tests/request_with_large_metadata.c
+++ b/test/core/end2end/tests/request_with_large_metadata.c
@@ -166,7 +166,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 2bf0fa3..2b52004 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -157,7 +157,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 80763fe..ac248f9 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -144,7 +144,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->server, &s,
&call_details,
&request_metadata_recv,
- f->server_cq, tag(101)));
+ f->server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index 968be74..ab03479 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -150,7 +150,8 @@
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
- f.server_cq, tag(101)));
+ f.server_cq,
+ tag(101)));
cq_expect_completion(v_server, tag(101), GRPC_OP_OK);
cq_verify(v_server);
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 6262699..0a113f0 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -55,7 +55,6 @@
static grpc_metadata_array initial_metadata_recv;
static grpc_metadata_array trailing_metadata_recv;
static grpc_byte_buffer *response_payload_recv = NULL;
-static grpc_call_details call_details;
static grpc_status_code status;
static char *details = NULL;
static size_t details_capacity = 0;
@@ -64,7 +63,6 @@
static void init_ping_pong_request(void) {
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
- grpc_call_details_init(&call_details);
op = ops;
@@ -97,6 +95,7 @@
grpc_call_start_batch(call, ops, op - ops, (void *)1));
grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
grpc_call_destroy(call);
+ grpc_byte_buffer_destroy(response_payload_recv);
call = NULL;
}
@@ -121,6 +120,7 @@
GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_batch(call, stream_step_ops, 2, (void *)1));
grpc_event_finish(grpc_completion_queue_next(cq, gpr_inf_future));
+ grpc_byte_buffer_destroy(response_payload_recv);
}
static double now(void) {
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index bc52059..ca0683f 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -87,7 +87,6 @@
static void request_call(void) {
grpc_metadata_array_init(&request_metadata_recv);
- grpc_call_details_init(&call_details);
grpc_server_request_call(server, &call, &call_details, &request_metadata_recv,
cq, tag(FLING_SERVER_NEW_REQUEST));
}
@@ -218,6 +217,8 @@
gpr_free(addr_buf);
addr = addr_buf = NULL;
+ grpc_call_details_init(&call_details);
+
request_call();
grpc_profiler_start("server.prof");
@@ -264,6 +265,8 @@
break;
case FLING_SERVER_WRITE_FOR_STREAMING:
/* Write completed at server */
+ grpc_byte_buffer_destroy(payload_buffer);
+ payload_buffer = NULL;
start_read_op(FLING_SERVER_READ_FOR_STREAMING);
break;
case FLING_SERVER_SEND_INIT_METADATA_FOR_STREAMING:
@@ -282,6 +285,8 @@
break;
case FLING_SERVER_BATCH_OPS_FOR_UNARY:
/* Finished unary call. */
+ grpc_byte_buffer_destroy(payload_buffer);
+ payload_buffer = NULL;
grpc_call_destroy(call);
request_call();
break;
@@ -305,6 +310,7 @@
grpc_event_finish(ev);
}
grpc_profiler_stop();
+ grpc_call_details_destroy(&call_details);
grpc_server_destroy(server);
grpc_completion_queue_destroy(cq);
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index e906f30..ae6994e 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -66,7 +66,7 @@
static void test_no_op_with_start(void) {
grpc_tcp_server *s = grpc_tcp_server_create();
LOG_TEST();
- grpc_tcp_server_start(s, NULL, on_connect, NULL);
+ grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
grpc_tcp_server_destroy(s);
}
@@ -93,7 +93,7 @@
GPR_ASSERT(
grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr)));
- grpc_tcp_server_start(s, NULL, on_connect, NULL);
+ grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
grpc_tcp_server_destroy(s);
}
@@ -120,7 +120,7 @@
GPR_ASSERT(getsockname(svrfd, (struct sockaddr *)&addr, &addr_len) == 0);
GPR_ASSERT(addr_len <= sizeof(addr));
- grpc_tcp_server_start(s, NULL, on_connect, NULL);
+ grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
for (i = 0; i < n; i++) {
deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(10000000));
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index c7b2b2e..e2ad78a 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -35,7 +35,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "src/core/support/cpu.h"
+#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
diff --git a/src/node/ext/event.h b/test/core/surface/multi_init_test.c
similarity index 76%
rename from src/node/ext/event.h
rename to test/core/surface/multi_init_test.c
index e06d8f0..dced882 100644
--- a/src/node/ext/event.h
+++ b/test/core/surface/multi_init_test.c
@@ -31,18 +31,33 @@
*
*/
-#ifndef NET_GRPC_NODE_EVENT_H_
-#define NET_GRPC_NODE_EVENT_H_
+#include <grpc/grpc.h>
+#include "test/core/util/test_config.h"
-#include <node.h>
-#include "grpc/grpc.h"
+static void test(int rounds) {
+ int i;
+ for (i = 0; i < rounds; i++) {
+ grpc_init();
+ }
+ for (i = 0; i < rounds; i++) {
+ grpc_shutdown();
+ }
+}
-namespace grpc {
-namespace node {
+static void test_mixed() {
+ grpc_init();
+ grpc_init();
+ grpc_shutdown();
+ grpc_init();
+ grpc_shutdown();
+ grpc_shutdown();
+}
-v8::Handle<v8::Value> CreateEventObject(grpc_event *event);
-
-} // namespace node
-} // namespace grpc
-
-#endif // NET_GRPC_NODE_EVENT_H_
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ test(1);
+ test(2);
+ test(3);
+ test_mixed();
+ return 0;
+}
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index b23db89..a2d190e 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -44,7 +44,7 @@
#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FUNCTION__)
/* a large number */
-#define MANY 1000000
+#define MANY 100000
static void test_no_op(void) {
grpc_mdctx *ctx;
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
new file mode 100644
index 0000000..fbf9bcb
--- /dev/null
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -0,0 +1,379 @@
+/*
+ *
+ * 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 <chrono>
+#include <thread>
+
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/echo_duplicate.pb.h"
+#include "test/cpp/util/echo.pb.h"
+#include "src/cpp/util/time.h"
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc++/status.h>
+#include <grpc++/stream.h>
+#include "test/core/util/port.h"
+#include <gtest/gtest.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace testing {
+
+namespace {
+
+void* tag(int i) {
+ return (void*)(gpr_intptr)i;
+}
+
+void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
+ bool ok;
+ void* got_tag;
+ EXPECT_TRUE(cq->Next(&got_tag, &ok));
+ EXPECT_EQ(expect_ok, ok);
+ EXPECT_EQ(tag(i), got_tag);
+}
+
+class AsyncEnd2endTest : public ::testing::Test {
+ protected:
+ AsyncEnd2endTest() : service_(&srv_cq_) {}
+
+ void SetUp() override {
+ int port = grpc_pick_unused_port_or_die();
+ server_address_ << "localhost:" << port;
+ // Setup server
+ ServerBuilder builder;
+ builder.AddPort(server_address_.str());
+ builder.RegisterAsyncService(&service_);
+ server_ = builder.BuildAndStart();
+ }
+
+ void TearDown() override { server_->Shutdown(); }
+
+ void ResetStub() {
+ std::shared_ptr<ChannelInterface> channel =
+ CreateChannel(server_address_.str(), ChannelArguments());
+ stub_.reset(grpc::cpp::test::util::TestService::NewStub(channel));
+ }
+
+ void server_ok(int i) {
+ verify_ok(&srv_cq_, i, true);
+ }
+ void client_ok(int i) {
+ verify_ok(&cli_cq_, i , true);
+ }
+ void server_fail(int i) {
+ verify_ok(&srv_cq_, i, false);
+ }
+ void client_fail(int i) {
+ verify_ok(&cli_cq_, i, false);
+ }
+
+ void SendRpc(int num_rpcs) {
+ for (int i = 0; i < num_rpcs; i++) {
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+
+ send_request.set_message("Hello");
+ stub_->Echo(
+ &cli_ctx, send_request, &recv_response, &recv_status, &cli_cq_, tag(1));
+
+ service_.RequestEcho(
+ &srv_ctx, &recv_request, &response_writer, &srv_cq_, tag(2));
+
+ server_ok(2);
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ response_writer.Finish(send_response, Status::OK, tag(3));
+
+ server_ok(3);
+
+ client_ok(1);
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.IsOk());
+ }
+ }
+
+ CompletionQueue cli_cq_;
+ CompletionQueue srv_cq_;
+ std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
+ std::unique_ptr<Server> server_;
+ grpc::cpp::test::util::TestService::AsyncService service_;
+ std::ostringstream server_address_;
+};
+
+TEST_F(AsyncEnd2endTest, SimpleRpc) {
+ ResetStub();
+ SendRpc(1);
+}
+
+TEST_F(AsyncEnd2endTest, SequentialRpcs) {
+ ResetStub();
+ SendRpc(10);
+}
+
+// Two pings and a final pong.
+TEST_F(AsyncEnd2endTest, SimpleClientStreaming) {
+ ResetStub();
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+ send_request.set_message("Hello");
+ ClientAsyncWriter<EchoRequest>* cli_stream =
+ stub_->RequestStream(&cli_ctx, &recv_response, &cli_cq_, tag(1));
+
+ service_.RequestRequestStream(
+ &srv_ctx, &srv_stream, &srv_cq_, tag(2));
+
+ server_ok(2);
+ client_ok(1);
+
+ cli_stream->Write(send_request, tag(3));
+ client_ok(3);
+
+ srv_stream.Read(&recv_request, tag(4));
+ server_ok(4);
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ cli_stream->Write(send_request, tag(5));
+ client_ok(5);
+
+ srv_stream.Read(&recv_request, tag(6));
+ server_ok(6);
+
+ EXPECT_EQ(send_request.message(), recv_request.message());
+ cli_stream->WritesDone(tag(7));
+ client_ok(7);
+
+ srv_stream.Read(&recv_request, tag(8));
+ server_fail(8);
+
+ send_response.set_message(recv_request.message());
+ srv_stream.Finish(send_response, Status::OK, tag(9));
+ server_ok(9);
+
+ cli_stream->Finish(&recv_status, tag(10));
+ client_ok(10);
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.IsOk());
+}
+
+// One ping, two pongs.
+TEST_F(AsyncEnd2endTest, SimpleServerStreaming) {
+ ResetStub();
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
+
+ send_request.set_message("Hello");
+ ClientAsyncReader<EchoResponse>* cli_stream =
+ stub_->ResponseStream(&cli_ctx, send_request, &cli_cq_, tag(1));
+
+ service_.RequestResponseStream(
+ &srv_ctx, &recv_request, &srv_stream, &srv_cq_, tag(2));
+
+ server_ok(2);
+ client_ok(1);
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ srv_stream.Write(send_response, tag(3));
+ server_ok(3);
+
+ cli_stream->Read(&recv_response, tag(4));
+ client_ok(4);
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ srv_stream.Write(send_response, tag(5));
+ server_ok(5);
+
+ cli_stream->Read(&recv_response, tag(6));
+ client_ok(6);
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ srv_stream.Finish(Status::OK, tag(7));
+ server_ok(7);
+
+ cli_stream->Read(&recv_response, tag(8));
+ client_fail(8);
+
+ cli_stream->Finish(&recv_status, tag(9));
+ client_ok(9);
+
+ EXPECT_TRUE(recv_status.IsOk());
+}
+
+// One ping, one pong.
+TEST_F(AsyncEnd2endTest, SimpleBidiStreaming) {
+ ResetStub();
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+ send_request.set_message("Hello");
+ ClientAsyncReaderWriter<EchoRequest, EchoResponse>* cli_stream =
+ stub_->BidiStream(&cli_ctx, &cli_cq_, tag(1));
+
+ service_.RequestBidiStream(
+ &srv_ctx, &srv_stream, &srv_cq_, tag(2));
+
+ server_ok(2);
+ client_ok(1);
+
+ cli_stream->Write(send_request, tag(3));
+ client_ok(3);
+
+ srv_stream.Read(&recv_request, tag(4));
+ server_ok(4);
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ srv_stream.Write(send_response, tag(5));
+ server_ok(5);
+
+ cli_stream->Read(&recv_response, tag(6));
+ client_ok(6);
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ cli_stream->WritesDone(tag(7));
+ client_ok(7);
+
+ srv_stream.Read(&recv_request, tag(8));
+ server_fail(8);
+
+ srv_stream.Finish(Status::OK, tag(9));
+ server_ok(9);
+
+ cli_stream->Finish(&recv_status, tag(10));
+ client_ok(10);
+
+ EXPECT_TRUE(recv_status.IsOk());
+}
+
+// Metadata tests
+TEST_F(AsyncEnd2endTest, ClientInitialMetadataRpc) {
+ ResetStub();
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+
+ send_request.set_message("Hello");
+ std::pair<grpc::string, grpc::string> meta1("key1", "val1");
+ std::pair<grpc::string, grpc::string> meta2("key2", "val2");
+ cli_ctx.AddMetadata(meta1.first, meta1.second);
+ cli_ctx.AddMetadata(meta2.first, meta2.second);
+
+ stub_->Echo(
+ &cli_ctx, send_request, &recv_response, &recv_status, &cli_cq_, tag(1));
+
+ service_.RequestEcho(
+ &srv_ctx, &recv_request, &response_writer, &srv_cq_, tag(2));
+ server_ok(2);
+ EXPECT_EQ(send_request.message(), recv_request.message());
+ auto client_initial_metadata = srv_ctx.client_metadata();
+ EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second);
+ EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second);
+ EXPECT_EQ(2, client_initial_metadata.size());
+
+ send_response.set_message(recv_request.message());
+ response_writer.Finish(send_response, Status::OK, tag(3));
+
+ server_ok(3);
+
+ client_ok(1);
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.IsOk());
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+ ::testing::InitGoogleTest(&argc, argv);
+ int result = RUN_ALL_TESTS();
+ grpc_shutdown();
+ google::protobuf::ShutdownProtobufLibrary();
+ return result;
+}
diff --git a/test/cpp/end2end/async_test_server.cc b/test/cpp/end2end/async_test_server.cc
deleted file mode 100644
index f18b6c0..0000000
--- a/test/cpp/end2end/async_test_server.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *
- * 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 "test/cpp/end2end/async_test_server.h"
-
-#include <chrono>
-
-#include <grpc/support/log.h>
-#include "src/cpp/proto/proto_utils.h"
-#include "test/cpp/util/echo.pb.h"
-#include <grpc++/async_server.h>
-#include <grpc++/async_server_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/status.h>
-#include <gtest/gtest.h>
-
-using grpc::cpp::test::util::EchoRequest;
-using grpc::cpp::test::util::EchoResponse;
-
-using std::chrono::duration_cast;
-using std::chrono::microseconds;
-using std::chrono::seconds;
-using std::chrono::system_clock;
-
-namespace grpc {
-namespace testing {
-
-AsyncTestServer::AsyncTestServer() : server_(&cq_), cq_drained_(false) {}
-
-AsyncTestServer::~AsyncTestServer() {}
-
-void AsyncTestServer::AddPort(const grpc::string& addr) {
- server_.AddPort(addr);
-}
-
-void AsyncTestServer::Start() { server_.Start(); }
-
-// Return true if deadline actual is within 0.5s from expected.
-bool DeadlineMatched(const system_clock::time_point& actual,
- const system_clock::time_point& expected) {
- microseconds diff_usecs = duration_cast<microseconds>(expected - actual);
- gpr_log(GPR_INFO, "diff_usecs= %d", diff_usecs.count());
- return diff_usecs.count() < 500000 && diff_usecs.count() > -500000;
-}
-
-void AsyncTestServer::RequestOneRpc() { server_.RequestOneRpc(); }
-
-void AsyncTestServer::MainLoop() {
- EchoRequest request;
- EchoResponse response;
- void* tag = nullptr;
-
- RequestOneRpc();
-
- while (true) {
- CompletionQueue::CompletionType t = cq_.Next(&tag);
- AsyncServerContext* server_context = static_cast<AsyncServerContext*>(tag);
- switch (t) {
- case CompletionQueue::SERVER_RPC_NEW:
- gpr_log(GPR_INFO, "SERVER_RPC_NEW %p", server_context);
- if (server_context) {
- EXPECT_EQ(server_context->method(), "/foo");
- // TODO(ctiller): verify deadline
- server_context->Accept(cq_.cq());
- // Handle only one rpc at a time.
- RequestOneRpc();
- server_context->StartRead(&request);
- }
- break;
- case CompletionQueue::RPC_END:
- gpr_log(GPR_INFO, "RPC_END %p", server_context);
- delete server_context;
- break;
- case CompletionQueue::SERVER_READ_OK:
- gpr_log(GPR_INFO, "SERVER_READ_OK %p", server_context);
- response.set_message(request.message());
- server_context->StartWrite(response, 0);
- break;
- case CompletionQueue::SERVER_READ_ERROR:
- gpr_log(GPR_INFO, "SERVER_READ_ERROR %p", server_context);
- server_context->StartWriteStatus(Status::OK);
- break;
- case CompletionQueue::HALFCLOSE_OK:
- gpr_log(GPR_INFO, "HALFCLOSE_OK %p", server_context);
- // Do nothing, just wait for RPC_END.
- break;
- case CompletionQueue::SERVER_WRITE_OK:
- gpr_log(GPR_INFO, "SERVER_WRITE_OK %p", server_context);
- server_context->StartRead(&request);
- break;
- case CompletionQueue::SERVER_WRITE_ERROR:
- EXPECT_TRUE(0);
- break;
- case CompletionQueue::QUEUE_CLOSED: {
- gpr_log(GPR_INFO, "QUEUE_CLOSED");
- HandleQueueClosed();
- return;
- }
- default:
- EXPECT_TRUE(0);
- break;
- }
- }
-}
-
-void AsyncTestServer::HandleQueueClosed() {
- std::unique_lock<std::mutex> lock(cq_drained_mu_);
- cq_drained_ = true;
- cq_drained_cv_.notify_all();
-}
-
-void AsyncTestServer::Shutdown() {
- // The server need to be shut down before cq_ as grpc_server flushes all
- // pending requested calls to the completion queue at shutdown.
- server_.Shutdown();
- cq_.Shutdown();
- std::unique_lock<std::mutex> lock(cq_drained_mu_);
- while (!cq_drained_) {
- cq_drained_cv_.wait(lock);
- }
-}
-
-} // namespace testing
-} // namespace grpc
diff --git a/test/cpp/end2end/async_test_server.h b/test/cpp/end2end/async_test_server.h
deleted file mode 100644
index a277061..0000000
--- a/test/cpp/end2end/async_test_server.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * 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 __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
-#define __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
-
-#include <condition_variable>
-#include <mutex>
-#include <string>
-
-#include <grpc++/async_server.h>
-#include <grpc++/completion_queue.h>
-
-namespace grpc {
-
-namespace testing {
-
-class AsyncTestServer {
- public:
- AsyncTestServer();
- virtual ~AsyncTestServer();
-
- void AddPort(const grpc::string& addr);
- void Start();
- void RequestOneRpc();
- virtual void MainLoop();
- void Shutdown();
-
- CompletionQueue* completion_queue() { return &cq_; }
-
- protected:
- void HandleQueueClosed();
-
- private:
- CompletionQueue cq_;
- AsyncServer server_;
- bool cq_drained_;
- std::mutex cq_drained_mu_;
- std::condition_variable cq_drained_cv_;
-};
-
-} // namespace testing
-} // namespace grpc
-
-#endif // __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 4dea77e..974717f 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -38,6 +38,7 @@
#include "test/cpp/util/echo_duplicate.pb.h"
#include "test/cpp/util/echo.pb.h"
#include "src/cpp/util/time.h"
+#include "src/cpp/server/thread_pool.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
@@ -76,6 +77,7 @@
response->mutable_param()->set_request_deadline(deadline.tv_sec);
}
}
+
} // namespace
class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
@@ -141,14 +143,17 @@
class End2endTest : public ::testing::Test {
protected:
+ End2endTest() : thread_pool_(2) {}
+
void SetUp() override {
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
// Setup server
ServerBuilder builder;
builder.AddPort(server_address_.str());
- builder.RegisterService(service_.service());
- builder.RegisterService(dup_pkg_service_.service());
+ builder.RegisterService(&service_);
+ builder.RegisterService(&dup_pkg_service_);
+ builder.SetThreadPool(&thread_pool_);
server_ = builder.BuildAndStart();
}
@@ -165,6 +170,7 @@
std::ostringstream server_address_;
TestServiceImpl service_;
TestServiceImplDupPkg dup_pkg_service_;
+ ThreadPool thread_pool_;
};
static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub,
@@ -290,7 +296,7 @@
request.set_message("hello");
EXPECT_TRUE(stream->Write(request));
stream->WritesDone();
- Status s = stream->Wait();
+ Status s = stream->Finish();
EXPECT_EQ(response.message(), request.message());
EXPECT_TRUE(s.IsOk());
@@ -308,7 +314,7 @@
EXPECT_TRUE(stream->Write(request));
EXPECT_TRUE(stream->Write(request));
stream->WritesDone();
- Status s = stream->Wait();
+ Status s = stream->Finish();
EXPECT_EQ(response.message(), "hellohello");
EXPECT_TRUE(s.IsOk());
@@ -323,7 +329,7 @@
request.set_message("hello");
ClientReader<EchoResponse>* stream =
- stub_->ResponseStream(&context, &request);
+ stub_->ResponseStream(&context, request);
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(), request.message() + "0");
EXPECT_TRUE(stream->Read(&response));
@@ -332,7 +338,7 @@
EXPECT_EQ(response.message(), request.message() + "2");
EXPECT_FALSE(stream->Read(&response));
- Status s = stream->Wait();
+ Status s = stream->Finish();
EXPECT_TRUE(s.IsOk());
delete stream;
@@ -366,7 +372,7 @@
stream->WritesDone();
EXPECT_FALSE(stream->Read(&response));
- Status s = stream->Wait();
+ Status s = stream->Finish();
EXPECT_TRUE(s.IsOk());
delete stream;
@@ -422,7 +428,7 @@
ClientContext context2;
ClientReaderWriter<EchoRequest, EchoResponse>* stream =
stub->BidiStream(&context2);
- s = stream->Wait();
+ s = stream->Finish();
EXPECT_FALSE(s.IsOk());
EXPECT_EQ(StatusCode::UNKNOWN, s.code());
EXPECT_EQ("Rpc sent on a lame channel.", s.details());
@@ -439,5 +445,6 @@
::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
grpc_shutdown();
+ google::protobuf::ShutdownProtobufLibrary();
return result;
}
diff --git a/test/cpp/end2end/sync_client_async_server_test.cc b/test/cpp/end2end/sync_client_async_server_test.cc
deleted file mode 100644
index 9955eb3..0000000
--- a/test/cpp/end2end/sync_client_async_server_test.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- *
- * 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 <chrono>
-#include <memory>
-#include <sstream>
-#include <string>
-
-#include <grpc/grpc.h>
-#include <grpc/support/thd.h>
-#include "test/cpp/util/echo.pb.h"
-#include <grpc++/channel_arguments.h>
-#include <grpc++/channel_interface.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/internal_stub.h>
-#include <grpc++/impl/rpc_method.h>
-#include <grpc++/status.h>
-#include <grpc++/stream.h>
-#include "test/cpp/end2end/async_test_server.h"
-#include "test/core/util/port.h"
-#include <gtest/gtest.h>
-
-using grpc::cpp::test::util::EchoRequest;
-using grpc::cpp::test::util::EchoResponse;
-
-using std::chrono::duration_cast;
-using std::chrono::microseconds;
-using std::chrono::seconds;
-using std::chrono::system_clock;
-
-using grpc::testing::AsyncTestServer;
-
-namespace grpc {
-namespace {
-
-void ServerLoop(void* s) {
- AsyncTestServer* server = static_cast<AsyncTestServer*>(s);
- server->MainLoop();
-}
-
-class End2endTest : public ::testing::Test {
- protected:
- void SetUp() override {
- int port = grpc_pick_unused_port_or_die();
- // TODO(yangg) protobuf has a StringPrintf, maybe use that
- std::ostringstream oss;
- oss << "[::]:" << port;
- // Setup server
- server_.reset(new AsyncTestServer());
- server_->AddPort(oss.str());
- server_->Start();
-
- RunServerThread();
-
- // Setup client
- oss.str("");
- oss << "127.0.0.1:" << port;
- std::shared_ptr<ChannelInterface> channel =
- CreateChannel(oss.str(), ChannelArguments());
- stub_.set_channel(channel);
- }
-
- void RunServerThread() {
- gpr_thd_id id;
- EXPECT_TRUE(gpr_thd_new(&id, ServerLoop, server_.get(), NULL));
- }
-
- void TearDown() override { server_->Shutdown(); }
-
- std::unique_ptr<AsyncTestServer> server_;
- InternalStub stub_;
-};
-
-TEST_F(End2endTest, NoOpTest) { EXPECT_TRUE(stub_.channel() != nullptr); }
-
-TEST_F(End2endTest, SimpleRpc) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo");
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- Status s =
- stub_.channel()->StartBlockingRpc(method, &context, request, &result);
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(s.IsOk());
-}
-
-TEST_F(End2endTest, KSequentialSimpleRpcs) {
- int k = 3;
- for (int i = 0; i < k; i++) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo");
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- Status s =
- stub_.channel()->StartBlockingRpc(method, &context, request, &result);
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(s.IsOk());
- }
-}
-
-TEST_F(End2endTest, OnePingpongBidiStream) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING);
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- StreamContextInterface* stream_interface =
- stub_.channel()->CreateStream(method, &context, nullptr, nullptr);
- std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream(
- new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface));
- EXPECT_TRUE(stream->Write(request));
- EXPECT_TRUE(stream->Read(&result));
- stream->WritesDone();
- EXPECT_FALSE(stream->Read(&result));
- Status s = stream->Wait();
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(s.IsOk());
-}
-
-TEST_F(End2endTest, TwoPingpongBidiStream) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING);
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- StreamContextInterface* stream_interface =
- stub_.channel()->CreateStream(method, &context, nullptr, nullptr);
- std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream(
- new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface));
- EXPECT_TRUE(stream->Write(request));
- EXPECT_TRUE(stream->Read(&result));
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(stream->Write(request));
- EXPECT_TRUE(stream->Read(&result));
- EXPECT_EQ(result.message(), request.message());
- stream->WritesDone();
- EXPECT_FALSE(stream->Read(&result));
- Status s = stream->Wait();
- EXPECT_TRUE(s.IsOk());
-}
-
-TEST_F(End2endTest, OnePingpongClientStream) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo", RpcMethod::RpcType::CLIENT_STREAMING);
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- StreamContextInterface* stream_interface =
- stub_.channel()->CreateStream(method, &context, nullptr, &result);
- std::unique_ptr<ClientWriter<EchoRequest>> stream(
- new ClientWriter<EchoRequest>(stream_interface));
- EXPECT_TRUE(stream->Write(request));
- stream->WritesDone();
- Status s = stream->Wait();
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(s.IsOk());
-}
-
-TEST_F(End2endTest, OnePingpongServerStream) {
- EchoRequest request;
- request.set_message("hello");
- EchoResponse result;
- ClientContext context;
- RpcMethod method("/foo", RpcMethod::RpcType::SERVER_STREAMING);
- std::chrono::system_clock::time_point deadline =
- std::chrono::system_clock::now() + std::chrono::seconds(10);
- context.set_absolute_deadline(deadline);
- StreamContextInterface* stream_interface =
- stub_.channel()->CreateStream(method, &context, &request, nullptr);
- std::unique_ptr<ClientReader<EchoResponse>> stream(
- new ClientReader<EchoResponse>(stream_interface));
- EXPECT_TRUE(stream->Read(&result));
- EXPECT_FALSE(stream->Read(nullptr));
- Status s = stream->Wait();
- EXPECT_EQ(result.message(), request.message());
- EXPECT_TRUE(s.IsOk());
-}
-
-} // namespace
-} // namespace grpc
-
-int main(int argc, char** argv) {
- grpc_init();
- ::testing::InitGoogleTest(&argc, argv);
- int result = RUN_ALL_TESTS();
- grpc_shutdown();
- return result;
-}
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 0fa76f0..57a503f 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -248,7 +248,7 @@
aggregated_payload_size += request_stream_sizes[i];
}
stream->WritesDone();
- grpc::Status s = stream->Wait();
+ grpc::Status s = stream->Finish();
GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
GPR_ASSERT(s.IsOk());
@@ -269,7 +269,7 @@
}
StreamingOutputCallResponse response;
std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
- stub->StreamingOutputCall(&context, &request));
+ stub->StreamingOutputCall(&context, request));
unsigned int i = 0;
while (stream->Read(&response)) {
@@ -278,7 +278,7 @@
++i;
}
GPR_ASSERT(response_stream_sizes.size() == i);
- grpc::Status s = stream->Wait();
+ grpc::Status s = stream->Finish();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Response streaming done.");
@@ -299,7 +299,7 @@
}
StreamingOutputCallResponse response;
std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
- stub->StreamingOutputCall(&context, &request));
+ stub->StreamingOutputCall(&context, request));
int i = 0;
while (stream->Read(&response)) {
@@ -311,7 +311,7 @@
++i;
}
GPR_ASSERT(kNumResponseMessages == i);
- grpc::Status s = stream->Wait();
+ grpc::Status s = stream->Finish();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Response streaming done.");
@@ -345,7 +345,7 @@
++i;
}
GPR_ASSERT(response_stream_sizes.size() == i);
- grpc::Status s = stream->Wait();
+ grpc::Status s = stream->Finish();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
}
@@ -378,7 +378,7 @@
stream->WritesDone();
GPR_ASSERT(!stream->Read(&response));
- grpc::Status s = stream->Wait();
+ grpc::Status s = stream->Finish();
GPR_ASSERT(s.IsOk());
gpr_log(GPR_INFO, "Ping pong streaming done.");
}
diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc
index 8a6be57..a839977 100644
--- a/test/cpp/interop/server.cc
+++ b/test/cpp/interop/server.cc
@@ -200,7 +200,7 @@
ServerBuilder builder;
builder.AddPort(server_address.str());
- builder.RegisterService(service.service());
+ builder.RegisterService(&service);
if (FLAGS_enable_ssl) {
SslServerCredentialsOptions ssl_opts = {
"", {{test_server1_key, test_server1_cert}}};
diff --git a/test/cpp/interop/test.proto b/test/cpp/interop/test.proto
index e358f3b..1162ad6 100644
--- a/test/cpp/interop/test.proto
+++ b/test/cpp/interop/test.proto
@@ -14,7 +14,7 @@
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
- // The server returns the client payload as-is.
+ // TODO(Issue 527): Describe required server behavior.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
diff --git a/test/cpp/qps/server.cc b/test/cpp/qps/server.cc
index 3a432b6..7180461 100644
--- a/test/cpp/qps/server.cc
+++ b/test/cpp/qps/server.cc
@@ -128,7 +128,7 @@
ServerBuilder builder;
builder.AddPort(server_address);
- builder.RegisterService(service.service());
+ builder.RegisterService(&service);
std::unique_ptr<ThreadPool> pool(new ThreadPool(FLAGS_server_threads));
builder.SetThreadPool(pool.get());
diff --git a/tools/dockerfile/grpc_python/Dockerfile b/tools/dockerfile/grpc_python/Dockerfile
new file mode 100644
index 0000000..d434b47
--- /dev/null
+++ b/tools/dockerfile/grpc_python/Dockerfile
@@ -0,0 +1,38 @@
+# Dockerfile for GRPC Python
+FROM grpc/python_base
+
+# Build the C library
+RUN cd /var/local/git/grpc \
+ && git pull --recurse-submodules \
+ && git submodule update --init --recursive
+
+# Build the C core.
+RUN make install_c -C /var/local/git/grpc
+
+# Build Python GRPC
+RUN cd /var/local/git/grpc \
+ && pip install src/python/src \
+ && pip install src/python/interop
+
+# Run Python GRPC's tests
+RUN cd /var/local/git/grpc \
+ # TODO(nathaniel): It would be nice for these to be auto-discoverable?
+ && python2.7 -B -m grpc._adapter._blocking_invocation_inline_service_test
+ && python2.7 -B -m grpc._adapter._c_test
+ && python2.7 -B -m grpc._adapter._event_invocation_synchronous_event_service_test
+ && python2.7 -B -m grpc._adapter._future_invocation_asynchronous_event_service_test
+ && python2.7 -B -m grpc._adapter._links_test
+ && python2.7 -B -m grpc._adapter._lonely_rear_link_test
+ && python2.7 -B -m grpc._adapter._low_test
+ && python2.7 -B -m grpc._framework.base.packets.implementations_test
+ && python2.7 -B -m grpc._framework.face.blocking_invocation_inline_service_test
+ && python2.7 -B -m grpc._framework.face.event_invocation_synchronous_event_service_test
+ && python2.7 -B -m grpc._framework.face.future_invocation_asynchronous_event_service_test
+ && python2.7 -B -m grpc._framework.foundation._later_test
+ && python2.7 -B -m grpc._framework.foundation._logging_pool_test
+
+# Add a cacerts directory containing the Google root pem file, allowing the interop client to access the production test instance
+ADD cacerts cacerts
+
+# Specify the default command such that the interop server runs on its known testing port
+CMD ["/bin/bash", "-l", "-c", "python2.7 -m interop.server --use_tls --port 8050"]
diff --git a/tools/dockerfile/grpc_python/README.md b/tools/dockerfile/grpc_python/README.md
new file mode 100644
index 0000000..efbdbef
--- /dev/null
+++ b/tools/dockerfile/grpc_python/README.md
@@ -0,0 +1,11 @@
+GRPC Python Dockerfile
+====================
+
+Dockerfile for creating the Python development instances
+
+As of 2015/02 this
+- is based on the GRPC Python base
+- adds a pull of the HEAD GRPC Python source from GitHub
+- builds it
+- runs its tests and aborts image creation if the tests don't pass
+- specifies the Python GRPC interop test server as default command
diff --git a/tools/dockerfile/grpc_python_base/Dockerfile b/tools/dockerfile/grpc_python_base/Dockerfile
new file mode 100644
index 0000000..98f695a
--- /dev/null
+++ b/tools/dockerfile/grpc_python_base/Dockerfile
@@ -0,0 +1,20 @@
+# Base Dockerfile for GRPC Python.
+#
+# Includes Python environment and installation dependencies.
+FROM grpc/base
+
+# Allows 'source' to work
+RUN rm /bin/sh && ln -s /bin/bash /bin/sh
+
+# Install Python development
+RUN apt-get update && apt-get install -y \
+ python-all-dev \
+ python3-all-dev \
+ python-pip \
+ python-virtualenv
+
+# Install Python packages from PyPI
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0-alpha-1
+
+# Get the GRPC source from GitHub
+RUN git clone --recursive git@github.com:google/grpc.git /var/local/git/grpc
diff --git a/tools/dockerfile/grpc_python_base/README.md b/tools/dockerfile/grpc_python_base/README.md
new file mode 100644
index 0000000..1d4767c
--- /dev/null
+++ b/tools/dockerfile/grpc_python_base/README.md
@@ -0,0 +1,7 @@
+GRPC Python Base Dockerfile
+========================
+
+Dockerfile for creating the Python GRPC development Docker instance.
+
+As of 2015/02 this
+- installs tools and dependencies needed to build GRPC Python
diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh
index 456ad4b..9ddbac7 100755
--- a/tools/gce_setup/interop_test_runner.sh
+++ b/tools/gce_setup/interop_test_runner.sh
@@ -8,7 +8,7 @@
source grpc_docker.sh
test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming)
clients=(cxx java go ruby node)
- servers=(cxx java go ruby node)
+ servers=(cxx java go ruby node python)
for test_case in "${test_cases[@]}"
do
for client in "${clients[@]}"
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index b45b9d6..3625412 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -11,5 +11,5 @@
virtualenv python2.7_virtual_environment
ln -sf $root/include/grpc python2.7_virtual_environment/include/grpc
source python2.7_virtual_environment/bin/activate
-pip install enum34==1.0.4 futures==2.2.0 protobuf==2.6.1
-CFLAGS=-I$root/include LDFLAGS=-L$root/libs/opt pip install src/python
+pip install enum34==1.0.4 futures==2.2.0 protobuf==3.0.0-alpha-1
+CFLAGS=-I$root/include LDFLAGS=-L$root/libs/opt pip install src/python/src
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index 7d3ee73..b792788 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -9,18 +9,18 @@
export LD_LIBRARY_PATH=$root/libs/opt
source python2.7_virtual_environment/bin/activate
# TODO(issue 215): Properly itemize these in run_tests.py so that they can be parallelized.
-python2.7 -B -m _adapter._blocking_invocation_inline_service_test
-python2.7 -B -m _adapter._c_test
-python2.7 -B -m _adapter._event_invocation_synchronous_event_service_test
-python2.7 -B -m _adapter._future_invocation_asynchronous_event_service_test
-python2.7 -B -m _adapter._links_test
-python2.7 -B -m _adapter._lonely_rear_link_test
-python2.7 -B -m _adapter._low_test
-python2.7 -B -m _framework.base.packets.implementations_test
-python2.7 -B -m _framework.face.blocking_invocation_inline_service_test
-python2.7 -B -m _framework.face.event_invocation_synchronous_event_service_test
-python2.7 -B -m _framework.face.future_invocation_asynchronous_event_service_test
-python2.7 -B -m _framework.foundation._later_test
-python2.7 -B -m _framework.foundation._logging_pool_test
+python2.7 -B -m grpc._adapter._blocking_invocation_inline_service_test
+python2.7 -B -m grpc._adapter._c_test
+python2.7 -B -m grpc._adapter._event_invocation_synchronous_event_service_test
+python2.7 -B -m grpc._adapter._future_invocation_asynchronous_event_service_test
+python2.7 -B -m grpc._adapter._links_test
+python2.7 -B -m grpc._adapter._lonely_rear_link_test
+python2.7 -B -m grpc._adapter._low_test
+python2.7 -B -m grpc.framework.base.packets.implementations_test
+python2.7 -B -m grpc.framework.face.blocking_invocation_inline_service_test
+python2.7 -B -m grpc.framework.face.event_invocation_synchronous_event_service_test
+python2.7 -B -m grpc.framework.face.future_invocation_asynchronous_event_service_test
+python2.7 -B -m grpc.framework.foundation._later_test
+python2.7 -B -m grpc.framework.foundation._logging_pool_test
# TODO(nathaniel): Get tests working under 3.4 (requires 3.X-friendly protobuf)
# python3.4 -B -m unittest discover -s src/python -p '*.py'
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 30b0da4..b5d6159 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -215,6 +215,10 @@
},
{
"language": "c",
+ "name": "multi_init_test"
+ },
+ {
+ "language": "c",
"name": "murmur_hash_test"
},
{
@@ -267,6 +271,10 @@
},
{
"language": "c++",
+ "name": "async_end2end_test"
+ },
+ {
+ "language": "c++",
"name": "channel_arguments_test"
},
{
@@ -279,18 +287,6 @@
},
{
"language": "c++",
- "name": "status_test"
- },
- {
- "language": "c++",
- "name": "sync_client_async_server_test"
- },
- {
- "language": "c++",
- "name": "thread_pool_test"
- },
- {
- "language": "c++",
"name": "pubsub_publisher_test"
},
{
@@ -298,6 +294,14 @@
"name": "pubsub_subscriber_test"
},
{
+ "language": "c++",
+ "name": "status_test"
+ },
+ {
+ "language": "c++",
+ "name": "thread_pool_test"
+ },
+ {
"language": "c",
"name": "chttp2_fake_security_cancel_after_accept_test"
},
diff --git a/vsprojects/vs2013/Grpc.mak b/vsprojects/vs2013/Grpc.mak
index ae57791..f4e9f46 100644
--- a/vsprojects/vs2013/Grpc.mak
+++ b/vsprojects/vs2013/Grpc.mak
@@ -25,10 +25,10 @@
$(OUT_DIR):
mkdir $(OUT_DIR)
-buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe
+buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe
echo All tests built.
-test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test
+test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test
echo All tests ran.
test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test
@@ -546,6 +546,14 @@
echo Running metadata_buffer_test
$(OUT_DIR)\metadata_buffer_test.exe
+multi_init_test.exe: grpc_test_util
+ echo Building multi_init_test
+ $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\multi_init_test.c
+ $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\multi_init_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multi_init_test.obj
+multi_init_test: multi_init_test.exe
+ echo Running multi_init_test
+ $(OUT_DIR)\multi_init_test.exe
+
murmur_hash_test.exe: grpc_test_util
echo Building murmur_hash_test
$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\murmur_hash_test.c
diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj
index fc740fe..dab819c 100644
--- a/vsprojects/vs2013/grpc.vcxproj
+++ b/vsprojects/vs2013/grpc.vcxproj
@@ -271,10 +271,10 @@
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
- </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters
index 75ecc7a..8c174d9 100644
--- a/vsprojects/vs2013/grpc.vcxproj.filters
+++ b/vsprojects/vs2013/grpc.vcxproj.filters
@@ -127,10 +127,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj b/vsprojects/vs2013/grpc_shared.vcxproj
index 71b4a0c..7ef520b 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj
+++ b/vsprojects/vs2013/grpc_shared.vcxproj
@@ -275,10 +275,10 @@
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
- </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj.filters b/vsprojects/vs2013/grpc_shared.vcxproj.filters
index 75ecc7a..8c174d9 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj.filters
+++ b/vsprojects/vs2013/grpc_shared.vcxproj.filters
@@ -127,10 +127,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj
index c5130ee..8b3b853 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj
@@ -233,10 +233,10 @@
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
- </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
</ClCompile>
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ </ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_windows.c">
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
index 50f3190..6fac846 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
@@ -88,10 +88,10 @@
<ClCompile Include="..\..\src\core\iomgr\pollset_kick.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+ <ClCompile Include="..\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
<Filter>src\core\iomgr</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\iomgr\pollset_posix.c">