diff options
211 files changed, 5451 insertions, 2537 deletions
@@ -113,6 +113,7 @@ GRPC_SECURE_PUBLIC_HDRS = [ GRPCXX_SRCS = [ "src/cpp/client/channel_cc.cc", "src/cpp/client/client_context.cc", + "src/cpp/client/client_interceptor.cc", "src/cpp/client/create_channel.cc", "src/cpp/client/create_channel_internal.cc", "src/cpp/client/create_channel_posix.cc", @@ -245,6 +246,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/config.h", "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", + "include/grpcpp/support/server_callback.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", "include/grpcpp/support/status_code_enum.h", @@ -820,6 +822,7 @@ grpc_cc_library( "src/core/lib/transport/timeout_encoding.cc", "src/core/lib/transport/transport.cc", "src/core/lib/transport/transport_op_string.cc", + "src/core/lib/uri/uri_parser.cc", ], hdrs = [ "src/core/lib/avl/avl.h", @@ -954,6 +957,7 @@ grpc_cc_library( "src/core/lib/transport/timeout_encoding.h", "src/core/lib/transport/transport.h", "src/core/lib/transport/transport_impl.h", + "src/core/lib/uri/uri_parser.h", ], external_deps = [ "zlib", @@ -1053,7 +1057,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/retry_throttle.cc", "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel_index.cc", - "src/core/ext/filters/client_channel/uri_parser.cc", ], hdrs = [ "src/core/ext/filters/client_channel/backup_poller.h", @@ -1077,7 +1080,6 @@ grpc_cc_library( "src/core/ext/filters/client_channel/retry_throttle.h", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.h", - "src/core/ext/filters/client_channel/uri_parser.h", ], language = "c++", deps = [ @@ -1957,7 +1959,7 @@ grpc_cc_library( name = "tsi", srcs = [ "src/core/tsi/alts/handshaker/alts_handshaker_client.cc", - "src/core/tsi/alts/handshaker/alts_tsi_event.cc", + "src/core/tsi/alts/handshaker/alts_shared_resource.cc", "src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc", "src/core/tsi/alts/handshaker/alts_tsi_utils.cc", "src/core/tsi/alts_transport_security.cc", @@ -1971,7 +1973,7 @@ grpc_cc_library( ], hdrs = [ "src/core/tsi/alts/handshaker/alts_handshaker_client.h", - "src/core/tsi/alts/handshaker/alts_tsi_event.h", + "src/core/tsi/alts/handshaker/alts_shared_resource.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h", "src/core/tsi/alts/handshaker/alts_tsi_utils.h", @@ -2088,6 +2090,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/rpc_service_method.h", "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", + "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index bafc890121..09d625fb02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1125,6 +1125,7 @@ add_library(grpc src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc src/core/ext/transport/chttp2/transport/bin_decoder.cc @@ -1197,7 +1198,7 @@ add_library(grpc src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc src/core/tsi/alts/frame_protector/frame_handler.cc src/core/tsi/alts/handshaker/alts_handshaker_client.cc - src/core/tsi/alts/handshaker/alts_tsi_event.cc + src/core/tsi/alts/handshaker/alts_shared_resource.cc src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc @@ -1248,7 +1249,6 @@ add_library(grpc src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/client_channel/health/health.pb.c src/core/tsi/alts_transport_security.cc @@ -1546,6 +1546,7 @@ add_library(grpc_cronet src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc src/core/ext/transport/cronet/transport/cronet_api_dummy.cc @@ -1600,7 +1601,6 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/client_channel/health/health.pb.c third_party/nanopb/pb_common.c @@ -1649,7 +1649,7 @@ add_library(grpc_cronet src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc src/core/tsi/alts/frame_protector/frame_handler.cc src/core/tsi/alts/handshaker/alts_handshaker_client.cc - src/core/tsi/alts/handshaker/alts_tsi_event.cc + src/core/tsi/alts/handshaker/alts_shared_resource.cc src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc @@ -1949,6 +1949,7 @@ add_library(grpc_test_util src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc @@ -1972,7 +1973,6 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/client_channel/health/health.pb.c third_party/nanopb/pb_common.c @@ -2268,6 +2268,7 @@ add_library(grpc_test_util_unsecure src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc @@ -2291,7 +2292,6 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/client_channel/health/health.pb.c third_party/nanopb/pb_common.c @@ -2566,6 +2566,7 @@ add_library(grpc_unsecure src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc @@ -2623,7 +2624,6 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/client_channel/health/health.pb.c third_party/nanopb/pb_common.c @@ -2862,6 +2862,7 @@ add_library(grpc++ src/cpp/server/secure_server_credentials.cc src/cpp/client/channel_cc.cc src/cpp/client/client_context.cc + src/cpp/client/client_interceptor.cc src/cpp/client/create_channel.cc src/cpp/client/create_channel_internal.cc src/cpp/client/create_channel_posix.cc @@ -3020,6 +3021,7 @@ foreach(_hdr include/grpcpp/support/config.h include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h + include/grpcpp/support/server_callback.h include/grpcpp/support/slice.h include/grpcpp/support/status.h include/grpcpp/support/status_code_enum.h @@ -3137,6 +3139,7 @@ foreach(_hdr include/grpcpp/impl/codegen/rpc_service_method.h include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h + include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h @@ -3231,6 +3234,7 @@ add_library(grpc++_cronet src/cpp/server/insecure_server_credentials.cc src/cpp/client/channel_cc.cc src/cpp/client/client_context.cc + src/cpp/client/client_interceptor.cc src/cpp/client/create_channel.cc src/cpp/client/create_channel_internal.cc src/cpp/client/create_channel_posix.cc @@ -3442,6 +3446,7 @@ add_library(grpc++_cronet src/core/lib/transport/timeout_encoding.cc src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc + src/core/lib/uri/uri_parser.cc src/core/lib/debug/trace.cc src/core/ext/transport/chttp2/alpn/alpn.cc src/core/ext/filters/http/client/http_client_filter.cc @@ -3470,7 +3475,6 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/subchannel.cc src/core/ext/filters/client_channel/subchannel_index.cc - src/core/ext/filters/client_channel/uri_parser.cc src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc @@ -3600,6 +3604,7 @@ foreach(_hdr include/grpcpp/support/config.h include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h + include/grpcpp/support/server_callback.h include/grpcpp/support/slice.h include/grpcpp/support/status.h include/grpcpp/support/status_code_enum.h @@ -3717,6 +3722,7 @@ foreach(_hdr include/grpcpp/impl/codegen/rpc_service_method.h include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h + include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h @@ -4131,6 +4137,7 @@ foreach(_hdr include/grpcpp/impl/codegen/rpc_service_method.h include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h + include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h @@ -4317,6 +4324,7 @@ foreach(_hdr include/grpcpp/impl/codegen/rpc_service_method.h include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h + include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h @@ -4373,6 +4381,7 @@ add_library(grpc++_unsecure src/cpp/server/insecure_server_credentials.cc src/cpp/client/channel_cc.cc src/cpp/client/client_context.cc + src/cpp/client/client_interceptor.cc src/cpp/client/create_channel.cc src/cpp/client/create_channel_internal.cc src/cpp/client/create_channel_posix.cc @@ -4530,6 +4539,7 @@ foreach(_hdr include/grpcpp/support/config.h include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h + include/grpcpp/support/server_callback.h include/grpcpp/support/slice.h include/grpcpp/support/status.h include/grpcpp/support/status_code_enum.h @@ -4647,6 +4657,7 @@ foreach(_hdr include/grpcpp/impl/codegen/rpc_service_method.h include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h + include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h @@ -3600,6 +3600,7 @@ LIBGRPC_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc \ src/core/ext/transport/chttp2/transport/bin_decoder.cc \ @@ -3672,7 +3673,7 @@ LIBGRPC_SRC = \ src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \ src/core/tsi/alts/frame_protector/frame_handler.cc \ src/core/tsi/alts/handshaker/alts_handshaker_client.cc \ - src/core/tsi/alts/handshaker/alts_tsi_event.cc \ + src/core/tsi/alts/handshaker/alts_shared_resource.cc \ src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \ @@ -3723,7 +3724,6 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ src/core/tsi/alts_transport_security.cc \ @@ -4015,6 +4015,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc \ src/core/ext/transport/cronet/transport/cronet_api_dummy.cc \ @@ -4069,7 +4070,6 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ third_party/nanopb/pb_common.c \ @@ -4118,7 +4118,7 @@ LIBGRPC_CRONET_SRC = \ src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \ src/core/tsi/alts/frame_protector/frame_handler.cc \ src/core/tsi/alts/handshaker/alts_handshaker_client.cc \ - src/core/tsi/alts/handshaker/alts_tsi_event.cc \ + src/core/tsi/alts/handshaker/alts_shared_resource.cc \ src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \ @@ -4411,6 +4411,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ @@ -4434,7 +4435,6 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ third_party/nanopb/pb_common.c \ @@ -4716,6 +4716,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ @@ -4739,7 +4740,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ third_party/nanopb/pb_common.c \ @@ -4987,6 +4987,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \ @@ -5044,7 +5045,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ third_party/nanopb/pb_common.c \ @@ -5248,6 +5248,7 @@ LIBGRPC++_SRC = \ src/cpp/server/secure_server_credentials.cc \ src/cpp/client/channel_cc.cc \ src/cpp/client/client_context.cc \ + src/cpp/client/client_interceptor.cc \ src/cpp/client/create_channel.cc \ src/cpp/client/create_channel_internal.cc \ src/cpp/client/create_channel_posix.cc \ @@ -5371,6 +5372,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/config.h \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ + include/grpcpp/support/server_callback.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ include/grpcpp/support/status_code_enum.h \ @@ -5488,6 +5490,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ + include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -5627,6 +5630,7 @@ LIBGRPC++_CRONET_SRC = \ src/cpp/server/insecure_server_credentials.cc \ src/cpp/client/channel_cc.cc \ src/cpp/client/client_context.cc \ + src/cpp/client/client_interceptor.cc \ src/cpp/client/create_channel.cc \ src/cpp/client/create_channel_internal.cc \ src/cpp/client/create_channel_posix.cc \ @@ -5838,6 +5842,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/transport/chttp2/alpn/alpn.cc \ src/core/ext/filters/http/client/http_client_filter.cc \ @@ -5866,7 +5871,6 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \ @@ -5960,6 +5964,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/config.h \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ + include/grpcpp/support/server_callback.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ include/grpcpp/support/status_code_enum.h \ @@ -6077,6 +6082,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ + include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -6476,6 +6482,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ + include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -6639,6 +6646,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ + include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -6734,6 +6742,7 @@ LIBGRPC++_UNSECURE_SRC = \ src/cpp/server/insecure_server_credentials.cc \ src/cpp/client/channel_cc.cc \ src/cpp/client/client_context.cc \ + src/cpp/client/client_interceptor.cc \ src/cpp/client/create_channel.cc \ src/cpp/client/create_channel_internal.cc \ src/cpp/client/create_channel_posix.cc \ @@ -6857,6 +6866,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/config.h \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ + include/grpcpp/support/server_callback.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ include/grpcpp/support/status_code_enum.h \ @@ -6974,6 +6984,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ + include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -25012,7 +25023,7 @@ src/core/tsi/alts/frame_protector/frame_handler.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/alts_handshaker_client.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc: $(OPENSSL_DEP) -src/core/tsi/alts/handshaker/alts_tsi_event.cc: $(OPENSSL_DEP) +src/core/tsi/alts/handshaker/alts_shared_resource.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/alts_tsi_utils.cc: $(OPENSSL_DEP) src/core/tsi/alts/handshaker/altscontext.pb.c: $(OPENSSL_DEP) diff --git a/build.yaml b/build.yaml index ba95fcfdd9..3ee13a7dec 100644 --- a/build.yaml +++ b/build.yaml @@ -36,7 +36,7 @@ filegroups: - src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h - src/core/tsi/alts/frame_protector/frame_handler.h - src/core/tsi/alts/handshaker/alts_handshaker_client.h - - src/core/tsi/alts/handshaker/alts_tsi_event.h + - src/core/tsi/alts/handshaker/alts_shared_resource.h - src/core/tsi/alts/handshaker/alts_tsi_handshaker.h - src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h @@ -56,7 +56,7 @@ filegroups: - src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc - src/core/tsi/alts/frame_protector/frame_handler.cc - src/core/tsi/alts/handshaker/alts_handshaker_client.cc - - src/core/tsi/alts/handshaker/alts_tsi_event.cc + - src/core/tsi/alts/handshaker/alts_shared_resource.cc - src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc @@ -382,6 +382,7 @@ filegroups: - src/core/lib/transport/timeout_encoding.cc - src/core/lib/transport/transport.cc - src/core/lib/transport/transport_op_string.cc + - src/core/lib/uri/uri_parser.cc deps: - gpr filegroups: @@ -538,6 +539,7 @@ filegroups: - src/core/lib/transport/timeout_encoding.h - src/core/lib/transport/transport.h - src/core/lib/transport/transport_impl.h + - src/core/lib/uri/uri_parser.h deps: - gpr uses: @@ -588,7 +590,6 @@ filegroups: - src/core/ext/filters/client_channel/retry_throttle.h - src/core/ext/filters/client_channel/subchannel.h - src/core/ext/filters/client_channel/subchannel_index.h - - src/core/ext/filters/client_channel/uri_parser.h src: - src/core/ext/filters/client_channel/backup_poller.cc - src/core/ext/filters/client_channel/channel_connectivity.cc @@ -612,7 +613,6 @@ filegroups: - src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/subchannel.cc - src/core/ext/filters/client_channel/subchannel_index.cc - - src/core/ext/filters/client_channel/uri_parser.cc plugin: grpc_client_channel uses: - grpc_base @@ -1245,6 +1245,7 @@ filegroups: - include/grpcpp/impl/codegen/rpc_service_method.h - include/grpcpp/impl/codegen/security/auth_context.h - include/grpcpp/impl/codegen/serialization_traits.h + - include/grpcpp/impl/codegen/server_callback.h - include/grpcpp/impl/codegen/server_context.h - include/grpcpp/impl/codegen/server_interceptor.h - include/grpcpp/impl/codegen/server_interface.h @@ -1363,6 +1364,7 @@ filegroups: - include/grpcpp/support/config.h - include/grpcpp/support/proto_buffer_reader.h - include/grpcpp/support/proto_buffer_writer.h + - include/grpcpp/support/server_callback.h - include/grpcpp/support/slice.h - include/grpcpp/support/status.h - include/grpcpp/support/status_code_enum.h @@ -1380,6 +1382,7 @@ filegroups: src: - src/cpp/client/channel_cc.cc - src/cpp/client/client_context.cc + - src/cpp/client/client_interceptor.cc - src/cpp/client/create_channel.cc - src/cpp/client/create_channel_internal.cc - src/cpp/client/create_channel_posix.cc @@ -234,6 +234,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/transport/timeout_encoding.cc \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ + src/core/lib/uri/uri_parser.cc \ src/core/lib/debug/trace.cc \ src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc \ src/core/ext/transport/chttp2/transport/bin_decoder.cc \ @@ -306,7 +307,7 @@ if test "$PHP_GRPC" != "no"; then src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \ src/core/tsi/alts/frame_protector/frame_handler.cc \ src/core/tsi/alts/handshaker/alts_handshaker_client.cc \ - src/core/tsi/alts/handshaker/alts_tsi_event.cc \ + src/core/tsi/alts/handshaker/alts_shared_resource.cc \ src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \ @@ -357,7 +358,6 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel_index.cc \ - src/core/ext/filters/client_channel/uri_parser.cc \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/client_channel/health/health.pb.c \ src/core/tsi/alts_transport_security.cc \ @@ -733,6 +733,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/slice) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/surface) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/uri) PHP_ADD_BUILD_DIR($ext_builddir/src/core/plugin_registry) PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi) PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/crypt) diff --git a/config.w32 b/config.w32 index da1279ccbc..8dff1229be 100644 --- a/config.w32 +++ b/config.w32 @@ -209,6 +209,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\transport\\timeout_encoding.cc " + "src\\core\\lib\\transport\\transport.cc " + "src\\core\\lib\\transport\\transport_op_string.cc " + + "src\\core\\lib\\uri\\uri_parser.cc " + "src\\core\\lib\\debug\\trace.cc " + "src\\core\\ext\\transport\\chttp2\\server\\secure\\server_secure_chttp2.cc " + "src\\core\\ext\\transport\\chttp2\\transport\\bin_decoder.cc " + @@ -281,7 +282,7 @@ if (PHP_GRPC != "no") { "src\\core\\tsi\\alts\\frame_protector\\alts_unseal_privacy_integrity_crypter.cc " + "src\\core\\tsi\\alts\\frame_protector\\frame_handler.cc " + "src\\core\\tsi\\alts\\handshaker\\alts_handshaker_client.cc " + - "src\\core\\tsi\\alts\\handshaker\\alts_tsi_event.cc " + + "src\\core\\tsi\\alts\\handshaker\\alts_shared_resource.cc " + "src\\core\\tsi\\alts\\handshaker\\alts_tsi_handshaker.cc " + "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_integrity_only_record_protocol.cc " + "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_privacy_integrity_record_protocol.cc " + @@ -332,7 +333,6 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " + - "src\\core\\ext\\filters\\client_channel\\uri_parser.cc " + "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " + "src\\core\\ext\\filters\\client_channel\\health\\health.pb.c " + "src\\core\\tsi\\alts_transport_security.cc " + @@ -749,6 +749,7 @@ if (PHP_GRPC != "no") { FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\slice"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\surface"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\transport"); + FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\uri"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\plugin_registry"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts"); diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 1eb850e976..d1172e62f4 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -140,3 +140,13 @@ some configuration as environment variables that can be set. * grpc_cfstream set to 1 to turn on CFStream experiment. With this experiment gRPC uses CFStream API to make TCP connections. The option is only available on iOS platform and when macro GRPC_CFSTREAM is defined. + +* GRPC_ARENA_INIT_STRATEGY + Selects the initialization strategy for blocks allocated in the arena. Valid + values are: + - no_init (default): Do not inialize the arena block. + - zero_init: Initialize the arena blocks with 0. + - non_zero_init: Initialize the arena blocks with a non-zero value. + + NOTE: This environment variable is experimental and will be removed. Thus, it + should not be relied upon. diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 485646171c..d4b0548532 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -118,6 +118,7 @@ Pod::Spec.new do |s| 'include/grpcpp/support/config.h', 'include/grpcpp/support/proto_buffer_reader.h', 'include/grpcpp/support/proto_buffer_writer.h', + 'include/grpcpp/support/server_callback.h', 'include/grpcpp/support/slice.h', 'include/grpcpp/support/status.h', 'include/grpcpp/support/status_code_enum.h', @@ -154,6 +155,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/rpc_service_method.h', 'include/grpcpp/impl/codegen/security/auth_context.h', 'include/grpcpp/impl/codegen/serialization_traits.h', + 'include/grpcpp/impl/codegen/server_callback.h', 'include/grpcpp/impl/codegen/server_context.h', 'include/grpcpp/impl/codegen/server_interceptor.h', 'include/grpcpp/impl/codegen/server_interface.h', @@ -193,6 +195,7 @@ Pod::Spec.new do |s| 'src/cpp/server/secure_server_credentials.cc', 'src/cpp/client/channel_cc.cc', 'src/cpp/client/client_context.cc', + 'src/cpp/client/client_interceptor.cc', 'src/cpp/client/create_channel.cc', 'src/cpp/client/create_channel_internal.cc', 'src/cpp/client/create_channel_posix.cc', @@ -311,7 +314,7 @@ Pod::Spec.new do |s| 'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h', 'src/core/tsi/alts/frame_protector/frame_handler.h', 'src/core/tsi/alts/handshaker/alts_handshaker_client.h', - 'src/core/tsi/alts/handshaker/alts_tsi_event.h', + 'src/core/tsi/alts/handshaker/alts_shared_resource.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h', @@ -354,7 +357,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', - 'src/core/ext/filters/client_channel/uri_parser.h', 'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/client_channel/health/health.pb.h', 'src/core/tsi/alts_transport_security.h', @@ -502,6 +504,7 @@ Pod::Spec.new do |s| 'src/core/lib/transport/timeout_encoding.h', 'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/uri/uri_parser.h', 'src/core/lib/debug/trace.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h', @@ -693,6 +696,7 @@ Pod::Spec.new do |s| 'src/core/lib/transport/timeout_encoding.h', 'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/uri/uri_parser.h', 'src/core/lib/debug/trace.h', 'src/core/ext/transport/inproc/inproc_transport.h', 'src/core/ext/filters/client_channel/health/health.pb.h' diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index bbd5d7e961..6a43420830 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -312,7 +312,7 @@ Pod::Spec.new do |s| 'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h', 'src/core/tsi/alts/frame_protector/frame_handler.h', 'src/core/tsi/alts/handshaker/alts_handshaker_client.h', - 'src/core/tsi/alts/handshaker/alts_tsi_event.h', + 'src/core/tsi/alts/handshaker/alts_shared_resource.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h', @@ -355,7 +355,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', - 'src/core/ext/filters/client_channel/uri_parser.h', 'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/client_channel/health/health.pb.h', 'src/core/tsi/alts_transport_security.h', @@ -503,6 +502,7 @@ Pod::Spec.new do |s| 'src/core/lib/transport/timeout_encoding.h', 'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/uri/uri_parser.h', 'src/core/lib/debug/trace.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h', @@ -674,6 +674,7 @@ Pod::Spec.new do |s| 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', 'src/core/ext/transport/chttp2/transport/bin_decoder.cc', @@ -746,7 +747,7 @@ Pod::Spec.new do |s| 'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', 'src/core/tsi/alts/frame_protector/frame_handler.cc', 'src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'src/core/tsi/alts/handshaker/alts_tsi_event.cc', + 'src/core/tsi/alts/handshaker/alts_shared_resource.cc', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', @@ -794,7 +795,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'src/core/tsi/alts_transport_security.cc', @@ -931,7 +931,7 @@ Pod::Spec.new do |s| 'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h', 'src/core/tsi/alts/frame_protector/frame_handler.h', 'src/core/tsi/alts/handshaker/alts_handshaker_client.h', - 'src/core/tsi/alts/handshaker/alts_tsi_event.h', + 'src/core/tsi/alts/handshaker/alts_shared_resource.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h', @@ -974,7 +974,6 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/subchannel.h', 'src/core/ext/filters/client_channel/subchannel_index.h', - 'src/core/ext/filters/client_channel/uri_parser.h', 'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/client_channel/health/health.pb.h', 'src/core/tsi/alts_transport_security.h', @@ -1122,6 +1121,7 @@ Pod::Spec.new do |s| 'src/core/lib/transport/timeout_encoding.h', 'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport_impl.h', + 'src/core/lib/uri/uri_parser.h', 'src/core/lib/debug/trace.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h', diff --git a/grpc.gemspec b/grpc.gemspec index a3924d0d93..a9d3a95f2c 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -244,7 +244,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h ) s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.h ) s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.h ) - s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.h ) + s.files += %w( src/core/tsi/alts/handshaker/alts_shared_resource.h ) s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.h ) s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h ) s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h ) @@ -291,7 +291,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel.h ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h ) - s.files += %w( src/core/ext/filters/client_channel/uri_parser.h ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.h ) s.files += %w( src/core/ext/filters/client_channel/health/health.pb.h ) s.files += %w( src/core/tsi/alts_transport_security.h ) @@ -439,6 +438,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/transport/timeout_encoding.h ) s.files += %w( src/core/lib/transport/transport.h ) s.files += %w( src/core/lib/transport/transport_impl.h ) + s.files += %w( src/core/lib/uri/uri_parser.h ) s.files += %w( src/core/lib/debug/trace.h ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h ) @@ -610,6 +610,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/transport/timeout_encoding.cc ) s.files += %w( src/core/lib/transport/transport.cc ) s.files += %w( src/core/lib/transport/transport_op_string.cc ) + s.files += %w( src/core/lib/uri/uri_parser.cc ) s.files += %w( src/core/lib/debug/trace.cc ) s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.cc ) @@ -682,7 +683,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc ) s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.cc ) s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.cc ) - s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.cc ) + s.files += %w( src/core/tsi/alts/handshaker/alts_shared_resource.cc ) s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc ) s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc ) s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc ) @@ -733,7 +734,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel.cc ) s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc ) - s.files += %w( src/core/ext/filters/client_channel/uri_parser.cc ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc ) s.files += %w( src/core/ext/filters/client_channel/health/health.pb.c ) s.files += %w( src/core/tsi/alts_transport_security.cc ) @@ -426,6 +426,7 @@ 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', 'src/core/ext/transport/chttp2/transport/bin_decoder.cc', @@ -498,7 +499,7 @@ 'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', 'src/core/tsi/alts/frame_protector/frame_handler.cc', 'src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'src/core/tsi/alts/handshaker/alts_tsi_event.cc', + 'src/core/tsi/alts/handshaker/alts_shared_resource.cc', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', @@ -549,7 +550,6 @@ 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'src/core/tsi/alts_transport_security.cc', @@ -786,6 +786,7 @@ 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', @@ -809,7 +810,6 @@ 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'third_party/nanopb/pb_common.c', @@ -1025,6 +1025,7 @@ 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', @@ -1048,7 +1049,6 @@ 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'third_party/nanopb/pb_common.c', @@ -1242,6 +1242,7 @@ 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc', @@ -1299,7 +1300,6 @@ 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'third_party/nanopb/pb_common.c', @@ -1386,6 +1386,7 @@ 'src/cpp/server/secure_server_credentials.cc', 'src/cpp/client/channel_cc.cc', 'src/cpp/client/client_context.cc', + 'src/cpp/client/client_interceptor.cc', 'src/cpp/client/create_channel.cc', 'src/cpp/client/create_channel_internal.cc', 'src/cpp/client/create_channel_posix.cc', @@ -1536,6 +1537,7 @@ 'src/cpp/server/insecure_server_credentials.cc', 'src/cpp/client/channel_cc.cc', 'src/cpp/client/client_context.cc', + 'src/cpp/client/client_interceptor.cc', 'src/cpp/client/create_channel.cc', 'src/cpp/client/create_channel_internal.cc', 'src/cpp/client/create_channel_posix.cc', diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h index 14209b85ee..4502b94b17 100644 --- a/include/grpcpp/channel.h +++ b/include/grpcpp/channel.h @@ -91,7 +91,7 @@ class Channel final : public ChannelInterface, internal::Call CreateCallInternal(const internal::RpcMethod& method, ClientContext* context, CompletionQueue* cq, - int interceptor_pos) override; + size_t interceptor_pos) override; const grpc::string host_; grpc_channel* const c_channel_; // owned diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h index 744b128141..89dcb12418 100644 --- a/include/grpcpp/impl/codegen/async_unary_call.h +++ b/include/grpcpp/impl/codegen/async_unary_call.h @@ -240,7 +240,7 @@ class ServerAsyncResponseWriter final /// metadata. void Finish(const W& msg, const Status& status, void* tag) { finish_buf_.set_output_tag(tag); - finish_buf_.set_cq_tag(&finish_buf_); + finish_buf_.set_core_cq_tag(&finish_buf_); if (!ctx_->sent_initial_metadata_) { finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, ctx_->initial_metadata_flags()); diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h index d54ae31852..abba5549b8 100644 --- a/include/grpcpp/impl/codegen/byte_buffer.h +++ b/include/grpcpp/impl/codegen/byte_buffer.h @@ -45,6 +45,8 @@ template <class ServiceType, class RequestType, class ResponseType> class RpcMethodHandler; template <class ServiceType, class RequestType, class ResponseType> class ServerStreamingHandler; +template <class ServiceType, class RequestType, class ResponseType> +class CallbackUnaryHandler; template <StatusCode code> class ErrorMethodHandler; template <class R> @@ -154,6 +156,8 @@ class ByteBuffer final { friend class internal::RpcMethodHandler; template <class ServiceType, class RequestType, class ResponseType> friend class internal::ServerStreamingHandler; + template <class ServiceType, class RequestType, class ResponseType> + friend class internal::CallbackUnaryHandler; template <StatusCode code> friend class internal::ErrorMethodHandler; template <class R> diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h index 826a5972a0..b4c34a01c9 100644 --- a/include/grpcpp/impl/codegen/call_op_set.h +++ b/include/grpcpp/impl/codegen/call_op_set.h @@ -769,19 +769,19 @@ class CallOpSet : public CallOpSetInterface, public Op5, public Op6 { public: - CallOpSet() : cq_tag_(this), return_tag_(this) {} + CallOpSet() : core_cq_tag_(this), return_tag_(this) {} // The copy constructor and assignment operator reset the value of - // cq_tag_, return_tag_, done_intercepting_ and interceptor_methods_ since - // those are only meaningful on a specific object, not across objects. + // core_cq_tag_, return_tag_, done_intercepting_ and interceptor_methods_ + // since those are only meaningful on a specific object, not across objects. CallOpSet(const CallOpSet& other) - : cq_tag_(this), + : core_cq_tag_(this), return_tag_(this), call_(other.call_), done_intercepting_(false), interceptor_methods_(InterceptorBatchMethodsImpl()) {} CallOpSet& operator=(const CallOpSet& other) { - cq_tag_ = this; + core_cq_tag_ = this; return_tag_ = this; call_ = other.call_; done_intercepting_ = false; @@ -833,13 +833,13 @@ class CallOpSet : public CallOpSetInterface, void set_output_tag(void* return_tag) { return_tag_ = return_tag; } - void* cq_tag() override { return cq_tag_; } + void* core_cq_tag() override { return core_cq_tag_; } - /// set_cq_tag is used to provide a different core CQ tag than "this". + /// set_core_cq_tag is used to provide a different core CQ tag than "this". /// This is used for callback-based tags, where the core tag is the core /// callback function. It does not change the use or behavior of any other /// function (such as FinalizeResult) - void set_cq_tag(void* cq_tag) { cq_tag_ = cq_tag; } + void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; } // This will be called while interceptors are run if the RPC is a hijacked // RPC. This should set hijacking state for each of the ops. @@ -865,7 +865,7 @@ class CallOpSet : public CallOpSetInterface, this->Op6::AddOp(ops, &nops); GPR_CODEGEN_ASSERT(GRPC_CALL_OK == g_core_codegen_interface->grpc_call_start_batch( - call_.call(), ops, nops, cq_tag(), nullptr)); + call_.call(), ops, nops, core_cq_tag(), nullptr)); } // Should be called after interceptors are done running on the finalize result @@ -874,7 +874,7 @@ class CallOpSet : public CallOpSetInterface, done_intercepting_ = true; GPR_CODEGEN_ASSERT(GRPC_CALL_OK == g_core_codegen_interface->grpc_call_start_batch( - call_.call(), nullptr, 0, cq_tag(), nullptr)); + call_.call(), nullptr, 0, core_cq_tag(), nullptr)); } private: @@ -905,7 +905,7 @@ class CallOpSet : public CallOpSetInterface, return interceptor_methods_.RunInterceptors(); } - void* cq_tag_; + void* core_cq_tag_; void* return_tag_; Call call_; bool done_intercepting_ = false; diff --git a/include/grpcpp/impl/codegen/call_op_set_interface.h b/include/grpcpp/impl/codegen/call_op_set_interface.h index 815227a299..3b74566a6d 100644 --- a/include/grpcpp/impl/codegen/call_op_set_interface.h +++ b/include/grpcpp/impl/codegen/call_op_set_interface.h @@ -38,9 +38,9 @@ class CallOpSetInterface : public CompletionQueueTag { virtual void FillOps(internal::Call* call) = 0; /// Get the tag to be used at the core completion queue. Generally, the - /// value of cq_tag will be "this". However, it can be overridden if we + /// value of core_cq_tag will be "this". However, it can be overridden if we /// want core to process the tag differently (e.g., as a core callback) - virtual void* cq_tag() = 0; + virtual void* core_cq_tag() = 0; // This will be called while interceptors are run if the RPC is a hijacked // RPC. This should set hijacking state for each of the ops. diff --git a/include/grpcpp/impl/codegen/callback_common.h b/include/grpcpp/impl/codegen/callback_common.h index eba9ec6edc..51367cf550 100644 --- a/include/grpcpp/impl/codegen/callback_common.h +++ b/include/grpcpp/impl/codegen/callback_common.h @@ -101,14 +101,18 @@ class CallbackWithStatusTag GPR_CODEGEN_ASSERT(ignored == ops_); // Last use of func_ or status_, so ok to move them out - CatchingCallback(std::move(func_), std::move(status_)); - + auto func = std::move(func_); + auto status = std::move(status_); func_ = nullptr; // reset to clear this out for sure status_ = Status(); // reset to clear this out for sure + CatchingCallback(std::move(func), std::move(status)); g_core_codegen_interface->grpc_call_unref(call_); } }; +/// CallbackWithSuccessTag can be reused multiple times, and will be used in +/// this fashion for streaming operations. As a result, it shouldn't clear +/// anything up until its destructor class CallbackWithSuccessTag : public grpc_experimental_completion_queue_functor { public: @@ -124,13 +128,39 @@ class CallbackWithSuccessTag // there are no tests catching the compiler warning. static void operator delete(void*, void*) { assert(0); } + CallbackWithSuccessTag() : call_(nullptr) {} + CallbackWithSuccessTag(grpc_call* call, std::function<void(bool)> f, - CompletionQueueTag* ops) - : call_(call), func_(std::move(f)), ops_(ops) { + CompletionQueueTag* ops) { + Set(call, f, ops); + } + + CallbackWithSuccessTag(const CallbackWithSuccessTag&) = delete; + CallbackWithSuccessTag& operator=(const CallbackWithSuccessTag&) = delete; + + ~CallbackWithSuccessTag() { Clear(); } + + // Set can only be called on a default-constructed or Clear'ed tag. + // It should never be called on a tag that was constructed with arguments + // or on a tag that has been Set before unless the tag has been cleared. + void Set(grpc_call* call, std::function<void(bool)> f, + CompletionQueueTag* ops) { + call_ = call; + func_ = std::move(f); + ops_ = ops; g_core_codegen_interface->grpc_call_ref(call); functor_run = &CallbackWithSuccessTag::StaticRun; } + void Clear() { + if (call_ != nullptr) { + func_ = nullptr; + grpc_call* call = call_; + call_ = nullptr; + g_core_codegen_interface->grpc_call_unref(call); + } + } + CompletionQueueTag* ops() { return ops_; } // force_run can not be performed on a tag if operations using this tag @@ -138,6 +168,9 @@ class CallbackWithSuccessTag // that are detected before the operations are internally processed. void force_run(bool ok) { Run(ok); } + /// check if this tag is currently set + operator bool() const { return call_ != nullptr; } + private: grpc_call* call_; std::function<void(bool)> func_; @@ -150,14 +183,14 @@ class CallbackWithSuccessTag void Run(bool ok) { void* ignored = ops_; bool new_ok = ok; - GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &new_ok)); + // Allow a "false" return value from FinalizeResult to silence the + // callback, just as it silences a CQ tag in the async cases + bool do_callback = ops_->FinalizeResult(&ignored, &new_ok); GPR_CODEGEN_ASSERT(ignored == ops_); - // Last use of func_, so ok to move it out for rvalue call above - CatchingCallback(std::move(func_), ok); - - func_ = nullptr; // reset to clear this out for sure - g_core_codegen_interface->grpc_call_unref(call_); + if (do_callback) { + CatchingCallback(func_, ok); + } } }; diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index e957ea6aab..6ec1ffb8c7 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -134,7 +134,7 @@ class ChannelInterface { virtual internal::Call CreateCallInternal(const internal::RpcMethod& method, ClientContext* context, CompletionQueue* cq, - int interceptor_pos) { + size_t interceptor_pos) { return internal::Call(); } @@ -143,7 +143,7 @@ class ChannelInterface { // channel. If the return value is nullptr, this channel doesn't support // callback operations. // TODO(vjpai): Consider a better default like using a global CQ - // Returns nullptr (rather than being pure) since this is a new method + // Returns nullptr (rather than being pure) since this is a post-1.0 method // and adding a new pure method to an interface would be a breaking change // (even though this is private and non-API) virtual CompletionQueue* CallbackCQ() { return nullptr; } diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index ecb00a0769..4baa819091 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -84,7 +84,7 @@ class CallbackUnaryCallImpl { ops->AllowNoMessage(); ops->ClientSendClose(); ops->ClientRecvStatus(context, tag->status_ptr()); - ops->set_cq_tag(tag); + ops->set_core_cq_tag(tag); call.PerformOps(ops); } }; diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h index 0e08a7ce01..f69c99ab22 100644 --- a/include/grpcpp/impl/codegen/client_interceptor.h +++ b/include/grpcpp/impl/codegen/client_interceptor.h @@ -19,6 +19,7 @@ #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H #define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H +#include <memory> #include <vector> #include <grpcpp/impl/codegen/interceptor.h> @@ -41,7 +42,14 @@ class ClientInterceptorFactoryInterface { virtual ~ClientInterceptorFactoryInterface() {} virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0; }; +} // namespace experimental +namespace internal { +extern experimental::ClientInterceptorFactoryInterface* + g_global_client_interceptor_factory; +} + +namespace experimental { class ClientRpcInfo { public: ClientRpcInfo() {} @@ -71,12 +79,21 @@ class ClientRpcInfo { void RegisterInterceptors( const std::vector<std::unique_ptr< experimental::ClientInterceptorFactoryInterface>>& creators, - int interceptor_pos) { + size_t interceptor_pos) { + if (interceptor_pos > creators.size()) { + // No interceptors to register + return; + } for (auto it = creators.begin() + interceptor_pos; it != creators.end(); ++it) { interceptors_.push_back(std::unique_ptr<experimental::Interceptor>( (*it)->CreateClientInterceptor(this))); } + if (internal::g_global_client_interceptor_factory != nullptr) { + interceptors_.push_back(std::unique_ptr<experimental::Interceptor>( + internal::g_global_client_interceptor_factory + ->CreateClientInterceptor(this))); + } } grpc::ClientContext* ctx_ = nullptr; @@ -90,6 +107,20 @@ class ClientRpcInfo { friend class grpc::ClientContext; }; +// PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL +// INTERCEPTOR. IF USAGE IS ABSOLUTELY NECESSARY, PLEASE READ THE SAFETY NOTES. +// Registers a global client interceptor factory object, which is used for all +// RPCs made in this process. If the argument is nullptr, the global +// interceptor factory is deregistered. The application is responsible for +// maintaining the life of the object while gRPC operations are in progress. It +// is unsafe to try to register/deregister if any gRPC operation is in progress. +// For safety, it is in the best interests of the developer to register the +// global interceptor factory once at the start of the process before any gRPC +// operations have begun. Deregistration is optional since gRPC does not +// maintain any references to the object. +void RegisterGlobalClientInterceptorFactory( + ClientInterceptorFactoryInterface* factory); + } // namespace experimental } // namespace grpc diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h index 5eef2c281f..d603c7c700 100644 --- a/include/grpcpp/impl/codegen/completion_queue.h +++ b/include/grpcpp/impl/codegen/completion_queue.h @@ -380,12 +380,18 @@ class ServerCompletionQueue : public CompletionQueue { ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {} private: + /// \param completion_type indicates whether this is a NEXT or CALLBACK + /// completion queue. /// \param polling_type Informs the GRPC library about the type of polling /// allowed on this completion queue. See grpc_cq_polling_type's description /// in grpc_types.h for more details. - ServerCompletionQueue(grpc_cq_polling_type polling_type) + /// \param shutdown_cb is the shutdown callback used for CALLBACK api queues + ServerCompletionQueue(grpc_cq_completion_type completion_type, + grpc_cq_polling_type polling_type, + grpc_experimental_completion_queue_functor* shutdown_cb) : CompletionQueue(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type, nullptr}), + GRPC_CQ_CURRENT_VERSION, completion_type, polling_type, + shutdown_cb}), polling_type_(polling_type) {} grpc_cq_polling_type polling_type_; diff --git a/include/grpcpp/impl/codegen/core_codegen_interface.h b/include/grpcpp/impl/codegen/core_codegen_interface.h index 25e3abccca..20a5b3300c 100644 --- a/include/grpcpp/impl/codegen/core_codegen_interface.h +++ b/include/grpcpp/impl/codegen/core_codegen_interface.h @@ -145,6 +145,15 @@ extern CoreCodegenInterface* g_core_codegen_interface; } \ } while (0) +/// Codegen specific version of \a GPR_DEBUG_ASSERT. +#ifndef NDEBUG +#define GPR_CODEGEN_DEBUG_ASSERT(x) GPR_CODEGEN_ASSERT(x) +#else +#define GPR_CODEGEN_DEBUG_ASSERT(x) \ + do { \ + } while (0) +#endif + } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H diff --git a/include/grpcpp/impl/codegen/intercepted_channel.h b/include/grpcpp/impl/codegen/intercepted_channel.h index 612e56d862..5255a6d147 100644 --- a/include/grpcpp/impl/codegen/intercepted_channel.h +++ b/include/grpcpp/impl/codegen/intercepted_channel.h @@ -42,7 +42,7 @@ class InterceptedChannel : public ChannelInterface { } private: - InterceptedChannel(ChannelInterface* channel, int pos) + InterceptedChannel(ChannelInterface* channel, size_t pos) : channel_(channel), interceptor_pos_(pos) {} Call CreateCall(const RpcMethod& method, ClientContext* context, @@ -70,7 +70,7 @@ class InterceptedChannel : public ChannelInterface { CompletionQueue* CallbackCQ() override { return channel_->CallbackCQ(); } ChannelInterface* channel_; - int interceptor_pos_; + size_t interceptor_pos_; friend class InterceptorBatchMethodsImpl; }; diff --git a/include/grpcpp/impl/codegen/rpc_service_method.h b/include/grpcpp/impl/codegen/rpc_service_method.h index e77f4046a3..f465c5fc2f 100644 --- a/include/grpcpp/impl/codegen/rpc_service_method.h +++ b/include/grpcpp/impl/codegen/rpc_service_method.h @@ -40,14 +40,28 @@ class MethodHandler { public: virtual ~MethodHandler() {} struct HandlerParameter { + /// Constructor for HandlerParameter + /// + /// \param c : the gRPC Call structure for this server call + /// \param context : the ServerContext structure for this server call + /// \param req : the request payload, if appropriate for this RPC + /// \param req_status : the request status after any interceptors have run + /// \param rpc_requester : used only by the callback API. It is a function + /// called by the RPC Controller to request another RPC (and also + /// to set up the state required to make that request possible) HandlerParameter(Call* c, ServerContext* context, void* req, - Status req_status) - : call(c), server_context(context), request(req), status(req_status) {} + Status req_status, std::function<void()> requester) + : call(c), + server_context(context), + request(req), + status(req_status), + call_requester(std::move(requester)) {} ~HandlerParameter() {} Call* call; ServerContext* server_context; void* request; Status status; + std::function<void()> call_requester; }; virtual void RunHandler(const HandlerParameter& param) = 0; @@ -71,25 +85,29 @@ class RpcServiceMethod : public RpcMethod { MethodHandler* handler) : RpcMethod(name, type), server_tag_(nullptr), - async_type_(AsyncType::UNSET), + api_type_(ApiType::SYNC), handler_(handler) {} - enum class AsyncType { - UNSET, + enum class ApiType { + SYNC, ASYNC, RAW, + CALL_BACK, // not CALLBACK because that is reserved in Windows + RAW_CALL_BACK, }; void set_server_tag(void* tag) { server_tag_ = tag; } void* server_tag() const { return server_tag_; } /// if MethodHandler is nullptr, then this is an async method MethodHandler* handler() const { return handler_.get(); } + ApiType api_type() const { return api_type_; } void SetHandler(MethodHandler* handler) { handler_.reset(handler); } - void SetServerAsyncType(RpcServiceMethod::AsyncType type) { - if (async_type_ == AsyncType::UNSET) { + void SetServerApiType(RpcServiceMethod::ApiType type) { + if ((api_type_ == ApiType::SYNC) && + (type == ApiType::ASYNC || type == ApiType::RAW)) { // this marks this method as async handler_.reset(); - } else { + } else if (api_type_ != ApiType::SYNC) { // this is not an error condition, as it allows users to declare a server // like WithRawMethod_foo<AsyncService>. However since it // overwrites behavior, it should be logged. @@ -98,24 +116,28 @@ class RpcServiceMethod : public RpcMethod { "You are marking method %s as '%s', even though it was " "previously marked '%s'. This behavior will overwrite the original " "behavior. If you expected this then ignore this message.", - name(), TypeToString(async_type_), TypeToString(type)); + name(), TypeToString(api_type_), TypeToString(type)); } - async_type_ = type; + api_type_ = type; } private: void* server_tag_; - AsyncType async_type_; + ApiType api_type_; std::unique_ptr<MethodHandler> handler_; - const char* TypeToString(RpcServiceMethod::AsyncType type) { + const char* TypeToString(RpcServiceMethod::ApiType type) { switch (type) { - case AsyncType::UNSET: - return "unset"; - case AsyncType::ASYNC: + case ApiType::SYNC: + return "sync"; + case ApiType::ASYNC: return "async"; - case AsyncType::RAW: + case ApiType::RAW: return "raw"; + case ApiType::CALL_BACK: + return "callback"; + case ApiType::RAW_CALL_BACK: + return "raw_callback"; default: GPR_UNREACHABLE_CODE(return "unknown"); } diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h new file mode 100644 index 0000000000..b866fc16dc --- /dev/null +++ b/include/grpcpp/impl/codegen/server_callback.h @@ -0,0 +1,200 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H +#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H + +#include <functional> + +#include <grpcpp/impl/codegen/call.h> +#include <grpcpp/impl/codegen/call_op_set.h> +#include <grpcpp/impl/codegen/callback_common.h> +#include <grpcpp/impl/codegen/config.h> +#include <grpcpp/impl/codegen/core_codegen_interface.h> +#include <grpcpp/impl/codegen/server_context.h> +#include <grpcpp/impl/codegen/server_interface.h> +#include <grpcpp/impl/codegen/status.h> + +namespace grpc { + +// forward declarations +namespace internal { +template <class ServiceType, class RequestType, class ResponseType> +class CallbackUnaryHandler; +} // namespace internal + +namespace experimental { + +// For unary RPCs, the exposed controller class is only an interface +// and the actual implementation is an internal class. +class ServerCallbackRpcController { + public: + virtual ~ServerCallbackRpcController() {} + + // The method handler must call this function when it is done so that + // the library knows to free its resources + virtual void Finish(Status s) = 0; + + // Allow the method handler to push out the initial metadata before + // the response and status are ready + virtual void SendInitialMetadata(std::function<void(bool)>) = 0; +}; + +} // namespace experimental + +namespace internal { + +template <class ServiceType, class RequestType, class ResponseType> +class CallbackUnaryHandler : public MethodHandler { + public: + CallbackUnaryHandler( + std::function<void(ServerContext*, const RequestType*, ResponseType*, + experimental::ServerCallbackRpcController*)> + func, + ServiceType* service) + : func_(func) {} + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a controller structure (that includes request/response) + g_core_codegen_interface->grpc_call_ref(param.call->call()); + auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) + ServerCallbackRpcControllerImpl( + param.server_context, param.call, + static_cast<RequestType*>(param.request), + std::move(param.call_requester)); + Status status = param.status; + + if (status.ok()) { + // Call the actual function handler and expect the user to call finish + CatchingCallback(std::move(func_), param.server_context, + controller->request(), controller->response(), + controller); + } else { + // if deserialization failed, we need to fail the call + controller->Finish(status); + } + } + + void* Deserialize(grpc_call* call, grpc_byte_buffer* req, + Status* status) final { + ByteBuffer buf; + buf.set_buffer(req); + auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(RequestType))) RequestType(); + *status = SerializationTraits<RequestType>::Deserialize(&buf, request); + buf.Release(); + if (status->ok()) { + return request; + } + request->~RequestType(); + return nullptr; + } + + private: + std::function<void(ServerContext*, const RequestType*, ResponseType*, + experimental::ServerCallbackRpcController*)> + func_; + + // The implementation class of ServerCallbackRpcController is a private member + // of CallbackUnaryHandler since it is never exposed anywhere, and this allows + // it to take advantage of CallbackUnaryHandler's friendships. + class ServerCallbackRpcControllerImpl + : public experimental::ServerCallbackRpcController { + public: + void Finish(Status s) override { + finish_tag_.Set( + call_.call(), + [this](bool) { + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackRpcControllerImpl(); // explicitly call + // destructor + g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + }, + &finish_buf_); + if (!ctx_->sent_initial_metadata_) { + finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (s.ok()) { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_buf_.SendMessage(resp_)); + } else { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, s); + } + finish_buf_.set_core_cq_tag(&finish_tag_); + call_.PerformOps(&finish_buf_); + } + + void SendInitialMetadata(std::function<void(bool)> f) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_tag_.Set(call_.call(), std::move(f), &meta_buf_); + meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_buf_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_buf_); + } + + private: + template <class SrvType, class ReqType, class RespType> + friend class CallbackUnaryHandler; + + ServerCallbackRpcControllerImpl(ServerContext* ctx, Call* call, + RequestType* req, + std::function<void()> call_requester) + : ctx_(ctx), + call_(*call), + req_(req), + call_requester_(std::move(call_requester)) {} + + ~ServerCallbackRpcControllerImpl() { req_->~RequestType(); } + + RequestType* request() { return req_; } + ResponseType* response() { return &resp_; } + + CallOpSet<CallOpSendInitialMetadata> meta_buf_; + CallbackWithSuccessTag meta_tag_; + CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, + CallOpServerSendStatus> + finish_buf_; + CallbackWithSuccessTag finish_tag_; + + ServerContext* ctx_; + Call call_; + RequestType* req_; + ResponseType resp_; + std::function<void()> call_requester_; + }; +}; + +} // namespace internal + +} // namespace grpc + +#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h index 7559fb3b34..82ee862f61 100644 --- a/include/grpcpp/impl/codegen/server_context.h +++ b/include/grpcpp/impl/codegen/server_context.h @@ -27,6 +27,7 @@ #include <grpcpp/impl/codegen/call.h> #include <grpcpp/impl/codegen/call_op_set.h> +#include <grpcpp/impl/codegen/callback_common.h> #include <grpcpp/impl/codegen/completion_queue_tag.h> #include <grpcpp/impl/codegen/config.h> #include <grpcpp/impl/codegen/create_auth_context.h> @@ -65,6 +66,8 @@ template <class ServiceType, class RequestType, class ResponseType> class ServerStreamingHandler; template <class ServiceType, class RequestType, class ResponseType> class BidiStreamingHandler; +template <class ServiceType, class RequestType, class ResponseType> +class CallbackUnaryHandler; template <class Streamer, bool WriteNeeded> class TemplatedBidiStreamingHandler; template <StatusCode code> @@ -137,7 +140,7 @@ class ServerContext { /// must end in "-bin". void AddTrailingMetadata(const grpc::string& key, const grpc::string& value); - /// IsCancelled is always safe to call when using sync API. + /// IsCancelled is always safe to call when using sync or callback API. /// When using async API, it is only safe to call IsCancelled after /// the AsyncNotifyWhenDone tag has been delivered. bool IsCancelled() const; @@ -267,6 +270,8 @@ class ServerContext { friend class ::grpc::internal::ServerStreamingHandler; template <class Streamer, bool WriteNeeded> friend class ::grpc::internal::TemplatedBidiStreamingHandler; + template <class ServiceType, class RequestType, class ResponseType> + friend class ::grpc::internal::CallbackUnaryHandler; template <StatusCode code> friend class internal::ErrorMethodHandler; friend class ::grpc::ClientContext; @@ -277,7 +282,7 @@ class ServerContext { class CompletionOp; - void BeginCompletionOp(internal::Call* call); + void BeginCompletionOp(internal::Call* call, bool callback); /// Return the tag queued by BeginCompletionOp() internal::CompletionQueueTag* GetCompletionOpTag(); @@ -285,6 +290,12 @@ class ServerContext { void set_call(grpc_call* call) { call_ = call; } + void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr); + + void Clear(); + + void Setup(gpr_timespec deadline); + uint32_t initial_metadata_flags() const { return 0; } experimental::ServerRpcInfo* set_server_rpc_info( @@ -302,6 +313,7 @@ class ServerContext { CompletionOp* completion_op_; bool has_notify_when_done_tag_; void* async_notify_when_done_tag_; + internal::CallbackWithSuccessTag completion_tag_; gpr_timespec deadline_; grpc_call* call_; @@ -321,7 +333,7 @@ class ServerContext { pending_ops_; bool has_pending_ops_; - experimental::ServerRpcInfo* rpc_info_ = nullptr; + experimental::ServerRpcInfo* rpc_info_; }; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h index 3967e96cfe..55c94f4d2f 100644 --- a/include/grpcpp/impl/codegen/server_interface.h +++ b/include/grpcpp/impl/codegen/server_interface.h @@ -335,14 +335,24 @@ class ServerInterface : public internal::CallHook { private: // EXPERIMENTAL // Getter method for the vector of interceptor factory objects. - // Returns a nullptr (rather than being pure) since this is a new method and - // adding a new pure method to an interface would be a breaking change (even - // though this is private and non-API) + // Returns a nullptr (rather than being pure) since this is a post-1.0 method + // and adding a new pure method to an interface would be a breaking change + // (even though this is private and non-API) virtual std::vector< std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>* interceptor_creators() { return nullptr; } + + // EXPERIMENTAL + // A method to get the callbackable completion queue associated with this + // server. If the return value is nullptr, this server doesn't support + // callback operations. + // TODO(vjpai): Consider a better default like using a global CQ + // Returns nullptr (rather than being pure) since this is a post-1.0 method + // and adding a new pure method to an interface would be a breaking change + // (even though this is private and non-API) + virtual CompletionQueue* CallbackCQ() { return nullptr; } }; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h index 9f1a052168..332a04c294 100644 --- a/include/grpcpp/impl/codegen/service_type.h +++ b/include/grpcpp/impl/codegen/service_type.h @@ -71,7 +71,20 @@ class Service { bool has_synchronous_methods() const { for (auto it = methods_.begin(); it != methods_.end(); ++it) { - if (*it && (*it)->handler() != nullptr) { + if (*it && + (*it)->api_type() == internal::RpcServiceMethod::ApiType::SYNC) { + return true; + } + } + return false; + } + + bool has_callback_methods() const { + for (auto it = methods_.begin(); it != methods_.end(); ++it) { + if (*it && ((*it)->api_type() == + internal::RpcServiceMethod::ApiType::CALL_BACK || + (*it)->api_type() == + internal::RpcServiceMethod::ApiType::RAW_CALL_BACK)) { return true; } } @@ -88,6 +101,43 @@ class Service { } protected: + // TODO(vjpai): Promote experimental contents once callback API is accepted + class experimental_type { + public: + explicit experimental_type(Service* service) : service_(service) {} + + void MarkMethodCallback(int index, internal::MethodHandler* handler) { + // This does not have to be a hard error, however no one has approached us + // with a use case yet. Please file an issue if you believe you have one. + size_t idx = static_cast<size_t>(index); + GPR_CODEGEN_ASSERT( + service_->methods_[idx].get() != nullptr && + "Cannot mark the method as 'callback' because it has already been " + "marked as 'generic'."); + service_->methods_[idx]->SetHandler(handler); + service_->methods_[idx]->SetServerApiType( + internal::RpcServiceMethod::ApiType::CALL_BACK); + } + + void MarkMethodRawCallback(int index, internal::MethodHandler* handler) { + // This does not have to be a hard error, however no one has approached us + // with a use case yet. Please file an issue if you believe you have one. + size_t idx = static_cast<size_t>(index); + GPR_CODEGEN_ASSERT( + service_->methods_[idx].get() != nullptr && + "Cannot mark the method as 'raw callback' because it has already " + "been marked as 'generic'."); + service_->methods_[idx]->SetHandler(handler); + service_->methods_[idx]->SetServerApiType( + internal::RpcServiceMethod::ApiType::RAW_CALL_BACK); + } + + private: + Service* service_; + }; + + experimental_type experimental() { return experimental_type(this); } + template <class Message> void RequestAsyncUnary(int index, ServerContext* context, Message* request, internal::ServerAsyncStreamingInterface* stream, @@ -138,8 +188,7 @@ class Service { methods_[idx].get() != nullptr && "Cannot mark the method as 'async' because it has already been " "marked as 'generic'."); - methods_[idx]->SetServerAsyncType( - internal::RpcServiceMethod::AsyncType::ASYNC); + methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::ASYNC); } void MarkMethodRaw(int index) { @@ -149,8 +198,7 @@ class Service { GPR_CODEGEN_ASSERT(methods_[idx].get() != nullptr && "Cannot mark the method as 'raw' because it has already " "been marked as 'generic'."); - methods_[idx]->SetServerAsyncType( - internal::RpcServiceMethod::AsyncType::RAW); + methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::RAW); } void MarkMethodGeneric(int index) { diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h index 82d60b0218..a14a4da578 100644 --- a/include/grpcpp/server.h +++ b/include/grpcpp/server.h @@ -201,6 +201,7 @@ class Server : public ServerInterface, private GrpcLibraryCodegen { friend class ServerInitializer; class SyncRequest; + class CallbackRequest; class UnimplementedAsyncRequest; class UnimplementedAsyncResponse; @@ -223,6 +224,8 @@ class Server : public ServerInterface, private GrpcLibraryCodegen { return max_receive_message_size_; }; + CompletionQueue* CallbackCQ() override; + ServerInitializer* initializer(); // A vector of interceptor factory objects. @@ -245,6 +248,9 @@ class Server : public ServerInterface, private GrpcLibraryCodegen { /// the \a sync_server_cqs) std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_; + /// Outstanding callback requests + std::vector<std::unique_ptr<CallbackRequest>> callback_reqs_; + // Server status std::mutex mu_; bool started_; @@ -268,6 +274,13 @@ class Server : public ServerInterface, private GrpcLibraryCodegen { // A special handler for resource exhausted in sync case std::unique_ptr<internal::MethodHandler> resource_exhausted_handler_; + + // callback_cq_ references the callbackable completion queue associated + // with this server (if any). It is set on the first call to CallbackCQ(). + // It is _not owned_ by the server; ownership belongs with its internal + // shutdown callback tag (invoked when the CQ is fully shutdown). + // It is protected by mu_ + CompletionQueue* callback_cq_ = nullptr; }; } // namespace grpc diff --git a/include/grpcpp/support/server_callback.h b/include/grpcpp/support/server_callback.h new file mode 100644 index 0000000000..b0aeeb53c5 --- /dev/null +++ b/include/grpcpp/support/server_callback.h @@ -0,0 +1,24 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_SUPPORT_SERVER_CALLBACK_H +#define GRPCPP_SUPPORT_SERVER_CALLBACK_H + +#include <grpcpp/impl/codegen/server_callback.h> + +#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_H diff --git a/package.xml b/package.xml index c90cee8fe9..69f952c466 100644 --- a/package.xml +++ b/package.xml @@ -249,7 +249,7 @@ <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.h" role="src" /> - <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.h" role="src" /> + <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_shared_resource.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h" role="src" /> @@ -296,7 +296,6 @@ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" /> - <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.h" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.h" role="src" /> @@ -444,6 +443,7 @@ <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" /> + <file baseinstalldir="/" name="src/core/lib/uri/uri_parser.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" /> @@ -615,6 +615,7 @@ <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.cc" role="src" /> + <file baseinstalldir="/" name="src/core/lib/uri/uri_parser.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/debug/trace.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.cc" role="src" /> @@ -687,7 +688,7 @@ <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.cc" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.cc" role="src" /> - <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.cc" role="src" /> + <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_shared_resource.cc" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc" role="src" /> @@ -738,7 +739,6 @@ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.cc" role="src" /> - <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.c" role="src" /> <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.cc" role="src" /> diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 16f31f9e94..efbf5314af 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -8,3 +8,4 @@ wheel>=0.29 futures>=2.2.0 google-auth>=1.0.0 oauth2client==4.1.0 +requests>=2.14.2 @@ -57,11 +57,13 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.abspath(PYTHON_STEM)) # Break import-style to ensure we can actually find our in-repo dependencies. +import _parallel_compile_patch import _spawn_patch import commands import grpc_core_dependencies import grpc_version +_parallel_compile_patch.monkeypatch_compile_maybe() _spawn_patch.monkeypatch_spawn() LICENSE = 'Apache License 2.0' @@ -87,19 +89,19 @@ BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False) # Export this variable to use the system installation of openssl. You need to # have the header files installed (in /usr/include/openssl) and during -# runtime, the shared libary must be installed +# runtime, the shared library must be installed BUILD_WITH_SYSTEM_OPENSSL = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_OPENSSL', False) # Export this variable to use the system installation of zlib. You need to # have the header files installed (in /usr/include/) and during -# runtime, the shared libary must be installed +# runtime, the shared library must be installed BUILD_WITH_SYSTEM_ZLIB = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_ZLIB', False) # Export this variable to use the system installation of cares. You need to # have the header files installed (in /usr/include/) and during -# runtime, the shared libary must be installed +# runtime, the shared library must be installed BUILD_WITH_SYSTEM_CARES = os.environ.get('GRPC_PYTHON_BUILD_SYSTEM_CARES', False) @@ -202,7 +204,7 @@ DEFINE_MACROS = ( ('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600), ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1)) if "win32" in sys.platform: - # TODO(zyc): Re-enble c-ares on x64 and x86 windows after fixing the + # TODO(zyc): Re-enable c-ares on x64 and x86 windows after fixing the # ares_library_init compilation issue DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1), ('GRPC_ARES', 0), ('NTDDI_VERSION', 0x06000000), diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 56716493dc..7986aca696 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -135,6 +135,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, "grpcpp/impl/codegen/method_handler_impl.h", "grpcpp/impl/codegen/proto_utils.h", "grpcpp/impl/codegen/rpc_method.h", + "grpcpp/impl/codegen/server_callback.h", "grpcpp/impl/codegen/service_type.h", "grpcpp/impl/codegen/status.h", "grpcpp/impl/codegen/stub_options.h", @@ -700,9 +701,9 @@ void PrintHeaderServerMethodSync(grpc_generator::Printer* printer, printer->Print(method->GetTrailingComments("//").c_str()); } -// Helper generator. Disabled the sync API for Request and Response, then adds +// Helper generator. Disables the sync API for Request and Response, then adds // in an async API for RealRequest and RealResponse types. This is to be used -// to generate async and raw APIs. +// to generate async and raw async APIs. void PrintHeaderServerAsyncMethodsHelper( grpc_generator::Printer* printer, const grpc_generator::Method* method, std::map<grpc::string, grpc::string>* vars) { @@ -829,6 +830,170 @@ void PrintHeaderServerMethodAsync(grpc_generator::Printer* printer, printer->Print(*vars, "};\n"); } +// Helper generator. Disables the sync API for Request and Response, then adds +// in a callback API for RealRequest and RealResponse types. This is to be used +// to generate callback and raw callback APIs. +void PrintHeaderServerCallbackMethodsHelper( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map<grpc::string, grpc::string>* vars) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "virtual void $Method$(" + "::grpc::ServerContext* context, const $RealRequest$* request, " + "$RealResponse$* response, " + "::grpc::experimental::ServerCallbackRpcController* " + "controller) { controller->Finish(::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\")); }\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) " + " override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } +} + +void PrintHeaderServerMethodCallback( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map<grpc::string, grpc::string>* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for the callback API + (*vars)["RealRequest"] = method->input_type_name(); + (*vars)["RealResponse"] = method->output_type_name(); + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print( + *vars, + "class ExperimentalWithCallbackMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) {}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, "ExperimentalWithCallbackMethod_$Method$() {\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" + " new ::grpc::internal::CallbackUnaryHandler< " + "ExperimentalWithCallbackMethod_$Method$<BaseClass>, $RealRequest$, " + "$RealResponse$>(\n" + " [this](::grpc::ServerContext* context,\n" + " const $RealRequest$* request,\n" + " $RealResponse$* response,\n" + " ::grpc::experimental::ServerCallbackRpcController* " + "controller) {\n" + " this->$" + "Method$(context, request, response, controller);\n" + " }, this));\n"); + } else if (ClientOnlyStreaming(method)) { + // TODO(vjpai): Add in code generation for all streaming methods + } else if (ServerOnlyStreaming(method)) { + // TODO(vjpai): Add in code generation for all streaming methods + } else if (method->BidiStreaming()) { + // TODO(vjpai): Add in code generation for all streaming methods + } + printer->Print(*vars, "}\n"); + printer->Print(*vars, + "~ExperimentalWithCallbackMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerCallbackMethodsHelper(printer, method, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderServerMethodRawCallback( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map<grpc::string, grpc::string>* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for raw API + (*vars)["RealRequest"] = "::grpc::ByteBuffer"; + (*vars)["RealResponse"] = "::grpc::ByteBuffer"; + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print(*vars, + "class ExperimentalWithRawCallbackMethod_$Method$ : public " + "BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) {}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, "ExperimentalWithRawCallbackMethod_$Method$() {\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" + " new ::grpc::internal::CallbackUnaryHandler< " + "ExperimentalWithRawCallbackMethod_$Method$<BaseClass>, $RealRequest$, " + "$RealResponse$>(\n" + " [this](::grpc::ServerContext* context,\n" + " const $RealRequest$* request,\n" + " $RealResponse$* response,\n" + " ::grpc::experimental::ServerCallbackRpcController* " + "controller) {\n" + " this->$" + "Method$(context, request, response, controller);\n" + " }, this));\n"); + } else if (ClientOnlyStreaming(method)) { + // TODO(vjpai): Add in code generation for all streaming methods + } else if (ServerOnlyStreaming(method)) { + // TODO(vjpai): Add in code generation for all streaming methods + } else if (method->BidiStreaming()) { + // TODO(vjpai): Add in code generation for all streaming methods + } + printer->Print(*vars, "}\n"); + printer->Print(*vars, + "~ExperimentalWithRawCallbackMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerCallbackMethodsHelper(printer, method, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + void PrintHeaderServerMethodStreamedUnary( grpc_generator::Printer* printer, const grpc_generator::Method* method, std::map<grpc::string, grpc::string>* vars) { @@ -1137,7 +1302,7 @@ void PrintHeaderService(grpc_generator::Printer* printer, printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { - (*vars)["method_name"] = service->method(i).get()->name(); + (*vars)["method_name"] = service->method(i)->name(); printer->Print(*vars, "WithAsyncMethod_$method_name$<"); } printer->Print("Service"); @@ -1146,6 +1311,24 @@ void PrintHeaderService(grpc_generator::Printer* printer, } printer->Print(" AsyncService;\n"); + // Server side - Callback + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodCallback(printer, service->method(i).get(), vars); + } + + printer->Print("typedef "); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + printer->Print(*vars, "ExperimentalWithCallbackMethod_$method_name$<"); + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(" >"); + } + printer->Print(" ExperimentalCallbackService;\n"); + // Server side - Generic for (int i = 0; i < service->method_count(); ++i) { (*vars)["Idx"] = as_string(i); @@ -1158,6 +1341,12 @@ void PrintHeaderService(grpc_generator::Printer* printer, PrintHeaderServerMethodRaw(printer, service->method(i).get(), vars); } + // Server side - Raw Callback + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodRawCallback(printer, service->method(i).get(), vars); + } + // Server side - Streamed Unary for (int i = 0; i < service->method_count(); ++i) { (*vars)["Idx"] = as_string(i); @@ -1167,7 +1356,7 @@ void PrintHeaderService(grpc_generator::Printer* printer, printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { - (*vars)["method_name"] = service->method(i).get()->name(); + (*vars)["method_name"] = service->method(i)->name(); if (service->method(i)->NoStreaming()) { printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); } @@ -1189,7 +1378,7 @@ void PrintHeaderService(grpc_generator::Printer* printer, printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { - (*vars)["method_name"] = service->method(i).get()->name(); + (*vars)["method_name"] = service->method(i)->name(); auto method = service->method(i); if (ServerOnlyStreaming(method.get())) { printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); @@ -1207,7 +1396,7 @@ void PrintHeaderService(grpc_generator::Printer* printer, // Server side - typedef for controlled both unary and server-side streaming printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { - (*vars)["method_name"] = service->method(i).get()->name(); + (*vars)["method_name"] = service->method(i)->name(); auto method = service->method(i); if (ServerOnlyStreaming(method.get())) { printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); @@ -1333,6 +1522,7 @@ grpc::string GetSourceIncludes(grpc_generator::File* file, "grpcpp/impl/codegen/client_callback.h", "grpcpp/impl/codegen/method_handler_impl.h", "grpcpp/impl/codegen/rpc_service_method.h", + "grpcpp/impl/codegen/server_callback.h", "grpcpp/impl/codegen/service_type.h", "grpcpp/impl/codegen/sync_stream.h"}; std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); @@ -1577,7 +1767,7 @@ void PrintSourceService(grpc_generator::Printer* printer, printer->Print(*vars, "static const char* $prefix$$Service$_method_names[] = {\n"); for (int i = 0; i < service->method_count(); ++i) { - (*vars)["Method"] = service->method(i).get()->name(); + (*vars)["Method"] = service->method(i)->name(); printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n"); } printer->Print(*vars, "};\n\n"); diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 91894689c3..d42961fc60 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -938,12 +938,26 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) { // (census filter is on top of this one) // - add census stats for retries +namespace { +struct call_data; + // State used for starting a retryable batch on a subchannel call. // This provides its own grpc_transport_stream_op_batch and other data // structures needed to populate the ops in the batch. // We allocate one struct on the arena for each attempt at starting a // batch on a given subchannel call. -typedef struct { +struct subchannel_batch_data { + subchannel_batch_data(grpc_call_element* elem, call_data* calld, int refcount, + bool set_on_complete); + // All dtor code must be added in `destroy`. This is because we may + // call closures in `subchannel_batch_data` after they are unrefed by + // `batch_data_unref`, and msan would complain about accessing this class + // after calling dtor. As a result we cannot call the `dtor` in + // `batch_data_unref`. + // TODO(soheil): We should try to call the dtor in `batch_data_unref`. + ~subchannel_batch_data() { destroy(); } + void destroy(); + gpr_refcount refs; grpc_call_element* elem; grpc_subchannel_call* subchannel_call; // Holds a ref. @@ -952,11 +966,23 @@ typedef struct { grpc_transport_stream_op_batch batch; // For intercepting on_complete. grpc_closure on_complete; -} subchannel_batch_data; +}; // Retry state associated with a subchannel call. // Stored in the parent_data of the subchannel call object. -typedef struct { +struct subchannel_call_retry_state { + explicit subchannel_call_retry_state(grpc_call_context_element* context) + : batch_payload(context), + started_send_initial_metadata(false), + completed_send_initial_metadata(false), + started_send_trailing_metadata(false), + completed_send_trailing_metadata(false), + started_recv_initial_metadata(false), + completed_recv_initial_metadata(false), + started_recv_trailing_metadata(false), + completed_recv_trailing_metadata(false), + retry_dispatched(false) {} + // subchannel_batch_data.batch.payload points to this. grpc_transport_stream_op_batch_payload batch_payload; // For send_initial_metadata. @@ -975,7 +1001,7 @@ typedef struct { // For intercepting recv_initial_metadata. grpc_metadata_batch recv_initial_metadata; grpc_closure recv_initial_metadata_ready; - bool trailing_metadata_available; + bool trailing_metadata_available = false; // For intercepting recv_message. grpc_closure recv_message_ready; grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_message; @@ -985,10 +1011,10 @@ typedef struct { grpc_closure recv_trailing_metadata_ready; // These fields indicate which ops have been started and completed on // this subchannel call. - size_t started_send_message_count; - size_t completed_send_message_count; - size_t started_recv_message_count; - size_t completed_recv_message_count; + size_t started_send_message_count = 0; + size_t completed_send_message_count = 0; + size_t started_recv_message_count = 0; + size_t completed_recv_message_count = 0; bool started_send_initial_metadata : 1; bool completed_send_initial_metadata : 1; bool started_send_trailing_metadata : 1; @@ -999,12 +1025,12 @@ typedef struct { bool completed_recv_trailing_metadata : 1; // State for callback processing. bool retry_dispatched : 1; - subchannel_batch_data* recv_initial_metadata_ready_deferred_batch; - grpc_error* recv_initial_metadata_error; - subchannel_batch_data* recv_message_ready_deferred_batch; - grpc_error* recv_message_error; - subchannel_batch_data* recv_trailing_metadata_internal_batch; -} subchannel_call_retry_state; + subchannel_batch_data* recv_initial_metadata_ready_deferred_batch = nullptr; + grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE; + subchannel_batch_data* recv_message_ready_deferred_batch = nullptr; + grpc_error* recv_message_error = GRPC_ERROR_NONE; + subchannel_batch_data* recv_trailing_metadata_internal_batch = nullptr; +}; // Pending batches stored in call data. typedef struct { @@ -1019,7 +1045,44 @@ typedef struct { Handles queueing of stream ops until a call object is ready, waiting for initial metadata before trying to create a call object, and handling cancellation gracefully. */ -typedef struct client_channel_call_data { +struct call_data { + call_data(grpc_call_element* elem, const channel_data& chand, + const grpc_call_element_args& args) + : deadline_state(elem, args.call_stack, args.call_combiner, + GPR_LIKELY(chand.deadline_checking_enabled) + ? args.deadline + : GRPC_MILLIS_INF_FUTURE), + path(grpc_slice_ref_internal(args.path)), + call_start_time(args.start_time), + deadline(args.deadline), + arena(args.arena), + owning_call(args.call_stack), + call_combiner(args.call_combiner), + pending_send_initial_metadata(false), + pending_send_message(false), + pending_send_trailing_metadata(false), + enable_retries(chand.enable_retries), + retry_committed(false), + last_attempt_got_server_pushback(false) {} + + ~call_data() { + if (GPR_LIKELY(subchannel_call != nullptr)) { + GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, + "client_channel_destroy_call"); + } + grpc_slice_unref_internal(path); + GRPC_ERROR_UNREF(cancel_error); + for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches); ++i) { + GPR_ASSERT(pending_batches[i].batch == nullptr); + } + for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) { + if (pick.subchannel_call_context[i].value != nullptr) { + pick.subchannel_call_context[i].destroy( + pick.subchannel_call_context[i].value); + } + } + } + // State for handling deadlines. // The code in deadline_filter.c requires this to be the first field. // TODO(roth): This is slightly sub-optimal in that grpc_deadline_state @@ -1038,24 +1101,24 @@ typedef struct client_channel_call_data { grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data; grpc_core::RefCountedPtr<ClientChannelMethodParams> method_params; - grpc_subchannel_call* subchannel_call; + grpc_subchannel_call* subchannel_call = nullptr; // Set when we get a cancel_stream op. - grpc_error* cancel_error; + grpc_error* cancel_error = GRPC_ERROR_NONE; grpc_core::LoadBalancingPolicy::PickState pick; grpc_closure pick_closure; grpc_closure pick_cancel_closure; - grpc_polling_entity* pollent; - bool pollent_added_to_interested_parties; + grpc_polling_entity* pollent = nullptr; + bool pollent_added_to_interested_parties = false; // Batches are added to this list when received from above. // They are removed when we are done handling the batch (i.e., when // either we have invoked all of the batch's callbacks or we have // passed the batch down to the subchannel call and are not // intercepting any of its callbacks). - pending_batch pending_batches[MAX_PENDING_BATCHES]; + pending_batch pending_batches[MAX_PENDING_BATCHES] = {}; bool pending_send_initial_metadata : 1; bool pending_send_message : 1; bool pending_send_trailing_metadata : 1; @@ -1064,8 +1127,8 @@ typedef struct client_channel_call_data { bool enable_retries : 1; bool retry_committed : 1; bool last_attempt_got_server_pushback : 1; - int num_attempts_completed; - size_t bytes_buffered_for_retry; + int num_attempts_completed = 0; + size_t bytes_buffered_for_retry = 0; grpc_core::ManualConstructor<grpc_core::BackOff> retry_backoff; grpc_timer retry_timer; @@ -1076,12 +1139,12 @@ typedef struct client_channel_call_data { // until all of these batches have completed. // Note that we actually only need to track replay batches, but it's // easier to track all batches with send ops. - int num_pending_retriable_subchannel_send_batches; + int num_pending_retriable_subchannel_send_batches = 0; // Cached data for retrying send ops. // send_initial_metadata - bool seen_send_initial_metadata; - grpc_linked_mdelem* send_initial_metadata_storage; + bool seen_send_initial_metadata = false; + grpc_linked_mdelem* send_initial_metadata_storage = nullptr; grpc_metadata_batch send_initial_metadata; uint32_t send_initial_metadata_flags; gpr_atm* peer_string; @@ -1092,14 +1155,13 @@ typedef struct client_channel_call_data { // Note: We inline the cache for the first 3 send_message ops and use // dynamic allocation after that. This number was essentially picked // at random; it could be changed in the future to tune performance. - grpc_core::ManualConstructor< - grpc_core::InlinedVector<grpc_core::ByteStreamCache*, 3>> - send_messages; + grpc_core::InlinedVector<grpc_core::ByteStreamCache*, 3> send_messages; // send_trailing_metadata - bool seen_send_trailing_metadata; - grpc_linked_mdelem* send_trailing_metadata_storage; + bool seen_send_trailing_metadata = false; + grpc_linked_mdelem* send_trailing_metadata_storage = nullptr; grpc_metadata_batch send_trailing_metadata; -} call_data; +}; +} // namespace // Forward declarations. static void retry_commit(grpc_call_element* elem, @@ -1143,7 +1205,7 @@ static void maybe_cache_send_ops_for_batch(call_data* calld, gpr_arena_alloc(calld->arena, sizeof(grpc_core::ByteStreamCache))); new (cache) grpc_core::ByteStreamCache( std::move(batch->payload->send_message.send_message)); - calld->send_messages->push_back(cache); + calld->send_messages.push_back(cache); } // Save metadata batch for send_trailing_metadata ops. if (batch->send_trailing_metadata) { @@ -1180,7 +1242,7 @@ static void free_cached_send_message(channel_data* chand, call_data* calld, "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR "]", chand, calld, idx); } - (*calld->send_messages)[idx]->Destroy(); + calld->send_messages[idx]->Destroy(); } // Frees cached send_trailing_metadata. @@ -1650,55 +1712,66 @@ static bool maybe_retry(grpc_call_element* elem, // subchannel_batch_data // -// Creates a subchannel_batch_data object on the call's arena with the -// specified refcount. If set_on_complete is true, the batch's -// on_complete callback will be set to point to on_complete(); -// otherwise, the batch's on_complete callback will be null. -static subchannel_batch_data* batch_data_create(grpc_call_element* elem, - int refcount, - bool set_on_complete) { - call_data* calld = static_cast<call_data*>(elem->call_data); +namespace { +subchannel_batch_data::subchannel_batch_data(grpc_call_element* elem, + call_data* calld, int refcount, + bool set_on_complete) + : elem(elem), + subchannel_call(GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call, + "batch_data_create")) { subchannel_call_retry_state* retry_state = static_cast<subchannel_call_retry_state*>( grpc_connected_subchannel_call_get_parent_data( calld->subchannel_call)); - subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>( - gpr_arena_alloc(calld->arena, sizeof(*batch_data))); - batch_data->elem = elem; - batch_data->subchannel_call = - GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call, "batch_data_create"); - batch_data->batch.payload = &retry_state->batch_payload; - gpr_ref_init(&batch_data->refs, refcount); + batch.payload = &retry_state->batch_payload; + gpr_ref_init(&refs, refcount); if (set_on_complete) { - GRPC_CLOSURE_INIT(&batch_data->on_complete, on_complete, batch_data, + GRPC_CLOSURE_INIT(&on_complete, ::on_complete, this, grpc_schedule_on_exec_ctx); - batch_data->batch.on_complete = &batch_data->on_complete; + batch.on_complete = &on_complete; } GRPC_CALL_STACK_REF(calld->owning_call, "batch_data"); +} + +void subchannel_batch_data::destroy() { + subchannel_call_retry_state* retry_state = + static_cast<subchannel_call_retry_state*>( + grpc_connected_subchannel_call_get_parent_data(subchannel_call)); + if (batch.send_initial_metadata) { + grpc_metadata_batch_destroy(&retry_state->send_initial_metadata); + } + if (batch.send_trailing_metadata) { + grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata); + } + if (batch.recv_initial_metadata) { + grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata); + } + if (batch.recv_trailing_metadata) { + grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata); + } + GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "batch_data_unref"); + call_data* calld = static_cast<call_data*>(elem->call_data); + GRPC_CALL_STACK_UNREF(calld->owning_call, "batch_data"); +} +} // namespace + +// Creates a subchannel_batch_data object on the call's arena with the +// specified refcount. If set_on_complete is true, the batch's +// on_complete callback will be set to point to on_complete(); +// otherwise, the batch's on_complete callback will be null. +static subchannel_batch_data* batch_data_create(grpc_call_element* elem, + int refcount, + bool set_on_complete) { + call_data* calld = static_cast<call_data*>(elem->call_data); + subchannel_batch_data* batch_data = + new (gpr_arena_alloc(calld->arena, sizeof(*batch_data))) + subchannel_batch_data(elem, calld, refcount, set_on_complete); return batch_data; } static void batch_data_unref(subchannel_batch_data* batch_data) { if (gpr_unref(&batch_data->refs)) { - subchannel_call_retry_state* retry_state = - static_cast<subchannel_call_retry_state*>( - grpc_connected_subchannel_call_get_parent_data( - batch_data->subchannel_call)); - if (batch_data->batch.send_initial_metadata) { - grpc_metadata_batch_destroy(&retry_state->send_initial_metadata); - } - if (batch_data->batch.send_trailing_metadata) { - grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata); - } - if (batch_data->batch.recv_initial_metadata) { - grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata); - } - if (batch_data->batch.recv_trailing_metadata) { - grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata); - } - GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref"); - call_data* calld = static_cast<call_data*>(batch_data->elem->call_data); - GRPC_CALL_STACK_UNREF(calld->owning_call, "batch_data"); + batch_data->destroy(); } } @@ -1996,7 +2069,7 @@ static bool pending_batch_is_unstarted( return true; } if (pending->batch->send_message && - retry_state->started_send_message_count < calld->send_messages->size()) { + retry_state->started_send_message_count < calld->send_messages.size()) { return true; } if (pending->batch->send_trailing_metadata && @@ -2152,7 +2225,7 @@ static void add_closures_for_replay_or_pending_send_ops( channel_data* chand = static_cast<channel_data*>(elem->channel_data); call_data* calld = static_cast<call_data*>(elem->call_data); bool have_pending_send_message_ops = - retry_state->started_send_message_count < calld->send_messages->size(); + retry_state->started_send_message_count < calld->send_messages.size(); bool have_pending_send_trailing_metadata_op = calld->seen_send_trailing_metadata && !retry_state->started_send_trailing_metadata; @@ -2344,7 +2417,7 @@ static void add_retriable_send_message_op( chand, calld, retry_state->started_send_message_count); } grpc_core::ByteStreamCache* cache = - (*calld->send_messages)[retry_state->started_send_message_count]; + calld->send_messages[retry_state->started_send_message_count]; ++retry_state->started_send_message_count; retry_state->send_message.Init(cache); batch_data->batch.send_message = true; @@ -2476,7 +2549,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( } // send_message. // Note that we can only have one send_message op in flight at a time. - if (retry_state->started_send_message_count < calld->send_messages->size() && + if (retry_state->started_send_message_count < calld->send_messages.size() && retry_state->started_send_message_count == retry_state->completed_send_message_count && !calld->pending_send_message) { @@ -2497,7 +2570,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( // to start, since we can't send down any more send_message ops after // send_trailing_metadata. if (calld->seen_send_trailing_metadata && - retry_state->started_send_message_count == calld->send_messages->size() && + retry_state->started_send_message_count == calld->send_messages.size() && !retry_state->started_send_trailing_metadata && !calld->pending_send_trailing_metadata) { if (grpc_client_channel_trace.enabled()) { @@ -2549,7 +2622,7 @@ static void add_subchannel_batches_for_pending_batches( // send_message ops after send_trailing_metadata. if (batch->send_trailing_metadata && (retry_state->started_send_message_count + batch->send_message < - calld->send_messages->size() || + calld->send_messages.size() || retry_state->started_send_trailing_metadata)) { continue; } @@ -2715,17 +2788,10 @@ static void create_subchannel_call(grpc_call_element* elem, grpc_error* error) { new_error = grpc_error_add_child(new_error, error); pending_batches_fail(elem, new_error, true /* yield_call_combiner */); } else { - grpc_core::channelz::SubchannelNode* channelz_subchannel = - calld->pick.connected_subchannel->channelz_subchannel(); - if (channelz_subchannel != nullptr) { - channelz_subchannel->RecordCallStarted(); - } if (parent_data_size > 0) { - subchannel_call_retry_state* retry_state = - static_cast<subchannel_call_retry_state*>( - grpc_connected_subchannel_call_get_parent_data( - calld->subchannel_call)); - retry_state->batch_payload.context = calld->pick.subchannel_call_context; + new (grpc_connected_subchannel_call_get_parent_data( + calld->subchannel_call)) + subchannel_call_retry_state(calld->pick.subchannel_call_context); } pending_batches_resume(elem); } @@ -3265,21 +3331,8 @@ static void cc_start_transport_stream_op_batch( /* Constructor for call_data */ static grpc_error* cc_init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); channel_data* chand = static_cast<channel_data*>(elem->channel_data); - // Initialize data members. - calld->path = grpc_slice_ref_internal(args->path); - calld->call_start_time = args->start_time; - calld->deadline = args->deadline; - calld->arena = args->arena; - calld->owning_call = args->call_stack; - calld->call_combiner = args->call_combiner; - if (GPR_LIKELY(chand->deadline_checking_enabled)) { - grpc_deadline_state_init(elem, args->call_stack, args->call_combiner, - calld->deadline); - } - calld->enable_retries = chand->enable_retries; - calld->send_messages.Init(); + new (elem->call_data) call_data(elem, *chand, *args); return GRPC_ERROR_NONE; } @@ -3288,34 +3341,12 @@ static void cc_destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* then_schedule_closure) { call_data* calld = static_cast<call_data*>(elem->call_data); - channel_data* chand = static_cast<channel_data*>(elem->channel_data); - if (GPR_LIKELY(chand->deadline_checking_enabled)) { - grpc_deadline_state_destroy(elem); - } - grpc_slice_unref_internal(calld->path); - calld->retry_throttle_data.reset(); - calld->method_params.reset(); - GRPC_ERROR_UNREF(calld->cancel_error); if (GPR_LIKELY(calld->subchannel_call != nullptr)) { grpc_subchannel_call_set_cleanup_closure(calld->subchannel_call, then_schedule_closure); then_schedule_closure = nullptr; - GRPC_SUBCHANNEL_CALL_UNREF(calld->subchannel_call, - "client_channel_destroy_call"); - } - for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { - GPR_ASSERT(calld->pending_batches[i].batch == nullptr); - } - if (GPR_LIKELY(calld->pick.connected_subchannel != nullptr)) { - calld->pick.connected_subchannel.reset(); - } - for (size_t i = 0; i < GRPC_CONTEXT_COUNT; ++i) { - if (calld->pick.subchannel_call_context[i].value != nullptr) { - calld->pick.subchannel_call_context[i].destroy( - calld->pick.subchannel_call_context[i].value); - } } - calld->send_messages.Destroy(); + calld->~call_data(); GRPC_CLOSURE_SCHED(then_schedule_closure, GRPC_ERROR_NONE); } diff --git a/src/core/ext/filters/client_channel/health/health_check_client.cc b/src/core/ext/filters/client_channel/health/health_check_client.cc index 591637aa86..587919596f 100644 --- a/src/core/ext/filters/client_channel/health/health_check_client.cc +++ b/src/core/ext/filters/client_channel/health/health_check_client.cc @@ -286,10 +286,9 @@ HealthCheckClient::CallState::CallState( health_check_client_(std::move(health_check_client)), pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)), arena_(gpr_arena_create(health_check_client_->connected_subchannel_ - ->GetInitialCallSizeEstimate(0))) { - memset(&call_combiner_, 0, sizeof(call_combiner_)); + ->GetInitialCallSizeEstimate(0))), + payload_(context_) { grpc_call_combiner_init(&call_combiner_); - memset(context_, 0, sizeof(context_)); gpr_atm_rel_store(&seen_response_, static_cast<gpr_atm>(0)); } diff --git a/src/core/ext/filters/client_channel/health/health_check_client.h b/src/core/ext/filters/client_channel/health/health_check_client.h index 7f77348f18..f6babef7d6 100644 --- a/src/core/ext/filters/client_channel/health/health_check_client.h +++ b/src/core/ext/filters/client_channel/health/health_check_client.h @@ -97,7 +97,7 @@ class HealthCheckClient gpr_arena* arena_; grpc_call_combiner call_combiner_; - grpc_call_context_element context_[GRPC_CONTEXT_COUNT]; + grpc_call_context_element context_[GRPC_CONTEXT_COUNT] = {}; // The streaming call to the backend. Always non-NULL. grpc_subchannel_call* call_; diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc index bfabc68c66..0716e46818 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -29,7 +29,6 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker_registry.h" #include "src/core/lib/gpr/env.h" @@ -37,6 +36,7 @@ #include "src/core/lib/http/format_request.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/uri/uri_parser.h" typedef struct http_connect_handshaker { // Base class. Must be first. diff --git a/src/core/ext/filters/client_channel/http_proxy.cc b/src/core/ext/filters/client_channel/http_proxy.cc index 26d3f479b7..8951a2920c 100644 --- a/src/core/ext/filters/client_channel/http_proxy.cc +++ b/src/core/ext/filters/client_channel/http_proxy.cc @@ -29,12 +29,12 @@ #include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/slice/b64.h" +#include "src/core/lib/uri/uri_parser.h" /** * Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 21f80b7b94..b0040457a6 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -63,29 +63,29 @@ class LoadBalancingPolicy /// State used for an LB pick. struct PickState { /// Initial metadata associated with the picking call. - grpc_metadata_batch* initial_metadata; + grpc_metadata_batch* initial_metadata = nullptr; /// Bitmask used for selective cancelling. See /// \a CancelMatchingPicksLocked() and \a GRPC_INITIAL_METADATA_* in /// grpc_types.h. - uint32_t initial_metadata_flags; + uint32_t initial_metadata_flags = 0; /// Storage for LB token in \a initial_metadata, or nullptr if not used. grpc_linked_mdelem lb_token_mdelem_storage; /// Closure to run when pick is complete, if not completed synchronously. /// If null, pick will fail if a result is not available synchronously. - grpc_closure* on_complete; + grpc_closure* on_complete = nullptr; /// Will be set to the selected subchannel, or nullptr on failure or when /// the LB policy decides to drop the call. RefCountedPtr<ConnectedSubchannel> connected_subchannel; /// Will be populated with context to pass to the subchannel call, if /// needed. - grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT]; + grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT] = {}; /// Upon success, \a *user_data will be set to whatever opaque information /// may need to be propagated from the LB policy, or nullptr if not needed. // TODO(roth): As part of revamping our metadata APIs, try to find a // way to clean this up and C++-ify it. - void** user_data; + void** user_data = nullptr; /// Next pointer. For internal use by LB policy. - PickState* next; + PickState* next = nullptr; }; // Not copyable nor movable. diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc index cc259bcdbf..399bb452f4 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc @@ -37,16 +37,27 @@ static void destroy_channel_elem(grpc_channel_element* elem) {} namespace { struct call_data { + call_data(const grpc_call_element_args& args) { + if (args.context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) { + // Get stats object from context and take a ref. + client_stats = static_cast<grpc_core::GrpcLbClientStats*>( + args.context[GRPC_GRPCLB_CLIENT_STATS].value) + ->Ref(); + // Record call started. + client_stats->AddCallStarted(); + } + } + // Stats object to update. grpc_core::RefCountedPtr<grpc_core::GrpcLbClientStats> client_stats; // State for intercepting send_initial_metadata. grpc_closure on_complete_for_send; grpc_closure* original_on_complete_for_send; - bool send_initial_metadata_succeeded; + bool send_initial_metadata_succeeded = false; // State for intercepting recv_initial_metadata. grpc_closure recv_initial_metadata_ready; grpc_closure* original_recv_initial_metadata_ready; - bool recv_initial_metadata_succeeded; + bool recv_initial_metadata_succeeded = false; }; } // namespace @@ -70,16 +81,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - // Get stats object from context and take a ref. GPR_ASSERT(args->context != nullptr); - if (args->context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) { - calld->client_stats = static_cast<grpc_core::GrpcLbClientStats*>( - args->context[GRPC_GRPCLB_CLIENT_STATS].value) - ->Ref(); - // Record call started. - calld->client_stats->AddCallStarted(); - } + new (elem->call_data) call_data(*args); return GRPC_ERROR_NONE; } @@ -97,6 +100,7 @@ static void destroy_call_elem(grpc_call_element* elem, // TODO(roth): Eliminate this once filter stack is converted to C++. calld->client_stats.reset(); } + calld->~call_data(); } static void start_transport_stream_op_batch( diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index 7fb4cbdcd2..38f8072e8d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -319,10 +319,6 @@ class XdsLb : public LoadBalancingPolicy { // The deserialized response from the balancer. May be nullptr until one // such response has arrived. xds_grpclb_serverlist* serverlist_ = nullptr; - // Index into serverlist for next pick. - // If the server at this index is a drop, we return a drop. - // Otherwise, we delegate to the RR policy. - size_t serverlist_index_ = 0; // Timeout in milliseconds for before using fallback backend addresses. // 0 means not using fallback. @@ -837,7 +833,6 @@ void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked( // serverlist instance will be destroyed either upon the next // update or when the XdsLb instance is destroyed. xdslb_policy->serverlist_ = serverlist; - xdslb_policy->serverlist_index_ = 0; xdslb_policy->CreateOrUpdateRoundRobinPolicyLocked(); } } else { @@ -1575,32 +1570,6 @@ void XdsLb::AddPendingPick(PendingPick* pp) { // completion callback even if the pick is available immediately. bool XdsLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp, grpc_error** error) { - // Check for drops if we are not using fallback backend addresses. - if (serverlist_ != nullptr) { - // Look at the index into the serverlist to see if we should drop this call. - xds_grpclb_server* server = serverlist_->servers[serverlist_index_++]; - if (serverlist_index_ == serverlist_->num_servers) { - serverlist_index_ = 0; // Wrap-around. - } - if (server->drop) { - // Update client load reporting stats to indicate the number of - // dropped calls. Note that we have to do this here instead of in - // the client_load_reporting filter, because we do not create a - // subchannel call (and therefore no client_load_reporting filter) - // for dropped calls. - if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { - lb_calld_->client_stats()->AddCallDroppedLocked( - server->load_balance_token); - } - if (force_async) { - GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE); - Delete(pp); - return false; - } - Delete(pp); - return true; - } - } // Set client_stats and user_data. if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) { pp->client_stats = lb_calld_->client_stats()->Ref(); diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index 62bdbf2689..a59deadb26 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -25,7 +25,7 @@ #include "src/core/ext/filters/client_channel/client_channel_factory.h" #include "src/core/ext/filters/client_channel/lb_policy.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/uri/uri_parser.h" // // representation of an LB address diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h index c2af0e6c49..5c050a2333 100644 --- a/src/core/ext/filters/client_channel/parse_address.h +++ b/src/core/ext/filters/client_channel/parse_address.h @@ -23,8 +23,8 @@ #include <stddef.h> -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/iomgr/resolve_address.h" +#include "src/core/lib/uri/uri_parser.h" /** Populate \a resolved_addr from \a uri, whose path is expected to contain a * unix socket path. Returns true upon success. */ diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h index 708eaf1147..74a3062e7f 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -20,9 +20,9 @@ #include <grpc/support/port_platform.h> #include "src/core/ext/filters/client_channel/lb_policy_factory.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/uri/uri_parser.h" #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \ "grpc.fake_resolver.response_generator" diff --git a/src/core/ext/filters/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h index ee3cfeeb9b..d891ef62e1 100644 --- a/src/core/ext/filters/client_channel/resolver_factory.h +++ b/src/core/ext/filters/client_channel/resolver_factory.h @@ -24,11 +24,11 @@ #include <grpc/support/string_util.h> #include "src/core/ext/filters/client_channel/resolver.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/gprpp/abstract.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/uri/uri_parser.h" namespace grpc_core { diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index e4c6efe862..a56db0201b 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -34,7 +34,6 @@ #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" @@ -54,6 +53,7 @@ #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/service_config.h" #include "src/core/lib/transport/status_metadata.h" +#include "src/core/lib/uri/uri_parser.h" #define INTERNAL_REF_BITS 16 #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) @@ -162,12 +162,16 @@ struct grpc_subchannel { }; struct grpc_subchannel_call { + grpc_subchannel_call(grpc_core::ConnectedSubchannel* connection, + const grpc_core::ConnectedSubchannel::CallArgs& args) + : connection(connection), deadline(args.deadline) {} + grpc_core::ConnectedSubchannel* connection; - grpc_closure* schedule_closure_after_destroy; + grpc_closure* schedule_closure_after_destroy = nullptr; // state needed to support channelz interception of recv trailing metadata. grpc_closure recv_trailing_metadata_ready; grpc_closure* original_recv_trailing_metadata; - grpc_metadata_batch* recv_trailing_metadata; + grpc_metadata_batch* recv_trailing_metadata = nullptr; grpc_millis deadline; }; @@ -905,6 +909,7 @@ static void subchannel_call_destroy(void* call, grpc_error* error) { grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c), nullptr, c->schedule_closure_after_destroy); connection->Unref(DEBUG_LOCATION, "subchannel_call"); + c->~grpc_subchannel_call(); } void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call* call, @@ -1102,14 +1107,12 @@ grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args, grpc_subchannel_call** call) { const size_t allocation_size = GetInitialCallSizeEstimate(args.parent_data_size); - *call = static_cast<grpc_subchannel_call*>( - gpr_arena_alloc(args.arena, allocation_size)); + *call = new (gpr_arena_alloc(args.arena, allocation_size)) + grpc_subchannel_call(this, args); grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call); RefCountedPtr<ConnectedSubchannel> connection = Ref(DEBUG_LOCATION, "subchannel_call"); connection.release(); // Ref is passed to the grpc_subchannel_call object. - (*call)->connection = this; - (*call)->deadline = args.deadline; const grpc_call_element_args call_args = { callstk, /* call_stack */ nullptr, /* server_transport_data */ @@ -1128,6 +1131,9 @@ grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args, return error; } grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent); + if (channelz_subchannel_ != nullptr) { + channelz_subchannel_->RecordCallStarted(); + } return GRPC_ERROR_NONE; } diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index d23ad67ad5..b4cb07f0f9 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -27,6 +27,7 @@ #include <grpc/support/time.h> #include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/channel_init.h" @@ -152,7 +153,11 @@ static void inject_recv_trailing_metadata_ready( // Callback and associated state for starting the timer after call stack // initialization has been completed. struct start_timer_after_init_state { - bool in_call_combiner; + start_timer_after_init_state(grpc_call_element* elem, grpc_millis deadline) + : elem(elem), deadline(deadline) {} + ~start_timer_after_init_state() { start_timer_if_needed(elem, deadline); } + + bool in_call_combiner = false; grpc_call_element* elem; grpc_millis deadline; grpc_closure closure; @@ -171,20 +176,16 @@ static void start_timer_after_init(void* arg, grpc_error* error) { "scheduling deadline timer"); return; } - start_timer_if_needed(state->elem, state->deadline); - gpr_free(state); + grpc_core::Delete(state); GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner, "done scheduling deadline timer"); } -void grpc_deadline_state_init(grpc_call_element* elem, - grpc_call_stack* call_stack, - grpc_call_combiner* call_combiner, - grpc_millis deadline) { - grpc_deadline_state* deadline_state = - static_cast<grpc_deadline_state*>(elem->call_data); - deadline_state->call_stack = call_stack; - deadline_state->call_combiner = call_combiner; +grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, + grpc_call_stack* call_stack, + grpc_call_combiner* call_combiner, + grpc_millis deadline) + : call_stack(call_stack), call_combiner(call_combiner) { // Deadline will always be infinite on servers, so the timer will only be // set on clients with a finite deadline. if (deadline != GRPC_MILLIS_INF_FUTURE) { @@ -196,21 +197,14 @@ void grpc_deadline_state_init(grpc_call_element* elem, // create a closure to start the timer, and we schedule that closure // to be run after call stack initialization is done. struct start_timer_after_init_state* state = - static_cast<struct start_timer_after_init_state*>( - gpr_zalloc(sizeof(*state))); - state->elem = elem; - state->deadline = deadline; + grpc_core::New<start_timer_after_init_state>(elem, deadline); GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_SCHED(&state->closure, GRPC_ERROR_NONE); } } -void grpc_deadline_state_destroy(grpc_call_element* elem) { - grpc_deadline_state* deadline_state = - static_cast<grpc_deadline_state*>(elem->call_data); - cancel_timer_if_needed(deadline_state); -} +grpc_deadline_state::~grpc_deadline_state() { cancel_timer_if_needed(this); } void grpc_deadline_state_reset(grpc_call_element* elem, grpc_millis new_deadline) { @@ -269,8 +263,8 @@ typedef struct server_call_data { // Constructor for call_data. Used for both client and server filters. static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - grpc_deadline_state_init(elem, args->call_stack, args->call_combiner, - args->deadline); + new (elem->call_data) grpc_deadline_state( + elem, args->call_stack, args->call_combiner, args->deadline); return GRPC_ERROR_NONE; } @@ -278,7 +272,9 @@ static grpc_error* init_call_elem(grpc_call_element* elem, static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { - grpc_deadline_state_destroy(elem); + grpc_deadline_state* deadline_state = + static_cast<grpc_deadline_state*>(elem->call_data); + deadline_state->~grpc_deadline_state(); } // Method for starting a call op for client filter. diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h index 1d797f445a..e37032999c 100644 --- a/src/core/ext/filters/deadline/deadline_filter.h +++ b/src/core/ext/filters/deadline/deadline_filter.h @@ -22,19 +22,23 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/timer.h" -typedef enum grpc_deadline_timer_state { +enum grpc_deadline_timer_state { GRPC_DEADLINE_STATE_INITIAL, GRPC_DEADLINE_STATE_PENDING, GRPC_DEADLINE_STATE_FINISHED -} grpc_deadline_timer_state; +}; // State used for filters that enforce call deadlines. // Must be the first field in the filter's call_data. -typedef struct grpc_deadline_state { +struct grpc_deadline_state { + grpc_deadline_state(grpc_call_element* elem, grpc_call_stack* call_stack, + grpc_call_combiner* call_combiner, grpc_millis deadline); + ~grpc_deadline_state(); + // We take a reference to the call stack for the timer callback. grpc_call_stack* call_stack; grpc_call_combiner* call_combiner; - grpc_deadline_timer_state timer_state; + grpc_deadline_timer_state timer_state = GRPC_DEADLINE_STATE_INITIAL; grpc_timer timer; grpc_closure timer_callback; // Closure to invoke when we receive trailing metadata. @@ -43,21 +47,13 @@ typedef struct grpc_deadline_state { // The original recv_trailing_metadata_ready closure, which we chain to // after our own closure is invoked. grpc_closure* original_recv_trailing_metadata_ready; -} grpc_deadline_state; +}; // // NOTE: All of these functions require that the first field in // elem->call_data is a grpc_deadline_state. // -// assumes elem->call_data is zero'd -void grpc_deadline_state_init(grpc_call_element* elem, - grpc_call_stack* call_stack, - grpc_call_combiner* call_combiner, - grpc_millis deadline); - -void grpc_deadline_state_destroy(grpc_call_element* elem); - // Cancels the existing timer and starts a new one with new_deadline. // // Note: It is generally safe to call this with an earlier deadline diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index cd459e47cd..bf9a01f659 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -37,10 +37,31 @@ #define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 /* default maximum size of payload eligable for GET request */ -static const size_t kMaxPayloadSizeForGet = 2048; +static constexpr size_t kMaxPayloadSizeForGet = 2048; + +static void recv_initial_metadata_ready(void* user_data, grpc_error* error); +static void recv_trailing_metadata_ready(void* user_data, grpc_error* error); +static void on_send_message_next_done(void* arg, grpc_error* error); +static void send_message_on_complete(void* arg, grpc_error* error); namespace { struct call_data { + call_data(grpc_call_element* elem, const grpc_call_element_args& args) + : call_combiner(args.call_combiner) { + GRPC_CLOSURE_INIT(&recv_initial_metadata_ready, + ::recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready, + ::recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&on_send_message_next_done, ::on_send_message_next_done, + elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&send_message_on_complete, ::send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); + } + + ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); } + grpc_call_combiner* call_combiner; // State for handling send_initial_metadata ops. grpc_linked_mdelem method; @@ -51,18 +72,18 @@ struct call_data { grpc_linked_mdelem user_agent; // State for handling recv_initial_metadata ops. grpc_metadata_batch* recv_initial_metadata; - grpc_error* recv_initial_metadata_error; - grpc_closure* original_recv_initial_metadata_ready; + grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE; + grpc_closure* original_recv_initial_metadata_ready = nullptr; grpc_closure recv_initial_metadata_ready; // State for handling recv_trailing_metadata ops. grpc_metadata_batch* recv_trailing_metadata; grpc_closure* original_recv_trailing_metadata_ready; grpc_closure recv_trailing_metadata_ready; - grpc_error* recv_trailing_metadata_error; - bool seen_recv_trailing_metadata_ready; + grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE; + bool seen_recv_trailing_metadata_ready = false; // State for handling send_message ops. grpc_transport_stream_op_batch* send_message_batch; - size_t send_message_bytes_read; + size_t send_message_bytes_read = 0; grpc_core::ManualConstructor<grpc_core::ByteStreamCache> send_message_cache; grpc_core::ManualConstructor<grpc_core::ByteStreamCache::CachingByteStream> send_message_caching_stream; @@ -442,18 +463,7 @@ done: /* Constructor for call_data */ static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - calld->call_combiner = args->call_combiner; - GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, - recv_initial_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, - elem, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, - on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); + new (elem->call_data) call_data(elem, *args); return GRPC_ERROR_NONE; } @@ -462,7 +472,7 @@ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); - GRPC_ERROR_UNREF(calld->recv_initial_metadata_error); + calld->~call_data(); } static grpc_mdelem scheme_from_args(const grpc_channel_args* args) { diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc index 933fe3c77b..9c8c8d9e18 100644 --- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc +++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc @@ -39,6 +39,10 @@ #include "src/core/lib/surface/call.h" #include "src/core/lib/transport/static_metadata.h" +static void start_send_message_batch(void* arg, grpc_error* unused); +static void send_message_on_complete(void* arg, grpc_error* error); +static void on_send_message_next_done(void* arg, grpc_error* error); + namespace { enum initial_metadata_state { // Initial metadata not yet seen. @@ -50,6 +54,23 @@ enum initial_metadata_state { }; struct call_data { + call_data(grpc_call_element* elem, const grpc_call_element_args& args) + : call_combiner(args.call_combiner) { + GRPC_CLOSURE_INIT(&start_send_message_batch_in_call_combiner, + start_send_message_batch, elem, + grpc_schedule_on_exec_ctx); + grpc_slice_buffer_init(&slices); + GRPC_CLOSURE_INIT(&send_message_on_complete, ::send_message_on_complete, + elem, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&on_send_message_next_done, ::on_send_message_next_done, + elem, grpc_schedule_on_exec_ctx); + } + + ~call_data() { + grpc_slice_buffer_destroy_internal(&slices); + GRPC_ERROR_UNREF(cancel_error); + } + grpc_call_combiner* call_combiner; grpc_linked_mdelem compression_algorithm_storage; grpc_linked_mdelem stream_compression_algorithm_storage; @@ -57,11 +78,12 @@ struct call_data { grpc_linked_mdelem accept_stream_encoding_storage; /** Compression algorithm we'll try to use. It may be given by incoming * metadata, or by the channel's default compression settings. */ - grpc_message_compression_algorithm message_compression_algorithm; - initial_metadata_state send_initial_metadata_state; - grpc_error* cancel_error; + grpc_message_compression_algorithm message_compression_algorithm = + GRPC_MESSAGE_COMPRESS_NONE; + initial_metadata_state send_initial_metadata_state = INITIAL_METADATA_UNSEEN; + grpc_error* cancel_error = GRPC_ERROR_NONE; grpc_closure start_send_message_batch_in_call_combiner; - grpc_transport_stream_op_batch* send_message_batch; + grpc_transport_stream_op_batch* send_message_batch = nullptr; grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */ grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> replacement_stream; @@ -424,16 +446,7 @@ static void compress_start_transport_stream_op_batch( /* Constructor for call_data */ static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - calld->call_combiner = args->call_combiner; - calld->cancel_error = GRPC_ERROR_NONE; - grpc_slice_buffer_init(&calld->slices); - GRPC_CLOSURE_INIT(&calld->start_send_message_batch_in_call_combiner, - start_send_message_batch, elem, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->on_send_message_next_done, - on_send_message_next_done, elem, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, - elem, grpc_schedule_on_exec_ctx); + new (elem->call_data) call_data(elem, *args); return GRPC_ERROR_NONE; } @@ -442,8 +455,7 @@ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); - grpc_slice_buffer_destroy_internal(&calld->slices); - GRPC_ERROR_UNREF(calld->cancel_error); + calld->~call_data(); } /* Constructor for channel_data */ diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 436ea09d94..ce1be8370c 100644 --- a/src/core/ext/filters/http/server/http_server_filter.cc +++ b/src/core/ext/filters/http/server/http_server_filter.cc @@ -35,9 +35,32 @@ #define EXPECTED_CONTENT_TYPE "application/grpc" #define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1 +static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err); +static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err); +static void hs_recv_message_ready(void* user_data, grpc_error* err); + namespace { struct call_data { + call_data(grpc_call_element* elem, const grpc_call_element_args& args) + : call_combiner(args.call_combiner) { + GRPC_CLOSURE_INIT(&recv_initial_metadata_ready, + hs_recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_message_ready, hs_recv_message_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready, + hs_recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + } + + ~call_data() { + GRPC_ERROR_UNREF(recv_initial_metadata_ready_error); + if (have_read_stream) { + read_stream->Orphan(); + } + } + grpc_call_combiner* call_combiner; // Outgoing headers to add to send_initial_metadata. @@ -47,27 +70,27 @@ struct call_data { // If we see the recv_message contents in the GET query string, we // store it here. grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> read_stream; - bool have_read_stream; + bool have_read_stream = false; // State for intercepting recv_initial_metadata. grpc_closure recv_initial_metadata_ready; - grpc_error* recv_initial_metadata_ready_error; + grpc_error* recv_initial_metadata_ready_error = GRPC_ERROR_NONE; grpc_closure* original_recv_initial_metadata_ready; - grpc_metadata_batch* recv_initial_metadata; + grpc_metadata_batch* recv_initial_metadata = nullptr; uint32_t* recv_initial_metadata_flags; - bool seen_recv_initial_metadata_ready; + bool seen_recv_initial_metadata_ready = false; // State for intercepting recv_message. grpc_closure* original_recv_message_ready; grpc_closure recv_message_ready; grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; - bool seen_recv_message_ready; + bool seen_recv_message_ready = false; // State for intercepting recv_trailing_metadata grpc_closure recv_trailing_metadata_ready; grpc_closure* original_recv_trailing_metadata_ready; grpc_error* recv_trailing_metadata_ready_error; - bool seen_recv_trailing_metadata_ready; + bool seen_recv_trailing_metadata_ready = false; }; struct channel_data { @@ -431,16 +454,7 @@ static void hs_start_transport_stream_op_batch( /* Constructor for call_data */ static grpc_error* hs_init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - calld->call_combiner = args->call_combiner; - GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, - hs_recv_initial_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_message_ready, hs_recv_message_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - hs_recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); + new (elem->call_data) call_data(elem, *args); return GRPC_ERROR_NONE; } @@ -449,10 +463,7 @@ static void hs_destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); - GRPC_ERROR_UNREF(calld->recv_initial_metadata_ready_error); - if (calld->have_read_stream) { - calld->read_stream->Orphan(); - } + calld->~call_data(); } /* Constructor for channel_data */ diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc index 8ac34c629f..6a7231ff7d 100644 --- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc +++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc @@ -25,7 +25,6 @@ #include <grpc/support/string_util.h> #include "src/core/ext/filters/client_channel/parse_address.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/ext/filters/load_reporting/registered_opencensus_objects.h" #include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h" #include "src/core/lib/channel/channel_args.h" @@ -36,6 +35,7 @@ #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/call.h" +#include "src/core/lib/uri/uri_parser.h" namespace grpc { diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc index 2d3b16d992..94d6942aa4 100644 --- a/src/core/ext/filters/message_size/message_size_filter.cc +++ b/src/core/ext/filters/message_size/message_size_filter.cc @@ -90,9 +90,53 @@ RefCountedPtr<MessageSizeLimits> MessageSizeLimits::CreateFromJson( } // namespace } // namespace grpc_core +static void recv_message_ready(void* user_data, grpc_error* error); +static void recv_trailing_metadata_ready(void* user_data, grpc_error* error); + namespace { +struct channel_data { + message_size_limits limits; + // Maps path names to refcounted_message_size_limits structs. + grpc_core::RefCountedPtr<grpc_core::SliceHashTable< + grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>> + method_limit_table; +}; + struct call_data { + call_data(grpc_call_element* elem, const channel_data& chand, + const grpc_call_element_args& args) + : call_combiner(args.call_combiner), limits(chand.limits) { + GRPC_CLOSURE_INIT(&recv_message_ready, ::recv_message_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready, + ::recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + // Get max sizes from channel data, then merge in per-method config values. + // Note: Per-method config is only available on the client, so we + // apply the max request size to the send limit and the max response + // size to the receive limit. + if (chand.method_limit_table != nullptr) { + grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits = + grpc_core::ServiceConfig::MethodConfigTableLookup( + *chand.method_limit_table, args.path); + if (limits != nullptr) { + if (limits->limits().max_send_size >= 0 && + (limits->limits().max_send_size < this->limits.max_send_size || + this->limits.max_send_size < 0)) { + this->limits.max_send_size = limits->limits().max_send_size; + } + if (limits->limits().max_recv_size >= 0 && + (limits->limits().max_recv_size < this->limits.max_recv_size || + this->limits.max_recv_size < 0)) { + this->limits.max_recv_size = limits->limits().max_recv_size; + } + } + } + } + + ~call_data() { GRPC_ERROR_UNREF(error); } + grpc_call_combiner* call_combiner; message_size_limits limits; // Receive closures are chained: we inject this closure as the @@ -101,25 +145,17 @@ struct call_data { grpc_closure recv_message_ready; grpc_closure recv_trailing_metadata_ready; // The error caused by a message that is too large, or GRPC_ERROR_NONE - grpc_error* error; + grpc_error* error = GRPC_ERROR_NONE; // Used by recv_message_ready. - grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; + grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr; // Original recv_message_ready callback, invoked after our own. - grpc_closure* next_recv_message_ready; + grpc_closure* next_recv_message_ready = nullptr; // Original recv_trailing_metadata callback, invoked after our own. grpc_closure* original_recv_trailing_metadata_ready; - bool seen_recv_trailing_metadata; + bool seen_recv_trailing_metadata = false; grpc_error* recv_trailing_metadata_error; }; -struct channel_data { - message_size_limits limits; - // Maps path names to refcounted_message_size_limits structs. - grpc_core::RefCountedPtr<grpc_core::SliceHashTable< - grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>> - method_limit_table; -}; - } // namespace // Callback invoked when we receive a message. Here we check the max @@ -228,38 +264,7 @@ static void start_transport_stream_op_batch( static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { channel_data* chand = static_cast<channel_data*>(elem->channel_data); - call_data* calld = static_cast<call_data*>(elem->call_data); - calld->call_combiner = args->call_combiner; - calld->next_recv_message_ready = nullptr; - calld->original_recv_trailing_metadata_ready = nullptr; - calld->error = GRPC_ERROR_NONE; - GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - // Get max sizes from channel data, then merge in per-method config values. - // Note: Per-method config is only available on the client, so we - // apply the max request size to the send limit and the max response - // size to the receive limit. - calld->limits = chand->limits; - if (chand->method_limit_table != nullptr) { - grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits = - grpc_core::ServiceConfig::MethodConfigTableLookup( - *chand->method_limit_table, args->path); - if (limits != nullptr) { - if (limits->limits().max_send_size >= 0 && - (limits->limits().max_send_size < calld->limits.max_send_size || - calld->limits.max_send_size < 0)) { - calld->limits.max_send_size = limits->limits().max_send_size; - } - if (limits->limits().max_recv_size >= 0 && - (limits->limits().max_recv_size < calld->limits.max_recv_size || - calld->limits.max_recv_size < 0)) { - calld->limits.max_recv_size = limits->limits().max_recv_size; - } - } - } + new (elem->call_data) call_data(elem, *chand, *args); return GRPC_ERROR_NONE; } @@ -268,7 +273,7 @@ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = (call_data*)elem->call_data; - GRPC_ERROR_UNREF(calld->error); + calld->~call_data(); } static int default_size(const grpc_channel_args* args, diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc index 5ce73a95d7..e73eee4353 100644 --- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc +++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc @@ -27,7 +27,6 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/ext/transport/chttp2/client/chttp2_connector.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/memory.h" @@ -39,6 +38,7 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/channel.h" +#include "src/core/lib/uri/uri_parser.h" static void client_channel_factory_ref( grpc_client_channel_factory* cc_factory) {} diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 287bc0454e..33d2b22aa5 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -366,15 +366,10 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr, grpc_resolved_addresses_destroy(resolved); arg = grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ); - if (grpc_channel_arg_get_bool(arg, false)) { - char* host; - char* port; - gpr_split_host_port(addr, &host, &port); - // allocated host's ownership is passed to ListenSocketNode. + if (grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT)) { state->channelz_listen_socket = grpc_core::MakeRefCounted<grpc_core::channelz::ListenSocketNode>( - grpc_core::UniquePtr<char>(host), *port_num); - gpr_free(port); + grpc_core::UniquePtr<char>(gpr_strdup(addr))); socket_uuid = state->channelz_listen_socket->uuid(); } diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 04874a9494..978ecd59e4 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -53,6 +53,7 @@ #include "src/core/lib/transport/timeout_encoding.h" #include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport_impl.h" +#include "src/core/lib/uri/uri_parser.h" #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) #define MAX_WINDOW 0x7fffffffu @@ -153,53 +154,52 @@ bool g_flow_control_enabled = true; /******************************************************************************* * CONSTRUCTION/DESTRUCTION/REFCOUNTING */ - -static void destruct_transport(grpc_chttp2_transport* t) { +grpc_chttp2_transport::~grpc_chttp2_transport() { size_t i; - if (t->channelz_socket != nullptr) { - t->channelz_socket.reset(); + if (channelz_socket != nullptr) { + channelz_socket.reset(); } - grpc_endpoint_destroy(t->ep); + grpc_endpoint_destroy(ep); - grpc_slice_buffer_destroy_internal(&t->qbuf); + grpc_slice_buffer_destroy_internal(&qbuf); - grpc_slice_buffer_destroy_internal(&t->outbuf); - grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor); + grpc_slice_buffer_destroy_internal(&outbuf); + grpc_chttp2_hpack_compressor_destroy(&hpack_compressor); - grpc_slice_buffer_destroy_internal(&t->read_buffer); - grpc_chttp2_hpack_parser_destroy(&t->hpack_parser); - grpc_chttp2_goaway_parser_destroy(&t->goaway_parser); + grpc_slice_buffer_destroy_internal(&read_buffer); + grpc_chttp2_hpack_parser_destroy(&hpack_parser); + grpc_chttp2_goaway_parser_destroy(&goaway_parser); for (i = 0; i < STREAM_LIST_COUNT; i++) { - GPR_ASSERT(t->lists[i].head == nullptr); - GPR_ASSERT(t->lists[i].tail == nullptr); + GPR_ASSERT(lists[i].head == nullptr); + GPR_ASSERT(lists[i].tail == nullptr); } - GRPC_ERROR_UNREF(t->goaway_error); + GRPC_ERROR_UNREF(goaway_error); - GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0); + GPR_ASSERT(grpc_chttp2_stream_map_size(&stream_map) == 0); - grpc_chttp2_stream_map_destroy(&t->stream_map); - grpc_connectivity_state_destroy(&t->channel_callback.state_tracker); + grpc_chttp2_stream_map_destroy(&stream_map); + grpc_connectivity_state_destroy(&channel_callback.state_tracker); - GRPC_COMBINER_UNREF(t->combiner, "chttp2_transport"); + GRPC_COMBINER_UNREF(combiner, "chttp2_transport"); - cancel_pings(t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed")); + cancel_pings(this, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed")); - while (t->write_cb_pool) { - grpc_chttp2_write_cb* next = t->write_cb_pool->next; - gpr_free(t->write_cb_pool); - t->write_cb_pool = next; + while (write_cb_pool) { + grpc_chttp2_write_cb* next = write_cb_pool->next; + gpr_free(write_cb_pool); + write_cb_pool = next; } - t->flow_control.Destroy(); + flow_control.Destroy(); - GRPC_ERROR_UNREF(t->closed_with_error); - gpr_free(t->ping_acks); - gpr_free(t->peer_string); - gpr_free(t); + GRPC_ERROR_UNREF(closed_with_error); + gpr_free(ping_acks); + gpr_free(peer_string); } #ifndef NDEBUG @@ -211,7 +211,8 @@ void grpc_chttp2_unref_transport(grpc_chttp2_transport* t, const char* reason, t, val, val - 1, reason, file, line); } if (!gpr_unref(&t->refs)) return; - destruct_transport(t); + t->~grpc_chttp2_transport(); + gpr_free(t); } void grpc_chttp2_ref_transport(grpc_chttp2_transport* t, const char* reason, @@ -226,7 +227,8 @@ void grpc_chttp2_ref_transport(grpc_chttp2_transport* t, const char* reason, #else void grpc_chttp2_unref_transport(grpc_chttp2_transport* t) { if (!gpr_unref(&t->refs)) return; - destruct_transport(t); + t->~grpc_chttp2_transport(); + gpr_free(t); } void grpc_chttp2_ref_transport(grpc_chttp2_transport* t) { gpr_ref(&t->refs); } @@ -395,8 +397,12 @@ static bool read_channel_args(grpc_chttp2_transport* t, } } if (channelz_enabled) { + // TODO(ncteisen): add an API to endpoint to query for local addr, and pass + // it in here, so SocketNode knows its own address. t->channelz_socket = - grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>(); + grpc_core::MakeRefCounted<grpc_core::channelz::SocketNode>( + grpc_core::UniquePtr<char>(), + grpc_core::UniquePtr<char>(gpr_strdup(t->peer_string))); } return enable_bdp; } @@ -476,115 +482,97 @@ static void init_keepalive_pings_if_enabled(grpc_chttp2_transport* t) { } } -static void init_transport(grpc_chttp2_transport* t, - const grpc_channel_args* channel_args, - grpc_endpoint* ep, bool is_client, - grpc_resource_user* resource_user) { +grpc_chttp2_transport::grpc_chttp2_transport( + const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client, + grpc_resource_user* resource_user) + : ep(ep), + peer_string(grpc_endpoint_get_peer(ep)), + resource_user(resource_user), + combiner(grpc_combiner_create()), + is_client(is_client), + next_stream_id(is_client ? 1 : 2), + deframe_state(is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0) { GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); - - t->base.vtable = get_vtable(); - t->ep = ep; + base.vtable = get_vtable(); /* one ref is for destroy */ - gpr_ref_init(&t->refs, 1); - t->combiner = grpc_combiner_create(); - t->peer_string = grpc_endpoint_get_peer(ep); - t->endpoint_reading = 1; - t->next_stream_id = is_client ? 1 : 2; - t->is_client = is_client; - t->resource_user = resource_user; - t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; - t->is_first_frame = true; - grpc_connectivity_state_init( - &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, - is_client ? "client_transport" : "server_transport"); - - grpc_slice_buffer_init(&t->qbuf); - grpc_slice_buffer_init(&t->outbuf); - grpc_chttp2_hpack_compressor_init(&t->hpack_compressor); - - init_transport_closures(t); - - t->goaway_error = GRPC_ERROR_NONE; - grpc_chttp2_goaway_parser_init(&t->goaway_parser); - grpc_chttp2_hpack_parser_init(&t->hpack_parser); - - grpc_slice_buffer_init(&t->read_buffer); - + gpr_ref_init(&refs, 1); /* 8 is a random stab in the dark as to a good initial size: it's small enough that it shouldn't waste memory for infrequently used connections, yet large enough that the exponential growth should happen nicely when it's needed. TODO(ctiller): tune this */ - grpc_chttp2_stream_map_init(&t->stream_map, 8); + grpc_chttp2_stream_map_init(&stream_map, 8); + grpc_slice_buffer_init(&read_buffer); + grpc_connectivity_state_init( + &channel_callback.state_tracker, GRPC_CHANNEL_READY, + is_client ? "client_transport" : "server_transport"); + grpc_slice_buffer_init(&outbuf); + if (is_client) { + grpc_slice_buffer_add(&outbuf, grpc_slice_from_copied_string( + GRPC_CHTTP2_CLIENT_CONNECT_STRING)); + } + grpc_chttp2_hpack_compressor_init(&hpack_compressor); + grpc_slice_buffer_init(&qbuf); /* copy in initial settings to all setting sets */ size_t i; int j; for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { - t->settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; + settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; } } - t->dirtied_local_settings = 1; - /* Hack: it's common for implementations to assume 65536 bytes initial send - window -- this should by rights be 0 */ - t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; - t->sent_local_settings = 0; - t->write_buffer_size = grpc_core::chttp2::kDefaultWindow; + grpc_chttp2_hpack_parser_init(&hpack_parser); + grpc_chttp2_goaway_parser_init(&goaway_parser); - if (is_client) { - grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string( - GRPC_CHTTP2_CLIENT_CONNECT_STRING)); - } + init_transport_closures(this); /* configure http2 the way we like it */ if (is_client) { - queue_setting_update(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); - queue_setting_update(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); + queue_setting_update(this, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); + queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); } - queue_setting_update(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, + queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, DEFAULT_MAX_HEADER_LIST_SIZE); - queue_setting_update(t, GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, - 1); - - configure_transport_ping_policy(t); - init_transport_keepalive_settings(t); + queue_setting_update(this, + GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1); - t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + configure_transport_ping_policy(this); + init_transport_keepalive_settings(this); bool enable_bdp = true; if (channel_args) { - enable_bdp = read_channel_args(t, channel_args, is_client); + enable_bdp = read_channel_args(this, channel_args, is_client); } if (g_flow_control_enabled) { - t->flow_control.Init<grpc_core::chttp2::TransportFlowControl>(t, - enable_bdp); + flow_control.Init<grpc_core::chttp2::TransportFlowControl>(this, + enable_bdp); } else { - t->flow_control.Init<grpc_core::chttp2::TransportFlowControlDisabled>(t); + flow_control.Init<grpc_core::chttp2::TransportFlowControlDisabled>(this); enable_bdp = false; } /* No pings allowed before receiving a header or data frame. */ - t->ping_state.pings_before_data_required = 0; - t->ping_state.is_delayed_ping_timer_set = false; - t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST; + ping_state.pings_before_data_required = 0; + ping_state.is_delayed_ping_timer_set = false; + ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST; - t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST; - t->ping_recv_state.ping_strikes = 0; + ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST; + ping_recv_state.ping_strikes = 0; - init_keepalive_pings_if_enabled(t); + init_keepalive_pings_if_enabled(this); if (enable_bdp) { - GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); - schedule_bdp_ping_locked(t); - grpc_chttp2_act_on_flowctl_action(t->flow_control->PeriodicUpdate(), t, + GRPC_CHTTP2_REF_TRANSPORT(this, "bdp_ping"); + schedule_bdp_ping_locked(this); + grpc_chttp2_act_on_flowctl_action(flow_control->PeriodicUpdate(), this, nullptr); } - grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); - post_benign_reclaimer(t); + grpc_chttp2_initiate_write(this, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); + post_benign_reclaimer(this); } static void destroy_transport_locked(void* tp, grpc_error* error) { @@ -594,6 +582,7 @@ static void destroy_transport_locked(void* tp, grpc_error* error) { t, grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"), GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state)); + // Must be the last line. GRPC_CHTTP2_UNREF_TRANSPORT(t, "destroy"); } @@ -678,115 +667,108 @@ void grpc_chttp2_stream_unref(grpc_chttp2_stream* s) { } #endif -static int init_stream(grpc_transport* gt, grpc_stream* gs, - grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { - GPR_TIMER_SCOPE("init_stream", 0); - grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt); - grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs); - - s->t = t; - s->refcount = refcount; +grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t, + grpc_stream_refcount* refcount, + const void* server_data, + gpr_arena* arena) + : t(t), refcount(refcount), metadata_buffer{{arena}, {arena}} { /* We reserve one 'active stream' that's dropped when the stream is read-closed. The others are for Chttp2IncomingByteStreams that are actively reading */ - GRPC_CHTTP2_STREAM_REF(s, "chttp2"); - - grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena); - grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena); - grpc_chttp2_data_parser_init(&s->data_parser); - grpc_slice_buffer_init(&s->flow_controlled_buffer); - s->deadline = GRPC_MILLIS_INF_FUTURE; - GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s, - grpc_schedule_on_exec_ctx); - grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer); - s->unprocessed_incoming_frames_buffer_cached_length = 0; - grpc_slice_buffer_init(&s->frame_storage); - grpc_slice_buffer_init(&s->compressed_data_buffer); - grpc_slice_buffer_init(&s->decompressed_data_buffer); - s->pending_byte_stream = false; - s->decompressed_header_bytes = 0; - GRPC_CLOSURE_INIT(&s->reset_byte_stream, reset_byte_stream, s, - grpc_combiner_scheduler(t->combiner)); - + GRPC_CHTTP2_STREAM_REF(this, "chttp2"); GRPC_CHTTP2_REF_TRANSPORT(t, "stream"); if (server_data) { - s->id = static_cast<uint32_t>((uintptr_t)server_data); - *t->accepting_stream = s; - grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); + id = static_cast<uint32_t>((uintptr_t)server_data); + *t->accepting_stream = this; + grpc_chttp2_stream_map_add(&t->stream_map, id, this); post_destructive_reclaimer(t); } - if (t->flow_control->flow_control_enabled()) { - s->flow_control.Init<grpc_core::chttp2::StreamFlowControl>( + flow_control.Init<grpc_core::chttp2::StreamFlowControl>( static_cast<grpc_core::chttp2::TransportFlowControl*>( t->flow_control.get()), - s); + this); } else { - s->flow_control.Init<grpc_core::chttp2::StreamFlowControlDisabled>(); + flow_control.Init<grpc_core::chttp2::StreamFlowControlDisabled>(); } - return 0; -} + grpc_slice_buffer_init(&frame_storage); + grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer); + grpc_slice_buffer_init(&flow_controlled_buffer); + grpc_slice_buffer_init(&compressed_data_buffer); + grpc_slice_buffer_init(&decompressed_data_buffer); -static void destroy_stream_locked(void* sp, grpc_error* error) { - GPR_TIMER_SCOPE("destroy_stream", 0); - grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp); - grpc_chttp2_transport* t = s->t; + GRPC_CLOSURE_INIT(&complete_fetch_locked, ::complete_fetch_locked, this, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&reset_byte_stream, ::reset_byte_stream, this, + grpc_combiner_scheduler(t->combiner)); +} +grpc_chttp2_stream::~grpc_chttp2_stream() { if (t->channelz_socket != nullptr) { - if ((t->is_client && s->eos_received) || (!t->is_client && s->eos_sent)) { + if ((t->is_client && eos_received) || (!t->is_client && eos_sent)) { t->channelz_socket->RecordStreamSucceeded(); } else { t->channelz_socket->RecordStreamFailed(); } } - GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0); - if (s->id != 0) { - GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == nullptr); + GPR_ASSERT((write_closed && read_closed) || id == 0); + if (id != 0) { + GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, id) == nullptr); } - grpc_slice_buffer_destroy_internal(&s->unprocessed_incoming_frames_buffer); - grpc_slice_buffer_destroy_internal(&s->frame_storage); - grpc_slice_buffer_destroy_internal(&s->compressed_data_buffer); - grpc_slice_buffer_destroy_internal(&s->decompressed_data_buffer); + grpc_slice_buffer_destroy_internal(&unprocessed_incoming_frames_buffer); + grpc_slice_buffer_destroy_internal(&frame_storage); + grpc_slice_buffer_destroy_internal(&compressed_data_buffer); + grpc_slice_buffer_destroy_internal(&decompressed_data_buffer); - grpc_chttp2_list_remove_stalled_by_transport(t, s); - grpc_chttp2_list_remove_stalled_by_stream(t, s); + grpc_chttp2_list_remove_stalled_by_transport(t, this); + grpc_chttp2_list_remove_stalled_by_stream(t, this); for (int i = 0; i < STREAM_LIST_COUNT; i++) { - if (GPR_UNLIKELY(s->included[i])) { + if (GPR_UNLIKELY(included[i])) { gpr_log(GPR_ERROR, "%s stream %d still included in list %d", - t->is_client ? "client" : "server", s->id, i); + t->is_client ? "client" : "server", id, i); abort(); } } - GPR_ASSERT(s->send_initial_metadata_finished == nullptr); - GPR_ASSERT(s->fetching_send_message == nullptr); - GPR_ASSERT(s->send_trailing_metadata_finished == nullptr); - GPR_ASSERT(s->recv_initial_metadata_ready == nullptr); - GPR_ASSERT(s->recv_message_ready == nullptr); - GPR_ASSERT(s->recv_trailing_metadata_finished == nullptr); - grpc_chttp2_data_parser_destroy(&s->data_parser); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]); - grpc_slice_buffer_destroy_internal(&s->flow_controlled_buffer); - GRPC_ERROR_UNREF(s->read_closed_error); - GRPC_ERROR_UNREF(s->write_closed_error); - GRPC_ERROR_UNREF(s->byte_stream_error); + GPR_ASSERT(send_initial_metadata_finished == nullptr); + GPR_ASSERT(fetching_send_message == nullptr); + GPR_ASSERT(send_trailing_metadata_finished == nullptr); + GPR_ASSERT(recv_initial_metadata_ready == nullptr); + GPR_ASSERT(recv_message_ready == nullptr); + GPR_ASSERT(recv_trailing_metadata_finished == nullptr); + grpc_slice_buffer_destroy_internal(&flow_controlled_buffer); + GRPC_ERROR_UNREF(read_closed_error); + GRPC_ERROR_UNREF(write_closed_error); + GRPC_ERROR_UNREF(byte_stream_error); - s->flow_control.Destroy(); + flow_control.Destroy(); if (t->resource_user != nullptr) { grpc_resource_user_free(t->resource_user, GRPC_RESOURCE_QUOTA_CALL_SIZE); } GRPC_CHTTP2_UNREF_TRANSPORT(t, "stream"); + GRPC_CLOSURE_SCHED(destroy_stream_arg, GRPC_ERROR_NONE); +} + +static int init_stream(grpc_transport* gt, grpc_stream* gs, + grpc_stream_refcount* refcount, const void* server_data, + gpr_arena* arena) { + GPR_TIMER_SCOPE("init_stream", 0); + grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt); + new (gs) grpc_chttp2_stream(t, refcount, server_data, arena); + return 0; +} - GRPC_CLOSURE_SCHED(s->destroy_stream_arg, GRPC_ERROR_NONE); +static void destroy_stream_locked(void* sp, grpc_error* error) { + GPR_TIMER_SCOPE("destroy_stream", 0); + grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp); + s->~grpc_chttp2_stream(); } static void destroy_stream(grpc_transport* gt, grpc_stream* gs, @@ -1721,8 +1703,8 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, gpr_free(str); } - op->handler_private.extra_arg = gs; GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op"); + op->handler_private.extra_arg = gs; GRPC_CLOSURE_SCHED( GRPC_CLOSURE_INIT(&op->handler_private.closure, perform_stream_op_locked, op, grpc_combiner_scheduler(t->combiner)), @@ -2728,6 +2710,7 @@ static void init_keepalive_ping_locked(void* arg, grpc_error* error) { grpc_chttp2_stream_map_size(&t->stream_map) > 0) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING; GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end"); + grpc_timer_init_unset(&t->keepalive_watchdog_timer); send_keepalive_ping_locked(t); grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_KEEPALIVE_PING); } else { @@ -3207,9 +3190,8 @@ intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport) { grpc_transport* grpc_create_chttp2_transport( const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client, grpc_resource_user* resource_user) { - grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>( - gpr_zalloc(sizeof(grpc_chttp2_transport))); - init_transport(t, channel_args, ep, is_client, resource_user); + auto t = new (gpr_malloc(sizeof(grpc_chttp2_transport))) + grpc_chttp2_transport(channel_args, ep, is_client, resource_user); return &t->base; } diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc index 933b32c03c..1de00735cf 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.cc +++ b/src/core/ext/transport/chttp2/transport/frame_data.cc @@ -32,18 +32,12 @@ #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/transport/transport.h" -grpc_error* grpc_chttp2_data_parser_init(grpc_chttp2_data_parser* parser) { - parser->state = GRPC_CHTTP2_DATA_FH_0; - parser->parsing_frame = nullptr; - return GRPC_ERROR_NONE; -} - -void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser* parser) { - if (parser->parsing_frame != nullptr) { - GRPC_ERROR_UNREF(parser->parsing_frame->Finished( +grpc_chttp2_data_parser::~grpc_chttp2_data_parser() { + if (parsing_frame != nullptr) { + GRPC_ERROR_UNREF(parsing_frame->Finished( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false)); } - GRPC_ERROR_UNREF(parser->error); + GRPC_ERROR_UNREF(error); } grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser, diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h index e5d01f764e..2c5da99fa6 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.h +++ b/src/core/ext/transport/chttp2/transport/frame_data.h @@ -43,20 +43,18 @@ namespace grpc_core { class Chttp2IncomingByteStream; } // namespace grpc_core -typedef struct { - grpc_chttp2_stream_state state; - uint8_t frame_type; - uint32_t frame_size; - grpc_error* error; +struct grpc_chttp2_data_parser { + grpc_chttp2_data_parser() = default; + ~grpc_chttp2_data_parser(); - bool is_frame_compressed; - grpc_core::Chttp2IncomingByteStream* parsing_frame; -} grpc_chttp2_data_parser; + grpc_chttp2_stream_state state = GRPC_CHTTP2_DATA_FH_0; + uint8_t frame_type = 0; + uint32_t frame_size = 0; + grpc_error* error = GRPC_ERROR_NONE; -/* initialize per-stream state for data frame parsing */ -grpc_error* grpc_chttp2_data_parser_init(grpc_chttp2_data_parser* parser); - -void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser* parser); + bool is_frame_compressed = false; + grpc_core::Chttp2IncomingByteStream* parsing_frame = nullptr; +}; /* start processing a new data frame */ grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser, diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc index 920d52770f..dbe9df6ae3 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc @@ -212,10 +212,6 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c, return new_index; } -/* dummy function */ -static void add_nothing(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, - size_t elem_size) {} - // Add a key to the dynamic table. Both key and value will be added to table at // the decoder. static void add_key_with_index(grpc_chttp2_hpack_compressor* c, @@ -524,17 +520,22 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, uint32_t indices_key; /* should this elem be in the table? */ - size_t decoder_space_usage = + const size_t decoder_space_usage = grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata); - bool should_add_elem = elem_interned && - decoder_space_usage < MAX_DECODER_SPACE_USAGE && - c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= - c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; - void (*maybe_add)(grpc_chttp2_hpack_compressor*, grpc_mdelem, size_t) = - should_add_elem ? add_elem : add_nothing; - void (*emit)(grpc_chttp2_hpack_compressor*, uint32_t, grpc_mdelem, - framer_state*) = - should_add_elem ? emit_lithdr_incidx : emit_lithdr_noidx; + const bool should_add_elem = elem_interned && + decoder_space_usage < MAX_DECODER_SPACE_USAGE && + c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= + c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; + + auto emit_maybe_add = [&should_add_elem, &elem, &st, &c, &indices_key, + &decoder_space_usage] { + if (should_add_elem) { + emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st); + add_elem(c, elem, decoder_space_usage); + } else { + emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st); + } + }; /* no hits for the elem... maybe there's a key? */ indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; @@ -542,8 +543,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ - emit(c, dynidx(c, indices_key), elem, st); - maybe_add(c, elem, decoder_space_usage); + emit_maybe_add(); return; } @@ -552,20 +552,23 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ - emit(c, dynidx(c, indices_key), elem, st); - maybe_add(c, elem, decoder_space_usage); + emit_maybe_add(); return; } /* no elem, key in the table... fall back to literal emission */ - bool should_add_key = + const bool should_add_key = !elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE; - emit = (should_add_elem || should_add_key) ? emit_lithdr_incidx_v - : emit_lithdr_noidx_v; - maybe_add = - should_add_elem ? add_elem : (should_add_key ? add_key : add_nothing); - emit(c, 0, elem, st); - maybe_add(c, elem, decoder_space_usage); + if (should_add_elem || should_add_key) { + emit_lithdr_incidx_v(c, 0, elem, st); + } else { + emit_lithdr_noidx_v(c, 0, elem, st); + } + if (should_add_elem) { + add_elem(c, elem, decoder_space_usage); + } else if (should_add_key) { + add_key(c, elem, decoder_space_usage); + } } #define STRLEN_LIT(x) (sizeof(x) - 1) diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc index 4d7dfd900f..dca15e7680 100644 --- a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc +++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc @@ -27,18 +27,6 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> -void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer* buffer, gpr_arena* arena) { - buffer->arena = arena; - grpc_metadata_batch_init(&buffer->batch); - buffer->batch.deadline = GRPC_MILLIS_INF_FUTURE; -} - -void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer* buffer) { - grpc_metadata_batch_destroy(&buffer->batch); -} - grpc_error* grpc_chttp2_incoming_metadata_buffer_add( grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) { buffer->size += GRPC_MDELEM_LENGTH(elem); diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h index d029cf00d4..c551b3cc8b 100644 --- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h +++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h @@ -23,17 +23,20 @@ #include "src/core/lib/transport/transport.h" -typedef struct { +struct grpc_chttp2_incoming_metadata_buffer { + grpc_chttp2_incoming_metadata_buffer(gpr_arena* arena) : arena(arena) { + grpc_metadata_batch_init(&batch); + batch.deadline = GRPC_MILLIS_INF_FUTURE; + } + ~grpc_chttp2_incoming_metadata_buffer() { + grpc_metadata_batch_destroy(&batch); + } + gpr_arena* arena; grpc_metadata_batch batch; - size_t size; // total size of metadata -} grpc_chttp2_incoming_metadata_buffer; - -/** assumes everything initially zeroed */ -void grpc_chttp2_incoming_metadata_buffer_init( - grpc_chttp2_incoming_metadata_buffer* buffer, gpr_arena* arena); -void grpc_chttp2_incoming_metadata_buffer_destroy( - grpc_chttp2_incoming_metadata_buffer* buffer); + size_t size = 0; // total size of metadata +}; + void grpc_chttp2_incoming_metadata_buffer_publish( grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 202017641b..3ee408c103 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -103,8 +103,8 @@ const char* grpc_chttp2_initiate_write_reason_string( grpc_chttp2_initiate_write_reason reason); typedef struct { - grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT]; - uint64_t inflight_id; + grpc_closure_list lists[GRPC_CHTTP2_PCL_COUNT] = {}; + uint64_t inflight_id = 0; } grpc_chttp2_ping_queue; typedef struct { @@ -280,6 +280,11 @@ typedef enum { } grpc_chttp2_keepalive_state; struct grpc_chttp2_transport { + grpc_chttp2_transport(const grpc_channel_args* channel_args, + grpc_endpoint* ep, bool is_client, + grpc_resource_user* resource_user); + ~grpc_chttp2_transport(); + grpc_transport base; /* must be first */ gpr_refcount refs; grpc_endpoint* ep; @@ -289,27 +294,27 @@ struct grpc_chttp2_transport { grpc_combiner* combiner; - grpc_closure* notify_on_receive_settings; + grpc_closure* notify_on_receive_settings = nullptr; /** write execution state of the transport */ - grpc_chttp2_write_state write_state; + grpc_chttp2_write_state write_state = GRPC_CHTTP2_WRITE_STATE_IDLE; /** is this the first write in a series of writes? set when we initiate writing from idle, cleared when we initiate writing from writing+more */ - bool is_first_write_in_batch; + bool is_first_write_in_batch = false; /** is the transport destroying itself? */ - uint8_t destroying; + uint8_t destroying = false; /** has the upper layer closed the transport? */ - grpc_error* closed_with_error; + grpc_error* closed_with_error = GRPC_ERROR_NONE; /** is there a read request to the endpoint outstanding? */ - uint8_t endpoint_reading; + uint8_t endpoint_reading = 1; - grpc_chttp2_optimization_target opt_target; + grpc_chttp2_optimization_target opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; /** various lists of streams */ - grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; + grpc_chttp2_stream_list lists[STREAM_LIST_COUNT] = {}; /** maps stream id to grpc_chttp2_stream objects */ grpc_chttp2_stream_map stream_map; @@ -326,7 +331,7 @@ struct grpc_chttp2_transport { /** address to place a newly accepted stream - set and unset by grpc_chttp2_parsing_accept_stream; used by init_stream to publish the accepted server stream */ - grpc_chttp2_stream** accepting_stream; + grpc_chttp2_stream** accepting_stream = nullptr; struct { /* accept stream callback */ @@ -350,41 +355,43 @@ struct grpc_chttp2_transport { /** how much data are we willing to buffer when the WRITE_BUFFER_HINT is set? */ - uint32_t write_buffer_size; + uint32_t write_buffer_size = grpc_core::chttp2::kDefaultWindow; /** Set to a grpc_error object if a goaway frame is received. By default, set * to GRPC_ERROR_NONE */ - grpc_error* goaway_error; + grpc_error* goaway_error = GRPC_ERROR_NONE; - grpc_chttp2_sent_goaway_state sent_goaway_state; + grpc_chttp2_sent_goaway_state sent_goaway_state = GRPC_CHTTP2_NO_GOAWAY_SEND; /** are the local settings dirty and need to be sent? */ - bool dirtied_local_settings; + bool dirtied_local_settings = true; /** have local settings been sent? */ - bool sent_local_settings; - /** bitmask of setting indexes to send out */ - uint32_t force_send_settings; + bool sent_local_settings = false; + /** bitmask of setting indexes to send out + Hack: it's common for implementations to assume 65536 bytes initial send + window -- this should by rights be 0 */ + uint32_t force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; /** settings values */ uint32_t settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS]; /** what is the next stream id to be allocated by this peer? copied to next_stream_id in parsing when parsing commences */ - uint32_t next_stream_id; + uint32_t next_stream_id = 0; /** last new stream id */ - uint32_t last_new_stream_id; + uint32_t last_new_stream_id = 0; /** ping queues for various ping insertion points */ - grpc_chttp2_ping_queue ping_queue; + grpc_chttp2_ping_queue ping_queue = grpc_chttp2_ping_queue(); grpc_chttp2_repeated_ping_policy ping_policy; grpc_chttp2_repeated_ping_state ping_state; - uint64_t ping_ctr; /* unique id for pings */ + uint64_t ping_ctr = 0; /* unique id for pings */ grpc_closure retry_initiate_ping_locked; /** ping acks */ - size_t ping_ack_count; - size_t ping_ack_capacity; - uint64_t* ping_acks; + size_t ping_ack_count = 0; + size_t ping_ack_capacity = 0; + uint64_t* ping_acks = nullptr; grpc_chttp2_server_ping_recv_state ping_recv_state; /** parser for headers */ @@ -410,22 +417,22 @@ struct grpc_chttp2_transport { int64_t initial_window_update = 0; /* deframing */ - grpc_chttp2_deframe_transport_state deframe_state; - uint8_t incoming_frame_type; - uint8_t incoming_frame_flags; - uint8_t header_eof; - bool is_first_frame; - uint32_t expect_continuation_stream_id; - uint32_t incoming_frame_size; - uint32_t incoming_stream_id; + grpc_chttp2_deframe_transport_state deframe_state = GRPC_DTS_CLIENT_PREFIX_0; + uint8_t incoming_frame_type = 0; + uint8_t incoming_frame_flags = 0; + uint8_t header_eof = 0; + bool is_first_frame = true; + uint32_t expect_continuation_stream_id = 0; + uint32_t incoming_frame_size = 0; + uint32_t incoming_stream_id = 0; /* active parser */ - void* parser_data; - grpc_chttp2_stream* incoming_stream; + void* parser_data = nullptr; + grpc_chttp2_stream* incoming_stream = nullptr; grpc_error* (*parser)(void* parser_user_data, grpc_chttp2_transport* t, grpc_chttp2_stream* s, grpc_slice slice, int is_last); - grpc_chttp2_write_cb* write_cb_pool; + grpc_chttp2_write_cb* write_cb_pool = nullptr; /* bdp estimator */ grpc_closure next_bdp_ping_timer_expired_locked; @@ -434,23 +441,23 @@ struct grpc_chttp2_transport { /* if non-NULL, close the transport with this error when writes are finished */ - grpc_error* close_transport_on_writes_finished; + grpc_error* close_transport_on_writes_finished = GRPC_ERROR_NONE; /* a list of closures to run after writes are finished */ - grpc_closure_list run_after_write; + grpc_closure_list run_after_write = GRPC_CLOSURE_LIST_INIT; /* buffer pool state */ /** have we scheduled a benign cleanup? */ - bool benign_reclaimer_registered; + bool benign_reclaimer_registered = false; /** have we scheduled a destructive cleanup? */ - bool destructive_reclaimer_registered; + bool destructive_reclaimer_registered = false; /** benign cleanup closure */ grpc_closure benign_reclaimer_locked; /** destructive cleanup closure */ grpc_closure destructive_reclaimer_locked; /* next bdp ping timer */ - bool have_next_bdp_ping_timer; + bool have_next_bdp_ping_timer = false; grpc_timer next_bdp_ping_timer; /* keep-alive ping support */ @@ -471,12 +478,12 @@ struct grpc_chttp2_transport { /** grace period for a ping to complete before watchdog kicks in */ grpc_millis keepalive_timeout; /** if keepalive pings are allowed when there's no outstanding streams */ - bool keepalive_permit_without_calls; + bool keepalive_permit_without_calls = false; /** keep-alive state machine state */ grpc_chttp2_keepalive_state keepalive_state; grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> channelz_socket; - uint32_t num_messages_in_next_write; + uint32_t num_messages_in_next_write = 0; }; typedef enum { @@ -487,6 +494,10 @@ typedef enum { } grpc_published_metadata_method; struct grpc_chttp2_stream { + grpc_chttp2_stream(grpc_chttp2_transport* t, grpc_stream_refcount* refcount, + const void* server_data, gpr_arena* arena); + ~grpc_chttp2_stream(); + grpc_chttp2_transport* t; grpc_stream_refcount* refcount; @@ -494,63 +505,63 @@ struct grpc_chttp2_stream { grpc_closure* destroy_stream_arg; grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; - uint8_t included[STREAM_LIST_COUNT]; + uint8_t included[STREAM_LIST_COUNT] = {}; /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; + uint32_t id = 0; /** things the upper layers would like to send */ - grpc_metadata_batch* send_initial_metadata; - grpc_closure* send_initial_metadata_finished; - grpc_metadata_batch* send_trailing_metadata; - grpc_closure* send_trailing_metadata_finished; + grpc_metadata_batch* send_initial_metadata = nullptr; + grpc_closure* send_initial_metadata_finished = nullptr; + grpc_metadata_batch* send_trailing_metadata = nullptr; + grpc_closure* send_trailing_metadata_finished = nullptr; grpc_core::OrphanablePtr<grpc_core::ByteStream> fetching_send_message; - uint32_t fetched_send_message_length; - grpc_slice fetching_slice; + uint32_t fetched_send_message_length = 0; + grpc_slice fetching_slice = grpc_empty_slice(); int64_t next_message_end_offset; - int64_t flow_controlled_bytes_written; - int64_t flow_controlled_bytes_flowed; + int64_t flow_controlled_bytes_written = 0; + int64_t flow_controlled_bytes_flowed = 0; grpc_closure complete_fetch_locked; - grpc_closure* fetching_send_message_finished; + grpc_closure* fetching_send_message_finished = nullptr; grpc_metadata_batch* recv_initial_metadata; - grpc_closure* recv_initial_metadata_ready; - bool* trailing_metadata_available; + grpc_closure* recv_initial_metadata_ready = nullptr; + bool* trailing_metadata_available = nullptr; grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; - grpc_closure* recv_message_ready; + grpc_closure* recv_message_ready = nullptr; grpc_metadata_batch* recv_trailing_metadata; - grpc_closure* recv_trailing_metadata_finished; + grpc_closure* recv_trailing_metadata_finished = nullptr; - grpc_transport_stream_stats* collecting_stats; - grpc_transport_stream_stats stats; + grpc_transport_stream_stats* collecting_stats = nullptr; + grpc_transport_stream_stats stats = grpc_transport_stream_stats(); /** Is this stream closed for writing. */ - bool write_closed; + bool write_closed = false; /** Is this stream reading half-closed. */ - bool read_closed; + bool read_closed = false; /** Are all published incoming byte streams closed. */ - bool all_incoming_byte_streams_finished; + bool all_incoming_byte_streams_finished = false; /** Has this stream seen an error. If true, then pending incoming frames can be thrown away. */ - bool seen_error; + bool seen_error = false; /** Are we buffering writes on this stream? If yes, we won't become writable until there's enough queued up in the flow_controlled_buffer */ - bool write_buffering; + bool write_buffering = false; /** Has trailing metadata been received. */ - bool received_trailing_metadata; + bool received_trailing_metadata = false; /* have we sent or received the EOS bit? */ - bool eos_received; - bool eos_sent; + bool eos_received = false; + bool eos_sent = false; /** the error that resulted in this stream being read-closed */ - grpc_error* read_closed_error; + grpc_error* read_closed_error = GRPC_ERROR_NONE; /** the error that resulted in this stream being write-closed */ - grpc_error* write_closed_error; + grpc_error* write_closed_error = GRPC_ERROR_NONE; - grpc_published_metadata_method published_metadata[2]; - bool final_metadata_requested; + grpc_published_metadata_method published_metadata[2] = {}; + bool final_metadata_requested = false; grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; @@ -560,33 +571,33 @@ struct grpc_chttp2_stream { * Accessed only by application thread when stream->pending_byte_stream == * true */ grpc_slice_buffer unprocessed_incoming_frames_buffer; - grpc_closure* on_next; /* protected by t combiner */ - bool pending_byte_stream; /* protected by t combiner */ + grpc_closure* on_next = nullptr; /* protected by t combiner */ + bool pending_byte_stream = false; /* protected by t combiner */ // cached length of buffer to be used by the transport thread in cases where // stream->pending_byte_stream == true. The value is saved before // application threads are allowed to modify // unprocessed_incoming_frames_buffer - size_t unprocessed_incoming_frames_buffer_cached_length; + size_t unprocessed_incoming_frames_buffer_cached_length = 0; grpc_closure reset_byte_stream; - grpc_error* byte_stream_error; /* protected by t combiner */ - bool received_last_frame; /* protected by t combiner */ + grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */ + bool received_last_frame = false; /* protected by t combiner */ - grpc_millis deadline; + grpc_millis deadline = GRPC_MILLIS_INF_FUTURE; /** saw some stream level error */ - grpc_error* forced_close_error; + grpc_error* forced_close_error = GRPC_ERROR_NONE; /** how many header frames have we received? */ - uint8_t header_frames_received; + uint8_t header_frames_received = 0; /** parsing state for data frames */ /* Accessed only by transport thread when stream->pending_byte_stream == false * Accessed only by application thread when stream->pending_byte_stream == * true */ grpc_chttp2_data_parser data_parser; /** number of bytes received - reset at end of parse thread execution */ - int64_t received_bytes; + int64_t received_bytes = 0; - bool sent_initial_metadata; - bool sent_trailing_metadata; + bool sent_initial_metadata = false; + bool sent_trailing_metadata = false; grpc_core::PolymorphicManualConstructor< grpc_core::chttp2::StreamFlowControlBase, @@ -596,32 +607,34 @@ struct grpc_chttp2_stream { grpc_slice_buffer flow_controlled_buffer; - grpc_chttp2_write_cb* on_flow_controlled_cbs; - grpc_chttp2_write_cb* on_write_finished_cbs; - grpc_chttp2_write_cb* finish_after_write; - size_t sending_bytes; + grpc_chttp2_write_cb* on_flow_controlled_cbs = nullptr; + grpc_chttp2_write_cb* on_write_finished_cbs = nullptr; + grpc_chttp2_write_cb* finish_after_write = nullptr; + size_t sending_bytes = 0; /* Stream compression method to be used. */ - grpc_stream_compression_method stream_compression_method; + grpc_stream_compression_method stream_compression_method = + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS; /* Stream decompression method to be used. */ - grpc_stream_compression_method stream_decompression_method; + grpc_stream_compression_method stream_decompression_method = + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS; /** Stream compression decompress context */ - grpc_stream_compression_context* stream_decompression_ctx; + grpc_stream_compression_context* stream_decompression_ctx = nullptr; /** Stream compression compress context */ - grpc_stream_compression_context* stream_compression_ctx; + grpc_stream_compression_context* stream_compression_ctx = nullptr; /** Buffer storing data that is compressed but not sent */ grpc_slice_buffer compressed_data_buffer; /** Amount of uncompressed bytes sent out when compressed_data_buffer is * emptied */ - size_t uncompressed_data_size; + size_t uncompressed_data_size = 0; /** Temporary buffer storing decompressed data */ grpc_slice_buffer decompressed_data_buffer; /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed */ - bool unprocessed_incoming_frames_decompressed; + bool unprocessed_incoming_frames_decompressed = false; /** gRPC header bytes that are already decompressed */ - size_t decompressed_header_bytes; + size_t decompressed_header_bytes = 0; }; /** Transport writing call flow: diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc index 81e2634e3a..349d8681d5 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.cc +++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc @@ -111,16 +111,21 @@ typedef struct grpc_cronet_transport grpc_cronet_transport; /* TODO (makdharma): reorder structure for memory efficiency per http://www.catb.org/esr/structure-packing/#_structure_reordering: */ struct read_state { + read_state(gpr_arena* arena) + : trailing_metadata(arena), initial_metadata(arena) { + grpc_slice_buffer_init(&read_slice_buffer); + } + /* vars to store data coming from server */ - char* read_buffer; - bool length_field_received; - int received_bytes; - int remaining_bytes; - int length_field; - bool compressed; - char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES]; - char* payload_field; - bool read_stream_closed; + char* read_buffer = nullptr; + bool length_field_received = false; + int received_bytes = 0; + int remaining_bytes = 0; + int length_field = 0; + bool compressed = 0; + char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES] = {}; + char* payload_field = nullptr; + bool read_stream_closed = 0; /* vars for holding data destined for the application */ grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sbs; @@ -128,59 +133,71 @@ struct read_state { /* vars for trailing metadata */ grpc_chttp2_incoming_metadata_buffer trailing_metadata; - bool trailing_metadata_valid; + bool trailing_metadata_valid = false; /* vars for initial metadata */ grpc_chttp2_incoming_metadata_buffer initial_metadata; }; struct write_state { - char* write_buffer; + char* write_buffer = nullptr; }; /* track state of one stream op */ struct op_state { - bool state_op_done[OP_NUM_OPS]; - bool state_callback_received[OP_NUM_OPS]; + op_state(gpr_arena* arena) : rs(arena) {} + + bool state_op_done[OP_NUM_OPS] = {}; + bool state_callback_received[OP_NUM_OPS] = {}; /* A non-zero gRPC status code has been seen */ - bool fail_state; + bool fail_state = false; /* Transport is discarding all buffered messages */ - bool flush_read; - bool flush_cronet_when_ready; - bool pending_write_for_trailer; - bool pending_send_message; + bool flush_read = false; + bool flush_cronet_when_ready = false; + bool pending_write_for_trailer = false; + bool pending_send_message = false; /* User requested RECV_TRAILING_METADATA */ - bool pending_recv_trailing_metadata; + bool pending_recv_trailing_metadata = false; /* Cronet has not issued a callback of a bidirectional read */ - bool pending_read_from_cronet; - grpc_error* cancel_error; + bool pending_read_from_cronet = false; + grpc_error* cancel_error = GRPC_ERROR_NONE; /* data structure for storing data coming from server */ struct read_state rs; /* data structure for storing data going to the server */ struct write_state ws; }; +struct stream_obj; + struct op_and_state { + op_and_state(stream_obj* s, const grpc_transport_stream_op_batch& op); + grpc_transport_stream_op_batch op; struct op_state state; - bool done; - struct stream_obj* s; /* Pointer back to the stream object */ - struct op_and_state* next; /* next op_and_state in the linked list */ + bool done = false; + struct stream_obj* s; /* Pointer back to the stream object */ + /* next op_and_state in the linked list */ + struct op_and_state* next; }; struct op_storage { - int num_pending_ops; - struct op_and_state* head; + int num_pending_ops = 0; + struct op_and_state* head = nullptr; }; struct stream_obj { + stream_obj(grpc_transport* gt, grpc_stream* gs, + grpc_stream_refcount* refcount, gpr_arena* arena); + ~stream_obj(); + gpr_arena* arena; - struct op_and_state* oas; - grpc_transport_stream_op_batch* curr_op; + struct op_and_state* oas = nullptr; + grpc_transport_stream_op_batch* curr_op = nullptr; grpc_cronet_transport* curr_ct; grpc_stream* curr_gs; - bidirectional_stream* cbs; - bidirectional_stream_header_array header_array; + bidirectional_stream* cbs = nullptr; + bidirectional_stream_header_array header_array = + bidirectional_stream_header_array(); // Zero-initialize the structure. /* Stream level state. Some state will be tracked both at stream and stream_op * level */ @@ -195,7 +212,6 @@ struct stream_obj { /* Refcount object of the stream */ grpc_stream_refcount* refcount; }; -typedef struct stream_obj stream_obj; #ifndef NDEBUG #define GRPC_CRONET_STREAM_REF(stream, reason) \ @@ -306,6 +322,10 @@ static grpc_error* make_error_with_desc(int error_code, const char* desc) { return error; } +inline op_and_state::op_and_state(stream_obj* s, + const grpc_transport_stream_op_batch& op) + : op(op), state(s->arena), s(s), next(s->storage.head) {} + /* Add a new stream op to op storage. */ @@ -314,14 +334,8 @@ static void add_to_storage(struct stream_obj* s, struct op_storage* storage = &s->storage; /* add new op at the beginning of the linked list. The memory is freed in remove_from_storage */ - struct op_and_state* new_op = static_cast<struct op_and_state*>( - gpr_malloc(sizeof(struct op_and_state))); - memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op_batch)); - memset(&new_op->state, 0, sizeof(new_op->state)); - new_op->s = s; - new_op->done = false; + op_and_state* new_op = grpc_core::New<op_and_state>(s, *op); gpr_mu_lock(&s->mu); - new_op->next = storage->head; storage->head = new_op; storage->num_pending_ops++; if (op->send_message) { @@ -347,7 +361,7 @@ static void remove_from_storage(struct stream_obj* s, } if (s->storage.head == oas) { s->storage.head = oas->next; - gpr_free(oas); + grpc_core::Delete(oas); s->storage.num_pending_ops--; CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas, s->storage.num_pending_ops); @@ -358,7 +372,7 @@ static void remove_from_storage(struct stream_obj* s, s->storage.num_pending_ops--; CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas, s->storage.num_pending_ops); - gpr_free(oas); + grpc_core::Delete(oas); break; } else if (GPR_UNLIKELY(curr->next == nullptr)) { CRONET_LOG(GPR_ERROR, "Reached end of LL and did not find op to free"); @@ -540,10 +554,6 @@ static void on_response_headers_received( } gpr_mu_lock(&s->mu); - memset(&s->state.rs.initial_metadata, 0, - sizeof(s->state.rs.initial_metadata)); - grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata, - s->arena); convert_cronet_array_to_metadata(headers, &s->state.rs.initial_metadata); s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true; if (!(s->state.state_op_done[OP_CANCEL_ERROR] || @@ -634,11 +644,7 @@ static void on_response_trailers_received( stream_obj* s = static_cast<stream_obj*>(stream->annotation); grpc_cronet_transport* t = s->curr_ct; gpr_mu_lock(&s->mu); - memset(&s->state.rs.trailing_metadata, 0, - sizeof(s->state.rs.trailing_metadata)); s->state.rs.trailing_metadata_valid = false; - grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata, - s->arena); convert_cronet_array_to_metadata(trailers, &s->state.rs.trailing_metadata); if (trailers->count > 0) { s->state.rs.trailing_metadata_valid = true; @@ -1354,36 +1360,28 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) { Functions used by upper layers to access transport functionality. */ +inline stream_obj::stream_obj(grpc_transport* gt, grpc_stream* gs, + grpc_stream_refcount* refcount, gpr_arena* arena) + : arena(arena), + curr_ct(reinterpret_cast<grpc_cronet_transport*>(gt)), + curr_gs(gs), + state(arena), + refcount(refcount) { + GRPC_CRONET_STREAM_REF(this, "cronet transport"); + gpr_mu_init(&mu); +} + +inline stream_obj::~stream_obj() { + null_and_maybe_free_read_buffer(this); + /* Clean up read_slice_buffer in case there is unread data. */ + grpc_slice_buffer_destroy_internal(&state.rs.read_slice_buffer); + GRPC_ERROR_UNREF(state.cancel_error); +} + static int init_stream(grpc_transport* gt, grpc_stream* gs, grpc_stream_refcount* refcount, const void* server_data, gpr_arena* arena) { - stream_obj* s = reinterpret_cast<stream_obj*>(gs); - - s->refcount = refcount; - GRPC_CRONET_STREAM_REF(s, "cronet transport"); - memset(&s->storage, 0, sizeof(s->storage)); - s->storage.head = nullptr; - memset(&s->state, 0, sizeof(s->state)); - s->curr_op = nullptr; - s->cbs = nullptr; - memset(&s->header_array, 0, sizeof(s->header_array)); - memset(&s->state.rs, 0, sizeof(s->state.rs)); - memset(&s->state.ws, 0, sizeof(s->state.ws)); - memset(s->state.state_op_done, 0, sizeof(s->state.state_op_done)); - memset(s->state.state_callback_received, 0, - sizeof(s->state.state_callback_received)); - s->state.fail_state = s->state.flush_read = false; - s->state.cancel_error = nullptr; - s->state.flush_cronet_when_ready = s->state.pending_write_for_trailer = false; - s->state.pending_send_message = false; - s->state.pending_recv_trailing_metadata = false; - s->state.pending_read_from_cronet = false; - - s->curr_gs = gs; - s->curr_ct = reinterpret_cast<grpc_cronet_transport*>(gt); - s->arena = arena; - - gpr_mu_init(&s->mu); + new (gs) stream_obj(gt, gs, refcount, arena); return 0; } @@ -1426,10 +1424,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, static void destroy_stream(grpc_transport* gt, grpc_stream* gs, grpc_closure* then_schedule_closure) { stream_obj* s = reinterpret_cast<stream_obj*>(gs); - null_and_maybe_free_read_buffer(s); - /* Clean up read_slice_buffer in case there is unread data. */ - grpc_slice_buffer_destroy_internal(&s->state.rs.read_slice_buffer); - GRPC_ERROR_UNREF(s->state.cancel_error); + s->~stream_obj(); GRPC_CLOSURE_SCHED(then_schedule_closure, GRPC_ERROR_NONE); } diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index 9dbd095843..61968de4d5 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -40,18 +40,68 @@ if (grpc_inproc_trace.enabled()) gpr_log(__VA_ARGS__); \ } while (0) -static grpc_slice g_empty_slice; -static grpc_slice g_fake_path_key; -static grpc_slice g_fake_path_value; -static grpc_slice g_fake_auth_key; -static grpc_slice g_fake_auth_value; +namespace { +grpc_slice g_empty_slice; +grpc_slice g_fake_path_key; +grpc_slice g_fake_path_value; +grpc_slice g_fake_auth_key; +grpc_slice g_fake_auth_value; + +struct inproc_stream; +bool cancel_stream_locked(inproc_stream* s, grpc_error* error); +void op_state_machine(void* arg, grpc_error* error); +void log_metadata(const grpc_metadata_batch* md_batch, bool is_client, + bool is_initial); +grpc_error* fill_in_metadata(inproc_stream* s, + const grpc_metadata_batch* metadata, + uint32_t flags, grpc_metadata_batch* out_md, + uint32_t* outflags, bool* markfilled); + +struct shared_mu { + shared_mu() { + // Share one lock between both sides since both sides get affected + gpr_mu_init(&mu); + gpr_ref_init(&refs, 2); + } -typedef struct { gpr_mu mu; gpr_refcount refs; -} shared_mu; +}; + +struct inproc_transport { + inproc_transport(const grpc_transport_vtable* vtable, shared_mu* mu, + bool is_client) + : mu(mu), is_client(is_client) { + base.vtable = vtable; + // Start each side of transport with 2 refs since they each have a ref + // to the other + gpr_ref_init(&refs, 2); + grpc_connectivity_state_init(&connectivity, GRPC_CHANNEL_READY, + is_client ? "inproc_client" : "inproc_server"); + } + + ~inproc_transport() { + grpc_connectivity_state_destroy(&connectivity); + if (gpr_unref(&mu->refs)) { + gpr_free(mu); + } + } + + void ref() { + INPROC_LOG(GPR_INFO, "ref_transport %p", this); + gpr_ref(&refs); + } + + void unref() { + INPROC_LOG(GPR_INFO, "unref_transport %p", this); + if (!gpr_unref(&refs)) { + return; + } + INPROC_LOG(GPR_INFO, "really_destroy_transport %p", this); + this->~inproc_transport(); + gpr_free(this); + } -typedef struct inproc_transport { grpc_transport base; shared_mu* mu; gpr_refcount refs; @@ -60,128 +110,174 @@ typedef struct inproc_transport { void (*accept_stream_cb)(void* user_data, grpc_transport* transport, const void* server_data); void* accept_stream_data; - bool is_closed; + bool is_closed = false; struct inproc_transport* other_side; - struct inproc_stream* stream_list; -} inproc_transport; + struct inproc_stream* stream_list = nullptr; +}; + +struct inproc_stream { + inproc_stream(inproc_transport* t, grpc_stream_refcount* refcount, + const void* server_data, gpr_arena* arena) + : t(t), refs(refcount), arena(arena) { + // Ref this stream right now for ctor and list. + ref("inproc_init_stream:init"); + ref("inproc_init_stream:list"); + + grpc_metadata_batch_init(&to_read_initial_md); + grpc_metadata_batch_init(&to_read_trailing_md); + GRPC_CLOSURE_INIT(&op_closure, op_state_machine, this, + grpc_schedule_on_exec_ctx); + grpc_metadata_batch_init(&write_buffer_initial_md); + grpc_metadata_batch_init(&write_buffer_trailing_md); + + stream_list_prev = nullptr; + gpr_mu_lock(&t->mu->mu); + stream_list_next = t->stream_list; + if (t->stream_list) { + t->stream_list->stream_list_prev = this; + } + t->stream_list = this; + gpr_mu_unlock(&t->mu->mu); + + if (!server_data) { + t->ref(); + inproc_transport* st = t->other_side; + st->ref(); + other_side = nullptr; // will get filled in soon + // Pass the client-side stream address to the server-side for a ref + ref("inproc_init_stream:clt"); // ref it now on behalf of server + // side to avoid destruction + INPROC_LOG(GPR_INFO, "calling accept stream cb %p %p", + st->accept_stream_cb, st->accept_stream_data); + (*st->accept_stream_cb)(st->accept_stream_data, &st->base, (void*)this); + } else { + // This is the server-side and is being called through accept_stream_cb + inproc_stream* cs = (inproc_stream*)server_data; + other_side = cs; + // Ref the server-side stream on behalf of the client now + ref("inproc_init_stream:srv"); + + // Now we are about to affect the other side, so lock the transport + // to make sure that it doesn't get destroyed + gpr_mu_lock(&t->mu->mu); + cs->other_side = this; + // Now transfer from the other side's write_buffer if any to the to_read + // buffer + if (cs->write_buffer_initial_md_filled) { + fill_in_metadata(this, &cs->write_buffer_initial_md, + cs->write_buffer_initial_md_flags, &to_read_initial_md, + &to_read_initial_md_flags, &to_read_initial_md_filled); + deadline = GPR_MIN(deadline, cs->write_buffer_deadline); + grpc_metadata_batch_clear(&cs->write_buffer_initial_md); + cs->write_buffer_initial_md_filled = false; + } + if (cs->write_buffer_trailing_md_filled) { + fill_in_metadata(this, &cs->write_buffer_trailing_md, 0, + &to_read_trailing_md, nullptr, + &to_read_trailing_md_filled); + grpc_metadata_batch_clear(&cs->write_buffer_trailing_md); + cs->write_buffer_trailing_md_filled = false; + } + if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) { + cancel_other_error = cs->write_buffer_cancel_error; + cs->write_buffer_cancel_error = GRPC_ERROR_NONE; + } + + gpr_mu_unlock(&t->mu->mu); + } + } + + ~inproc_stream() { + GRPC_ERROR_UNREF(write_buffer_cancel_error); + GRPC_ERROR_UNREF(cancel_self_error); + GRPC_ERROR_UNREF(cancel_other_error); + + if (recv_inited) { + grpc_slice_buffer_destroy_internal(&recv_message); + } + + t->unref(); + + if (closure_at_destroy) { + GRPC_CLOSURE_SCHED(closure_at_destroy, GRPC_ERROR_NONE); + } + } + +#ifndef NDEBUG +#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason) +#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs, reason) +#else +#define STREAM_REF(refs, reason) grpc_stream_ref(refs) +#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs) +#endif + void ref(const char* reason) { + INPROC_LOG(GPR_INFO, "ref_stream %p %s", this, reason); + STREAM_REF(refs, reason); + } + + void unref(const char* reason) { + INPROC_LOG(GPR_INFO, "unref_stream %p %s", this, reason); + STREAM_UNREF(refs, reason); + } +#undef STREAM_REF +#undef STREAM_UNREF -typedef struct inproc_stream { inproc_transport* t; grpc_metadata_batch to_read_initial_md; - uint32_t to_read_initial_md_flags; - bool to_read_initial_md_filled; + uint32_t to_read_initial_md_flags = 0; + bool to_read_initial_md_filled = false; grpc_metadata_batch to_read_trailing_md; - bool to_read_trailing_md_filled; - bool ops_needed; - bool op_closure_scheduled; + bool to_read_trailing_md_filled = false; + bool ops_needed = false; + bool op_closure_scheduled = false; grpc_closure op_closure; // Write buffer used only during gap at init time when client-side // stream is set up but server side stream is not yet set up grpc_metadata_batch write_buffer_initial_md; - bool write_buffer_initial_md_filled; - uint32_t write_buffer_initial_md_flags; - grpc_millis write_buffer_deadline; + bool write_buffer_initial_md_filled = false; + uint32_t write_buffer_initial_md_flags = 0; + grpc_millis write_buffer_deadline = GRPC_MILLIS_INF_FUTURE; grpc_metadata_batch write_buffer_trailing_md; - bool write_buffer_trailing_md_filled; - grpc_error* write_buffer_cancel_error; + bool write_buffer_trailing_md_filled = false; + grpc_error* write_buffer_cancel_error = GRPC_ERROR_NONE; struct inproc_stream* other_side; - bool other_side_closed; // won't talk anymore - bool write_buffer_other_side_closed; // on hold + bool other_side_closed = false; // won't talk anymore + bool write_buffer_other_side_closed = false; // on hold grpc_stream_refcount* refs; - grpc_closure* closure_at_destroy; + grpc_closure* closure_at_destroy = nullptr; gpr_arena* arena; - grpc_transport_stream_op_batch* send_message_op; - grpc_transport_stream_op_batch* send_trailing_md_op; - grpc_transport_stream_op_batch* recv_initial_md_op; - grpc_transport_stream_op_batch* recv_message_op; - grpc_transport_stream_op_batch* recv_trailing_md_op; + grpc_transport_stream_op_batch* send_message_op = nullptr; + grpc_transport_stream_op_batch* send_trailing_md_op = nullptr; + grpc_transport_stream_op_batch* recv_initial_md_op = nullptr; + grpc_transport_stream_op_batch* recv_message_op = nullptr; + grpc_transport_stream_op_batch* recv_trailing_md_op = nullptr; grpc_slice_buffer recv_message; grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> recv_stream; - bool recv_inited; + bool recv_inited = false; - bool initial_md_sent; - bool trailing_md_sent; - bool initial_md_recvd; - bool trailing_md_recvd; + bool initial_md_sent = false; + bool trailing_md_sent = false; + bool initial_md_recvd = false; + bool trailing_md_recvd = false; - bool closed; + bool closed = false; - grpc_error* cancel_self_error; - grpc_error* cancel_other_error; + grpc_error* cancel_self_error = GRPC_ERROR_NONE; + grpc_error* cancel_other_error = GRPC_ERROR_NONE; - grpc_millis deadline; + grpc_millis deadline = GRPC_MILLIS_INF_FUTURE; - bool listed; + bool listed = true; struct inproc_stream* stream_list_prev; struct inproc_stream* stream_list_next; -} inproc_stream; - -static bool cancel_stream_locked(inproc_stream* s, grpc_error* error); -static void op_state_machine(void* arg, grpc_error* error); - -static void ref_transport(inproc_transport* t) { - INPROC_LOG(GPR_INFO, "ref_transport %p", t); - gpr_ref(&t->refs); -} - -static void really_destroy_transport(inproc_transport* t) { - INPROC_LOG(GPR_INFO, "really_destroy_transport %p", t); - grpc_connectivity_state_destroy(&t->connectivity); - if (gpr_unref(&t->mu->refs)) { - gpr_free(t->mu); - } - gpr_free(t); -} - -static void unref_transport(inproc_transport* t) { - INPROC_LOG(GPR_INFO, "unref_transport %p", t); - if (gpr_unref(&t->refs)) { - really_destroy_transport(t); - } -} - -#ifndef NDEBUG -#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason) -#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs, reason) -#else -#define STREAM_REF(refs, reason) grpc_stream_ref(refs) -#define STREAM_UNREF(refs, reason) grpc_stream_unref(refs) -#endif - -static void ref_stream(inproc_stream* s, const char* reason) { - INPROC_LOG(GPR_INFO, "ref_stream %p %s", s, reason); - STREAM_REF(s->refs, reason); -} - -static void unref_stream(inproc_stream* s, const char* reason) { - INPROC_LOG(GPR_INFO, "unref_stream %p %s", s, reason); - STREAM_UNREF(s->refs, reason); -} - -static void really_destroy_stream(inproc_stream* s) { - INPROC_LOG(GPR_INFO, "really_destroy_stream %p", s); +}; - GRPC_ERROR_UNREF(s->write_buffer_cancel_error); - GRPC_ERROR_UNREF(s->cancel_self_error); - GRPC_ERROR_UNREF(s->cancel_other_error); - - if (s->recv_inited) { - grpc_slice_buffer_destroy_internal(&s->recv_message); - } - - unref_transport(s->t); - - if (s->closure_at_destroy) { - GRPC_CLOSURE_SCHED(s->closure_at_destroy, GRPC_ERROR_NONE); - } -} - -static void log_metadata(const grpc_metadata_batch* md_batch, bool is_client, - bool is_initial) { +void log_metadata(const grpc_metadata_batch* md_batch, bool is_client, + bool is_initial) { for (grpc_linked_mdelem* md = md_batch->list.head; md != nullptr; md = md->next) { char* key = grpc_slice_to_c_string(GRPC_MDKEY(md->md)); @@ -193,10 +289,10 @@ static void log_metadata(const grpc_metadata_batch* md_batch, bool is_client, } } -static grpc_error* fill_in_metadata(inproc_stream* s, - const grpc_metadata_batch* metadata, - uint32_t flags, grpc_metadata_batch* out_md, - uint32_t* outflags, bool* markfilled) { +grpc_error* fill_in_metadata(inproc_stream* s, + const grpc_metadata_batch* metadata, + uint32_t flags, grpc_metadata_batch* out_md, + uint32_t* outflags, bool* markfilled) { if (grpc_inproc_trace.enabled()) { log_metadata(metadata, s->t->is_client, outflags != nullptr); } @@ -221,109 +317,16 @@ static grpc_error* fill_in_metadata(inproc_stream* s, return error; } -static int init_stream(grpc_transport* gt, grpc_stream* gs, - grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { +int init_stream(grpc_transport* gt, grpc_stream* gs, + grpc_stream_refcount* refcount, const void* server_data, + gpr_arena* arena) { INPROC_LOG(GPR_INFO, "init_stream %p %p %p", gt, gs, server_data); inproc_transport* t = reinterpret_cast<inproc_transport*>(gt); - inproc_stream* s = reinterpret_cast<inproc_stream*>(gs); - s->arena = arena; - - s->refs = refcount; - // Ref this stream right now - ref_stream(s, "inproc_init_stream:init"); - - grpc_metadata_batch_init(&s->to_read_initial_md); - s->to_read_initial_md_flags = 0; - s->to_read_initial_md_filled = false; - grpc_metadata_batch_init(&s->to_read_trailing_md); - s->to_read_trailing_md_filled = false; - grpc_metadata_batch_init(&s->write_buffer_initial_md); - s->write_buffer_initial_md_flags = 0; - s->write_buffer_initial_md_filled = false; - grpc_metadata_batch_init(&s->write_buffer_trailing_md); - s->write_buffer_trailing_md_filled = false; - s->ops_needed = false; - s->op_closure_scheduled = false; - GRPC_CLOSURE_INIT(&s->op_closure, op_state_machine, s, - grpc_schedule_on_exec_ctx); - s->t = t; - s->closure_at_destroy = nullptr; - s->other_side_closed = false; - - s->initial_md_sent = s->trailing_md_sent = s->initial_md_recvd = - s->trailing_md_recvd = false; - - s->closed = false; - - s->cancel_self_error = GRPC_ERROR_NONE; - s->cancel_other_error = GRPC_ERROR_NONE; - s->write_buffer_cancel_error = GRPC_ERROR_NONE; - s->deadline = GRPC_MILLIS_INF_FUTURE; - s->write_buffer_deadline = GRPC_MILLIS_INF_FUTURE; - - s->stream_list_prev = nullptr; - gpr_mu_lock(&t->mu->mu); - s->listed = true; - ref_stream(s, "inproc_init_stream:list"); - s->stream_list_next = t->stream_list; - if (t->stream_list) { - t->stream_list->stream_list_prev = s; - } - t->stream_list = s; - gpr_mu_unlock(&t->mu->mu); - - if (!server_data) { - ref_transport(t); - inproc_transport* st = t->other_side; - ref_transport(st); - s->other_side = nullptr; // will get filled in soon - // Pass the client-side stream address to the server-side for a ref - ref_stream(s, "inproc_init_stream:clt"); // ref it now on behalf of server - // side to avoid destruction - INPROC_LOG(GPR_INFO, "calling accept stream cb %p %p", st->accept_stream_cb, - st->accept_stream_data); - (*st->accept_stream_cb)(st->accept_stream_data, &st->base, (void*)s); - } else { - // This is the server-side and is being called through accept_stream_cb - inproc_stream* cs = (inproc_stream*)server_data; - s->other_side = cs; - // Ref the server-side stream on behalf of the client now - ref_stream(s, "inproc_init_stream:srv"); - - // Now we are about to affect the other side, so lock the transport - // to make sure that it doesn't get destroyed - gpr_mu_lock(&s->t->mu->mu); - cs->other_side = s; - // Now transfer from the other side's write_buffer if any to the to_read - // buffer - if (cs->write_buffer_initial_md_filled) { - fill_in_metadata(s, &cs->write_buffer_initial_md, - cs->write_buffer_initial_md_flags, - &s->to_read_initial_md, &s->to_read_initial_md_flags, - &s->to_read_initial_md_filled); - s->deadline = GPR_MIN(s->deadline, cs->write_buffer_deadline); - grpc_metadata_batch_clear(&cs->write_buffer_initial_md); - cs->write_buffer_initial_md_filled = false; - } - if (cs->write_buffer_trailing_md_filled) { - fill_in_metadata(s, &cs->write_buffer_trailing_md, 0, - &s->to_read_trailing_md, nullptr, - &s->to_read_trailing_md_filled); - grpc_metadata_batch_clear(&cs->write_buffer_trailing_md); - cs->write_buffer_trailing_md_filled = false; - } - if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) { - s->cancel_other_error = cs->write_buffer_cancel_error; - cs->write_buffer_cancel_error = GRPC_ERROR_NONE; - } - - gpr_mu_unlock(&s->t->mu->mu); - } + new (gs) inproc_stream(t, refcount, server_data, arena); return 0; // return value is not important } -static void close_stream_locked(inproc_stream* s) { +void close_stream_locked(inproc_stream* s) { if (!s->closed) { // Release the metadata that we would have written out grpc_metadata_batch_destroy(&s->write_buffer_initial_md); @@ -341,21 +344,21 @@ static void close_stream_locked(inproc_stream* s) { n->stream_list_prev = p; } s->listed = false; - unref_stream(s, "close_stream:list"); + s->unref("close_stream:list"); } s->closed = true; - unref_stream(s, "close_stream:closing"); + s->unref("close_stream:closing"); } } // This function means that we are done talking/listening to the other side -static void close_other_side_locked(inproc_stream* s, const char* reason) { +void close_other_side_locked(inproc_stream* s, const char* reason) { if (s->other_side != nullptr) { // First release the metadata that came from the other side's arena grpc_metadata_batch_destroy(&s->to_read_initial_md); grpc_metadata_batch_destroy(&s->to_read_trailing_md); - unref_stream(s->other_side, reason); + s->other_side->unref(reason); s->other_side_closed = true; s->other_side = nullptr; } else if (!s->other_side_closed) { @@ -367,9 +370,9 @@ static void close_other_side_locked(inproc_stream* s, const char* reason) { // this stream_op_batch is only one of the pending operations for this // stream. This is called when one of the pending operations for the stream // is done and about to be NULLed out -static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error, - grpc_transport_stream_op_batch* op, - const char* msg) { +void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error, + grpc_transport_stream_op_batch* op, + const char* msg) { int is_sm = static_cast<int>(op == s->send_message_op); int is_stm = static_cast<int>(op == s->send_trailing_md_op); // TODO(vjpai): We should not consider the recv ops here, since they @@ -386,8 +389,7 @@ static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error, } } -static void maybe_schedule_op_closure_locked(inproc_stream* s, - grpc_error* error) { +void maybe_schedule_op_closure_locked(inproc_stream* s, grpc_error* error) { if (s && s->ops_needed && !s->op_closure_scheduled) { GRPC_CLOSURE_SCHED(&s->op_closure, GRPC_ERROR_REF(error)); s->op_closure_scheduled = true; @@ -395,7 +397,7 @@ static void maybe_schedule_op_closure_locked(inproc_stream* s, } } -static void fail_helper_locked(inproc_stream* s, grpc_error* error) { +void fail_helper_locked(inproc_stream* s, grpc_error* error) { INPROC_LOG(GPR_INFO, "op_state_machine %p fail_helper", s); // If we're failing this side, we need to make sure that // we also send or have already sent trailing metadata @@ -525,8 +527,7 @@ static void fail_helper_locked(inproc_stream* s, grpc_error* error) { // that the incoming byte stream's next() call will always return // synchronously. That assumption is true today but may not always be // true in the future. -static void message_transfer_locked(inproc_stream* sender, - inproc_stream* receiver) { +void message_transfer_locked(inproc_stream* sender, inproc_stream* receiver) { size_t remaining = sender->send_message_op->payload->send_message.send_message->length(); if (receiver->recv_inited) { @@ -572,7 +573,7 @@ static void message_transfer_locked(inproc_stream* sender, sender->send_message_op = nullptr; } -static void op_state_machine(void* arg, grpc_error* error) { +void op_state_machine(void* arg, grpc_error* error) { // This function gets called when we have contents in the unprocessed reads // Get what we want based on our ops wanted // Schedule our appropriate closures @@ -607,10 +608,8 @@ static void op_state_machine(void* arg, grpc_error* error) { if (other->recv_message_op) { message_transfer_locked(s, other); maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE); - } else if (!s->t->is_client && - (s->trailing_md_sent || other->recv_trailing_md_op)) { - // A server send will never be matched if the client is waiting - // for trailing metadata already + } else if (!s->t->is_client && s->trailing_md_sent) { + // A server send will never be matched if the server already sent status s->send_message_op->payload->send_message.send_message.reset(); complete_if_batch_end_locked( s, GRPC_ERROR_NONE, s->send_message_op, @@ -621,11 +620,15 @@ static void op_state_machine(void* arg, grpc_error* error) { // Pause a send trailing metadata if there is still an outstanding // send message unless we know that the send message will never get // matched to a receive. This happens on the client if the server has - // already sent status. + // already sent status or on the server if the client has requested + // status if (s->send_trailing_md_op && (!s->send_message_op || (s->t->is_client && - (s->trailing_md_recvd || s->to_read_trailing_md_filled)))) { + (s->trailing_md_recvd || s->to_read_trailing_md_filled)) || + (!s->t->is_client && other && + (other->trailing_md_recvd || other->to_read_trailing_md_filled || + other->recv_trailing_md_op)))) { grpc_metadata_batch* dest = (other == nullptr) ? &s->write_buffer_trailing_md : &other->to_read_trailing_md; @@ -723,16 +726,6 @@ static void op_state_machine(void* arg, grpc_error* error) { maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE); } } - if (s->recv_trailing_md_op && s->t->is_client && other && - other->send_message_op) { - INPROC_LOG(GPR_INFO, - "op_state_machine %p scheduling trailing-metadata-ready %p", s, - GRPC_ERROR_NONE); - GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_NONE); - maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE); - } if (s->to_read_trailing_md_filled) { if (s->trailing_md_recvd) { new_err = @@ -748,6 +741,7 @@ static void op_state_machine(void* arg, grpc_error* error) { if (s->recv_message_op != nullptr) { // This message needs to be wrapped up because it will never be // satisfied + *s->recv_message_op->payload->recv_message.recv_message = nullptr; INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s); GRPC_CLOSURE_SCHED( s->recv_message_op->payload->recv_message.recv_message_ready, @@ -810,6 +804,7 @@ static void op_state_machine(void* arg, grpc_error* error) { // No further message will come on this stream, so finish off the // recv_message_op INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s); + *s->recv_message_op->payload->recv_message.recv_message = nullptr; GRPC_CLOSURE_SCHED( s->recv_message_op->payload->recv_message.recv_message_ready, GRPC_ERROR_NONE); @@ -847,7 +842,7 @@ done: GRPC_ERROR_UNREF(new_err); } -static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) { +bool cancel_stream_locked(inproc_stream* s, grpc_error* error) { bool ret = false; // was the cancel accepted INPROC_LOG(GPR_INFO, "cancel_stream %p with %s", s, grpc_error_string(error)); if (s->cancel_self_error == GRPC_ERROR_NONE) { @@ -900,10 +895,10 @@ static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) { return ret; } -static void do_nothing(void* arg, grpc_error* error) {} +void do_nothing(void* arg, grpc_error* error) {} -static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, - grpc_transport_stream_op_batch* op) { +void perform_stream_op(grpc_transport* gt, grpc_stream* gs, + grpc_transport_stream_op_batch* op) { INPROC_LOG(GPR_INFO, "perform_stream_op %p %p %p", gt, gs, op); inproc_stream* s = reinterpret_cast<inproc_stream*>(gs); gpr_mu* mu = &s->t->mu->mu; // save aside in case s gets closed @@ -1012,18 +1007,18 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, } // We want to initiate the closure if: - // 1. We want to send a message and the other side wants to receive or end + // 1. We want to send a message and the other side wants to receive // 2. We want to send trailing metadata and there isn't an unmatched send + // or the other side wants trailing metadata // 3. We want initial metadata and the other side has sent it // 4. We want to receive a message and there is a message ready // 5. There is trailing metadata, even if nothing specifically wants // that because that can shut down the receive message as well - if ((op->send_message && other && - ((other->recv_message_op != nullptr) || - (other->recv_trailing_md_op != nullptr))) || - (op->send_trailing_metadata && !op->send_message) || + if ((op->send_message && other && other->recv_message_op != nullptr) || + (op->send_trailing_metadata && + (!s->send_message_op || (other && other->recv_trailing_md_op))) || (op->recv_initial_metadata && s->to_read_initial_md_filled) || - (op->recv_message && other && (other->send_message_op != nullptr)) || + (op->recv_message && other && other->send_message_op != nullptr) || (s->to_read_trailing_md_filled || s->trailing_md_recvd)) { if (!s->op_closure_scheduled) { GRPC_CLOSURE_SCHED(&s->op_closure, GRPC_ERROR_NONE); @@ -1083,7 +1078,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, GRPC_ERROR_UNREF(error); } -static void close_transport_locked(inproc_transport* t) { +void close_transport_locked(inproc_transport* t) { INPROC_LOG(GPR_INFO, "close_transport %p %d", t, t->is_closed); grpc_connectivity_state_set( &t->connectivity, GRPC_CHANNEL_SHUTDOWN, @@ -1103,7 +1098,7 @@ static void close_transport_locked(inproc_transport* t) { } } -static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { +void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { inproc_transport* t = reinterpret_cast<inproc_transport*>(gt); INPROC_LOG(GPR_INFO, "perform_transport_op %p %p", t, op); gpr_mu_lock(&t->mu->mu); @@ -1136,39 +1131,64 @@ static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { gpr_mu_unlock(&t->mu->mu); } -static void destroy_stream(grpc_transport* gt, grpc_stream* gs, - grpc_closure* then_schedule_closure) { +void destroy_stream(grpc_transport* gt, grpc_stream* gs, + grpc_closure* then_schedule_closure) { INPROC_LOG(GPR_INFO, "destroy_stream %p %p", gs, then_schedule_closure); inproc_stream* s = reinterpret_cast<inproc_stream*>(gs); s->closure_at_destroy = then_schedule_closure; - really_destroy_stream(s); + s->~inproc_stream(); } -static void destroy_transport(grpc_transport* gt) { +void destroy_transport(grpc_transport* gt) { inproc_transport* t = reinterpret_cast<inproc_transport*>(gt); INPROC_LOG(GPR_INFO, "destroy_transport %p", t); gpr_mu_lock(&t->mu->mu); close_transport_locked(t); gpr_mu_unlock(&t->mu->mu); - unref_transport(t->other_side); - unref_transport(t); + t->other_side->unref(); + t->unref(); } /******************************************************************************* * INTEGRATION GLUE */ -static void set_pollset(grpc_transport* gt, grpc_stream* gs, - grpc_pollset* pollset) { +void set_pollset(grpc_transport* gt, grpc_stream* gs, grpc_pollset* pollset) { // Nothing to do here } -static void set_pollset_set(grpc_transport* gt, grpc_stream* gs, - grpc_pollset_set* pollset_set) { +void set_pollset_set(grpc_transport* gt, grpc_stream* gs, + grpc_pollset_set* pollset_set) { // Nothing to do here } -static grpc_endpoint* get_endpoint(grpc_transport* t) { return nullptr; } +grpc_endpoint* get_endpoint(grpc_transport* t) { return nullptr; } + +const grpc_transport_vtable inproc_vtable = { + sizeof(inproc_stream), "inproc", init_stream, + set_pollset, set_pollset_set, perform_stream_op, + perform_transport_op, destroy_stream, destroy_transport, + get_endpoint}; + +/******************************************************************************* + * Main inproc transport functions + */ +void inproc_transports_create(grpc_transport** server_transport, + const grpc_channel_args* server_args, + grpc_transport** client_transport, + const grpc_channel_args* client_args) { + INPROC_LOG(GPR_INFO, "inproc_transports_create"); + shared_mu* mu = new (gpr_malloc(sizeof(*mu))) shared_mu(); + inproc_transport* st = new (gpr_malloc(sizeof(*st))) + inproc_transport(&inproc_vtable, mu, /*is_client=*/false); + inproc_transport* ct = new (gpr_malloc(sizeof(*ct))) + inproc_transport(&inproc_vtable, mu, /*is_client=*/true); + st->other_side = ct; + ct->other_side = st; + *server_transport = reinterpret_cast<grpc_transport*>(st); + *client_transport = reinterpret_cast<grpc_transport*>(ct); +} +} // namespace /******************************************************************************* * GLOBAL INIT AND DESTROY @@ -1190,48 +1210,6 @@ void grpc_inproc_transport_init(void) { g_fake_auth_value = grpc_slice_from_static_string("inproc-fail"); } -static const grpc_transport_vtable inproc_vtable = { - sizeof(inproc_stream), "inproc", init_stream, - set_pollset, set_pollset_set, perform_stream_op, - perform_transport_op, destroy_stream, destroy_transport, - get_endpoint}; - -/******************************************************************************* - * Main inproc transport functions - */ -static void inproc_transports_create(grpc_transport** server_transport, - const grpc_channel_args* server_args, - grpc_transport** client_transport, - const grpc_channel_args* client_args) { - INPROC_LOG(GPR_INFO, "inproc_transports_create"); - inproc_transport* st = - static_cast<inproc_transport*>(gpr_zalloc(sizeof(*st))); - inproc_transport* ct = - static_cast<inproc_transport*>(gpr_zalloc(sizeof(*ct))); - // Share one lock between both sides since both sides get affected - st->mu = ct->mu = static_cast<shared_mu*>(gpr_malloc(sizeof(*st->mu))); - gpr_mu_init(&st->mu->mu); - gpr_ref_init(&st->mu->refs, 2); - st->base.vtable = &inproc_vtable; - ct->base.vtable = &inproc_vtable; - // Start each side of transport with 2 refs since they each have a ref - // to the other - gpr_ref_init(&st->refs, 2); - gpr_ref_init(&ct->refs, 2); - st->is_client = false; - ct->is_client = true; - grpc_connectivity_state_init(&st->connectivity, GRPC_CHANNEL_READY, - "inproc_server"); - grpc_connectivity_state_init(&ct->connectivity, GRPC_CHANNEL_READY, - "inproc_client"); - st->other_side = ct; - ct->other_side = st; - st->stream_list = nullptr; - ct->stream_list = nullptr; - *server_transport = reinterpret_cast<grpc_transport*>(st); - *client_transport = reinterpret_cast<grpc_transport*>(ct); -} - grpc_channel* grpc_inproc_channel_create(grpc_server* server, grpc_channel_args* args, void* reserved) { diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc index 056fcd93de..df956c7176 100644 --- a/src/core/lib/channel/channel_stack.cc +++ b/src/core/lib/channel/channel_stack.cc @@ -157,7 +157,6 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack, size_t count = channel_stack->count; grpc_call_element* call_elems; char* user_data; - size_t i; elem_args->call_stack->count = count; GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy, @@ -168,10 +167,14 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack, /* init per-filter data */ grpc_error* first_error = GRPC_ERROR_NONE; - for (i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].call_data = user_data; + user_data += + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); + } + for (size_t i = 0; i < count; i++) { grpc_error* error = call_elems[i].filter->init_call_elem(&call_elems[i], elem_args); if (error != GRPC_ERROR_NONE) { @@ -181,8 +184,6 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack, GRPC_ERROR_UNREF(error); } } - user_data += - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); } return first_error; } diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 35c3fb01ea..0de8c67079 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -79,11 +79,11 @@ typedef struct { } grpc_call_stats; /** Information about the call upon completion. */ -typedef struct { +struct grpc_call_final_info { grpc_call_stats stats; - grpc_status_code final_status; - const char* error_string; -} grpc_call_final_info; + grpc_status_code final_status = GRPC_STATUS_OK; + const char* error_string = nullptr; +}; /* Channel filters specify: 1. the amount of memory needed in the channel & call (via the sizeof_XXX diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 032654b861..8d589f5983 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -30,15 +30,18 @@ #include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/channel/status_util.h" +#include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/slice/b64.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/server.h" #include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/uri/uri_parser.h" namespace grpc_core { namespace channelz { @@ -277,7 +280,61 @@ grpc_json* ServerNode::RenderJson() { return top_level_json; } -SocketNode::SocketNode() : BaseNode(EntityType::kSocket) {} +static void PopulateSocketAddressJson(grpc_json* json, const char* name, + const char* addr_str) { + if (addr_str == nullptr) return; + grpc_json* json_iterator = nullptr; + json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + grpc_uri* uri = grpc_uri_parse(addr_str, true); + if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) || + (strcmp(uri->scheme, "ipv6") == 0))) { + const char* host_port = uri->path; + if (*host_port == '/') ++host_port; + char* host = nullptr; + char* port = nullptr; + GPR_ASSERT(gpr_split_host_port(host_port, &host, &port)); + int port_num = -1; + if (port != nullptr) { + port_num = atoi(port); + } + char* b64_host = grpc_base64_encode(host, strlen(host), false, false); + json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address", + nullptr, GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_add_number_string_child(json, json_iterator, + "port", port_num); + json_iterator = grpc_json_create_child(json_iterator, json, "ip_address", + b64_host, GRPC_JSON_STRING, true); + gpr_free(host); + gpr_free(port); + + } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) { + json_iterator = grpc_json_create_child(json_iterator, json, "uds_address", + nullptr, GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = + grpc_json_create_child(json_iterator, json, "filename", + gpr_strdup(uri->path), GRPC_JSON_STRING, true); + } else { + json_iterator = grpc_json_create_child(json_iterator, json, "other_address", + nullptr, GRPC_JSON_OBJECT, false); + json = json_iterator; + json_iterator = nullptr; + json_iterator = grpc_json_create_child(json_iterator, json, "name", + addr_str, GRPC_JSON_STRING, false); + } + grpc_uri_destroy(uri); +} + +SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote) + : BaseNode(EntityType::kSocket), + local_(std::move(local)), + remote_(std::move(remote)) {} void SocketNode::RecordStreamStartedFromLocal() { gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1)); @@ -315,6 +372,9 @@ grpc_json* SocketNode::RenderJson() { json_iterator = nullptr; json_iterator = grpc_json_add_number_string_child(json, json_iterator, "socketId", uuid()); + json = top_level_json; + PopulateSocketAddressJson(json, "remote", remote_.get()); + PopulateSocketAddressJson(json, "local", local_.get()); // reset json iterators to top level object json = top_level_json; json_iterator = nullptr; @@ -374,8 +434,8 @@ grpc_json* SocketNode::RenderJson() { return top_level_json; } -ListenSocketNode::ListenSocketNode(UniquePtr<char> host, int port) - : BaseNode(EntityType::kSocket), host_(std::move(host)), port_(port) {} +ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr) + : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {} grpc_json* ListenSocketNode::RenderJson() { // We need to track these three json objects to build our object @@ -390,19 +450,7 @@ grpc_json* ListenSocketNode::RenderJson() { json_iterator = grpc_json_add_number_string_child(json, json_iterator, "socketId", uuid()); json = top_level_json; - json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "local", nullptr, - GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address", - nullptr, GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = - grpc_json_add_number_string_child(json, json_iterator, "port", port_); - json_iterator = grpc_json_create_child(json_iterator, json, "ip_address", - host_.get(), GRPC_JSON_STRING, false); + PopulateSocketAddressJson(json, "local", local_addr_.get()); return top_level_json; } diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 8e66623142..64ab5cb3a6 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -232,7 +232,7 @@ class ServerNode : public BaseNode { // Handles channelz bookkeeping for sockets class SocketNode : public BaseNode { public: - SocketNode(); + SocketNode(UniquePtr<char> local, UniquePtr<char> remote); ~SocketNode() override {} grpc_json* RenderJson() override; @@ -262,21 +262,21 @@ class SocketNode : public BaseNode { gpr_atm last_remote_stream_created_millis_ = 0; gpr_atm last_message_sent_millis_ = 0; gpr_atm last_message_received_millis_ = 0; - UniquePtr<char> peer_string_; + UniquePtr<char> local_; + UniquePtr<char> remote_; }; // Handles channelz bookkeeping for listen sockets class ListenSocketNode : public BaseNode { public: // ListenSocketNode takes ownership of host. - ListenSocketNode(UniquePtr<char> host, int port); + explicit ListenSocketNode(UniquePtr<char> local_addr); ~ListenSocketNode() override {} grpc_json* RenderJson() override; private: - UniquePtr<char> host_; - int port_; + UniquePtr<char> local_addr_; }; // Creation functions diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc index 8fc1b58adc..bc23b90a66 100644 --- a/src/core/lib/channel/channelz_registry.cc +++ b/src/core/lib/channel/channelz_registry.cc @@ -210,6 +210,17 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { return json_str; } +void ChannelzRegistry::InternalLogAllEntities() { + MutexLock lock(&mu_); + for (size_t i = 0; i < entities_.size(); ++i) { + if (entities_[i] != nullptr) { + char* json = entities_[i]->RenderJsonString(); + gpr_log(GPR_INFO, "%s", json); + gpr_free(json); + } + } +} + } // namespace channelz } // namespace grpc_core diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h index 326f0201c7..73b330785d 100644 --- a/src/core/lib/channel/channelz_registry.h +++ b/src/core/lib/channel/channelz_registry.h @@ -62,6 +62,10 @@ class ChannelzRegistry { return Default()->InternalGetServers(start_server_id); } + // Test only helper function to dump the JSON representation to std out. + // This can aid in debugging channelz code. + static void LogAllEntities() { Default()->InternalLogAllEntities(); } + private: GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE @@ -96,6 +100,8 @@ class ChannelzRegistry { // Else, will return idx of the first uuid higher than the target. int FindByUuidLocked(intptr_t uuid, bool direct_hit_needed); + void InternalLogAllEntities(); + // protects members gpr_mu mu_; InlinedVector<BaseNode*, 20> entities_; diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h index 5daf48a9a9..763e4ffc9f 100644 --- a/src/core/lib/channel/context.h +++ b/src/core/lib/channel/context.h @@ -41,9 +41,9 @@ typedef enum { GRPC_CONTEXT_COUNT } grpc_context_index; -typedef struct { - void* value; - void (*destroy)(void*); -} grpc_call_context_element; +struct grpc_call_context_element { + void* value = nullptr; + void (*destroy)(void*) = nullptr; +}; #endif /* GRPC_CORE_LIB_CHANNEL_CONTEXT_H */ diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc index 77f9357146..836a7ca793 100644 --- a/src/core/lib/gpr/arena.cc +++ b/src/core/lib/gpr/arena.cc @@ -21,6 +21,7 @@ #include "src/core/lib/gpr/arena.h" #include <string.h> +#include <new> #include <grpc/support/alloc.h> #include <grpc/support/atm.h> @@ -28,34 +29,79 @@ #include <grpc/support/sync.h> #include "src/core/lib/gpr/alloc.h" +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/memory.h" + +namespace { +enum init_strategy { + NO_INIT, // Do not initialize the arena blocks. + ZERO_INIT, // Initialize arena blocks with 0. + NON_ZERO_INIT, // Initialize arena blocks with a non-zero value. +}; + +gpr_once g_init_strategy_once = GPR_ONCE_INIT; +init_strategy g_init_strategy = NO_INIT; +} // namespace + +static void set_strategy_from_env() { + char* str = gpr_getenv("GRPC_ARENA_INIT_STRATEGY"); + if (str == nullptr) { + g_init_strategy = NO_INIT; + } else if (strcmp(str, "zero_init") == 0) { + g_init_strategy = ZERO_INIT; + } else if (strcmp(str, "non_zero_init") == 0) { + g_init_strategy = NON_ZERO_INIT; + } else { + g_init_strategy = NO_INIT; + } + gpr_free(str); +} + +static void* gpr_arena_alloc_maybe_init(size_t size) { + void* mem = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT); + gpr_once_init(&g_init_strategy_once, set_strategy_from_env); + if (GPR_UNLIKELY(g_init_strategy != NO_INIT)) { + if (g_init_strategy == ZERO_INIT) { + memset(mem, 0, size); + } else { // NON_ZERO_INIT. + memset(mem, 0xFE, size); + } + } + return mem; +} + +void gpr_arena_init() { + gpr_once_init(&g_init_strategy_once, set_strategy_from_env); +} // Uncomment this to use a simple arena that simply allocates the // requested amount of memory for each call to gpr_arena_alloc(). This // effectively eliminates the efficiency gain of using an arena, but it // may be useful for debugging purposes. //#define SIMPLE_ARENA_FOR_DEBUGGING - #ifdef SIMPLE_ARENA_FOR_DEBUGGING struct gpr_arena { + gpr_arena() { gpr_mu_init(&mu); } + ~gpr_arena() { + gpr_mu_destroy(&mu); + for (size_t i = 0; i < num_ptrs; ++i) { + gpr_free_aligned(ptrs[i]); + } + gpr_free(ptrs); + } + gpr_mu mu; - void** ptrs; - size_t num_ptrs; + void** ptrs = nullptr; + size_t num_ptrs = 0; }; gpr_arena* gpr_arena_create(size_t ignored_initial_size) { - gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena)); - gpr_mu_init(&arena->mu); - return arena; + return grpc_core::New<gpr_arena>(); } size_t gpr_arena_destroy(gpr_arena* arena) { - gpr_mu_destroy(&arena->mu); - for (size_t i = 0; i < arena->num_ptrs; ++i) { - gpr_free(arena->ptrs[i]); - } - gpr_free(arena->ptrs); - gpr_free(arena); + grpc_core::Delete(arena); return 1; // Value doesn't matter, since it won't be used. } @@ -63,7 +109,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { gpr_mu_lock(&arena->mu); arena->ptrs = (void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1)); - void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size); + void* retval = arena->ptrs[arena->num_ptrs++] = + gpr_arena_alloc_maybe_init(size); gpr_mu_unlock(&arena->mu); return retval; } @@ -77,45 +124,45 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { // would allow us to use the alignment actually needed by the caller. typedef struct zone { - zone* next; + zone* next = nullptr; } zone; struct gpr_arena { + gpr_arena(size_t initial_size) + : initial_zone_size(initial_size), last_zone(&initial_zone) { + gpr_mu_init(&arena_growth_mutex); + } + ~gpr_arena() { + gpr_mu_destroy(&arena_growth_mutex); + zone* z = initial_zone.next; + while (z) { + zone* next_z = z->next; + z->~zone(); + gpr_free_aligned(z); + z = next_z; + } + } + // Keep track of the total used size. We use this in our call sizing // historesis. - gpr_atm total_used; + gpr_atm total_used = 0; size_t initial_zone_size; zone initial_zone; zone* last_zone; gpr_mu arena_growth_mutex; }; -static void* zalloc_aligned(size_t size) { - void* ptr = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT); - memset(ptr, 0, size); - return ptr; -} - gpr_arena* gpr_arena_create(size_t initial_size) { initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); - gpr_arena* a = static_cast<gpr_arena*>(zalloc_aligned( - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)); - a->initial_zone_size = initial_size; - a->last_zone = &a->initial_zone; - gpr_mu_init(&a->arena_growth_mutex); - return a; + return new (gpr_arena_alloc_maybe_init( + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)) + gpr_arena(initial_size); } size_t gpr_arena_destroy(gpr_arena* arena) { - gpr_mu_destroy(&arena->arena_growth_mutex); - gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); - zone* z = arena->initial_zone.next; + const gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); + arena->~gpr_arena(); gpr_free_aligned(arena); - while (z) { - zone* next_z = z->next; - gpr_free_aligned(z); - z = next_z; - } return static_cast<size_t>(size); } @@ -132,8 +179,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { // sizing historesis (that is, most calls should have a large enough initial // zone and will not need to grow the arena). gpr_mu_lock(&arena->arena_growth_mutex); - zone* z = static_cast<zone*>( - zalloc_aligned(GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)); + zone* z = new (gpr_arena_alloc_maybe_init( + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)) zone(); arena->last_zone->next = z; arena->last_zone = z; gpr_mu_unlock(&arena->arena_growth_mutex); diff --git a/src/core/lib/gpr/arena.h b/src/core/lib/gpr/arena.h index 6d2a073dd5..069892b228 100644 --- a/src/core/lib/gpr/arena.h +++ b/src/core/lib/gpr/arena.h @@ -37,5 +37,7 @@ gpr_arena* gpr_arena_create(size_t initial_size); void* gpr_arena_alloc(gpr_arena* arena, size_t size); // Destroy an arena, returning the total number of bytes allocated size_t gpr_arena_destroy(gpr_arena* arena); +// Initializes the Arena component. +void gpr_arena_init(); #endif /* GRPC_CORE_LIB_GPR_ARENA_H */ diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc index 00a839b64c..90dda45ba3 100644 --- a/src/core/lib/iomgr/call_combiner.cc +++ b/src/core/lib/iomgr/call_combiner.cc @@ -40,6 +40,8 @@ static gpr_atm encode_cancel_state_error(grpc_error* error) { } void grpc_call_combiner_init(grpc_call_combiner* call_combiner) { + gpr_atm_no_barrier_store(&call_combiner->cancel_state, 0); + gpr_atm_no_barrier_store(&call_combiner->size, 0); gpr_mpscq_init(&call_combiner->queue); } diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h index 6f7ddd4043..c943fb1557 100644 --- a/src/core/lib/iomgr/call_combiner.h +++ b/src/core/lib/iomgr/call_combiner.h @@ -41,12 +41,12 @@ extern grpc_core::TraceFlag grpc_call_combiner_trace; typedef struct { - gpr_atm size; // size_t, num closures in queue or currently executing + gpr_atm size = 0; // size_t, num closures in queue or currently executing gpr_mpscq queue; // Either 0 (if not cancelled and no cancellation closure set), // a grpc_closure* (if the lowest bit is 0), // or a grpc_error* (if the lowest bit is 1). - gpr_atm cancel_state; + gpr_atm cancel_state = 0; } grpc_call_combiner; // Assumes memory was initialized to zero. diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index f14c723844..bde3437c02 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -114,6 +114,7 @@ inline grpc_closure* grpc_closure_init(grpc_closure* closure, closure->cb = cb; closure->cb_arg = cb_arg; closure->scheduler = scheduler; + closure->error_data.error = GRPC_ERROR_NONE; #ifndef NDEBUG closure->scheduled = false; closure->file_initiated = nullptr; diff --git a/src/core/lib/iomgr/polling_entity.h b/src/core/lib/iomgr/polling_entity.h index a95e08524c..6f4c5bdd66 100644 --- a/src/core/lib/iomgr/polling_entity.h +++ b/src/core/lib/iomgr/polling_entity.h @@ -34,13 +34,13 @@ typedef enum grpc_pollset_tag { * functions that accept a pollset XOR a pollset_set to do so through an * abstract interface. No ownership is taken. */ -typedef struct grpc_polling_entity { +struct grpc_polling_entity { union { - grpc_pollset* pollset; + grpc_pollset* pollset = nullptr; grpc_pollset_set* pollset_set; } pollent; - grpc_pollset_tag tag; -} grpc_polling_entity; + grpc_pollset_tag tag = GRPC_POLLS_NONE; +}; grpc_polling_entity grpc_polling_entity_create_from_pollset_set( grpc_pollset_set* pollset_set); diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc index bdfc1d70c3..c4b3a9336d 100644 --- a/src/core/lib/iomgr/socket_utils_common_posix.cc +++ b/src/core/lib/iomgr/socket_utils_common_posix.cc @@ -302,8 +302,9 @@ grpc_error* grpc_set_socket_tcp_user_timeout( return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)"); } if (newval != timeout) { - return GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Failed to set TCP_USER_TIMEOUT"); + /* Do not fail on failing to set TCP_USER_TIMEOUT for now. */ + gpr_log(GPR_ERROR, "Failed to set TCP_USER_TIMEOUT"); + return GRPC_ERROR_NONE; } } #else diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc index 94c9c69fcd..16f40b4f55 100644 --- a/src/core/lib/security/context/security_context.cc +++ b/src/core/lib/security/context/security_context.cc @@ -81,38 +81,45 @@ void grpc_auth_context_release(grpc_auth_context* context) { } /* --- grpc_client_security_context --- */ +grpc_client_security_context::~grpc_client_security_context() { + grpc_call_credentials_unref(creds); + GRPC_AUTH_CONTEXT_UNREF(auth_context, "client_security_context"); + if (extension.instance != nullptr && extension.destroy != nullptr) { + extension.destroy(extension.instance); + } +} grpc_client_security_context* grpc_client_security_context_create( gpr_arena* arena) { - return static_cast<grpc_client_security_context*>( - gpr_arena_alloc(arena, sizeof(grpc_client_security_context))); + return new (gpr_arena_alloc(arena, sizeof(grpc_client_security_context))) + grpc_client_security_context(); } void grpc_client_security_context_destroy(void* ctx) { grpc_core::ExecCtx exec_ctx; grpc_client_security_context* c = static_cast<grpc_client_security_context*>(ctx); - grpc_call_credentials_unref(c->creds); - GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); - if (c->extension.instance != nullptr && c->extension.destroy != nullptr) { - c->extension.destroy(c->extension.instance); - } + c->~grpc_client_security_context(); } /* --- grpc_server_security_context --- */ +grpc_server_security_context::~grpc_server_security_context() { + GRPC_AUTH_CONTEXT_UNREF(auth_context, "server_security_context"); + if (extension.instance != nullptr && extension.destroy != nullptr) { + extension.destroy(extension.instance); + } +} + grpc_server_security_context* grpc_server_security_context_create( gpr_arena* arena) { - return static_cast<grpc_server_security_context*>( - gpr_arena_alloc(arena, sizeof(grpc_server_security_context))); + return new (gpr_arena_alloc(arena, sizeof(grpc_server_security_context))) + grpc_server_security_context(); } void grpc_server_security_context_destroy(void* ctx) { grpc_server_security_context* c = static_cast<grpc_server_security_context*>(ctx); - GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context"); - if (c->extension.instance != nullptr && c->extension.destroy != nullptr) { - c->extension.destroy(c->extension.instance); - } + c->~grpc_server_security_context(); } /* --- grpc_auth_context --- */ diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h index a8e1c3fd64..e45415f63b 100644 --- a/src/core/lib/security/context/security_context.h +++ b/src/core/lib/security/context/security_context.h @@ -34,18 +34,20 @@ struct gpr_arena; /* Property names are always NULL terminated. */ -typedef struct { - grpc_auth_property* array; - size_t count; - size_t capacity; -} grpc_auth_property_array; +struct grpc_auth_property_array { + grpc_auth_property* array = nullptr; + size_t count = 0; + size_t capacity = 0; +}; struct grpc_auth_context { - struct grpc_auth_context* chained; + grpc_auth_context() { gpr_ref_init(&refcount, 0); } + + struct grpc_auth_context* chained = nullptr; grpc_auth_property_array properties; gpr_refcount refcount; - const char* peer_identity_property_name; - grpc_pollset* pollset; + const char* peer_identity_property_name = nullptr; + grpc_pollset* pollset = nullptr; }; /* Creation. */ @@ -76,20 +78,23 @@ void grpc_auth_property_reset(grpc_auth_property* property); Extension to the security context that may be set in a filter and accessed later by a higher level method on a grpc_call object. */ -typedef struct { - void* instance; - void (*destroy)(void*); -} grpc_security_context_extension; +struct grpc_security_context_extension { + void* instance = nullptr; + void (*destroy)(void*) = nullptr; +}; /* --- grpc_client_security_context --- Internal client-side security context. */ -typedef struct { - grpc_call_credentials* creds; - grpc_auth_context* auth_context; +struct grpc_client_security_context { + grpc_client_security_context() = default; + ~grpc_client_security_context(); + + grpc_call_credentials* creds = nullptr; + grpc_auth_context* auth_context = nullptr; grpc_security_context_extension extension; -} grpc_client_security_context; +}; grpc_client_security_context* grpc_client_security_context_create( gpr_arena* arena); @@ -99,10 +104,13 @@ void grpc_client_security_context_destroy(void* ctx); Internal server-side security context. */ -typedef struct { - grpc_auth_context* auth_context; +struct grpc_server_security_context { + grpc_server_security_context() = default; + ~grpc_server_security_context(); + + grpc_auth_context* auth_context = nullptr; grpc_security_context_extension extension; -} grpc_server_security_context; +}; grpc_server_security_context* grpc_server_security_context_create( gpr_arena* arena); diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index b486d25ab2..3878958b38 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -142,8 +142,8 @@ grpc_channel_credentials* grpc_channel_credentials_find_in_args( /* --- grpc_credentials_mdelem_array. --- */ typedef struct { - grpc_mdelem* md; - size_t size; + grpc_mdelem* md = nullptr; + size_t size = 0; } grpc_credentials_mdelem_array; /// Takes a new ref to \a md. diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc index e34eacc8d7..6955e8698e 100644 --- a/src/core/lib/security/transport/client_auth_filter.cc +++ b/src/core/lib/security/transport/client_auth_filter.cc @@ -43,20 +43,39 @@ namespace { /* We can have a per-call credentials. */ struct call_data { + call_data(grpc_call_element* elem, const grpc_call_element_args& args) + : arena(args.arena), + owning_call(args.call_stack), + call_combiner(args.call_combiner) {} + + // This method is technically the dtor of this class. However, since + // `get_request_metadata_cancel_closure` can run in parallel to + // `destroy_call_elem`, we cannot call the dtor in them. Otherwise, + // fields will be accessed after calling dtor, and msan correctly complains + // that the memory is not initialized. + void destroy() { + grpc_credentials_mdelem_array_destroy(&md_array); + grpc_call_credentials_unref(creds); + grpc_slice_unref_internal(host); + grpc_slice_unref_internal(method); + grpc_auth_metadata_context_reset(&auth_md_context); + } + gpr_arena* arena; grpc_call_stack* owning_call; grpc_call_combiner* call_combiner; - grpc_call_credentials* creds; - grpc_slice host; - grpc_slice method; + grpc_call_credentials* creds = nullptr; + grpc_slice host = grpc_empty_slice(); + grpc_slice method = grpc_empty_slice(); /* pollset{_set} bound to this call; if we need to make external network requests, they should be done under a pollset added to this pollset_set so that work can progress when this call wants work to progress */ - grpc_polling_entity* pollent; + grpc_polling_entity* pollent = nullptr; grpc_credentials_mdelem_array md_array; - grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; - grpc_auth_metadata_context auth_md_context; + grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT] = {}; + grpc_auth_metadata_context auth_md_context = + grpc_auth_metadata_context(); // Zero-initialize the C struct. grpc_closure async_result_closure; grpc_closure check_call_host_cancel_closure; grpc_closure get_request_metadata_cancel_closure; @@ -334,12 +353,7 @@ static void auth_start_transport_stream_op_batch( /* Constructor for call_data */ static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - calld->arena = args->arena; - calld->owning_call = args->call_stack; - calld->call_combiner = args->call_combiner; - calld->host = grpc_empty_slice(); - calld->method = grpc_empty_slice(); + new (elem->call_data) call_data(elem, *args); return GRPC_ERROR_NONE; } @@ -354,11 +368,7 @@ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); - grpc_credentials_mdelem_array_destroy(&calld->md_array); - grpc_call_credentials_unref(calld->creds); - grpc_slice_unref_internal(calld->host); - grpc_slice_unref_internal(calld->method); - grpc_auth_metadata_context_reset(&calld->auth_md_context); + calld->destroy(); } /* Constructor for channel_data */ diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc index f40f969bb7..34d8435907 100644 --- a/src/core/lib/security/transport/secure_endpoint.cc +++ b/src/core/lib/security/transport/secure_endpoint.cc @@ -22,6 +22,8 @@ headers. Therefore, sockaddr.h must always be included first */ #include <grpc/support/port_platform.h> +#include <new> + #include "src/core/lib/iomgr/sockaddr.h" #include <grpc/slice.h> @@ -31,6 +33,7 @@ #include <grpc/support/sync.h> #include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/tsi_error.h" @@ -40,44 +43,68 @@ #define STAGING_BUFFER_SIZE 8192 -typedef struct { +static void on_read(void* user_data, grpc_error* error); + +namespace { +struct secure_endpoint { + secure_endpoint(const grpc_endpoint_vtable* vtable, + tsi_frame_protector* protector, + tsi_zero_copy_grpc_protector* zero_copy_protector, + grpc_endpoint* transport, grpc_slice* leftover_slices, + size_t leftover_nslices) + : wrapped_ep(transport), + protector(protector), + zero_copy_protector(zero_copy_protector) { + base.vtable = vtable; + gpr_mu_init(&protector_mu); + GRPC_CLOSURE_INIT(&on_read, ::on_read, this, grpc_schedule_on_exec_ctx); + grpc_slice_buffer_init(&source_buffer); + grpc_slice_buffer_init(&leftover_bytes); + for (size_t i = 0; i < leftover_nslices; i++) { + grpc_slice_buffer_add(&leftover_bytes, + grpc_slice_ref_internal(leftover_slices[i])); + } + grpc_slice_buffer_init(&output_buffer); + gpr_ref_init(&ref, 1); + } + + ~secure_endpoint() { + grpc_endpoint_destroy(wrapped_ep); + tsi_frame_protector_destroy(protector); + tsi_zero_copy_grpc_protector_destroy(zero_copy_protector); + grpc_slice_buffer_destroy_internal(&source_buffer); + grpc_slice_buffer_destroy_internal(&leftover_bytes); + grpc_slice_unref_internal(read_staging_buffer); + grpc_slice_unref_internal(write_staging_buffer); + grpc_slice_buffer_destroy_internal(&output_buffer); + gpr_mu_destroy(&protector_mu); + } + grpc_endpoint base; grpc_endpoint* wrapped_ep; struct tsi_frame_protector* protector; struct tsi_zero_copy_grpc_protector* zero_copy_protector; gpr_mu protector_mu; /* saved upper level callbacks and user_data. */ - grpc_closure* read_cb; - grpc_closure* write_cb; + grpc_closure* read_cb = nullptr; + grpc_closure* write_cb = nullptr; grpc_closure on_read; - grpc_slice_buffer* read_buffer; + grpc_slice_buffer* read_buffer = nullptr; grpc_slice_buffer source_buffer; /* saved handshaker leftover data to unprotect. */ grpc_slice_buffer leftover_bytes; /* buffers for read and write */ - grpc_slice read_staging_buffer; - - grpc_slice write_staging_buffer; + grpc_slice read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); + grpc_slice write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); grpc_slice_buffer output_buffer; gpr_refcount ref; -} secure_endpoint; +}; +} // namespace grpc_core::TraceFlag grpc_trace_secure_endpoint(false, "secure_endpoint"); -static void destroy(secure_endpoint* secure_ep) { - secure_endpoint* ep = secure_ep; - grpc_endpoint_destroy(ep->wrapped_ep); - tsi_frame_protector_destroy(ep->protector); - tsi_zero_copy_grpc_protector_destroy(ep->zero_copy_protector); - grpc_slice_buffer_destroy_internal(&ep->leftover_bytes); - grpc_slice_unref_internal(ep->read_staging_buffer); - grpc_slice_unref_internal(ep->write_staging_buffer); - grpc_slice_buffer_destroy_internal(&ep->output_buffer); - grpc_slice_buffer_destroy_internal(&ep->source_buffer); - gpr_mu_destroy(&ep->protector_mu); - gpr_free(ep); -} +static void destroy(secure_endpoint* ep) { grpc_core::Delete(ep); } #ifndef NDEBUG #define SECURE_ENDPOINT_UNREF(ep, reason) \ @@ -405,25 +432,8 @@ grpc_endpoint* grpc_secure_endpoint_create( struct tsi_zero_copy_grpc_protector* zero_copy_protector, grpc_endpoint* transport, grpc_slice* leftover_slices, size_t leftover_nslices) { - size_t i; - secure_endpoint* ep = - static_cast<secure_endpoint*>(gpr_malloc(sizeof(secure_endpoint))); - ep->base.vtable = &vtable; - ep->wrapped_ep = transport; - ep->protector = protector; - ep->zero_copy_protector = zero_copy_protector; - grpc_slice_buffer_init(&ep->leftover_bytes); - for (i = 0; i < leftover_nslices; i++) { - grpc_slice_buffer_add(&ep->leftover_bytes, - grpc_slice_ref_internal(leftover_slices[i])); - } - ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); - ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); - grpc_slice_buffer_init(&ep->output_buffer); - grpc_slice_buffer_init(&ep->source_buffer); - ep->read_buffer = nullptr; - GRPC_CLOSURE_INIT(&ep->on_read, on_read, ep, grpc_schedule_on_exec_ctx); - gpr_mu_init(&ep->protector_mu); - gpr_ref_init(&ep->ref, 1); + secure_endpoint* ep = grpc_core::New<secure_endpoint>( + &vtable, protector, zero_copy_protector, transport, leftover_slices, + leftover_nslices); return &ep->base; } diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index 4d6b133809..854a1c4af9 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -275,9 +275,6 @@ static void on_handshake_next_done_grpc_wrapper( tsi_result result, void* user_data, const unsigned char* bytes_to_send, size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) { security_handshaker* h = static_cast<security_handshaker*>(user_data); - // This callback will be invoked by TSI in a non-grpc thread, so it's - // safe to create our own exec_ctx here. - grpc_core::ExecCtx exec_ctx; gpr_mu_lock(&h->mu); grpc_error* error = on_handshake_next_done_locked( h, result, bytes_to_send, bytes_to_send_size, handshaker_result); diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc index b99fc5e178..362f49a584 100644 --- a/src/core/lib/security/transport/server_auth_filter.cc +++ b/src/core/lib/security/transport/server_auth_filter.cc @@ -28,6 +28,9 @@ #include "src/core/lib/security/transport/auth_filters.h" #include "src/core/lib/slice/slice_internal.h" +static void recv_initial_metadata_ready(void* arg, grpc_error* error); +static void recv_trailing_metadata_ready(void* user_data, grpc_error* error); + namespace { enum async_state { STATE_INIT = 0, @@ -35,28 +38,55 @@ enum async_state { STATE_CANCELLED, }; +struct channel_data { + grpc_auth_context* auth_context; + grpc_server_credentials* creds; +}; + struct call_data { + call_data(grpc_call_element* elem, const grpc_call_element_args& args) + : call_combiner(args.call_combiner), owning_call(args.call_stack) { + GRPC_CLOSURE_INIT(&recv_initial_metadata_ready, + ::recv_initial_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready, + ::recv_trailing_metadata_ready, elem, + grpc_schedule_on_exec_ctx); + // Create server security context. Set its auth context from channel + // data and save it in the call context. + grpc_server_security_context* server_ctx = + grpc_server_security_context_create(args.arena); + channel_data* chand = static_cast<channel_data*>(elem->channel_data); + server_ctx->auth_context = + GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter"); + if (args.context[GRPC_CONTEXT_SECURITY].value != nullptr) { + args.context[GRPC_CONTEXT_SECURITY].destroy( + args.context[GRPC_CONTEXT_SECURITY].value); + } + args.context[GRPC_CONTEXT_SECURITY].value = server_ctx; + args.context[GRPC_CONTEXT_SECURITY].destroy = + grpc_server_security_context_destroy; + } + + ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); } + grpc_call_combiner* call_combiner; grpc_call_stack* owning_call; grpc_transport_stream_op_batch* recv_initial_metadata_batch; grpc_closure* original_recv_initial_metadata_ready; grpc_closure recv_initial_metadata_ready; - grpc_error* recv_initial_metadata_error; + grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE; grpc_closure recv_trailing_metadata_ready; grpc_closure* original_recv_trailing_metadata_ready; grpc_error* recv_trailing_metadata_error; - bool seen_recv_trailing_metadata_ready; + bool seen_recv_trailing_metadata_ready = false; grpc_metadata_array md; const grpc_metadata* consumed_md; size_t num_consumed_md; grpc_closure cancel_closure; - gpr_atm state; // async_state + gpr_atm state = STATE_INIT; // async_state }; -struct channel_data { - grpc_auth_context* auth_context; - grpc_server_credentials* creds; -}; } // namespace static grpc_metadata_array metadata_batch_to_md_array( @@ -244,29 +274,7 @@ static void auth_start_transport_stream_op_batch( /* Constructor for call_data */ static grpc_error* init_call_elem(grpc_call_element* elem, const grpc_call_element_args* args) { - call_data* calld = static_cast<call_data*>(elem->call_data); - channel_data* chand = static_cast<channel_data*>(elem->channel_data); - calld->call_combiner = args->call_combiner; - calld->owning_call = args->call_stack; - GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, - recv_initial_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, elem, - grpc_schedule_on_exec_ctx); - // Create server security context. Set its auth context from channel - // data and save it in the call context. - grpc_server_security_context* server_ctx = - grpc_server_security_context_create(args->arena); - server_ctx->auth_context = - GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter"); - if (args->context[GRPC_CONTEXT_SECURITY].value != nullptr) { - args->context[GRPC_CONTEXT_SECURITY].destroy( - args->context[GRPC_CONTEXT_SECURITY].value); - } - args->context[GRPC_CONTEXT_SECURITY].value = server_ctx; - args->context[GRPC_CONTEXT_SECURITY].destroy = - grpc_server_security_context_destroy; + new (elem->call_data) call_data(elem, *args); return GRPC_ERROR_NONE; } @@ -275,7 +283,7 @@ static void destroy_call_elem(grpc_call_element* elem, const grpc_call_final_info* final_info, grpc_closure* ignored) { call_data* calld = static_cast<call_data*>(elem->call_data); - GRPC_ERROR_UNREF(calld->recv_initial_metadata_error); + calld->~call_data(); } /* Constructor for channel_data */ diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index a9349afa68..735a78ad08 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -72,8 +72,11 @@ // Used to create arena for the first call. #define ESTIMATED_MDELEM_COUNT 16 -typedef struct batch_control { - grpc_call* call; +struct batch_control { + batch_control() { gpr_ref_init(&steps_to_complete, 0); } + + grpc_call* call = nullptr; + grpc_transport_stream_op_batch op; /* Share memory for cq_completion and notify_tag as they are never needed simultaneously. Each byte used in this data structure count as six bytes per call, so any savings we can make are worthwhile, @@ -96,84 +99,110 @@ typedef struct batch_control { grpc_closure start_batch; grpc_closure finish_batch; gpr_refcount steps_to_complete; - gpr_atm batch_error; - grpc_transport_stream_op_batch op; -} batch_control; + gpr_atm batch_error = reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE); +}; + +struct parent_call { + parent_call() { gpr_mu_init(&child_list_mu); } + ~parent_call() { gpr_mu_destroy(&child_list_mu); } -typedef struct { gpr_mu child_list_mu; - grpc_call* first_child; -} parent_call; + grpc_call* first_child = nullptr; +}; -typedef struct { +struct child_call { + child_call(grpc_call* parent) : parent(parent) {} grpc_call* parent; /** siblings: children of the same parent form a list, and this list is protected under parent->mu */ - grpc_call* sibling_next; - grpc_call* sibling_prev; -} child_call; + grpc_call* sibling_next = nullptr; + grpc_call* sibling_prev = nullptr; +}; #define RECV_NONE ((gpr_atm)0) #define RECV_INITIAL_METADATA_FIRST ((gpr_atm)1) struct grpc_call { + grpc_call(gpr_arena* arena, const grpc_call_create_args& args) + : arena(arena), + cq(args.cq), + channel(args.channel), + is_client(args.server_transport_data == nullptr), + stream_op_payload(context) { + gpr_ref_init(&ext_ref, 1); + grpc_call_combiner_init(&call_combiner); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE; + } + } + } + + ~grpc_call() { + gpr_free(static_cast<void*>(const_cast<char*>(final_info.error_string))); + grpc_call_combiner_destroy(&call_combiner); + } + gpr_refcount ext_ref; gpr_arena* arena; grpc_call_combiner call_combiner; grpc_completion_queue* cq; grpc_polling_entity pollent; grpc_channel* channel; - gpr_timespec start_time; - /* parent_call* */ gpr_atm parent_call_atm; - child_call* child; + gpr_timespec start_time = gpr_now(GPR_CLOCK_MONOTONIC); + /* parent_call* */ gpr_atm parent_call_atm = 0; + child_call* child = nullptr; /* client or server call */ bool is_client; /** has grpc_call_unref been called */ - bool destroy_called; + bool destroy_called = false; /** flag indicating that cancellation is inherited */ - bool cancellation_is_inherited; + bool cancellation_is_inherited = false; /** which ops are in-flight */ - bool sent_initial_metadata; - bool sending_message; - bool sent_final_op; - bool received_initial_metadata; - bool receiving_message; - bool requested_final_op; - gpr_atm any_ops_sent_atm; - gpr_atm received_final_op_atm; - - batch_control* active_batches[MAX_CONCURRENT_BATCHES]; + bool sent_initial_metadata = false; + bool sending_message = false; + bool sent_final_op = false; + bool received_initial_metadata = false; + bool receiving_message = false; + bool requested_final_op = false; + gpr_atm any_ops_sent_atm = 0; + gpr_atm received_final_op_atm = 0; + + batch_control* active_batches[MAX_CONCURRENT_BATCHES] = {}; grpc_transport_stream_op_batch_payload stream_op_payload; /* first idx: is_receiving, second idx: is_trailing */ - grpc_metadata_batch metadata_batch[2][2]; + grpc_metadata_batch metadata_batch[2][2] = {}; /* Buffered read metadata waiting to be returned to the application. Element 0 is initial metadata, element 1 is trailing metadata. */ - grpc_metadata_array* buffered_metadata[2]; + grpc_metadata_array* buffered_metadata[2] = {}; grpc_metadata compression_md; // A char* indicating the peer name. - gpr_atm peer_string; + gpr_atm peer_string = 0; /* Call data useful used for reporting. Only valid after the call has * completed */ grpc_call_final_info final_info; /* Compression algorithm for *incoming* data */ - grpc_message_compression_algorithm incoming_message_compression_algorithm; + grpc_message_compression_algorithm incoming_message_compression_algorithm = + GRPC_MESSAGE_COMPRESS_NONE; /* Stream compression algorithm for *incoming* data */ - grpc_stream_compression_algorithm incoming_stream_compression_algorithm; - /* Supported encodings (compression algorithms), a bitset */ - uint32_t encodings_accepted_by_peer; + grpc_stream_compression_algorithm incoming_stream_compression_algorithm = + GRPC_STREAM_COMPRESS_NONE; + /* Supported encodings (compression algorithms), a bitset. + * Always support no compression. */ + uint32_t encodings_accepted_by_peer = 1 << GRPC_MESSAGE_COMPRESS_NONE; /* Supported stream encodings (stream compression algorithms), a bitset */ - uint32_t stream_encodings_accepted_by_peer; + uint32_t stream_encodings_accepted_by_peer = 0; /* Contexts for various subsystems (security, tracing, ...). */ - grpc_call_context_element context[GRPC_CONTEXT_COUNT]; + grpc_call_context_element context[GRPC_CONTEXT_COUNT] = {}; /* for the client, extra metadata is initial metadata; for the server, it's trailing metadata */ @@ -184,14 +213,14 @@ struct grpc_call { grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sending_stream; grpc_core::OrphanablePtr<grpc_core::ByteStream> receiving_stream; - grpc_byte_buffer** receiving_buffer; - grpc_slice receiving_slice; + grpc_byte_buffer** receiving_buffer = nullptr; + grpc_slice receiving_slice = grpc_empty_slice(); grpc_closure receiving_slice_ready; grpc_closure receiving_stream_ready; grpc_closure receiving_initial_metadata_ready; grpc_closure receiving_trailing_metadata_ready; - uint32_t test_only_last_message_flags; - gpr_atm cancelled; + uint32_t test_only_last_message_flags = 0; + gpr_atm cancelled = 0; grpc_closure release_call; @@ -207,7 +236,7 @@ struct grpc_call { grpc_server* server; } server; } final_op; - gpr_atm status_error; + gpr_atm status_error = 0; /* recv_state can contain one of the following values: RECV_NONE : : no initial metadata and messages received @@ -225,7 +254,7 @@ struct grpc_call { For 1, 4: See receiving_initial_metadata_ready() function For 2, 3: See receiving_stream_ready() function */ - gpr_atm recv_state; + gpr_atm recv_state = 0; }; grpc_core::TraceFlag grpc_call_error_trace(false, "call_error"); @@ -269,11 +298,10 @@ void* grpc_call_arena_alloc(grpc_call* call, size_t size) { static parent_call* get_or_create_parent_call(grpc_call* call) { parent_call* p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm); if (p == nullptr) { - p = static_cast<parent_call*>(gpr_arena_alloc(call->arena, sizeof(*p))); - gpr_mu_init(&p->child_list_mu); + p = new (gpr_arena_alloc(call->arena, sizeof(*p))) parent_call(); if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm) nullptr, (gpr_atm)p)) { - gpr_mu_destroy(&p->child_list_mu); + p->~parent_call(); p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm); } } @@ -292,7 +320,9 @@ size_t grpc_call_get_initial_size_estimate() { grpc_error* grpc_call_create(const grpc_call_create_args* args, grpc_call** out_call) { GPR_TIMER_SCOPE("grpc_call_create", 0); - size_t i, j; + + GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); + grpc_error* error = GRPC_ERROR_NONE; grpc_channel_stack* channel_stack = grpc_channel_get_channel_stack(args->channel); @@ -300,27 +330,19 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, size_t initial_size = grpc_channel_get_call_size_estimate(args->channel); GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size); gpr_arena* arena = gpr_arena_create(initial_size); - call = static_cast<grpc_call*>( - gpr_arena_alloc(arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) + - channel_stack->call_stack_size)); - gpr_ref_init(&call->ext_ref, 1); - gpr_atm_no_barrier_store(&call->cancelled, 0); - call->arena = arena; - grpc_call_combiner_init(&call->call_combiner); + call = new (gpr_arena_alloc( + arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) + + channel_stack->call_stack_size)) grpc_call(arena, *args); *out_call = call; - call->channel = args->channel; - call->cq = args->cq; - call->start_time = gpr_now(GPR_CLOCK_MONOTONIC); - /* Always support no compression */ - GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_MESSAGE_COMPRESS_NONE); - call->is_client = args->server_transport_data == nullptr; - call->stream_op_payload.context = call->context; grpc_slice path = grpc_empty_slice(); if (call->is_client) { + call->final_op.client.status_details = nullptr; + call->final_op.client.status = nullptr; + call->final_op.client.error_string = nullptr; GRPC_STATS_INC_CLIENT_CALLS_CREATED(); GPR_ASSERT(args->add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); - for (i = 0; i < args->add_initial_metadata_count; i++) { + for (size_t i = 0; i < args->add_initial_metadata_count; i++) { call->send_extra_metadata[i].md = args->add_initial_metadata[i]; if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]), GRPC_MDSTR_PATH)) { @@ -332,23 +354,18 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, static_cast<int>(args->add_initial_metadata_count); } else { GRPC_STATS_INC_SERVER_CALLS_CREATED(); + call->final_op.server.cancelled = nullptr; call->final_op.server.server = args->server; GPR_ASSERT(args->add_initial_metadata_count == 0); call->send_extra_metadata_count = 0; } - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - call->metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE; - } - } - grpc_millis send_deadline = args->send_deadline; + grpc_millis send_deadline = args->send_deadline; bool immediately_cancel = false; if (args->parent != nullptr) { - call->child = - static_cast<child_call*>(gpr_arena_alloc(arena, sizeof(child_call))); - call->child->parent = args->parent; + call->child = new (gpr_arena_alloc(arena, sizeof(child_call))) + child_call(args->parent); GRPC_CALL_INTERNAL_REF(args->parent, "child"); GPR_ASSERT(call->is_client); @@ -382,10 +399,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, } } } - call->send_deadline = send_deadline; - - GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); /* initial refcount dropped by grpc_call_unref */ grpc_call_element_args call_args = {CALL_STACK_FROM_CALL(call), args->server_transport_data, @@ -413,6 +427,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, } gpr_mu_unlock(&pc->child_list_mu); } + if (error != GRPC_ERROR_NONE) { cancel_with_error(call, GRPC_ERROR_REF(error)); } @@ -487,9 +502,9 @@ void grpc_call_internal_unref(grpc_call* c REF_ARG) { static void release_call(void* call, grpc_error* error) { grpc_call* c = static_cast<grpc_call*>(call); grpc_channel* channel = c->channel; - gpr_free(static_cast<void*>(const_cast<char*>(c->final_info.error_string))); - grpc_call_combiner_destroy(&c->call_combiner); - grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(c->arena)); + gpr_arena* arena = c->arena; + c->~grpc_call(); + grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(arena)); GRPC_CHANNEL_INTERNAL_UNREF(channel, "call"); } @@ -505,7 +520,7 @@ static void destroy_call(void* call, grpc_error* error) { c->receiving_stream.reset(); parent_call* pc = get_parent_call(c); if (pc != nullptr) { - gpr_mu_destroy(&pc->child_list_mu); + pc->~parent_call(); } for (ii = 0; ii < c->send_extra_metadata_count; ii++) { GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md); @@ -1100,10 +1115,11 @@ static batch_control* reuse_or_allocate_batch_control(grpc_call* call, if (bctl->call != nullptr) { return nullptr; } - memset(bctl, 0, sizeof(*bctl)); + bctl->~batch_control(); + bctl->op = {}; } else { - bctl = static_cast<batch_control*>( - gpr_arena_alloc(call->arena, sizeof(batch_control))); + bctl = new (gpr_arena_alloc(call->arena, sizeof(batch_control))) + batch_control(); *pslot = bctl; } bctl->call = call; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 123be79c88..e47cb4360e 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -108,7 +108,8 @@ grpc_channel* grpc_channel_create_with_builder( channel->resource_user = resource_user; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT; - size_t channel_tracer_max_memory = 0; // default to off + size_t channel_tracer_max_memory = + GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT; bool internal_channel = false; // this creates the default ChannelNode. Different types of channels may // override this to ensure a correct ChannelNode is created. @@ -147,7 +148,6 @@ grpc_channel* grpc_channel_create_with_builder( 0x1; /* always support no compression */ } else if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) { - GPR_ASSERT(channel_tracer_max_memory == 0); const grpc_integer_options options = { GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}; channel_tracer_max_memory = @@ -322,8 +322,8 @@ static grpc_call* grpc_channel_create_call_internal( } grpc_call_create_args args; - memset(&args, 0, sizeof(args)); args.channel = channel; + args.server = nullptr; args.parent = parent_call; args.propagation_mask = propagation_mask; args.cq = cq; diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc index b81ae73b4d..661022ec5f 100644 --- a/src/core/lib/surface/completion_queue.cc +++ b/src/core/lib/surface/completion_queue.cc @@ -859,8 +859,8 @@ static void cq_end_op_for_callback( gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { - cq_finish_shutdown_callback(cq); gpr_mu_unlock(cq->mu); + cq_finish_shutdown_callback(cq); } else { gpr_mu_unlock(cq->mu); } diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 0ad82fed99..c6198b8ae7 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -123,6 +123,7 @@ void grpc_init(void) { grpc_core::Fork::GlobalInit(); grpc_fork_handlers_auto_register(); gpr_time_init(); + gpr_arena_init(); grpc_stats_init(); grpc_slice_intern_init(); grpc_mdctx_global_init(); diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 72391ca697..93b1933809 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -824,11 +824,16 @@ static void accept_stream(void* cd, grpc_transport* transport, channel_data* chand = static_cast<channel_data*>(cd); /* create a call */ grpc_call_create_args args; - memset(&args, 0, sizeof(args)); args.channel = chand->channel; + args.server = chand->server; + args.parent = nullptr; + args.propagation_mask = 0; + args.cq = nullptr; + args.pollset_set_alternative = nullptr; args.server_transport_data = transport_server_data; + args.add_initial_metadata = nullptr; + args.add_initial_metadata_count = 0; args.send_deadline = GRPC_MILLIS_INF_FUTURE; - args.server = chand->server; grpc_call* call; grpc_error* error = grpc_call_create(&args, &call); grpc_call_element* elem = @@ -840,8 +845,9 @@ static void accept_stream(void* cd, grpc_transport* transport, } call_data* calld = static_cast<call_data*>(elem->call_data); grpc_op op; - memset(&op, 0, sizeof(op)); op.op = GRPC_OP_RECV_INITIAL_METADATA; + op.flags = 0; + op.reserved = nullptr; op.data.recv_initial_metadata.recv_initial_metadata = &calld->initial_metadata; GRPC_CLOSURE_INIT(&calld->got_initial_metadata, got_initial_metadata, elem, diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index 0bcbb32d1f..f6e8bbf205 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -31,9 +31,11 @@ #include "src/core/lib/transport/static_metadata.h" typedef struct grpc_linked_mdelem { + grpc_linked_mdelem() {} + grpc_mdelem md; - struct grpc_linked_mdelem* next; - struct grpc_linked_mdelem* prev; + struct grpc_linked_mdelem* next = nullptr; + struct grpc_linked_mdelem* prev = nullptr; void* reserved; } grpc_linked_mdelem; diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 9e784635c6..edfa7030d1 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -81,16 +81,16 @@ void grpc_stream_unref(grpc_stream_refcount* refcount); grpc_slice grpc_slice_from_stream_owned_buffer(grpc_stream_refcount* refcount, void* buffer, size_t length); -typedef struct { - uint64_t framing_bytes; - uint64_t data_bytes; - uint64_t header_bytes; -} grpc_transport_one_way_stats; +struct grpc_transport_one_way_stats { + uint64_t framing_bytes = 0; + uint64_t data_bytes = 0; + uint64_t header_bytes = 0; +}; -typedef struct grpc_transport_stream_stats { +struct grpc_transport_stream_stats { grpc_transport_one_way_stats incoming; grpc_transport_one_way_stats outgoing; -} grpc_transport_stream_stats; +}; void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats* from, grpc_transport_one_way_stats* to); @@ -121,7 +121,16 @@ typedef struct grpc_transport_stream_op_batch_payload /* Transport stream op: a set of operations to perform on a transport against a single stream */ -typedef struct grpc_transport_stream_op_batch { +struct grpc_transport_stream_op_batch { + grpc_transport_stream_op_batch() + : send_initial_metadata(false), + send_trailing_metadata(false), + send_message(false), + recv_initial_metadata(false), + recv_message(false), + recv_trailing_metadata(false), + cancel_stream(false) {} + /** Should be scheduled when all of the non-recv operations in the batch are complete. @@ -131,10 +140,10 @@ typedef struct grpc_transport_stream_op_batch { scheduled as soon as the non-recv ops are complete, regardless of whether or not the recv ops are complete. If a batch contains only recv ops, on_complete can be null. */ - grpc_closure* on_complete; + grpc_closure* on_complete = nullptr; /** Values for the stream op (fields set are determined by flags above) */ - grpc_transport_stream_op_batch_payload* payload; + grpc_transport_stream_op_batch_payload* payload = nullptr; /** Send initial metadata to the peer, from the provided metadata batch. */ bool send_initial_metadata : 1; @@ -163,24 +172,33 @@ typedef struct grpc_transport_stream_op_batch { * current handler of the op */ grpc_handler_private_op_data handler_private; -} grpc_transport_stream_op_batch; +}; struct grpc_transport_stream_op_batch_payload { + explicit grpc_transport_stream_op_batch_payload( + grpc_call_context_element* context) + : context(context) {} + ~grpc_transport_stream_op_batch_payload() { + // We don't really own `send_message`, so release ownership and let the + // owner clean the data. + send_message.send_message.release(); + } + struct { - grpc_metadata_batch* send_initial_metadata; + grpc_metadata_batch* send_initial_metadata = nullptr; /** Iff send_initial_metadata != NULL, flags associated with send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */ - uint32_t send_initial_metadata_flags; + uint32_t send_initial_metadata_flags = 0; // If non-NULL, will be set by the transport to the peer string (a char*). // The transport retains ownership of the string. // Note: This pointer may be used by the transport after the // send_initial_metadata op is completed. It must remain valid // until the call is destroyed. - gpr_atm* peer_string; + gpr_atm* peer_string = nullptr; } send_initial_metadata; struct { - grpc_metadata_batch* send_trailing_metadata; + grpc_metadata_batch* send_trailing_metadata = nullptr; } send_trailing_metadata; struct { @@ -192,39 +210,39 @@ struct grpc_transport_stream_op_batch_payload { } send_message; struct { - grpc_metadata_batch* recv_initial_metadata; + grpc_metadata_batch* recv_initial_metadata = nullptr; // Flags are used only on the server side. If non-null, will be set to // a bitfield of the GRPC_INITIAL_METADATA_xxx macros (e.g., to // indicate if the call is idempotent). - uint32_t* recv_flags; + uint32_t* recv_flags = nullptr; /** Should be enqueued when initial metadata is ready to be processed. */ - grpc_closure* recv_initial_metadata_ready; + grpc_closure* recv_initial_metadata_ready = nullptr; // If not NULL, will be set to true if trailing metadata is // immediately available. This may be a signal that we received a // Trailers-Only response. - bool* trailing_metadata_available; + bool* trailing_metadata_available = nullptr; // If non-NULL, will be set by the transport to the peer string (a char*). // The transport retains ownership of the string. // Note: This pointer may be used by the transport after the // recv_initial_metadata op is completed. It must remain valid // until the call is destroyed. - gpr_atm* peer_string; + gpr_atm* peer_string = nullptr; } recv_initial_metadata; struct { // Will be set by the transport to point to the byte stream // containing a received message. // Will be NULL if trailing metadata is received instead of a message. - grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message; + grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message = nullptr; /** Should be enqueued when one message is ready to be processed. */ - grpc_closure* recv_message_ready; + grpc_closure* recv_message_ready = nullptr; } recv_message; struct { - grpc_metadata_batch* recv_trailing_metadata; - grpc_transport_stream_stats* collect_stats; + grpc_metadata_batch* recv_trailing_metadata = nullptr; + grpc_transport_stream_stats* collect_stats = nullptr; /** Should be enqueued when initial metadata is ready to be processed. */ - grpc_closure* recv_trailing_metadata_ready; + grpc_closure* recv_trailing_metadata_ready = nullptr; } recv_trailing_metadata; /** Forcefully close this stream. @@ -240,7 +258,7 @@ struct grpc_transport_stream_op_batch_payload { struct { // Error contract: the transport that gets this op must cause cancel_error // to be unref'ed after processing it - grpc_error* cancel_error; + grpc_error* cancel_error = GRPC_ERROR_NONE; } cancel_stream; /* Indexes correspond to grpc_context_index enum values */ diff --git a/src/core/ext/filters/client_channel/uri_parser.cc b/src/core/lib/uri/uri_parser.cc index 0572034a9c..f212c7d2c0 100644 --- a/src/core/ext/filters/client_channel/uri_parser.cc +++ b/src/core/lib/uri/uri_parser.cc @@ -18,7 +18,7 @@ #include <grpc/support/port_platform.h> -#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/uri/uri_parser.h" #include <string.h> diff --git a/src/core/ext/filters/client_channel/uri_parser.h b/src/core/lib/uri/uri_parser.h index d749f23308..b6771bbde3 100644 --- a/src/core/ext/filters/client_channel/uri_parser.h +++ b/src/core/lib/uri/uri_parser.h @@ -16,8 +16,8 @@ * */ -#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H -#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H +#ifndef GRPC_CORE_LIB_URI_URI_PARSER_H +#define GRPC_CORE_LIB_URI_URI_PARSER_H #include <grpc/support/port_platform.h> @@ -47,4 +47,4 @@ const char* grpc_uri_get_query_arg(const grpc_uri* uri, const char* key); /** destroy a uri */ void grpc_uri_destroy(grpc_uri* uri); -#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H */ +#endif /* GRPC_CORE_LIB_URI_URI_PARSER_H */ diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc index 17e8026096..941ca13114 100644 --- a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc @@ -25,30 +25,165 @@ #include <grpc/support/log.h> #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel.h" #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" +#include "src/core/tsi/alts/handshaker/alts_shared_resource.h" +#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" +#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" + +#define TSI_ALTS_INITIAL_BUFFER_SIZE 256 const int kHandshakerClientOpNum = 4; +struct alts_handshaker_client { + const alts_handshaker_client_vtable* vtable; +}; + typedef struct alts_grpc_handshaker_client { alts_handshaker_client base; + alts_tsi_handshaker* handshaker; grpc_call* call; + /* A pointer to a function handling the interaction with handshaker service. + * That is, it points to grpc_call_start_batch_and_execute when the handshaker + * client is used in a non-testing use case and points to a custom function + * that validates the data to be sent to handshaker service in a testing use + * case. */ alts_grpc_caller grpc_caller; + /* A callback function provided by gRPC to handle the response returned from + * handshaker service. It also serves to bring the control safely back to + * application when dedicated CQ and thread are used. */ + grpc_iomgr_cb_func grpc_cb; + /* A gRPC closure to be scheduled when the response from handshaker service + * is received. It will be initialized with grpc_cb. */ + grpc_closure on_handshaker_service_resp_recv; + /* Buffers containing information to be sent (or received) to (or from) the + * handshaker service. */ + grpc_byte_buffer* send_buffer; + grpc_byte_buffer* recv_buffer; + grpc_status_code status; + /* Initial metadata to be received from handshaker service. */ + grpc_metadata_array recv_initial_metadata; + /* A callback function provided by an application to be invoked when response + * is received from handshaker service. */ + tsi_handshaker_on_next_done_cb cb; + void* user_data; + /* ALTS credential options passed in from the caller. */ + grpc_alts_credentials_options* options; + /* target name information to be passed to handshaker service for server + * authorization check. */ + grpc_slice target_name; + /* boolean flag indicating if the handshaker client is used at client + * (is_client = true) or server (is_client = false) side. */ + bool is_client; + /* a temporary store for data received from handshaker service used to extract + * unused data. */ + grpc_slice recv_bytes; + /* a buffer containing data to be sent to the grpc client or server's peer. */ + unsigned char* buffer; + size_t buffer_size; } alts_grpc_handshaker_client; -static grpc_call_error grpc_start_batch(grpc_call* call, const grpc_op* ops, - size_t nops, void* tag) { - return grpc_call_start_batch(call, ops, nops, tag, nullptr); +static void handshaker_client_send_buffer_destroy( + alts_grpc_handshaker_client* client) { + GPR_ASSERT(client != nullptr); + grpc_byte_buffer_destroy(client->send_buffer); + client->send_buffer = nullptr; +} + +static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) { + GPR_ASSERT(resp != nullptr); + if (resp->has_result) { + return true; + } + return false; +} + +void alts_handshaker_client_handle_response(alts_handshaker_client* c, + bool is_ok) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + grpc_byte_buffer* recv_buffer = client->recv_buffer; + grpc_status_code status = client->status; + tsi_handshaker_on_next_done_cb cb = client->cb; + void* user_data = client->user_data; + alts_tsi_handshaker* handshaker = client->handshaker; + + /* Invalid input check. */ + if (cb == nullptr) { + gpr_log(GPR_ERROR, + "cb is nullptr in alts_tsi_handshaker_handle_response()"); + return; + } + if (handshaker == nullptr || recv_buffer == nullptr) { + gpr_log(GPR_ERROR, + "Invalid arguments to alts_tsi_handshaker_handle_response()"); + cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); + return; + } + if (alts_tsi_handshaker_has_shutdown(handshaker)) { + gpr_log(GPR_ERROR, "TSI handshake shutdown"); + cb(TSI_HANDSHAKE_SHUTDOWN, user_data, nullptr, 0, nullptr); + return; + } + /* Failed grpc call check. */ + if (!is_ok || status != GRPC_STATUS_OK) { + gpr_log(GPR_ERROR, "grpc call made to handshaker service failed"); + cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); + return; + } + grpc_gcp_handshaker_resp* resp = + alts_tsi_utils_deserialize_response(recv_buffer); + grpc_byte_buffer_destroy(client->recv_buffer); + client->recv_buffer = nullptr; + /* Invalid handshaker response check. */ + if (resp == nullptr) { + gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed"); + cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr); + return; + } + grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg); + unsigned char* bytes_to_send = nullptr; + size_t bytes_to_send_size = 0; + if (slice != nullptr) { + bytes_to_send_size = GRPC_SLICE_LENGTH(*slice); + while (bytes_to_send_size > client->buffer_size) { + client->buffer_size *= 2; + client->buffer = static_cast<unsigned char*>( + gpr_realloc(client->buffer, client->buffer_size)); + } + memcpy(client->buffer, GRPC_SLICE_START_PTR(*slice), bytes_to_send_size); + bytes_to_send = client->buffer; + } + tsi_handshaker_result* result = nullptr; + if (is_handshake_finished_properly(resp)) { + alts_tsi_handshaker_result_create(resp, client->is_client, &result); + alts_tsi_handshaker_result_set_unused_bytes(result, &client->recv_bytes, + resp->bytes_consumed); + } + grpc_status_code code = static_cast<grpc_status_code>(resp->status.code); + if (code != GRPC_STATUS_OK) { + grpc_slice* details = static_cast<grpc_slice*>(resp->status.details.arg); + if (details != nullptr) { + char* error_details = grpc_slice_to_c_string(*details); + gpr_log(GPR_ERROR, "Error from handshaker service:%s", error_details); + gpr_free(error_details); + } + } + grpc_gcp_handshaker_resp_destroy(resp); + cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send, + bytes_to_send_size, result); } /** - * Populate grpc operation data with the fields of ALTS TSI event and make a - * grpc call. + * Populate grpc operation data with the fields of ALTS handshaker client and + * make a grpc call. */ -static tsi_result make_grpc_call(alts_handshaker_client* client, - alts_tsi_event* event, bool is_start) { - GPR_ASSERT(client != nullptr && event != nullptr); - alts_grpc_handshaker_client* grpc_client = - reinterpret_cast<alts_grpc_handshaker_client*>(client); +static tsi_result make_grpc_call(alts_handshaker_client* c, bool is_start) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); grpc_op ops[kHandshakerClientOpNum]; memset(ops, 0, sizeof(ops)); grpc_op* op = ops; @@ -59,22 +194,22 @@ static tsi_result make_grpc_call(alts_handshaker_client* client, GPR_ASSERT(op - ops <= kHandshakerClientOpNum); op->op = GRPC_OP_RECV_INITIAL_METADATA; op->data.recv_initial_metadata.recv_initial_metadata = - &event->initial_metadata; + &client->recv_initial_metadata; op++; GPR_ASSERT(op - ops <= kHandshakerClientOpNum); } op->op = GRPC_OP_SEND_MESSAGE; - op->data.send_message.send_message = event->send_buffer; + op->data.send_message.send_message = client->send_buffer; op++; GPR_ASSERT(op - ops <= kHandshakerClientOpNum); op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message.recv_message = &event->recv_buffer; + op->data.recv_message.recv_message = &client->recv_buffer; op++; GPR_ASSERT(op - ops <= kHandshakerClientOpNum); - GPR_ASSERT(grpc_client->grpc_caller != nullptr); - if (grpc_client->grpc_caller(grpc_client->call, ops, - static_cast<size_t>(op - ops), - (void*)event) != GRPC_CALL_OK) { + GPR_ASSERT(client->grpc_caller != nullptr); + if (client->grpc_caller(client->call, ops, static_cast<size_t>(op - ops), + &client->on_handshaker_service_resp_recv) != + GRPC_CALL_OK) { gpr_log(GPR_ERROR, "Start batch operation failed"); return TSI_INTERNAL_ERROR; } @@ -82,7 +217,11 @@ static tsi_result make_grpc_call(alts_handshaker_client* client, } /* Create and populate a client_start handshaker request, then serialize it. */ -static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) { +static grpc_byte_buffer* get_serialized_start_client( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); bool ok = true; grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(CLIENT_START_REQ); @@ -91,14 +230,14 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) { ok &= grpc_gcp_handshaker_req_add_application_protocol( req, ALTS_APPLICATION_PROTOCOL); ok &= grpc_gcp_handshaker_req_add_record_protocol(req, ALTS_RECORD_PROTOCOL); - grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions; + grpc_gcp_rpc_protocol_versions* versions = &client->options->rpc_versions; ok &= grpc_gcp_handshaker_req_set_rpc_versions( req, versions->max_rpc_version.major, versions->max_rpc_version.minor, versions->min_rpc_version.major, versions->min_rpc_version.minor); - char* target_name = grpc_slice_to_c_string(event->target_name); + char* target_name = grpc_slice_to_c_string(client->target_name); ok &= grpc_gcp_handshaker_req_set_target_name(req, target_name); target_service_account* ptr = - (reinterpret_cast<grpc_alts_credentials_client_options*>(event->options)) + (reinterpret_cast<grpc_alts_credentials_client_options*>(client->options)) ->target_account_list_head; while (ptr != nullptr) { grpc_gcp_handshaker_req_add_target_identity_service_account(req, ptr->data); @@ -116,19 +255,21 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) { return buffer; } -static tsi_result handshaker_client_start_client(alts_handshaker_client* client, - alts_tsi_event* event) { - if (client == nullptr || event == nullptr) { - gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_client()"); +static tsi_result handshaker_client_start_client(alts_handshaker_client* c) { + if (c == nullptr) { + gpr_log(GPR_ERROR, "client is nullptr in handshaker_client_start_client()"); return TSI_INVALID_ARGUMENT; } - grpc_byte_buffer* buffer = get_serialized_start_client(event); + grpc_byte_buffer* buffer = get_serialized_start_client(c); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); if (buffer == nullptr) { gpr_log(GPR_ERROR, "get_serialized_start_client() failed"); return TSI_INTERNAL_ERROR; } - event->send_buffer = buffer; - tsi_result result = make_grpc_call(client, event, true /* is_start */); + handshaker_client_send_buffer_destroy(client); + client->send_buffer = buffer; + tsi_result result = make_grpc_call(&client->base, true /* is_start */); if (result != TSI_OK) { gpr_log(GPR_ERROR, "make_grpc_call() failed"); } @@ -137,8 +278,11 @@ static tsi_result handshaker_client_start_client(alts_handshaker_client* client, /* Create and populate a start_server handshaker request, then serialize it. */ static grpc_byte_buffer* get_serialized_start_server( - alts_tsi_event* event, grpc_slice* bytes_received) { + alts_handshaker_client* c, grpc_slice* bytes_received) { + GPR_ASSERT(c != nullptr); GPR_ASSERT(bytes_received != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(SERVER_START_REQ); bool ok = grpc_gcp_handshaker_req_add_application_protocol( @@ -148,7 +292,7 @@ static grpc_byte_buffer* get_serialized_start_server( ok &= grpc_gcp_handshaker_req_set_in_bytes( req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received), GRPC_SLICE_LENGTH(*bytes_received)); - grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions; + grpc_gcp_rpc_protocol_versions* versions = &client->options->rpc_versions; ok &= grpc_gcp_handshaker_req_set_rpc_versions( req, versions->max_rpc_version.major, versions->max_rpc_version.minor, versions->min_rpc_version.major, versions->min_rpc_version.minor); @@ -163,20 +307,22 @@ static grpc_byte_buffer* get_serialized_start_server( return buffer; } -static tsi_result handshaker_client_start_server(alts_handshaker_client* client, - alts_tsi_event* event, +static tsi_result handshaker_client_start_server(alts_handshaker_client* c, grpc_slice* bytes_received) { - if (client == nullptr || event == nullptr || bytes_received == nullptr) { + if (c == nullptr || bytes_received == nullptr) { gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_start_server()"); return TSI_INVALID_ARGUMENT; } - grpc_byte_buffer* buffer = get_serialized_start_server(event, bytes_received); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + grpc_byte_buffer* buffer = get_serialized_start_server(c, bytes_received); if (buffer == nullptr) { gpr_log(GPR_ERROR, "get_serialized_start_server() failed"); return TSI_INTERNAL_ERROR; } - event->send_buffer = buffer; - tsi_result result = make_grpc_call(client, event, true /* is_start */); + handshaker_client_send_buffer_destroy(client); + client->send_buffer = buffer; + tsi_result result = make_grpc_call(&client->base, true /* is_start */); if (result != TSI_OK) { gpr_log(GPR_ERROR, "make_grpc_call() failed"); } @@ -201,40 +347,48 @@ static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) { return buffer; } -static tsi_result handshaker_client_next(alts_handshaker_client* client, - alts_tsi_event* event, +static tsi_result handshaker_client_next(alts_handshaker_client* c, grpc_slice* bytes_received) { - if (client == nullptr || event == nullptr || bytes_received == nullptr) { + if (c == nullptr || bytes_received == nullptr) { gpr_log(GPR_ERROR, "Invalid arguments to handshaker_client_next()"); return TSI_INVALID_ARGUMENT; } + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + grpc_slice_unref_internal(client->recv_bytes); + client->recv_bytes = grpc_slice_ref(*bytes_received); grpc_byte_buffer* buffer = get_serialized_next(bytes_received); if (buffer == nullptr) { gpr_log(GPR_ERROR, "get_serialized_next() failed"); return TSI_INTERNAL_ERROR; } - event->send_buffer = buffer; - tsi_result result = make_grpc_call(client, event, false /* is_start */); + handshaker_client_send_buffer_destroy(client); + client->send_buffer = buffer; + tsi_result result = make_grpc_call(&client->base, false /* is_start */); if (result != TSI_OK) { gpr_log(GPR_ERROR, "make_grpc_call() failed"); } return result; } -static void handshaker_client_shutdown(alts_handshaker_client* client) { - GPR_ASSERT(client != nullptr); - alts_grpc_handshaker_client* grpc_client = - reinterpret_cast<alts_grpc_handshaker_client*>(client); - GPR_ASSERT(grpc_call_cancel(grpc_client->call, nullptr) == GRPC_CALL_OK); +static void handshaker_client_shutdown(alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + if (client->call != nullptr) { + GPR_ASSERT(grpc_call_cancel(client->call, nullptr) == GRPC_CALL_OK); + } } -static void handshaker_client_destruct(alts_handshaker_client* client) { - if (client == nullptr) { +static void handshaker_client_destruct(alts_handshaker_client* c) { + if (c == nullptr) { return; } - alts_grpc_handshaker_client* grpc_client = - reinterpret_cast<alts_grpc_handshaker_client*>(client); - grpc_call_unref(grpc_client->call); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + if (client->call != nullptr) { + grpc_call_unref(client->call); + } } static const alts_handshaker_client_vtable vtable = { @@ -243,22 +397,45 @@ static const alts_handshaker_client_vtable vtable = { handshaker_client_destruct}; alts_handshaker_client* alts_grpc_handshaker_client_create( - grpc_channel* channel, grpc_completion_queue* queue, - const char* handshaker_service_url) { - if (channel == nullptr || queue == nullptr || - handshaker_service_url == nullptr) { + alts_tsi_handshaker* handshaker, grpc_channel* channel, + const char* handshaker_service_url, grpc_pollset_set* interested_parties, + grpc_alts_credentials_options* options, grpc_slice target_name, + grpc_iomgr_cb_func grpc_cb, tsi_handshaker_on_next_done_cb cb, + void* user_data, alts_handshaker_client_vtable* vtable_for_testing, + bool is_client) { + if (channel == nullptr || handshaker_service_url == nullptr) { gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()"); return nullptr; } alts_grpc_handshaker_client* client = static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client))); - client->grpc_caller = grpc_start_batch; + client->grpc_caller = grpc_call_start_batch_and_execute; + client->handshaker = handshaker; + client->cb = cb; + client->user_data = user_data; + client->send_buffer = nullptr; + client->recv_buffer = nullptr; + client->options = grpc_alts_credentials_options_copy(options); + client->target_name = grpc_slice_copy(target_name); + client->recv_bytes = grpc_empty_slice(); + grpc_metadata_array_init(&client->recv_initial_metadata); + client->grpc_cb = grpc_cb; + client->is_client = is_client; + client->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE; + client->buffer = static_cast<unsigned char*>(gpr_zalloc(client->buffer_size)); grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url); - client->call = grpc_channel_create_call( - channel, nullptr, GRPC_PROPAGATE_DEFAULTS, queue, - grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice, - gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); - client->base.vtable = &vtable; + client->call = + strcmp(handshaker_service_url, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING) == + 0 + ? nullptr + : grpc_channel_create_pollset_set_call( + channel, nullptr, GRPC_PROPAGATE_DEFAULTS, interested_parties, + grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice, + GRPC_MILLIS_INF_FUTURE, nullptr); + client->base.vtable = + vtable_for_testing == nullptr ? &vtable : vtable_for_testing; + GRPC_CLOSURE_INIT(&client->on_handshaker_service_resp_recv, client->grpc_cb, + client, grpc_schedule_on_exec_ctx); grpc_slice_unref_internal(slice); return &client->base; } @@ -267,21 +444,114 @@ namespace grpc_core { namespace internal { void alts_handshaker_client_set_grpc_caller_for_testing( - alts_handshaker_client* client, alts_grpc_caller caller) { - GPR_ASSERT(client != nullptr && caller != nullptr); - alts_grpc_handshaker_client* grpc_client = - reinterpret_cast<alts_grpc_handshaker_client*>(client); - grpc_client->grpc_caller = caller; + alts_handshaker_client* c, alts_grpc_caller caller) { + GPR_ASSERT(c != nullptr && caller != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + client->grpc_caller = caller; +} + +grpc_byte_buffer* alts_handshaker_client_get_send_buffer_for_testing( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + return client->send_buffer; +} + +grpc_byte_buffer** alts_handshaker_client_get_recv_buffer_addr_for_testing( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + return &client->recv_buffer; +} + +grpc_metadata_array* alts_handshaker_client_get_initial_metadata_for_testing( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + return &client->recv_initial_metadata; +} + +void alts_handshaker_client_set_recv_bytes_for_testing( + alts_handshaker_client* c, grpc_slice* recv_bytes) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + client->recv_bytes = grpc_slice_ref(*recv_bytes); +} + +void alts_handshaker_client_set_fields_for_testing( + alts_handshaker_client* c, alts_tsi_handshaker* handshaker, + tsi_handshaker_on_next_done_cb cb, void* user_data, + grpc_byte_buffer* recv_buffer, grpc_status_code status) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + client->handshaker = handshaker; + client->cb = cb; + client->user_data = user_data; + client->recv_buffer = recv_buffer; + client->status = status; +} + +void alts_handshaker_client_check_fields_for_testing( + alts_handshaker_client* c, tsi_handshaker_on_next_done_cb cb, + void* user_data, bool has_sent_start_message, grpc_slice* recv_bytes) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + GPR_ASSERT(client->cb == cb); + GPR_ASSERT(client->user_data == user_data); + if (recv_bytes != nullptr) { + GPR_ASSERT(grpc_slice_cmp(client->recv_bytes, *recv_bytes) == 0); + } + GPR_ASSERT(alts_tsi_handshaker_get_has_sent_start_message_for_testing( + client->handshaker) == has_sent_start_message); +} + +void alts_handshaker_client_set_vtable_for_testing( + alts_handshaker_client* c, alts_handshaker_client_vtable* vtable) { + GPR_ASSERT(c != nullptr); + GPR_ASSERT(vtable != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + client->base.vtable = vtable; +} + +alts_tsi_handshaker* alts_handshaker_client_get_handshaker_for_testing( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + return client->handshaker; +} + +void alts_handshaker_client_set_cb_for_testing( + alts_handshaker_client* c, tsi_handshaker_on_next_done_cb cb) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + client->cb = cb; +} + +grpc_closure* alts_handshaker_client_get_closure_for_testing( + alts_handshaker_client* c) { + GPR_ASSERT(c != nullptr); + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + return &client->on_handshaker_service_resp_recv; } } // namespace internal } // namespace grpc_core -tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client, - alts_tsi_event* event) { +tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client) { if (client != nullptr && client->vtable != nullptr && client->vtable->client_start != nullptr) { - return client->vtable->client_start(client, event); + return client->vtable->client_start(client); } gpr_log(GPR_ERROR, "client or client->vtable has not been initialized properly"); @@ -289,11 +559,10 @@ tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client, } tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client, - alts_tsi_event* event, grpc_slice* bytes_received) { if (client != nullptr && client->vtable != nullptr && client->vtable->server_start != nullptr) { - return client->vtable->server_start(client, event, bytes_received); + return client->vtable->server_start(client, bytes_received); } gpr_log(GPR_ERROR, "client or client->vtable has not been initialized properly"); @@ -301,11 +570,10 @@ tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client, } tsi_result alts_handshaker_client_next(alts_handshaker_client* client, - alts_tsi_event* event, grpc_slice* bytes_received) { if (client != nullptr && client->vtable != nullptr && client->vtable->next != nullptr) { - return client->vtable->next(client, event, bytes_received); + return client->vtable->next(client, bytes_received); } gpr_log(GPR_ERROR, "client or client->vtable has not been initialized properly"); @@ -319,11 +587,22 @@ void alts_handshaker_client_shutdown(alts_handshaker_client* client) { } } -void alts_handshaker_client_destroy(alts_handshaker_client* client) { - if (client != nullptr) { - if (client->vtable != nullptr && client->vtable->destruct != nullptr) { - client->vtable->destruct(client); +void alts_handshaker_client_destroy(alts_handshaker_client* c) { + if (c != nullptr) { + if (c->vtable != nullptr && c->vtable->destruct != nullptr) { + c->vtable->destruct(c); } + alts_grpc_handshaker_client* client = + reinterpret_cast<alts_grpc_handshaker_client*>(c); + grpc_byte_buffer_destroy(client->send_buffer); + grpc_byte_buffer_destroy(client->recv_buffer); + client->send_buffer = nullptr; + client->recv_buffer = nullptr; + grpc_metadata_array_destroy(&client->recv_initial_metadata); + grpc_slice_unref_internal(client->recv_bytes); + grpc_slice_unref_internal(client->target_name); + grpc_alts_credentials_options_destroy(client->options); + gpr_free(client->buffer); gpr_free(client); } } diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.h b/src/core/tsi/alts/handshaker/alts_handshaker_client.h index 8dd8fe440d..4b489875f3 100644 --- a/src/core/tsi/alts/handshaker/alts_handshaker_client.h +++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.h @@ -21,16 +21,24 @@ #include <grpc/support/port_platform.h> +#include <grpc/byte_buffer.h> +#include <grpc/byte_buffer_reader.h> #include <grpc/grpc.h> -#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" +#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" +#include "src/core/tsi/transport_security_interface.h" + +#include "src/core/lib/iomgr/closure.h" +#include "src/core/lib/iomgr/pollset_set.h" #define ALTS_SERVICE_METHOD "/grpc.gcp.HandshakerService/DoHandshake" #define ALTS_APPLICATION_PROTOCOL "grpc" #define ALTS_RECORD_PROTOCOL "ALTSRP_GCM_AES128_REKEY" +#define ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING "lame" const size_t kAltsAes128GcmRekeyKeyLength = 44; +typedef struct alts_tsi_handshaker alts_tsi_handshaker; /** * A ALTS handshaker client interface. It is used to communicate with * ALTS handshaker service by scheduling a handshaker request that could be one @@ -41,63 +49,52 @@ typedef struct alts_handshaker_client alts_handshaker_client; /* A function that makes the grpc call to the handshaker service. */ typedef grpc_call_error (*alts_grpc_caller)(grpc_call* call, const grpc_op* ops, - size_t nops, void* tag); + size_t nops, grpc_closure* tag); /* V-table for ALTS handshaker client operations. */ typedef struct alts_handshaker_client_vtable { - tsi_result (*client_start)(alts_handshaker_client* client, - alts_tsi_event* event); + tsi_result (*client_start)(alts_handshaker_client* client); tsi_result (*server_start)(alts_handshaker_client* client, - alts_tsi_event* event, grpc_slice* bytes_received); - tsi_result (*next)(alts_handshaker_client* client, alts_tsi_event* event, + grpc_slice* bytes_received); + tsi_result (*next)(alts_handshaker_client* client, grpc_slice* bytes_received); void (*shutdown)(alts_handshaker_client* client); void (*destruct)(alts_handshaker_client* client); } alts_handshaker_client_vtable; -struct alts_handshaker_client { - const alts_handshaker_client_vtable* vtable; -}; - /** * This method schedules a client_start handshaker request to ALTS handshaker * service. * * - client: ALTS handshaker client instance. - * - event: ALTS TSI event instance. * * It returns TSI_OK on success and an error status code on failure. */ -tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client, - alts_tsi_event* event); +tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client); /** * This method schedules a server_start handshaker request to ALTS handshaker * service. * * - client: ALTS handshaker client instance. - * - event: ALTS TSI event instance. * - bytes_received: bytes in out_frames returned from the peer's handshaker * response. * * It returns TSI_OK on success and an error status code on failure. */ tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client, - alts_tsi_event* event, grpc_slice* bytes_received); /** * This method schedules a next handshaker request to ALTS handshaker service. * * - client: ALTS handshaker client instance. - * - event: ALTS TSI event instance. * - bytes_received: bytes in out_frames returned from the peer's handshaker * response. * * It returns TSI_OK on success and an error status code on failure. */ tsi_result alts_handshaker_client_next(alts_handshaker_client* client, - alts_tsi_event* event, grpc_slice* bytes_received); /** @@ -110,38 +107,51 @@ tsi_result alts_handshaker_client_next(alts_handshaker_client* client, void alts_handshaker_client_shutdown(alts_handshaker_client* client); /** - * This method destroys a ALTS handshaker client. + * This method destroys an ALTS handshaker client. * - * - client: a ALTS handshaker client instance. + * - client: an ALTS handshaker client instance. */ void alts_handshaker_client_destroy(alts_handshaker_client* client); /** - * This method creates a ALTS handshaker client. + * This method creates an ALTS handshaker client. * + * - handshaker: ALTS TSI handshaker to which the created handshaker client + * belongs to. * - channel: grpc channel to ALTS handshaker service. - * - queue: grpc completion queue. * - handshaker_service_url: address of ALTS handshaker service in the format of * "host:port". - * - * It returns the created ALTS handshaker client on success, and NULL on - * failure. + * - interested_parties: set of pollsets interested in this connection. + * - options: ALTS credentials options containing information passed from TSI + * caller (e.g., rpc protocol versions) + * - target_name: the name of the endpoint that the channel is connecting to, + * and will be used for secure naming check + * - grpc_cb: gRPC provided callbacks passed from TSI handshaker. + * - cb: callback to be executed when tsi_handshaker_next API compltes. + * - user_data: argument passed to cb. + * - vtable_for_testing: ALTS handshaker client vtable instance used for + * testing purpose. + * - is_client: a boolean value indicating if the created handshaker client is + * used at the client (is_client = true) or server (is_client = false) side. It + * returns the created ALTS handshaker client on success, and NULL on failure. */ alts_handshaker_client* alts_grpc_handshaker_client_create( - grpc_channel* channel, grpc_completion_queue* queue, - const char* handshaker_service_url); - -namespace grpc_core { -namespace internal { + alts_tsi_handshaker* handshaker, grpc_channel* channel, + const char* handshaker_service_url, grpc_pollset_set* interested_parties, + grpc_alts_credentials_options* options, grpc_slice target_name, + grpc_iomgr_cb_func grpc_cb, tsi_handshaker_on_next_done_cb cb, + void* user_data, alts_handshaker_client_vtable* vtable_for_testing, + bool is_client); /** - * Unsafe, use for testing only. It allows the caller to change the way that - * GRPC calls are made to the handshaker service. + * This method handles handshaker response returned from ALTS handshaker + * service. Note that the only reason the API is exposed is that it is used in + * alts_shared_resources.cc. + * + * - client: an ALTS handshaker client instance. + * - is_ok: a boolean value indicating if the handshaker response is ok to read. */ -void alts_handshaker_client_set_grpc_caller_for_testing( - alts_handshaker_client* client, alts_grpc_caller caller); - -} // namespace internal -} // namespace grpc_core +void alts_handshaker_client_handle_response(alts_handshaker_client* client, + bool is_ok); #endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H */ diff --git a/src/core/tsi/alts/handshaker/alts_shared_resource.cc b/src/core/tsi/alts/handshaker/alts_shared_resource.cc new file mode 100644 index 0000000000..ffb5e1c655 --- /dev/null +++ b/src/core/tsi/alts/handshaker/alts_shared_resource.cc @@ -0,0 +1,73 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/support/port_platform.h> + +#include "src/core/tsi/alts/handshaker/alts_shared_resource.h" + +#include <grpc/support/log.h> + +#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" + +static alts_shared_resource_dedicated g_alts_resource_dedicated; +static alts_shared_resource* g_shared_resources = alts_get_shared_resource(); + +alts_shared_resource_dedicated* grpc_alts_get_shared_resource_dedicated(void) { + return &g_alts_resource_dedicated; +} + +static void thread_worker(void* arg) { + while (true) { + grpc_event event = + grpc_completion_queue_next(g_alts_resource_dedicated.cq, + gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT); + if (event.type == GRPC_QUEUE_SHUTDOWN) { + break; + } + GPR_ASSERT(event.type == GRPC_OP_COMPLETE); + alts_handshaker_client* client = + static_cast<alts_handshaker_client*>(event.tag); + alts_handshaker_client_handle_response(client, event.success); + } +} + +void grpc_alts_shared_resource_dedicated_init() { + g_alts_resource_dedicated.cq = nullptr; +} + +void grpc_alts_shared_resource_dedicated_start() { + g_alts_resource_dedicated.cq = grpc_completion_queue_create_for_next(nullptr); + g_alts_resource_dedicated.thread = + grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr); + g_alts_resource_dedicated.interested_parties = grpc_pollset_set_create(); + grpc_pollset_set_add_pollset(g_alts_resource_dedicated.interested_parties, + grpc_cq_pollset(g_alts_resource_dedicated.cq)); + g_alts_resource_dedicated.thread.Start(); +} + +void grpc_alts_shared_resource_dedicated_shutdown() { + if (g_alts_resource_dedicated.cq != nullptr) { + grpc_pollset_set_del_pollset(g_alts_resource_dedicated.interested_parties, + grpc_cq_pollset(g_alts_resource_dedicated.cq)); + grpc_completion_queue_shutdown(g_alts_resource_dedicated.cq); + g_alts_resource_dedicated.thread.Join(); + grpc_pollset_set_destroy(g_alts_resource_dedicated.interested_parties); + grpc_completion_queue_destroy(g_alts_resource_dedicated.cq); + } +} diff --git a/src/core/tsi/alts/handshaker/alts_shared_resource.h b/src/core/tsi/alts/handshaker/alts_shared_resource.h new file mode 100644 index 0000000000..a07da305a8 --- /dev/null +++ b/src/core/tsi/alts/handshaker/alts_shared_resource.h @@ -0,0 +1,70 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H +#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H + +#include <grpc/support/port_platform.h> + +#include <grpc/grpc.h> +#include <grpc/support/sync.h> + +#include "src/core/lib/gprpp/thd.h" +#include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/surface/completion_queue.h" + +/** + * Main struct containing ALTS shared resources used when + * employing the dedicated completion queue and thread. + */ +typedef struct alts_shared_resource_dedicated { + grpc_core::Thread thread; + grpc_completion_queue* cq; + grpc_pollset_set* interested_parties; + grpc_cq_completion storage; +} alts_shared_resource_dedicated; + +/* This method returns the address of alts_shared_resource_dedicated + * object shared by all TSI handshakes. + */ +alts_shared_resource_dedicated* grpc_alts_get_shared_resource_dedicated(void); + +/** + * This method destroys the alts_shared_resource_dedicated object + * shared by all TSI handshakes. The applicaiton is responsible for + * invoking the API before calling grpc_shutdown(). + */ +void grpc_alts_shared_resource_dedicated_shutdown(); + +/** + * This method initializes the alts_shared_resource_dedicated object + * shared by all TSI handshakes. The application is responsible for + * invoking the API after calling grpc_init(); + */ +void grpc_alts_shared_resource_dedicated_init(); + +/** + * This method populates various fields of the alts_shared_resource_dedicated + * object shared by all TSI handshakes and start the dedicated thread. + * The API will be invoked by the caller in a lazy manner. That is, + * it will get invoked when ALTS TSI handshake occurs for the first time. + */ +void grpc_alts_shared_resource_dedicated_start(); + +#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_SHARED_RESOURCE_H \ + */ diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.cc b/src/core/tsi/alts/handshaker/alts_tsi_event.cc deleted file mode 100644 index cb36d5ebd1..0000000000 --- a/src/core/tsi/alts/handshaker/alts_tsi_event.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include <grpc/support/port_platform.h> - -#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" - -#include <grpc/grpc.h> -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> - -#include "src/core/lib/slice/slice_internal.h" - -tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker, - tsi_handshaker_on_next_done_cb cb, - void* user_data, - grpc_alts_credentials_options* options, - grpc_slice target_name, - alts_tsi_event** event) { - if (event == nullptr || handshaker == nullptr || cb == nullptr) { - gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_event_create()"); - return TSI_INVALID_ARGUMENT; - } - alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e))); - e->handshaker = handshaker; - e->cb = cb; - e->user_data = user_data; - e->options = grpc_alts_credentials_options_copy(options); - e->target_name = grpc_slice_copy(target_name); - grpc_metadata_array_init(&e->initial_metadata); - grpc_metadata_array_init(&e->trailing_metadata); - *event = e; - return TSI_OK; -} - -void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok) { - if (event == nullptr) { - gpr_log( - GPR_ERROR, - "ALTS TSI event is nullptr in alts_tsi_event_dispatch_to_handshaker()"); - return; - } - alts_tsi_handshaker_handle_response(event->handshaker, event->recv_buffer, - event->status, &event->details, event->cb, - event->user_data, is_ok); -} - -void alts_tsi_event_destroy(alts_tsi_event* event) { - if (event == nullptr) { - return; - } - grpc_byte_buffer_destroy(event->send_buffer); - grpc_byte_buffer_destroy(event->recv_buffer); - grpc_metadata_array_destroy(&event->initial_metadata); - grpc_metadata_array_destroy(&event->trailing_metadata); - grpc_slice_unref_internal(event->details); - grpc_slice_unref_internal(event->target_name); - grpc_alts_credentials_options_destroy(event->options); - gpr_free(event); -} diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.h b/src/core/tsi/alts/handshaker/alts_tsi_event.h deleted file mode 100644 index 043e75d4a9..0000000000 --- a/src/core/tsi/alts/handshaker/alts_tsi_event.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H -#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H - -#include <grpc/support/port_platform.h> - -#include <grpc/byte_buffer.h> -#include <grpc/byte_buffer_reader.h> - -#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" -#include "src/core/tsi/transport_security_interface.h" - -/** - * A ALTS TSI event interface. In asynchronous implementation of - * tsi_handshaker_next(), the function will exit after scheduling a handshaker - * request to ALTS handshaker service without waiting for response to return. - * The event is used to link the scheduled handshaker request with the - * corresponding response so that enough context information can be inferred - * from it to handle the response. All APIs in the header are thread-compatible. - */ - -/** - * Main struct for ALTS TSI event. It retains ownership on send_buffer and - * recv_buffer, but not on handshaker. - */ -typedef struct alts_tsi_event { - alts_tsi_handshaker* handshaker; - grpc_byte_buffer* send_buffer; - grpc_byte_buffer* recv_buffer; - grpc_status_code status; - grpc_slice details; - grpc_metadata_array initial_metadata; - grpc_metadata_array trailing_metadata; - tsi_handshaker_on_next_done_cb cb; - void* user_data; - grpc_alts_credentials_options* options; - grpc_slice target_name; -} alts_tsi_event; - -/** - * This method creates a ALTS TSI event. - * - * - handshaker: ALTS TSI handshaker instance associated with the event to be - * created. The created event does not own the handshaker instance. - * - cb: callback function to be called when handling data received from ALTS - * handshaker service. - * - user_data: argument to callback function. - * - options: ALTS credentials options. - * - target_name: name of endpoint used for secure naming check. - * - event: address of ALTS TSI event instance to be returned from the method. - * - * It returns TSI_OK on success and an error status code on failure. - */ -tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker, - tsi_handshaker_on_next_done_cb cb, - void* user_data, - grpc_alts_credentials_options* options, - grpc_slice target_name, - alts_tsi_event** event); - -/** - * This method dispatches a ALTS TSI event received from the handshaker service, - * and a boolean flag indicating if the event is valid to read to ALTS TSI - * handshaker to process. It is called by TSI thread. - * - * - event: ALTS TSI event instance. - * - is_ok: a boolean value indicating if the event is valid to read. - */ -void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok); - -/** - * This method destroys the ALTS TSI event. - */ -void alts_tsi_event_destroy(alts_tsi_event* event); - -#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H */ diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc index dfdd659b87..1639252883 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc @@ -26,34 +26,37 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include <grpc/support/sync.h> #include <grpc/support/thd_id.h> #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gprpp/thd.h" +#include "src/core/lib/iomgr/closure.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/alts/frame_protector/alts_frame_protector.h" #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" +#include "src/core/tsi/alts/handshaker/alts_shared_resource.h" #include "src/core/tsi/alts/handshaker/alts_tsi_utils.h" #include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h" #include "src/core/tsi/alts_transport_security.h" -#define TSI_ALTS_INITIAL_BUFFER_SIZE 256 - -static alts_shared_resource* kSharedResource = alts_get_shared_resource(); +static alts_shared_resource* g_shared_resources = alts_get_shared_resource(); /* Main struct for ALTS TSI handshaker. */ -typedef struct alts_tsi_handshaker { +struct alts_tsi_handshaker { tsi_handshaker base; alts_handshaker_client* client; - grpc_slice recv_bytes; grpc_slice target_name; - unsigned char* buffer; - size_t buffer_size; bool is_client; bool has_sent_start_message; + bool has_created_handshaker_client; + bool use_dedicated_cq; + char* handshaker_service_url; + grpc_pollset_set* interested_parties; grpc_alts_credentials_options* options; -} alts_tsi_handshaker; + alts_handshaker_client_vtable* client_vtable_for_testing; +}; /* Main struct for ALTS TSI handshaker result. */ typedef struct alts_tsi_handshaker_result { @@ -193,9 +196,9 @@ static const tsi_handshaker_result_vtable result_vtable = { handshaker_result_create_frame_protector, handshaker_result_get_unused_bytes, handshaker_result_destroy}; -static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp, - bool is_client, - tsi_handshaker_result** self) { +tsi_result alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp* resp, + bool is_client, + tsi_handshaker_result** self) { if (self == nullptr || resp == nullptr) { gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()"); return TSI_INVALID_ARGUMENT; @@ -234,6 +237,41 @@ static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp, return TSI_OK; } +static void init_shared_resources(const char* handshaker_service_url, + bool use_dedicated_cq) { + GPR_ASSERT(handshaker_service_url != nullptr); + gpr_mu_lock(&g_shared_resources->mu); + if (g_shared_resources->channel == nullptr) { + g_shared_resources->channel = + grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr); + if (use_dedicated_cq) { + grpc_alts_shared_resource_dedicated_start(); + } + } + gpr_mu_unlock(&g_shared_resources->mu); +} + +/* gRPC provided callback used when gRPC thread model is applied. */ +static void on_handshaker_service_resp_recv(void* arg, grpc_error* error) { + alts_handshaker_client* client = static_cast<alts_handshaker_client*>(arg); + if (client == nullptr) { + gpr_log(GPR_ERROR, "ALTS handshaker client is nullptr"); + return; + } + alts_handshaker_client_handle_response(client, true); +} + +/* gRPC provided callback used when dedicatd CQ and thread are used. + * It serves to safely bring the control back to application. */ +static void on_handshaker_service_resp_recv_dedicated(void* arg, + grpc_error* error) { + alts_shared_resource_dedicated* resource = + grpc_alts_get_shared_resource_dedicated(); + grpc_cq_end_op(resource->cq, arg, GRPC_ERROR_NONE, + [](void* done_arg, grpc_cq_completion* storage) {}, nullptr, + &resource->storage); +} + static tsi_result handshaker_next( tsi_handshaker* self, const unsigned char* received_bytes, size_t received_bytes_size, const unsigned char** bytes_to_send, @@ -250,12 +288,32 @@ static tsi_result handshaker_next( alts_tsi_handshaker* handshaker = reinterpret_cast<alts_tsi_handshaker*>(self); tsi_result ok = TSI_OK; - alts_tsi_event* event = nullptr; - ok = alts_tsi_event_create(handshaker, cb, user_data, handshaker->options, - handshaker->target_name, &event); - if (ok != TSI_OK) { - gpr_log(GPR_ERROR, "Failed to create ALTS TSI event"); - return ok; + if (!handshaker->has_created_handshaker_client) { + init_shared_resources(handshaker->handshaker_service_url, + handshaker->use_dedicated_cq); + if (handshaker->use_dedicated_cq) { + handshaker->interested_parties = + grpc_alts_get_shared_resource_dedicated()->interested_parties; + GPR_ASSERT(handshaker->interested_parties != nullptr); + } + grpc_iomgr_cb_func grpc_cb = handshaker->use_dedicated_cq + ? on_handshaker_service_resp_recv_dedicated + : on_handshaker_service_resp_recv; + handshaker->client = alts_grpc_handshaker_client_create( + handshaker, g_shared_resources->channel, + handshaker->handshaker_service_url, handshaker->interested_parties, + handshaker->options, handshaker->target_name, grpc_cb, cb, user_data, + handshaker->client_vtable_for_testing, handshaker->is_client); + if (handshaker->client == nullptr) { + gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client"); + return TSI_FAILED_PRECONDITION; + } + handshaker->has_created_handshaker_client = true; + } + if (handshaker->use_dedicated_cq && + handshaker->client_vtable_for_testing == nullptr) { + GPR_ASSERT(grpc_cq_begin_op(grpc_alts_get_shared_resource_dedicated()->cq, + handshaker->client)); } grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0) ? grpc_empty_slice() @@ -264,16 +322,11 @@ static tsi_result handshaker_next( received_bytes_size); if (!handshaker->has_sent_start_message) { ok = handshaker->is_client - ? alts_handshaker_client_start_client(handshaker->client, event) - : alts_handshaker_client_start_server(handshaker->client, event, - &slice); + ? alts_handshaker_client_start_client(handshaker->client) + : alts_handshaker_client_start_server(handshaker->client, &slice); handshaker->has_sent_start_message = true; } else { - if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) { - grpc_slice_unref_internal(handshaker->recv_bytes); - } - handshaker->recv_bytes = grpc_slice_ref(slice); - ok = alts_handshaker_client_next(handshaker->client, event, &slice); + ok = alts_handshaker_client_next(handshaker->client, &slice); } grpc_slice_unref_internal(slice); if (ok != TSI_OK) { @@ -283,6 +336,22 @@ static tsi_result handshaker_next( return TSI_ASYNC; } +/* + * This API will be invoked by a non-gRPC application, and an ExecCtx needs + * to be explicitly created in order to invoke ALTS handshaker client API's + * that assumes the caller is inside gRPC core. + */ +static tsi_result handshaker_next_dedicated( + tsi_handshaker* self, const unsigned char* received_bytes, + size_t received_bytes_size, const unsigned char** bytes_to_send, + size_t* bytes_to_send_size, tsi_handshaker_result** result, + tsi_handshaker_on_next_done_cb cb, void* user_data) { + grpc_core::ExecCtx exec_ctx; + return handshaker_next(self, received_bytes, received_bytes_size, + bytes_to_send, bytes_to_send_size, result, cb, + user_data); +} + static void handshaker_shutdown(tsi_handshaker* self) { GPR_ASSERT(self != nullptr); if (self->handshake_shutdown) { @@ -300,10 +369,9 @@ static void handshaker_destroy(tsi_handshaker* self) { alts_tsi_handshaker* handshaker = reinterpret_cast<alts_tsi_handshaker*>(self); alts_handshaker_client_destroy(handshaker->client); - grpc_slice_unref_internal(handshaker->recv_bytes); grpc_slice_unref_internal(handshaker->target_name); grpc_alts_credentials_options_destroy(handshaker->options); - gpr_free(handshaker->buffer); + gpr_free(handshaker->handshaker_service_url); gpr_free(handshaker); } @@ -313,36 +381,19 @@ static const tsi_handshaker_vtable handshaker_vtable = { nullptr, handshaker_destroy, handshaker_next, handshaker_shutdown}; -static void thread_worker(void* arg) { - while (true) { - grpc_event event = grpc_completion_queue_next( - kSharedResource->cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); - GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT); - if (event.type == GRPC_QUEUE_SHUTDOWN) { - /* signal alts_tsi_shutdown() to destroy completion queue. */ - grpc_tsi_alts_signal_for_cq_destroy(); - break; - } - /* event.type == GRPC_OP_COMPLETE. */ - alts_tsi_event* alts_event = static_cast<alts_tsi_event*>(event.tag); - alts_tsi_event_dispatch_to_handshaker(alts_event, event.success); - alts_tsi_event_destroy(alts_event); - } -} - -static void init_shared_resources(const char* handshaker_service_url) { - GPR_ASSERT(handshaker_service_url != nullptr); - gpr_mu_lock(&kSharedResource->mu); - if (kSharedResource->channel == nullptr) { - gpr_cv_init(&kSharedResource->cv); - kSharedResource->channel = - grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr); - kSharedResource->cq = grpc_completion_queue_create_for_next(nullptr); - kSharedResource->thread = - grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr); - kSharedResource->thread.Start(); - } - gpr_mu_unlock(&kSharedResource->mu); +static const tsi_handshaker_vtable handshaker_vtable_dedicated = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + handshaker_destroy, + handshaker_next_dedicated, + handshaker_shutdown}; + +bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker) { + GPR_ASSERT(handshaker != nullptr); + return handshaker->base.handshake_shutdown; } tsi_result alts_tsi_handshaker_create( @@ -354,40 +405,29 @@ tsi_result alts_tsi_handshaker_create( gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()"); return TSI_INVALID_ARGUMENT; } - init_shared_resources(handshaker_service_url); - alts_handshaker_client* client = alts_grpc_handshaker_client_create( - kSharedResource->channel, kSharedResource->cq, handshaker_service_url); - if (client == nullptr) { - gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client"); - return TSI_FAILED_PRECONDITION; - } alts_tsi_handshaker* handshaker = static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker))); - handshaker->client = client; - handshaker->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE; - handshaker->buffer = - static_cast<unsigned char*>(gpr_zalloc(handshaker->buffer_size)); + handshaker->use_dedicated_cq = interested_parties == nullptr; + handshaker->client = nullptr; handshaker->is_client = is_client; handshaker->has_sent_start_message = false; handshaker->target_name = target_name == nullptr ? grpc_empty_slice() : grpc_slice_from_static_string(target_name); + handshaker->interested_parties = interested_parties; + handshaker->has_created_handshaker_client = false; + handshaker->handshaker_service_url = gpr_strdup(handshaker_service_url); handshaker->options = grpc_alts_credentials_options_copy(options); - handshaker->base.vtable = &handshaker_vtable; + handshaker->base.vtable = handshaker->use_dedicated_cq + ? &handshaker_vtable_dedicated + : &handshaker_vtable; *self = &handshaker->base; return TSI_OK; } -static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) { - GPR_ASSERT(resp != nullptr); - if (resp->has_result) { - return true; - } - return false; -} - -static void set_unused_bytes(tsi_handshaker_result* self, - grpc_slice* recv_bytes, size_t bytes_consumed) { +void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* self, + grpc_slice* recv_bytes, + size_t bytes_consumed) { GPR_ASSERT(recv_bytes != nullptr && self != nullptr); if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) { return; @@ -402,81 +442,6 @@ static void set_unused_bytes(tsi_handshaker_result* self, result->unused_bytes_size); } -void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker, - grpc_byte_buffer* recv_buffer, - grpc_status_code status, - grpc_slice* details, - tsi_handshaker_on_next_done_cb cb, - void* user_data, bool is_ok) { - /* Invalid input check. */ - if (cb == nullptr) { - gpr_log(GPR_ERROR, - "cb is nullptr in alts_tsi_handshaker_handle_response()"); - return; - } - if (handshaker == nullptr || recv_buffer == nullptr) { - gpr_log(GPR_ERROR, - "Invalid arguments to alts_tsi_handshaker_handle_response()"); - cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); - return; - } - if (handshaker->base.handshake_shutdown) { - gpr_log(GPR_ERROR, "TSI handshake shutdown"); - cb(TSI_HANDSHAKE_SHUTDOWN, user_data, nullptr, 0, nullptr); - return; - } - /* Failed grpc call check. */ - if (!is_ok || status != GRPC_STATUS_OK) { - gpr_log(GPR_ERROR, "grpc call made to handshaker service failed"); - if (details != nullptr) { - char* error_details = grpc_slice_to_c_string(*details); - gpr_log(GPR_ERROR, "error details:%s", error_details); - gpr_free(error_details); - } - cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr); - return; - } - grpc_gcp_handshaker_resp* resp = - alts_tsi_utils_deserialize_response(recv_buffer); - /* Invalid handshaker response check. */ - if (resp == nullptr) { - gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed"); - cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr); - return; - } - grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg); - unsigned char* bytes_to_send = nullptr; - size_t bytes_to_send_size = 0; - if (slice != nullptr) { - bytes_to_send_size = GRPC_SLICE_LENGTH(*slice); - while (bytes_to_send_size > handshaker->buffer_size) { - handshaker->buffer_size *= 2; - handshaker->buffer = static_cast<unsigned char*>( - gpr_realloc(handshaker->buffer, handshaker->buffer_size)); - } - memcpy(handshaker->buffer, GRPC_SLICE_START_PTR(*slice), - bytes_to_send_size); - bytes_to_send = handshaker->buffer; - } - tsi_handshaker_result* result = nullptr; - if (is_handshake_finished_properly(resp)) { - create_handshaker_result(resp, handshaker->is_client, &result); - set_unused_bytes(result, &handshaker->recv_bytes, resp->bytes_consumed); - } - grpc_status_code code = static_cast<grpc_status_code>(resp->status.code); - if (code != GRPC_STATUS_OK) { - grpc_slice* details = static_cast<grpc_slice*>(resp->status.details.arg); - if (details != nullptr) { - char* error_details = grpc_slice_to_c_string(*details); - gpr_log(GPR_ERROR, "Error from handshaker service:%s", error_details); - gpr_free(error_details); - } - } - grpc_gcp_handshaker_resp_destroy(resp); - cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send, - bytes_to_send_size, result); -} - namespace grpc_core { namespace internal { @@ -486,29 +451,16 @@ bool alts_tsi_handshaker_get_has_sent_start_message_for_testing( return handshaker->has_sent_start_message; } -bool alts_tsi_handshaker_get_is_client_for_testing( - alts_tsi_handshaker* handshaker) { +void alts_tsi_handshaker_set_client_vtable_for_testing( + alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable) { GPR_ASSERT(handshaker != nullptr); - return handshaker->is_client; + handshaker->client_vtable_for_testing = vtable; } -void alts_tsi_handshaker_set_recv_bytes_for_testing( - alts_tsi_handshaker* handshaker, grpc_slice* slice) { - GPR_ASSERT(handshaker != nullptr && slice != nullptr); - handshaker->recv_bytes = grpc_slice_ref(*slice); -} - -grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing( +bool alts_tsi_handshaker_get_is_client_for_testing( alts_tsi_handshaker* handshaker) { GPR_ASSERT(handshaker != nullptr); - return handshaker->recv_bytes; -} - -void alts_tsi_handshaker_set_client_for_testing( - alts_tsi_handshaker* handshaker, alts_handshaker_client* client) { - GPR_ASSERT(handshaker != nullptr && client != nullptr); - alts_handshaker_client_destroy(handshaker->client); - handshaker->client = client; + return handshaker->is_client; } alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing( diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h index 48ce69b1da..c961eae498 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h @@ -25,6 +25,8 @@ #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" +#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" +#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h" #include "src/core/tsi/alts_transport_security.h" #include "src/core/tsi/transport_security.h" #include "src/core/tsi/transport_security_interface.h" @@ -35,10 +37,6 @@ const size_t kTsiAltsNumOfPeerProperties = 3; -/** - * Main struct for ALTS TSI handshaker. All APIs in the header are - * thread-comptabile. - */ typedef struct alts_tsi_handshaker alts_tsi_handshaker; /** @@ -56,7 +54,9 @@ typedef struct alts_tsi_handshaker alts_tsi_handshaker; * - self: address of ALTS TSI handshaker instance to be returned from the * method. * - * It returns TSI_OK on success and an error status code on failure. + * It returns TSI_OK on success and an error status code on failure. Note that + * if interested_parties is nullptr, a dedicated TSI thread will be created and + * used. */ tsi_result alts_tsi_handshaker_create( const grpc_alts_credentials_options* options, const char* target_name, @@ -64,23 +64,32 @@ tsi_result alts_tsi_handshaker_create( grpc_pollset_set* interested_parties, tsi_handshaker** self); /** - * This method handles handshaker response returned from ALTS handshaker - * service. + * This method creates an ALTS TSI handshaker result instance. * - * - handshaker: ALTS TSI handshaker instance. - * - recv_buffer: buffer holding data received from the handshaker service. - * - status: status of the grpc call made to the handshaker service. - * - details: error details of the grpc call made to the handshaker service. - * - cb: callback function of ALTS TSI event. - * - user_data: argument of callback function. - * - is_ok: a boolean value indicating if the handshaker response is ok to read. + * - resp: data received from the handshaker service. + * - is_client: a boolean value indicating if the result belongs to a + * client or not. + * - result: address of ALTS TSI handshaker result instance. + */ +tsi_result alts_tsi_handshaker_result_create(grpc_gcp_handshaker_resp* resp, + bool is_client, + tsi_handshaker_result** result); + +/** + * This method sets unused bytes of ALTS TSI handshaker result instance. * + * - result: an ALTS TSI handshaker result instance. + * - recv_bytes: data received from the handshaker service. + * - bytes_consumed: size of data consumed by the handshaker service. + */ +void alts_tsi_handshaker_result_set_unused_bytes(tsi_handshaker_result* result, + grpc_slice* recv_bytes, + size_t bytes_consumed); + +/** + * This method returns a boolean value indicating if an ALTS TSI handshaker + * has been shutdown or not. */ -void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker, - grpc_byte_buffer* recv_buffer, - grpc_status_code status, - grpc_slice* details, - tsi_handshaker_on_next_done_cb cb, - void* user_data, bool is_ok); +bool alts_tsi_handshaker_has_shutdown(alts_tsi_handshaker* handshaker); #endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H */ diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h index 9612071407..ec2616e95f 100644 --- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h +++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h @@ -27,27 +27,55 @@ namespace grpc_core { namespace internal { /** - * Unsafe, use for testing only. It allows the caller to change the way the - * ALTS TSI handshaker schedules handshaker requests. - */ -void alts_tsi_handshaker_set_client_for_testing(alts_tsi_handshaker* handshaker, - alts_handshaker_client* client); + * Unsafe, use for testing only. */ alts_handshaker_client* alts_tsi_handshaker_get_client_for_testing( alts_tsi_handshaker* handshaker); -/* For testing only. */ bool alts_tsi_handshaker_get_has_sent_start_message_for_testing( alts_tsi_handshaker* handshaker); +void alts_tsi_handshaker_set_client_vtable_for_testing( + alts_tsi_handshaker* handshaker, alts_handshaker_client_vtable* vtable); + bool alts_tsi_handshaker_get_is_client_for_testing( alts_tsi_handshaker* handshaker); -void alts_tsi_handshaker_set_recv_bytes_for_testing( - alts_tsi_handshaker* handshaker, grpc_slice* slice); +void alts_handshaker_client_set_grpc_caller_for_testing( + alts_handshaker_client* client, alts_grpc_caller caller); -grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing( - alts_tsi_handshaker* handshaker); +grpc_byte_buffer* alts_handshaker_client_get_send_buffer_for_testing( + alts_handshaker_client* client); + +grpc_byte_buffer** alts_handshaker_client_get_recv_buffer_addr_for_testing( + alts_handshaker_client* client); + +grpc_metadata_array* alts_handshaker_client_get_initial_metadata_for_testing( + alts_handshaker_client* client); + +void alts_handshaker_client_set_recv_bytes_for_testing( + alts_handshaker_client* client, grpc_slice* recv_bytes); + +void alts_handshaker_client_check_fields_for_testing( + alts_handshaker_client* client, tsi_handshaker_on_next_done_cb cb, + void* user_data, bool has_sent_start_message, grpc_slice* recv_bytes); + +void alts_handshaker_client_set_fields_for_testing( + alts_handshaker_client* client, alts_tsi_handshaker* handshaker, + tsi_handshaker_on_next_done_cb cb, void* user_data, + grpc_byte_buffer* recv_buffer, grpc_status_code status); + +void alts_handshaker_client_set_vtable_for_testing( + alts_handshaker_client* client, alts_handshaker_client_vtable* vtable); + +alts_tsi_handshaker* alts_handshaker_client_get_handshaker_for_testing( + alts_handshaker_client* client); + +void alts_handshaker_client_set_cb_for_testing( + alts_handshaker_client* client, tsi_handshaker_on_next_done_cb cb); + +grpc_closure* alts_handshaker_client_get_closure_for_testing( + alts_handshaker_client* client); } // namespace internal } // namespace grpc_core diff --git a/src/core/tsi/alts_transport_security.cc b/src/core/tsi/alts_transport_security.cc index dac23bbf7a..5a1494ae5c 100644 --- a/src/core/tsi/alts_transport_security.cc +++ b/src/core/tsi/alts_transport_security.cc @@ -18,48 +18,24 @@ #include <grpc/support/port_platform.h> -#include "src/core/tsi/alts_transport_security.h" - #include <string.h> +#include "src/core/tsi/alts_transport_security.h" + static alts_shared_resource g_alts_resource; alts_shared_resource* alts_get_shared_resource(void) { return &g_alts_resource; } -static void grpc_tsi_alts_wait_for_cq_drain() { - gpr_mu_lock(&g_alts_resource.mu); - while (!g_alts_resource.is_cq_drained) { - gpr_cv_wait(&g_alts_resource.cv, &g_alts_resource.mu, - gpr_inf_future(GPR_CLOCK_REALTIME)); - } - gpr_mu_unlock(&g_alts_resource.mu); -} - -void grpc_tsi_alts_signal_for_cq_destroy() { - gpr_mu_lock(&g_alts_resource.mu); - g_alts_resource.is_cq_drained = true; - gpr_cv_signal(&g_alts_resource.cv); - gpr_mu_unlock(&g_alts_resource.mu); -} - void grpc_tsi_alts_init() { g_alts_resource.channel = nullptr; - g_alts_resource.cq = nullptr; - g_alts_resource.is_cq_drained = false; gpr_mu_init(&g_alts_resource.mu); - gpr_cv_init(&g_alts_resource.cv); } void grpc_tsi_alts_shutdown() { - if (g_alts_resource.cq != nullptr) { - grpc_completion_queue_shutdown(g_alts_resource.cq); - grpc_tsi_alts_wait_for_cq_drain(); - grpc_completion_queue_destroy(g_alts_resource.cq); + if (g_alts_resource.channel != nullptr) { grpc_channel_destroy(g_alts_resource.channel); - g_alts_resource.thread.Join(); } - gpr_cv_destroy(&g_alts_resource.cv); gpr_mu_destroy(&g_alts_resource.mu); } diff --git a/src/core/tsi/alts_transport_security.h b/src/core/tsi/alts_transport_security.h index d6b8e11137..f4319d10d2 100644 --- a/src/core/tsi/alts_transport_security.h +++ b/src/core/tsi/alts_transport_security.h @@ -27,21 +27,12 @@ #include "src/core/lib/gprpp/thd.h" typedef struct alts_shared_resource { - grpc_core::Thread thread; grpc_channel* channel; - grpc_completion_queue* cq; gpr_mu mu; - gpr_cv cv; - bool is_cq_drained; } alts_shared_resource; /* This method returns the address of alts_shared_resource object shared by all * TSI handshakes. */ alts_shared_resource* alts_get_shared_resource(void); -/* This method signals the thread that invokes grpc_tsi_alts_shutdown() to - * continue with destroying the cq as a part of shutdown process. */ - -void grpc_tsi_alts_signal_for_cq_destroy(void); - #endif /* GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H */ diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 5e7ecf0ebf..8e1cea0269 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -115,7 +115,7 @@ void ChannelResetConnectionBackoff(Channel* channel) { internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, ClientContext* context, CompletionQueue* cq, - int interceptor_pos) { + size_t interceptor_pos) { const bool kRegistered = method.channel_tag() && context->authority().empty(); grpc_call* c_call = nullptr; if (kRegistered) { @@ -229,7 +229,7 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor { static void Run(grpc_experimental_completion_queue_functor* cb, int) { auto* callback = static_cast<ShutdownCallback*>(cb); delete callback->cq_; - grpc_core::Delete(callback); + delete callback; } private: @@ -242,7 +242,7 @@ CompletionQueue* Channel::CallbackCQ() { // if there is no explicit per-channel CQ registered std::lock_guard<std::mutex> l(mu_); if (callback_cq_ == nullptr) { - auto* shutdown_callback = grpc_core::New<ShutdownCallback>(); + auto* shutdown_callback = new ShutdownCallback; callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback}); diff --git a/src/cpp/client/client_interceptor.cc b/src/cpp/client/client_interceptor.cc new file mode 100644 index 0000000000..3a5cac9830 --- /dev/null +++ b/src/cpp/client/client_interceptor.cc @@ -0,0 +1,34 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpcpp/impl/codegen/client_interceptor.h> + +namespace grpc { + +namespace internal { +experimental::ClientInterceptorFactoryInterface* + g_global_client_interceptor_factory = nullptr; +} + +namespace experimental { +void RegisterGlobalClientInterceptorFactory( + ClientInterceptorFactoryInterface* factory) { + internal::g_global_client_interceptor_factory = factory; +} +} // namespace experimental +} // namespace grpc diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index d1cd78e755..7faaa20e78 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -228,9 +228,10 @@ int MetadataCredentialsPluginWrapper::GetMetadata( } if (w->plugin_->IsBlocking()) { // Asynchronous return. - w->thread_pool_->Add( - std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context, - cb, user_data, nullptr, nullptr, nullptr, nullptr)); + w->thread_pool_->Add([w, context, cb, user_data] { + w->MetadataCredentialsPluginWrapper::InvokePlugin( + context, cb, user_data, nullptr, nullptr, nullptr, nullptr); + }); return 0; } else { // Synchronous return. diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc index 6893201e2e..d93a54aed7 100644 --- a/src/cpp/common/completion_queue_cc.cc +++ b/src/cpp/common/completion_queue_cc.cc @@ -60,10 +60,10 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( case GRPC_QUEUE_SHUTDOWN: return SHUTDOWN; case GRPC_OP_COMPLETE: - auto cq_tag = static_cast<internal::CompletionQueueTag*>(ev.tag); + auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(ev.tag); *ok = ev.success != 0; - *tag = cq_tag; - if (cq_tag->FinalizeResult(tag, ok)) { + *tag = core_cq_tag; + if (core_cq_tag->FinalizeResult(tag, ok)) { return GOT_EVENT; } break; @@ -87,9 +87,9 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) { flushed_ = true; if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag, &res)) { - auto cq_tag = static_cast<internal::CompletionQueueTag*>(res_tag); + auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(res_tag); *ok = res == 1; - if (cq_tag->FinalizeResult(tag, ok)) { + if (core_cq_tag->FinalizeResult(tag, ok)) { return true; } } diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 536bf022dd..ebb17def32 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -43,9 +43,10 @@ void AuthMetadataProcessorAyncWrapper::Process( return; } if (w->processor_->IsBlocking()) { - w->thread_pool_->Add( - std::bind(&AuthMetadataProcessorAyncWrapper::InvokeProcessor, w, - context, md, num_md, cb, user_data)); + w->thread_pool_->Add([w, context, md, num_md, cb, user_data] { + w->AuthMetadataProcessorAyncWrapper::InvokeProcessor(context, md, num_md, + cb, user_data); + }); } else { // invoke directly. w->InvokeProcessor(context, md, num_md, cb, user_data); diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index fc42b6c886..0dc03b6876 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -71,7 +71,9 @@ ServerBuilder::~ServerBuilder() { std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue( bool is_frequently_polled) { ServerCompletionQueue* cq = new ServerCompletionQueue( - is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING); + GRPC_CQ_NEXT, + is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING, + nullptr); cqs_.push_back(cq); return std::unique_ptr<ServerCompletionQueue>(cq); } @@ -256,15 +258,22 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { // Create completion queues to listen to incoming rpc requests for (int i = 0; i < sync_server_settings_.num_cqs; i++) { - sync_server_cqs->emplace_back(new ServerCompletionQueue(polling_type)); + sync_server_cqs->emplace_back( + new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr)); } } - std::unique_ptr<Server> server(new Server( - max_receive_message_size_, &args, sync_server_cqs, - sync_server_settings_.min_pollers, sync_server_settings_.max_pollers, - sync_server_settings_.cq_timeout_msec, resource_quota_, - std::move(interceptor_creators_))); + // == Determine if the server has any callback methods == + bool has_callback_methods = false; + for (auto it = services_.begin(); it != services_.end(); ++it) { + if ((*it)->service->has_callback_methods()) { + has_callback_methods = true; + break; + } + } + + // TODO(vjpai): Add a section here for plugins once they can support callback + // methods if (has_sync_methods) { // This is a Sync server @@ -276,6 +285,16 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { sync_server_settings_.cq_timeout_msec); } + if (has_callback_methods) { + gpr_log(GPR_INFO, "Callback server."); + } + + std::unique_ptr<Server> server(new Server( + max_receive_message_size_, &args, sync_server_cqs, + sync_server_settings_.min_pollers, sync_server_settings_.max_pollers, + sync_server_settings_.cq_timeout_msec, resource_quota_, + std::move(interceptor_creators_))); + ServerInitializer* initializer = server->initializer(); // Register all the completion queues with the server. i.e @@ -289,6 +308,12 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { num_frequently_polled_cqs++; } + if (has_callback_methods) { + auto* cq = server->CallbackCQ(); + grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr); + num_frequently_polled_cqs++; + } + // cqs_ contains the completion queue added by calling the ServerBuilder's // AddCompletionQueue() API. Some of them may not be frequently polled (i.e by // calling Next() or AsyncNext()) and hence are not safe to be used for diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 6f911e1392..c031528a8f 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -147,9 +147,9 @@ class Server::UnimplementedAsyncResponse final class Server::SyncRequest final : public internal::CompletionQueueTag { public: - SyncRequest(internal::RpcServiceMethod* method, void* tag) + SyncRequest(internal::RpcServiceMethod* method, void* method_tag) : method_(method), - tag_(tag), + method_tag_(method_tag), in_flight_(false), has_request_payload_( method->method_type() == internal::RpcMethod::NORMAL_RPC || @@ -176,10 +176,10 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { void Request(grpc_server* server, grpc_completion_queue* notify_cq) { GPR_ASSERT(cq_ && !in_flight_); in_flight_ = true; - if (tag_) { + if (method_tag_) { if (GRPC_CALL_OK != grpc_server_request_registered_call( - server, tag_, &call_, &deadline_, &request_metadata_, + server, method_tag_, &call_, &deadline_, &request_metadata_, has_request_payload_ ? &request_payload_ : nullptr, cq_, notify_cq, this)) { TeardownRequest(); @@ -211,6 +211,9 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { return true; } + // The CallData class represents a call that is "active" as opposed + // to just being requested. It wraps and takes ownership of the cq from + // the call request class CallData final { public: explicit CallData(Server* server, SyncRequest* mrd) @@ -265,8 +268,8 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { interceptor_methods_.SetRecvMessage(request_); } - auto f = std::bind(&CallData::ContinueRunAfterInterception, this); - if (interceptor_methods_.RunInterceptors(f)) { + if (interceptor_methods_.RunInterceptors( + [this]() { ContinueRunAfterInterception(); })) { ContinueRunAfterInterception(); } else { // There were interceptors to be run, so ContinueRunAfterInterception @@ -276,12 +279,12 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { void ContinueRunAfterInterception() { { - ctx_.BeginCompletionOp(&call_); + ctx_.BeginCompletionOp(&call_, false); global_callbacks_->PreSynchronousRequest(&ctx_); auto* handler = resources_ ? method_->handler() : server_->resource_exhausted_handler_.get(); handler->RunHandler(internal::MethodHandler::HandlerParameter( - &call_, &ctx_, request_, request_status_)); + &call_, &ctx_, request_, request_status_, nullptr)); request_ = nullptr; global_callbacks_->PostSynchronousRequest(&ctx_); @@ -314,7 +317,7 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { private: internal::RpcServiceMethod* const method_; - void* const tag_; + void* const method_tag_; bool in_flight_; const bool has_request_payload_; grpc_call* call_; @@ -325,6 +328,176 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { grpc_completion_queue* cq_; }; +class Server::CallbackRequest final : public internal::CompletionQueueTag { + public: + CallbackRequest(Server* server, internal::RpcServiceMethod* method, + void* method_tag) + : server_(server), + method_(method), + method_tag_(method_tag), + has_request_payload_( + method->method_type() == internal::RpcMethod::NORMAL_RPC || + method->method_type() == internal::RpcMethod::SERVER_STREAMING), + cq_(server->CallbackCQ()), + tag_(this) { + Setup(); + } + + ~CallbackRequest() { Clear(); } + + void Request() { + if (method_tag_) { + if (GRPC_CALL_OK != + grpc_server_request_registered_call( + server_->c_server(), method_tag_, &call_, &deadline_, + &request_metadata_, + has_request_payload_ ? &request_payload_ : nullptr, cq_->cq(), + cq_->cq(), static_cast<void*>(&tag_))) { + return; + } + } else { + if (!call_details_) { + call_details_ = new grpc_call_details; + grpc_call_details_init(call_details_); + } + if (grpc_server_request_call(server_->c_server(), &call_, call_details_, + &request_metadata_, cq_->cq(), cq_->cq(), + static_cast<void*>(&tag_)) != GRPC_CALL_OK) { + return; + } + } + } + + bool FinalizeResult(void** tag, bool* status) override { return false; } + + private: + class CallbackCallTag : public grpc_experimental_completion_queue_functor { + public: + CallbackCallTag(Server::CallbackRequest* req) : req_(req) { + functor_run = &CallbackCallTag::StaticRun; + } + + // force_run can not be performed on a tag if operations using this tag + // have been sent to PerformOpsOnCall. It is intended for error conditions + // that are detected before the operations are internally processed. + void force_run(bool ok) { Run(ok); } + + private: + Server::CallbackRequest* req_; + internal::Call* call_; + + static void StaticRun(grpc_experimental_completion_queue_functor* cb, + int ok) { + static_cast<CallbackCallTag*>(cb)->Run(static_cast<bool>(ok)); + } + void Run(bool ok) { + void* ignored = req_; + bool new_ok = ok; + GPR_ASSERT(!req_->FinalizeResult(&ignored, &new_ok)); + GPR_ASSERT(ignored == req_); + + if (!ok) { + // The call has been shutdown + req_->Clear(); + return; + } + + // Bind the call, deadline, and metadata from what we got + req_->ctx_.set_call(req_->call_); + req_->ctx_.cq_ = req_->cq_; + req_->ctx_.BindDeadlineAndMetadata(req_->deadline_, + &req_->request_metadata_); + req_->request_metadata_.count = 0; + + // Create a C++ Call to control the underlying core call + call_ = new (grpc_call_arena_alloc(req_->call_, sizeof(internal::Call))) + internal::Call( + req_->call_, req_->server_, req_->cq_, + req_->server_->max_receive_message_size(), + req_->ctx_.set_server_rpc_info( + req_->method_->name(), req_->server_->interceptor_creators_)); + + req_->interceptor_methods_.SetCall(call_); + req_->interceptor_methods_.SetReverse(); + // Set interception point for RECV INITIAL METADATA + req_->interceptor_methods_.AddInterceptionHookPoint( + experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); + req_->interceptor_methods_.SetRecvInitialMetadata( + &req_->ctx_.client_metadata_); + + if (req_->has_request_payload_) { + // Set interception point for RECV MESSAGE + req_->request_ = req_->method_->handler()->Deserialize( + req_->call_, req_->request_payload_, &req_->request_status_); + req_->request_payload_ = nullptr; + req_->interceptor_methods_.AddInterceptionHookPoint( + experimental::InterceptionHookPoints::POST_RECV_MESSAGE); + req_->interceptor_methods_.SetRecvMessage(req_->request_); + } + + if (req_->interceptor_methods_.RunInterceptors( + [this] { ContinueRunAfterInterception(); })) { + ContinueRunAfterInterception(); + } else { + // There were interceptors to be run, so ContinueRunAfterInterception + // will be run when interceptors are done. + } + } + void ContinueRunAfterInterception() { + req_->ctx_.BeginCompletionOp(call_, true); + req_->method_->handler()->RunHandler( + internal::MethodHandler::HandlerParameter( + call_, &req_->ctx_, req_->request_, req_->request_status_, + [this] { + req_->Reset(); + req_->Request(); + })); + } + }; + + void Reset() { + Clear(); + Setup(); + } + + void Clear() { + if (call_details_) { + delete call_details_; + call_details_ = nullptr; + } + grpc_metadata_array_destroy(&request_metadata_); + if (has_request_payload_ && request_payload_) { + grpc_byte_buffer_destroy(request_payload_); + } + ctx_.Clear(); + interceptor_methods_.ClearState(); + } + + void Setup() { + grpc_metadata_array_init(&request_metadata_); + ctx_.Setup(gpr_inf_future(GPR_CLOCK_REALTIME)); + request_payload_ = nullptr; + request_ = nullptr; + request_status_ = Status(); + } + + Server* const server_; + internal::RpcServiceMethod* const method_; + void* const method_tag_; + const bool has_request_payload_; + grpc_byte_buffer* request_payload_; + void* request_; + Status request_status_; + grpc_call_details* call_details_ = nullptr; + grpc_call* call_; + gpr_timespec deadline_; + grpc_metadata_array request_metadata_; + CompletionQueue* cq_; + CallbackCallTag tag_; + ServerContext ctx_; + internal::InterceptorBatchMethodsImpl interceptor_methods_; +}; + // Implementation of ThreadManager. Each instance of SyncRequestThreadManager // manages a pool of threads that poll for incoming Sync RPCs and call the // appropriate RPC handlers @@ -504,6 +677,9 @@ Server::Server( Server::~Server() { { std::unique_lock<std::mutex> lock(mu_); + if (callback_cq_ != nullptr) { + callback_cq_->Shutdown(); + } if (started_ && !shutdown_) { lock.unlock(); Shutdown(); @@ -576,21 +752,28 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { } internal::RpcServiceMethod* method = it->get(); - void* tag = grpc_server_register_method( + void* method_registration_tag = grpc_server_register_method( server_, method->name(), host ? host->c_str() : nullptr, PayloadHandlingForMethod(method), 0); - if (tag == nullptr) { + if (method_registration_tag == nullptr) { gpr_log(GPR_DEBUG, "Attempt to register %s multiple times", method->name()); return false; } - if (method->handler() == nullptr) { // Async method - method->set_server_tag(tag); - } else { + if (method->handler() == nullptr) { // Async method without handler + method->set_server_tag(method_registration_tag); + } else if (method->api_type() == + internal::RpcServiceMethod::ApiType::SYNC) { for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) { - (*it)->AddSyncMethod(method, tag); + (*it)->AddSyncMethod(method, method_registration_tag); } + } else { + // a callback method + auto* req = new CallbackRequest(this, method, method_registration_tag); + callback_reqs_.emplace_back(req); + // Enqueue it so that it will be Request'ed later once + // all request matchers are created at core server startup } method_name = method->name(); @@ -641,7 +824,8 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { // performance. This ensures that we don't introduce thread hops // for application requests that wind up on this CQ, which is polled // in its own thread. - health_check_cq = new ServerCompletionQueue(GRPC_CQ_NON_POLLING); + health_check_cq = + new ServerCompletionQueue(GRPC_CQ_NEXT, GRPC_CQ_NON_POLLING, nullptr); grpc_server_register_completion_queue(server_, health_check_cq->cq(), nullptr); default_health_check_service_impl = @@ -678,6 +862,10 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { (*it)->Start(); } + for (auto& cbreq : callback_reqs_) { + cbreq->Request(); + } + if (default_health_check_service_impl != nullptr) { default_health_check_service_impl->StartServingThread(); } @@ -793,10 +981,8 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, interceptor_methods_.AddInterceptionHookPoint( experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_); - auto f = std::bind(&ServerInterface::BaseAsyncRequest:: - ContinueFinalizeResultAfterInterception, - this); - if (interceptor_methods_.RunInterceptors(f)) { + if (interceptor_methods_.RunInterceptors( + [this]() { ContinueFinalizeResultAfterInterception(); })) { // There are no interceptors to run. Continue } else { // There were interceptors to be run, so @@ -806,7 +992,7 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, } } if (*status && call_) { - context_->BeginCompletionOp(&call_wrapper_); + context_->BeginCompletionOp(&call_wrapper_, false); } *tag = tag_; if (delete_on_finalize_) { @@ -817,7 +1003,7 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, void ServerInterface::BaseAsyncRequest:: ContinueFinalizeResultAfterInterception() { - context_->BeginCompletionOp(&call_wrapper_); + context_->BeginCompletionOp(&call_wrapper_, false); // Queue a tag which will be returned immediately grpc_core::ExecCtx exec_ctx; grpc_cq_begin_op(notification_cq_->cq(), this); @@ -910,4 +1096,41 @@ Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( ServerInitializer* Server::initializer() { return server_initializer_.get(); } +namespace { +class ShutdownCallback : public grpc_experimental_completion_queue_functor { + public: + ShutdownCallback() { functor_run = &ShutdownCallback::Run; } + // TakeCQ takes ownership of the cq into the shutdown callback + // so that the shutdown callback will be responsible for destroying it + void TakeCQ(CompletionQueue* cq) { cq_ = cq; } + + // The Run function will get invoked by the completion queue library + // when the shutdown is actually complete + static void Run(grpc_experimental_completion_queue_functor* cb, int) { + auto* callback = static_cast<ShutdownCallback*>(cb); + delete callback->cq_; + delete callback; + } + + private: + CompletionQueue* cq_ = nullptr; +}; +} // namespace + +CompletionQueue* Server::CallbackCQ() { + // TODO(vjpai): Consider using a single global CQ for the default CQ + // if there is no explicit per-server CQ registered + std::lock_guard<std::mutex> l(mu_); + if (callback_cq_ == nullptr) { + auto* shutdown_callback = new ShutdownCallback; + callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, + shutdown_callback}); + + // Transfer ownership of the new cq to its own shutdown callback + shutdown_callback->TakeCQ(callback_cq_); + } + return callback_cq_; +}; + } // namespace grpc diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index e61fec9966..396996e5bc 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -45,11 +45,18 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { : call_(*call), has_tag_(false), tag_(nullptr), + core_cq_tag_(this), refs_(2), finalized_(false), cancelled_(0), done_intercepting_(false) {} + // CompletionOp isn't copyable or movable + CompletionOp(const CompletionOp&) = delete; + CompletionOp& operator=(const CompletionOp&) = delete; + CompletionOp(CompletionOp&&) = delete; + CompletionOp& operator=(CompletionOp&&) = delete; + ~CompletionOp() { if (call_.server_rpc_info()) { call_.server_rpc_info()->Unref(); @@ -85,8 +92,9 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { tag_ = tag; } - /// TODO(vjpai): Allow override of cq_tag if appropriate for callback API - void* cq_tag() override { return this; } + void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; } + + void* core_cq_tag() override { return core_cq_tag_; } void Unref(); @@ -130,6 +138,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { internal::Call call_; bool has_tag_; void* tag_; + void* core_cq_tag_; std::mutex mu_; int refs_; bool finalized_; @@ -157,8 +166,8 @@ void ServerContext::CompletionOp::FillOps(internal::Call* call) { interceptor_methods_.SetCall(&call_); interceptor_methods_.SetReverse(); interceptor_methods_.SetCallOpSetInterface(this); - GPR_ASSERT(GRPC_CALL_OK == - grpc_call_start_batch(call->call(), &ops, 1, this, nullptr)); + GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), &ops, 1, + core_cq_tag_, nullptr)); /* No interceptors to run here */ } @@ -209,43 +218,50 @@ bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) { // ServerContext body -ServerContext::ServerContext() - : completion_op_(nullptr), - has_notify_when_done_tag_(false), - async_notify_when_done_tag_(nullptr), - deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)), - call_(nullptr), - cq_(nullptr), - sent_initial_metadata_(false), - compression_level_set_(false), - has_pending_ops_(false) {} - -ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata_array* arr) - : completion_op_(nullptr), - has_notify_when_done_tag_(false), - async_notify_when_done_tag_(nullptr), - deadline_(deadline), - call_(nullptr), - cq_(nullptr), - sent_initial_metadata_(false), - compression_level_set_(false), - has_pending_ops_(false) { +ServerContext::ServerContext() { Setup(gpr_inf_future(GPR_CLOCK_REALTIME)); } + +ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata_array* arr) { + Setup(deadline); std::swap(*client_metadata_.arr(), *arr); } -ServerContext::~ServerContext() { +void ServerContext::Setup(gpr_timespec deadline) { + completion_op_ = nullptr; + has_notify_when_done_tag_ = false; + async_notify_when_done_tag_ = nullptr; + deadline_ = deadline; + call_ = nullptr; + cq_ = nullptr; + sent_initial_metadata_ = false; + compression_level_set_ = false; + has_pending_ops_ = false; + rpc_info_ = nullptr; +} + +void ServerContext::BindDeadlineAndMetadata(gpr_timespec deadline, + grpc_metadata_array* arr) { + deadline_ = deadline; + std::swap(*client_metadata_.arr(), *arr); +} + +ServerContext::~ServerContext() { Clear(); } + +void ServerContext::Clear() { if (call_) { grpc_call_unref(call_); } if (completion_op_) { completion_op_->Unref(); + completion_tag_.Clear(); } if (rpc_info_) { rpc_info_->Unref(); } + // Don't need to clear out call_, completion_op_, or rpc_info_ because this is + // either called from destructor or just before Setup } -void ServerContext::BeginCompletionOp(internal::Call* call) { +void ServerContext::BeginCompletionOp(internal::Call* call, bool callback) { GPR_ASSERT(!completion_op_); if (rpc_info_) { rpc_info_->Ref(); @@ -254,7 +270,10 @@ void ServerContext::BeginCompletionOp(internal::Call* call) { completion_op_ = new (grpc_call_arena_alloc(call->call(), sizeof(CompletionOp))) CompletionOp(call); - if (has_notify_when_done_tag_) { + if (callback) { + completion_tag_.Set(call->call(), nullptr, completion_op_); + completion_op_->set_core_cq_tag(&completion_tag_); + } else if (has_notify_when_done_tag_) { completion_op_->set_tag(async_notify_when_done_tag_); } call->PerformOps(completion_op_); @@ -289,12 +308,15 @@ void ServerContext::TryCancel() const { } bool ServerContext::IsCancelled() const { - if (has_notify_when_done_tag_) { - // when using async API, but the result is only valid + if (completion_tag_) { + // When using callback API, this result is always valid. + return completion_op_->CheckCancelledAsync(); + } else if (has_notify_when_done_tag_) { + // When using async API, the result is only valid // if the tag has already been delivered at the completion queue return completion_op_ && completion_op_->CheckCancelledAsync(); } else { - // when using sync API + // when using sync API, the result is always valid return completion_op_ && completion_op_->CheckCancelled(cq_); } } diff --git a/src/csharp/BUILD-INTEGRATION.md b/src/csharp/BUILD-INTEGRATION.md new file mode 100644 index 0000000000..3addc2403c --- /dev/null +++ b/src/csharp/BUILD-INTEGRATION.md @@ -0,0 +1,357 @@ +Protocol Buffers/gRPC Integration Into .NET Build +================================================= + +With Grpc.Tools package version 1.17 we made it easier to compile .proto files +in your project using the `dotnet build` command, Visual Studio, or command-line +MSBuild. You need to configure the .csproj project according to the way you want +to integrate Protocol Buffer files into your build. If you are upgrading an +existing project, read through this list of common scenarios and decide if any +one of them matches your approach. The protoc command line migration is +explained near the end of this document; this migration may be the quickest but +not the long-term solution. + +There is also a Reference section at the end of the file. + +Reporting issues +---------------- + +First thing first, if you found a bug in this new build system, or have a +scenario that is not easily covered, please open an [issue in the gRPC +repository](https://github.com/grpc/grpc/issues), and **tag the user @kkm000** +somewhere in the text (for example, include `/cc @kkm000` at end of the issue +text) to seize his immediate attention. + +Common scenarios +---------------- + +### I just want to compile .proto files into my library + +This is the approach taken by the examples in the `csharp/examples` directory. +Protoc output files (for example, `Helloworld.cs` and `HelloworldGrpc.cs` +compiled from `helloworld.proto`) are placed among *object* and other temporary +files of your project, and automatically provided as inputs to the C# compiler. +As with other automatically generated .cs files, they are included in the source +and symbols NuGet package, if you build one. + +Simply reference your .proto files in a `<Protobuf>` item group. The following +example will add all .proto files in a project and all its subdirectories +(excluding special directories such as `bin` and `obj`): + +```xml + <ItemGroup> + <Protobuf Include="**/*.proto" /> + </ItemGroup> +``` + +You must add a reference to the NuGet packages Grpc.Tools and Grpc (the latter +is a meta-package, in turn referencing Grpc.Core and Google.Protobuf packages). +It is **very important** to mark Grpc.Tools as a development-only dependency, so +that the *users* of your library do not fetch the tools package: + +* "Classic" .csproj with `packages.config` (Visual Studio, Mono): This is + handled automatically by NuGet. See the attribute added by Visual Studio to the + [packages.config](../../examples/csharp/HelloworldLegacyCsproj/Greeter/packages.config#L6) + file in the HelloworldLegacyCsproj/Greeter example. + +* "SDK" .csproj (Visual Studio, `dotnet new`): Add an attribute + `PrivateAssets="All"` to the Grpc.Tools package reference. See an example in the + [Greeter.csproj](../../examples/csharp/Helloworld/Greeter/Greeter.csproj#L10) + example project in this repository. If adding a package reference in Visual + Studio, edit the project file and add this attribute. [This is a bug in NuGet + client](https://github.com/NuGet/Home/issues/4125). + +If building a NuGet package from your library with the nuget command line tool +from a .nuspec file, then the spec file may (and probably should) reference the +Grpc metapackage, but **do not add a reference to Grpc.Tools** to it. .NET "SDK" +projects handle this automatically when called from `dotnet pack` by excluding +any packages with private assets, such as thus marked Grpc.Tools. + +#### Per-file options that can be set in Visual Studio + +For a "classic" project, you can only add .proto files with all options set to +default (if you find it necessary to modify these options, then hand-edit the +.csproj file). Click on the "show all files" button, add files to project, then +change file type of the .proto files to "Protobuf" in the Properties window +drop-down. This menu item will appear after you import the Grpc.Tools package: + +![Properties in a classic project](doc/integration.md-fig.1-classic.png) + +For an "SDK" project, you have more control of some frequently used options. +**You may need to open and close Visual Studio** for this form to appear in the +properties window after adding a reference to Grpc.Tools package (we do not know +whether this is a bug or by design, but it looks like a bug): + +![Properties in an SDK project](doc/integration.md-fig.2-sdk.png) + +You can also change options of multiple files at once by selecting them in the +Project Explorer together. + +See the Reference section at end of this file for options that can be set +per-file by modifying the source .csproj directly. + +#### My .proto files are in a directory outside the project + +Refer to the example files +[RouteGuide.csproj](../../examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj#L58-L60) +and [Greeter.csproj](../../examples/csharp/Helloworld/Greeter/Greeter.csproj#L11) +in this repository. For the files to show up in Visual Studio properly, add a +`Link` attribute with just a filename to the `<Protobuf>` item. This will be the +display name of the file. In the `Include` attribute, specify the complete path +to file. A relative path is based off the project directory. + +Or, if using Visual Studio, add files _as links_ from outside directory. In the +Add Files dialog, there is a little [down arrow near the Open +button](https://stackoverflow.com/a/9770061). Click on it, and choose "Add as +link". If you do not select this option, Visual Studio will copy files to the +project directory instead. + +### I just want to generate proto and gRPC C# sources from my .proto files (no C# compile) + +Suppose you want to place generated files right beside each respective source +.proto file. Create a .csproj library file in the common root of your .proto +tree, and add a reference to Grpc.Tools package (this works in Windows too, `$` +below stands for a command prompt in either platform): + +``` +/myproject/myprotofiles$ dotnet new classlib + . . . + Restoring packages for /myproject/myprotofiles/myprotofiles.csproj... + . . . +/myproject/myprotofiles$ rm *.cs <-- remove all *.cs files from template; +C:\myproject\myprotofiles> del *.cs /y <-- on Windows, use the del command instead. +/myproject/myprotofiles$ dotnet add package Grpc.Tools +``` + +(the latter command also accepts an optional `--version X.Y` switch for a +specific version of package, should you need one). Next open the generated +.csproj file in a text editor. + +Since you are not building a package, you may not worry about adding +`PrivateAssets="All"` attribute, but it will not hurt, in case you are +repurposing the project at some time later. The important part is (1) tell the +gRPC tools to select the whole directory of files; (2) order placement of each +output besides its source, and (3) not compile the generated .cs files. Add the +following stanza under the `<Project>` xml node: + +```xml + <ItemGroup> + <Protobuf Include="**/*.proto" OutputDir="%(RelativePath)" CompileOutputs="false" /> + </ItemGroup> +``` + +The `Include` tells the build system to recursively examine project directory +and its subdirectories (`**`) include all files matching the wildcard `*.proto`. +You can instead selectively include your files or selectively exclude files from +the glob pattern; [MSBuild documentation explains +that](https://docs.microsoft.com/visualstudio/msbuild/msbuild-items). The +`OutputDir="%(RelativePath)"` orders the output directory for each .cs file be +same as the corresponding .proto directory. Finally, `CompileOutputs="false"` +prevents compiling the generated files into an assembly. + +Note that an empty assembly is still generated, but you should ignore it. As +with any build system, it is used to detect out-of-date dependencies and +recompile them. + +#### I am getting a warning about a missing expected file! + +When we are preparing compile, there is no way to know whether a given proto +file will produce a *Grpc.cs output or not. If the proto file has a `service` +clause, it will; otherwise, it won't, but the build script cannot know that in +advance. When we are treating generated .cs files as temporary, this is ok, but +when generating them for you, creating empty files is probably not. You need to +tell the compiler which files should be compiled with gRPC services, and which +only contain protobuffer message definitions. + +One option is just ignore the warning. Another is quench it by setting the +property `Protobuf_NoWarnMissingExpected` to `true`: + +```xml +<PropertyGroup> + <Protobuf_NoWarnMissingExpected>true</Protobuf_NoWarnMissingExpected> +</PropertyGroup> +``` + +For a small to medium projects this is sufficient. But because of a missing +output dependency, the corresponding .proto file will be recompiled on every +build. If your project is large, or if other large builds depend on generated +files, and are also needlessly recompiled, you'll want to prevent these rebuilds +when files have not in fact changed, as follows: + +##### Explicitly tell protoc for which files it should use the gRPC plugin + +You need to set the `Protobuf` item property `GrpcServices` to `None` for those +.proto inputs which do not have a `service` declared (or, optionally, those +which do but you do not want a service/client stub for). The default value for +the `GrpcServices` is `Both` (both client and server stub are generated). This +is easy enough to do with glob patterns if your files are laid out in +directories according to their service use, for example: + +```xml + <ItemGroup> + <Protobuf Include="**/*.proto" OutputDir="%(RelativePath)" + CompileOutputs="false" GrpcServices="None" /> + <Protobuf Update="**/hello/*.proto;**/bye/*.proto" GrpcServices="Both" /> + </ItemGroup> +``` + +In this sample, all .proto files are compiled with `GrpcServices="None"`, except +for .proto files in subdirectories on any tree level named `hello/` and `bye`, +which will take `GrpcServices="Both"` Note the use of the `Update` attribute +instead of `Include`. If you write `Include` by mistake, the files will be added +to compile *twice*, once with, and once without GrpcServices. Pay attention not +to do that! + +Another example would be the use of globbing if your service .proto files are +named according to a pattern, for example `*_services.proto`. In this case, The +`Update` attribute can be written as `Update="**/*_service.proto"`, to set the +attribute `GrpcServices="Both"` only on these files. + +But what if no patterns work, and you cannot sort a large set of .proto file +into those containing a service and those not? As a last resort, + +##### Force creating empty .cs files for missing outputs. + +Naturally, this results in a dirtier compiler output tree, but you may clean it +using other ways (for example, by not copying zero-length .cs files to their +final destination). Remember, though, that the files are still important to keep +in their output locations to prevent needless recompilation. You may force +generating empty files by setting the property `Protobuf_TouchMissingExpected` +to `true`: + +```xml + <PropertyGroup> + <Protobuf_TouchMissingExpected>true</Protobuf_TouchMissingExpected> + </PropertyGroup> +``` + +#### But I do not use gRPC at all, I need only protobuffer messages compiled + +Set `GrpcServices="None"` on all proto files: + +```xml + <ItemGroup> + <Protobuf Include="**/*.proto" OutputDir="%(RelativeDir)" + CompileOutputs="false" GrpcServices="None" /> + </ItemGroup> +``` + +#### That's good so far, but I do not want the `bin` and `obj` directories in my tree + +You may create the project in a subdirectory of the root of your files, such as, +for example, `.build`. In this case, you want to refer to the proto files +relative to that `.build/` directory as + +```xml + <ItemGroup> + <Protobuf Include="../**/*.proto" ProtoRoot=".." + OutputDir="%(RelativeDir)" CompileOutputs="false" /> + </ItemGroup> +``` + +Pay attention to the `ProtoRoot` property. It needs to be set to the directory +where `import` declarations in the .proto files are looking for files, since the +project root is no longer the same as the proto root. + +Alternatively, you may place the project in a directory *above* your proto root, +and refer to the files with a subdirectory name: + +```xml + <ItemGroup> + <Protobuf Include="proto_root/**/*.proto" ProtoRoot="proto_root" + OutputDir="%(RelativeDir)" CompileOutputs="false" /> + </ItemGroup> +``` + +### Alas, this all is nice, but my scenario is more complex, -OR- +### I'll investigate that when I have time. I just want to run protoc as I did before. + +One option is examine our [.targets and .props files](Grpc.Tools/build/) and see +if you can create your own build sequence from the provided targets so that it +fits your needs. Also please open an issue (and tag @kkm000 in it!) with your +scenario. We'll try to support it if it appears general enough. + +But if you just want to run `protoc` using MsBuild `<Exec>` task, as you +probably did before the version 1.17 of Grpc.Tools, we have a few build +variables that point to resolved names of tools and common protoc imports. +You'll have to roll your own dependency checking (or go with a full +recompilation each time, if that works for you), but at the very least each +version of the Tools package will point to the correct location of the files, +and resolve the compiler and plugin executables appropriate for the host system. +These property variables are: + +* `Protobuf_ProtocFullPath` points to the full path and filename of protoc executable, e. g., + "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\bin\windows\protoc.exe". + +* `gRPC_PluginFullPath` points to the full path and filename of gRPC plugin, such as + "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\bin\windows\grpc_csharp_plugin.exe" + +* `Protobuf_StandardImportsPath` points to the standard proto import directory, for example, + "C:\Users\kkm\.nuget\packages\grpc.tools\1.17.0\build\native\include". This is + the directory where a declaration such as `import "google/protobuf/wrappers.proto";` + in a proto file would find its target. + +Use MSBuild property expansion syntax `$(VariableName)` in your protoc command +line to substitute these variables, for instance, + +```xml + <Target Name="MyProtoCompile"> + <PropertyGroup> + <ProtoCCommand>$(Protobuf_ProtocFullPath) --plugin=protoc-gen-grpc=$(gRPC_PluginFullPath) -I $(Protobuf_StandardImportsPath) ....rest of your command.... </ProtoCCommand> + </PropertyGroup> + <Message Importance="high" Text="$(ProtoCCommand)" /> + <Exec Command="$(ProtoCCommand)" /> + </Target> +``` + +Also make sure *not* to include any file names to the `Protobuf` item +collection, otherwise they will be compiled by default. If, by any chance, you +used that name for your build scripting, you must rename it. + +### What about C++ projects? + +This is in the works. Currently, the same variables as above are set to point to +the protoc binary, C++ gRPC plugin and the standard imports, but nothing else. +Do not use the `Protobuf` item collection name so that your project remains +future-proof. We'll use it for C++ projects too. + +Reference +--------- + +### Protobuf item metadata reference + +The following metadata are recognized on the `<Protobuf>` items. + +| Name | Default | Value | Synopsis | +|----------------|-----------|----------------------|----------------------------------| +| Access | `public` | `public`, `internal` | Generated class access | +| ProtoCompile | `true` | `true`, `false` | Pass files to protoc? | +| ProtoRoot | See notes | A directory | Common root for set of files | +| CompileOutputs | `true` | `true`, `false` | C#-compile generated files? | +| OutputDir | See notes | A directory | Directory for generated C# files | +| GrpcOutputDir | See notes | A directory | Directory for generated stubs | +| GrpcServices | `both` | `none`, `client`, | Generated gRPC stubs | +| | | `server`, `both` | | + +__Notes__ + +* __ProtoRoot__ +For files _inside_ the project cone, `ProtoRoot` is set by default to the +project directory. For every file _outside_ of the project directory, the value +is set to this file's containing directory name, individually per file. If you +include a subtree of proto files that lies outside of the project directory, you +need to set this metadatum. There is an example in this file above. The path in +this variable is relative to the project directory. + +* __OutputDir__ +The default value for this metadatum is the value of the property +`Protobuf_OutputPath`. This property, in turn, unless you set it in your +project, will be set to the value of the standard MSBuild property +`IntermediateOutputPath`, which points to the location of compilation object +outputs, such as "obj/Release/netstandard1.5/". The path in this property is +considered relative to the project directory. + +* __GrpcOutputDir__ +Unless explicitly set, will follow `OutputDir` for any given file. + +* __Access__ +Sets generated class access on _both_ generated message and gRPC stub classes. diff --git a/src/csharp/README.md b/src/csharp/README.md index d8aed94988..9a91035d06 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -87,6 +87,7 @@ $ python tools/run_tests/run_tests.py -l csharp -c dbg DOCUMENTATION ------------- +- [.NET Build Integration](BUILD-INTEGRATION.md) - [API Reference][] - [Helloworld Example][] - [RouteGuide Tutorial][] diff --git a/src/csharp/doc/integration.md-fig.1-classic.png b/src/csharp/doc/integration.md-fig.1-classic.png Binary files differnew file mode 100644 index 0000000000..80c57261ad --- /dev/null +++ b/src/csharp/doc/integration.md-fig.1-classic.png diff --git a/src/csharp/doc/integration.md-fig.2-sdk.png b/src/csharp/doc/integration.md-fig.2-sdk.png Binary files differnew file mode 100644 index 0000000000..6d653e4a58 --- /dev/null +++ b/src/csharp/doc/integration.md-fig.2-sdk.png diff --git a/src/proto/grpc/reflection/v1alpha/BUILD b/src/proto/grpc/reflection/v1alpha/BUILD index 4605418447..4d919d029e 100644 --- a/src/proto/grpc/reflection/v1alpha/BUILD +++ b/src/proto/grpc/reflection/v1alpha/BUILD @@ -22,3 +22,11 @@ grpc_proto_library( name = "reflection_proto", srcs = ["reflection.proto"], ) + +filegroup( + name = "reflection_proto_file", + srcs = [ + "reflection.proto", + ], +) + diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD index 16721ff2ed..7048911b9a 100644 --- a/src/proto/grpc/testing/BUILD +++ b/src/proto/grpc/testing/BUILD @@ -15,6 +15,8 @@ licenses(["notice"]) # Apache v2 load("//bazel:grpc_build_system.bzl", "grpc_proto_library", "grpc_package") +load("@grpc_python_dependencies//:requirements.bzl", "requirement") +load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") grpc_package(name = "testing", visibility = "public") @@ -58,12 +60,30 @@ grpc_proto_library( has_services = False, ) +py_proto_library( + name = "py_empty_proto", + protos = ["empty.proto",], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + grpc_proto_library( name = "messages_proto", srcs = ["messages.proto"], has_services = False, ) +py_proto_library( + name = "py_messages_proto", + protos = ["messages.proto",], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + grpc_proto_library( name = "metrics_proto", srcs = ["metrics.proto"], @@ -116,3 +136,17 @@ grpc_proto_library( "messages_proto", ], ) + +py_proto_library( + name = "py_test_proto", + protos = ["test.proto",], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], + proto_deps = [ + ":py_empty_proto", + ":py_messages_proto", + ] +) + diff --git a/src/proto/grpc/testing/proto2/BUILD.bazel b/src/proto/grpc/testing/proto2/BUILD.bazel new file mode 100644 index 0000000000..c4c4f004ef --- /dev/null +++ b/src/proto/grpc/testing/proto2/BUILD.bazel @@ -0,0 +1,30 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") +load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") + +package(default_visibility = ["//visibility:public"]) + +py_proto_library( + name = "empty2_proto", + protos = [ + "empty2.proto", + ], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + +py_proto_library( + name = "empty2_extensions_proto", + protos = [ + "empty2_extensions.proto", + ], + proto_deps = [ + ":empty2_proto", + ], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + diff --git a/src/python/.gitignore b/src/python/.gitignore index 7b520579a0..41813129bd 100644 --- a/src/python/.gitignore +++ b/src/python/.gitignore @@ -1,3 +1,4 @@ gens/ *_pb2.py *_pb2_grpc.py +*.egg-info/ diff --git a/src/python/grpcio/_parallel_compile_patch.py b/src/python/grpcio/_parallel_compile_patch.py new file mode 100644 index 0000000000..4d03ef49ba --- /dev/null +++ b/src/python/grpcio/_parallel_compile_patch.py @@ -0,0 +1,63 @@ +# Copyright 2018 The gRPC Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Patches the compile() to allow enable parallel compilation of C/C++. + +build_ext has lots of C/C++ files and normally them one by one. +Enabling parallel build helps a lot. +""" + +import distutils.ccompiler +import os + +try: + BUILD_EXT_COMPILER_JOBS = int( + os.environ.get('GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS', '1')) +except ValueError: + BUILD_EXT_COMPILER_JOBS = 1 + + +# monkey-patch for parallel compilation +def _parallel_compile(self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None): + # setup the same way as distutils.ccompiler.CCompiler + # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564 + macros, objects, extra_postargs, pp_opts, build = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + + def _compile_single_file(obj): + try: + src, ext = build[obj] + except KeyError: + return + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + + # run compilation of individual files in parallel + import multiprocessing.pool + multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map( + _compile_single_file, objects) + return objects + + +def monkeypatch_compile_maybe(): + """Monkeypatching is dumb, but the build speed gain is worth it.""" + if BUILD_EXT_COMPILER_JOBS > 1: + distutils.ccompiler.CCompiler.compile = _parallel_compile diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py index 0a3097111f..3cb0eb179e 100644 --- a/src/python/grpcio/commands.py +++ b/src/python/grpcio/commands.py @@ -274,8 +274,14 @@ class BuildExt(build_ext.build_ext): extra_defines = [ 'EXTRA_DEFINES="GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1"' ] + # Ensure the BoringSSL are built instead of using system provided + # libraries. It prevents dependency issues while distributing to + # Mac users who use MacPorts to manage their libraries. #17002 + mod_env = dict(os.environ) + mod_env['REQUIRE_CUSTOM_LIBRARIES_opt'] = '1' make_process = subprocess.Popen( ['make'] + extra_defines + targets, + env=mod_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) make_out, make_err = make_process.communicate() diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index eeeb4ddb33..734eac3801 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -24,8 +24,8 @@ from grpc import _grpcio_metadata from grpc._cython import cygrpc from grpc.framework.foundation import callable_util -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) _USER_AGENT = 'grpc-python/{}'.format(_grpcio_metadata.__version__) @@ -980,8 +980,9 @@ class Channel(grpc.Channel): # for as long as they are in use and to close them after using them, # then deletion of this grpc._channel.Channel instance can be made to # effect closure of the underlying cygrpc.Channel instance. - cygrpc.fork_unregister_channel(self) + if cygrpc is not None: # Globals may have already been collected. + cygrpc.fork_unregister_channel(self) # This prevent the failed-at-initializing object removal from failing. # Though the __init__ failed, the removal will still trigger __del__. - if hasattr(self, "_connectivity_state"): + if _moot is not None and hasattr(self, "_connectivity_state"): _moot(self._connectivity_state) diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py index 3805c7e82a..42f3a4e614 100644 --- a/src/python/grpcio/grpc/_common.py +++ b/src/python/grpcio/grpc/_common.py @@ -20,8 +20,8 @@ import six import grpc from grpc._cython import cygrpc -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = { cygrpc.ConnectivityState.idle: @@ -66,18 +66,13 @@ def encode(s): if isinstance(s, bytes): return s else: - return s.encode('ascii') + return s.encode('utf8') def decode(b): - if isinstance(b, str): - return b - else: - try: - return b.decode('utf8') - except UnicodeDecodeError: - _LOGGER.exception('Invalid encoding on %s', b) - return b.decode('latin1') + if isinstance(b, bytes): + return b.decode('utf-8', 'replace') + return b def _transform(message, transformer, exception_message): diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi index 334e561baa..fa356d913e 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi @@ -14,8 +14,8 @@ import logging -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) # This function will ascii encode unicode string inputs if neccesary. # In Python3, unicode strings are the default str type. diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi index 7decae95bb..e17ca6d335 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi @@ -14,14 +14,16 @@ from libc.string cimport memcpy -import pkg_resources +import pkgutil cdef grpc_ssl_roots_override_result ssl_roots_override_callback( char **pem_root_certs) nogil: with gil: - temporary_pem_root_certs = pkg_resources.resource_string( - __name__.rstrip('.cygrpc'), '_credentials/roots.pem') + pkg = __name__ + if pkg.endswith('.cygrpc'): + pkg = pkg[:-len('.cygrpc')] + temporary_pem_root_certs = pkgutil.get_data(pkg, '_credentials/roots.pem') pem_root_certs[0] = <char *>gpr_malloc(len(temporary_pem_root_certs) + 1) memcpy( pem_root_certs[0], <char *>temporary_pem_root_certs, diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi index 5779437b92..f9d1e863ca 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi @@ -18,8 +18,8 @@ import logging import time import grpc -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) cdef class Server: diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx index 026f7ba2e3..ae5c07bfc8 100644 --- a/src/python/grpcio/grpc/_cython/cygrpc.pyx +++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx @@ -15,7 +15,6 @@ cimport cpython -import pkg_resources import os.path import sys diff --git a/src/python/grpcio/grpc/_plugin_wrapping.py b/src/python/grpcio/grpc/_plugin_wrapping.py index 88ab4d8371..53af2ff913 100644 --- a/src/python/grpcio/grpc/_plugin_wrapping.py +++ b/src/python/grpcio/grpc/_plugin_wrapping.py @@ -20,8 +20,8 @@ import grpc from grpc import _common from grpc._cython import cygrpc -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) class _AuthMetadataContext( diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index daa000a6e1..7276a7fd90 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -27,7 +27,6 @@ from grpc import _interceptor from grpc._cython import cygrpc from grpc.framework.foundation import callable_util -logging.basicConfig() _LOGGER = logging.getLogger(__name__) _SHUTDOWN_TAG = 'shutdown' diff --git a/src/python/grpcio/grpc/framework/foundation/callable_util.py b/src/python/grpcio/grpc/framework/foundation/callable_util.py index fb8d5f7c1e..36066e19df 100644 --- a/src/python/grpcio/grpc/framework/foundation/callable_util.py +++ b/src/python/grpcio/grpc/framework/foundation/callable_util.py @@ -21,8 +21,8 @@ import logging import six -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) class Outcome(six.with_metaclass(abc.ABCMeta)): diff --git a/src/python/grpcio/grpc/framework/foundation/logging_pool.py b/src/python/grpcio/grpc/framework/foundation/logging_pool.py index 7702d1785f..dfb8dbdc30 100644 --- a/src/python/grpcio/grpc/framework/foundation/logging_pool.py +++ b/src/python/grpcio/grpc/framework/foundation/logging_pool.py @@ -17,8 +17,8 @@ import logging from concurrent import futures -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) def _wrap(behavior): diff --git a/src/python/grpcio/grpc/framework/foundation/stream_util.py b/src/python/grpcio/grpc/framework/foundation/stream_util.py index 9184f95873..e03130cced 100644 --- a/src/python/grpcio/grpc/framework/foundation/stream_util.py +++ b/src/python/grpcio/grpc/framework/foundation/stream_util.py @@ -19,8 +19,8 @@ import threading from grpc.framework.foundation import stream _NO_VALUE = object() -logging.basicConfig() _LOGGER = logging.getLogger(__name__) +_LOGGER.addHandler(logging.NullHandler()) class TransformingConsumer(stream.Consumer): diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index cb48b9f62c..42a4a7aa04 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -208,6 +208,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/transport/timeout_encoding.cc', 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', 'src/core/ext/transport/chttp2/transport/bin_decoder.cc', @@ -280,7 +281,7 @@ CORE_SOURCE_FILES = [ 'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', 'src/core/tsi/alts/frame_protector/frame_handler.cc', 'src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'src/core/tsi/alts/handshaker/alts_tsi_event.cc', + 'src/core/tsi/alts/handshaker/alts_shared_resource.cc', 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', @@ -331,7 +332,6 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/subchannel.cc', 'src/core/ext/filters/client_channel/subchannel_index.cc', - 'src/core/ext/filters/client_channel/uri_parser.cc', 'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/client_channel/health/health.pb.c', 'src/core/tsi/alts_transport_security.cc', diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel new file mode 100644 index 0000000000..3a2ba26371 --- /dev/null +++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel @@ -0,0 +1,34 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") +load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") + +package(default_visibility = ["//visibility:public"]) + +genrule( + name = "mv_reflection_proto", + srcs = [ + "//src/proto/grpc/reflection/v1alpha:reflection_proto_file", + ], + outs = ["reflection.proto",], + cmd = "cp $< $@", +) + +py_proto_library( + name = "py_reflection_proto", + protos = [":mv_reflection_proto",], + with_grpc = True, + deps = [ + requirement('protobuf'), + ], +) + +py_library( + name = "grpc_reflection", + srcs = ["reflection.py",], + deps = [ + ":py_reflection_proto", + "//src/python/grpcio/grpc:grpcio", + requirement('protobuf'), + ], + imports=["../../",], +) + diff --git a/src/python/grpcio_tests/tests/_sanity/_sanity_test.py b/src/python/grpcio_tests/tests/_sanity/_sanity_test.py index b4079850ff..7da6e7b34c 100644 --- a/src/python/grpcio_tests/tests/_sanity/_sanity_test.py +++ b/src/python/grpcio_tests/tests/_sanity/_sanity_test.py @@ -13,9 +13,9 @@ # limitations under the License. import json +import pkgutil import unittest -import pkg_resources import six import tests @@ -35,7 +35,7 @@ class SanityTest(unittest.TestCase): loader.suite) }) - tests_json_string = pkg_resources.resource_string('tests', 'tests.json') + tests_json_string = pkgutil.get_data('tests', 'tests.json') tests_json = json.loads(tests_json_string.decode() if six.PY3 else tests_json_string) diff --git a/src/python/grpcio_tests/tests/interop/BUILD.bazel b/src/python/grpcio_tests/tests/interop/BUILD.bazel new file mode 100644 index 0000000000..a39f30d32a --- /dev/null +++ b/src/python/grpcio_tests/tests/interop/BUILD.bazel @@ -0,0 +1,97 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "_intraop_test_case", + srcs = ["_intraop_test_case.py"], + deps = [ + ":methods", + ], + imports=["../../",], +) + +py_library( + name = "client", + srcs = ["client.py"], + deps = [ + "//src/python/grpcio/grpc:grpcio", + ":methods", + ":resources", + "//src/proto/grpc/testing:py_test_proto", + requirement('google-auth'), + ], + imports=["../../",], +) + +py_library( + name = "methods", + srcs = ["methods.py"], + deps = [ + "//src/python/grpcio/grpc:grpcio", + "//src/proto/grpc/testing:py_empty_proto", + "//src/proto/grpc/testing:py_messages_proto", + "//src/proto/grpc/testing:py_test_proto", + requirement('google-auth'), + requirement('requests'), + requirement('enum34'), + ], + imports=["../../",], +) + +py_library( + name = "resources", + srcs = ["resources.py"], + data = [ + "//src/python/grpcio_tests/tests/interop/credentials", + ], +) + +py_library( + name = "server", + srcs = ["server.py"], + deps = [ + "//src/python/grpcio/grpc:grpcio", + ":methods", + ":resources", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/proto/grpc/testing:py_test_proto", + ], + imports=["../../",], +) + +py_test( + name="_insecure_intraop_test", + size="small", + srcs=["_insecure_intraop_test.py",], + main="_insecure_intraop_test.py", + deps=[ + "//src/python/grpcio/grpc:grpcio", + ":_intraop_test_case", + ":methods", + ":server", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/proto/grpc/testing:py_test_proto", + ], + imports=["../../",], + data=[ + "//src/python/grpcio_tests/tests/unit/credentials", + ], +) + +py_test( + name="_secure_intraop_test", + size="small", + srcs=["_secure_intraop_test.py",], + main="_secure_intraop_test.py", + deps=[ + "//src/python/grpcio/grpc:grpcio", + ":_intraop_test_case", + ":methods", + ":server", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/proto/grpc/testing:py_test_proto", + ], + imports=["../../",], +) + diff --git a/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel b/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel new file mode 100644 index 0000000000..bc2b997292 --- /dev/null +++ b/src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name="credentials", + srcs=glob([ + "**", + ]), +) + diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py index cda15a68a3..721dedf0b7 100644 --- a/src/python/grpcio_tests/tests/interop/methods.py +++ b/src/python/grpcio_tests/tests/interop/methods.py @@ -457,6 +457,22 @@ def _per_rpc_creds(stub, args): response.username)) +def _special_status_message(stub, args): + details = b'\t\ntest with whitespace\r\nand Unicode BMP \xe2\x98\xba and non-BMP \xf0\x9f\x98\x88\t\n'.decode( + 'utf-8') + code = 2 + status = grpc.StatusCode.UNKNOWN # code = 2 + + # Test with a UnaryCall + request = messages_pb2.SimpleRequest( + response_type=messages_pb2.COMPRESSABLE, + response_size=1, + payload=messages_pb2.Payload(body=b'\x00'), + response_status=messages_pb2.EchoStatus(code=code, message=details)) + response_future = stub.UnaryCall.future(request) + _validate_status_code_and_details(response_future, status, details) + + @enum.unique class TestCase(enum.Enum): EMPTY_UNARY = 'empty_unary' @@ -476,6 +492,7 @@ class TestCase(enum.Enum): JWT_TOKEN_CREDS = 'jwt_token_creds' PER_RPC_CREDS = 'per_rpc_creds' TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server' + SPECIAL_STATUS_MESSAGE = 'special_status_message' def test_interoperability(self, stub, args): if self is TestCase.EMPTY_UNARY: @@ -512,6 +529,8 @@ class TestCase(enum.Enum): _jwt_token_creds(stub, args) elif self is TestCase.PER_RPC_CREDS: _per_rpc_creds(stub, args) + elif self is TestCase.SPECIAL_STATUS_MESSAGE: + _special_status_message(stub, args) else: raise NotImplementedError( 'Test case "%s" not implemented!' % self.name) diff --git a/src/python/grpcio_tests/tests/interop/resources.py b/src/python/grpcio_tests/tests/interop/resources.py index 2f76cf5db6..a55919a60a 100644 --- a/src/python/grpcio_tests/tests/interop/resources.py +++ b/src/python/grpcio_tests/tests/interop/resources.py @@ -14,27 +14,24 @@ """Constants and functions for data used in interoperability testing.""" import argparse +import pkgutil import os -import pkg_resources - _ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem' _PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key' _CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem' def test_root_certificates(): - return pkg_resources.resource_string(__name__, - _ROOT_CERTIFICATES_RESOURCE_PATH) + return pkgutil.get_data(__name__, _ROOT_CERTIFICATES_RESOURCE_PATH) def private_key(): - return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH) + return pkgutil.get_data(__name__, _PRIVATE_KEY_RESOURCE_PATH) def certificate_chain(): - return pkg_resources.resource_string(__name__, - _CERTIFICATE_CHAIN_RESOURCE_PATH) + return pkgutil.get_data(__name__, _CERTIFICATE_CHAIN_RESOURCE_PATH) def parse_bool(value): diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py index 768cdaf468..72f88a1c98 100644 --- a/src/python/grpcio_tests/tests/interop/server.py +++ b/src/python/grpcio_tests/tests/interop/server.py @@ -25,8 +25,8 @@ from tests.interop import methods from tests.interop import resources from tests.unit import test_common -logging.basicConfig() _ONE_DAY_IN_SECONDS = 60 * 60 * 24 +logging.basicConfig() _LOGGER = logging.getLogger(__name__) diff --git a/src/python/grpcio_tests/tests/reflection/BUILD.bazel b/src/python/grpcio_tests/tests/reflection/BUILD.bazel new file mode 100644 index 0000000000..c0efb0b7ce --- /dev/null +++ b/src/python/grpcio_tests/tests/reflection/BUILD.bazel @@ -0,0 +1,21 @@ +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +py_test( + name="_reflection_servicer_test", + size="small", + timeout="moderate", + srcs=["_reflection_servicer_test.py",], + main="_reflection_servicer_test.py", + deps=[ + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_reflection/grpc_reflection/v1alpha:grpc_reflection", + "//src/python/grpcio_tests/tests/unit:test_common", + "//src/proto/grpc/testing:py_empty_proto", + "//src/proto/grpc/testing/proto2:empty2_extensions_proto", + requirement('protobuf'), + ], + imports=["../../",], +) + diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 76d5d22d57..c5ea8c5fbb 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -42,10 +42,12 @@ "unit._cython.cygrpc_test.SecureServerSecureClient", "unit._cython.cygrpc_test.TypeSmokeTest", "unit._empty_message_test.EmptyMessageTest", + "unit._error_message_encoding_test.ErrorMessageEncodingTest", "unit._exit_test.ExitTest", "unit._interceptor_test.InterceptorTest", "unit._invalid_metadata_test.InvalidMetadataTest", "unit._invocation_defects_test.InvocationDefectsTest", + "unit._logging_test.LoggingTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_test.MetadataTest", "unit._reconnect_test.ReconnectTest", diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel index dcd6d9fbb2..de33b81e32 100644 --- a/src/python/grpcio_tests/tests/unit/BUILD.bazel +++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel @@ -17,6 +17,7 @@ GRPCIO_TESTS_UNIT = [ "_interceptor_test.py", "_invalid_metadata_test.py", "_invocation_defects_test.py", + "_logging_test.py", "_metadata_code_details_test.py", "_metadata_test.py", # TODO: Issue 16336 diff --git a/src/python/grpcio_tests/tests/unit/_api_test.py b/src/python/grpcio_tests/tests/unit/_api_test.py index f6245be77d..38072861a4 100644 --- a/src/python/grpcio_tests/tests/unit/_api_test.py +++ b/src/python/grpcio_tests/tests/unit/_api_test.py @@ -14,6 +14,7 @@ """Test of gRPC Python's application-layer API.""" import unittest +import logging import six @@ -102,4 +103,5 @@ class ChannelTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_auth_context_test.py b/src/python/grpcio_tests/tests/unit/_auth_context_test.py index d174051070..b1b5bbdcab 100644 --- a/src/python/grpcio_tests/tests/unit/_auth_context_test.py +++ b/src/python/grpcio_tests/tests/unit/_auth_context_test.py @@ -15,6 +15,7 @@ import pickle import unittest +import logging import grpc from grpc import _channel @@ -187,4 +188,5 @@ class AuthContextTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_auth_test.py b/src/python/grpcio_tests/tests/unit/_auth_test.py index e2cb938936..d9df2add4f 100644 --- a/src/python/grpcio_tests/tests/unit/_auth_test.py +++ b/src/python/grpcio_tests/tests/unit/_auth_test.py @@ -16,6 +16,7 @@ import collections import threading import unittest +import logging from grpc import _auth @@ -77,4 +78,5 @@ class AccessTokenAuthMetadataPluginTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_channel_args_test.py b/src/python/grpcio_tests/tests/unit/_channel_args_test.py index dd1d2969a2..228c0e4c16 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_args_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_args_test.py @@ -15,6 +15,7 @@ from concurrent import futures import unittest +import logging import grpc @@ -62,4 +63,5 @@ class ChannelArgsTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_channel_close_test.py b/src/python/grpcio_tests/tests/unit/_channel_close_test.py index af3a9ee1ee..82fa165710 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_close_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_close_test.py @@ -13,6 +13,7 @@ # limitations under the License. """Tests server and client side compression.""" +import logging import threading import time import unittest @@ -182,4 +183,5 @@ class ChannelCloseTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py index f9eb0011dc..727fb7d65f 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py @@ -13,6 +13,7 @@ # limitations under the License. """Tests of grpc._channel.Channel connectivity.""" +import logging import threading import time import unittest @@ -142,4 +143,5 @@ class ChannelConnectivityTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py index 30b486079c..345460ef40 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py @@ -15,6 +15,7 @@ import threading import unittest +import logging import grpc from tests.unit.framework.common import test_constants @@ -85,4 +86,5 @@ class ChannelReadyFutureTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py index 0b11f03adf..876d8e827e 100644 --- a/src/python/grpcio_tests/tests/unit/_compression_test.py +++ b/src/python/grpcio_tests/tests/unit/_compression_test.py @@ -15,6 +15,7 @@ import unittest +import logging import grpc from grpc import _grpcio_metadata @@ -117,4 +118,5 @@ class CompressionTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_credentials_test.py b/src/python/grpcio_tests/tests/unit/_credentials_test.py index f487fe66a2..be7378ecbc 100644 --- a/src/python/grpcio_tests/tests/unit/_credentials_test.py +++ b/src/python/grpcio_tests/tests/unit/_credentials_test.py @@ -14,6 +14,7 @@ """Tests of credentials.""" import unittest +import logging import grpc @@ -54,4 +55,5 @@ class CredentialsTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_empty_message_test.py b/src/python/grpcio_tests/tests/unit/_empty_message_test.py index c55ef61c13..3e8393b53c 100644 --- a/src/python/grpcio_tests/tests/unit/_empty_message_test.py +++ b/src/python/grpcio_tests/tests/unit/_empty_message_test.py @@ -13,6 +13,7 @@ # limitations under the License. import unittest +import logging import grpc @@ -118,4 +119,5 @@ class EmptyMessageTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py b/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py new file mode 100644 index 0000000000..6c551df3ec --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py @@ -0,0 +1,86 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests 'utf-8' encoded error message.""" + +import unittest +import weakref + +import grpc + +from tests.unit import test_common +from tests.unit.framework.common import test_constants + +_UNICODE_ERROR_MESSAGES = [ + b'\xe2\x80\x9d'.decode('utf-8'), + b'abc\x80\xd0\xaf'.decode('latin-1'), + b'\xc3\xa9'.decode('utf-8'), +] + +_REQUEST = b'\x00\x00\x00' +_RESPONSE = b'\x00\x00\x00' + +_UNARY_UNARY = '/test/UnaryUnary' + + +class _MethodHandler(grpc.RpcMethodHandler): + + def __init__(self, request_streaming=None, response_streaming=None): + self.request_streaming = request_streaming + self.response_streaming = response_streaming + self.request_deserializer = None + self.response_serializer = None + self.unary_stream = None + self.stream_unary = None + self.stream_stream = None + + def unary_unary(self, request, servicer_context): + servicer_context.set_code(grpc.StatusCode.UNKNOWN) + servicer_context.set_details(request.decode('utf-8')) + return _RESPONSE + + +class _GenericHandler(grpc.GenericRpcHandler): + + def __init__(self, test): + self._test = test + + def service(self, handler_call_details): + return _MethodHandler() + + +class ErrorMessageEncodingTest(unittest.TestCase): + + def setUp(self): + self._server = test_common.test_server() + self._server.add_generic_rpc_handlers((_GenericHandler( + weakref.proxy(self)),)) + port = self._server.add_insecure_port('[::]:0') + self._server.start() + self._channel = grpc.insecure_channel('localhost:%d' % port) + + def tearDown(self): + self._server.stop(0) + + def testMessageEncoding(self): + for message in _UNICODE_ERROR_MESSAGES: + multi_callable = self._channel.unary_unary(_UNARY_UNARY) + with self.assertRaises(grpc.RpcError) as cm: + multi_callable(message.encode('utf-8')) + + self.assertEqual(cm.exception.code(), grpc.StatusCode.UNKNOWN) + self.assertEqual(cm.exception.details(), message) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py index 0a0239a63d..f489db12cb 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py +++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py @@ -16,6 +16,7 @@ import argparse import threading import time +import logging import grpc @@ -161,6 +162,7 @@ def infinite_request_iterator(): if __name__ == '__main__': + logging.basicConfig() parser = argparse.ArgumentParser() parser.add_argument('scenario', type=str) parser.add_argument( diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py index f40f3ae07c..5226537579 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_test.py +++ b/src/python/grpcio_tests/tests/unit/_exit_test.py @@ -26,6 +26,7 @@ import sys import threading import time import unittest +import logging from tests.unit import _exit_scenarios @@ -187,4 +188,5 @@ class ExitTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_interceptor_test.py b/src/python/grpcio_tests/tests/unit/_interceptor_test.py index 3d547b71cd..99db0ac58b 100644 --- a/src/python/grpcio_tests/tests/unit/_interceptor_test.py +++ b/src/python/grpcio_tests/tests/unit/_interceptor_test.py @@ -17,6 +17,7 @@ import collections import itertools import threading import unittest +import logging from concurrent import futures import grpc @@ -598,4 +599,5 @@ class InterceptorTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py index f153089a24..9771764635 100644 --- a/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py +++ b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py @@ -14,6 +14,7 @@ """Test of RPCs made against gRPC Python's application-layer API.""" import unittest +import logging import grpc @@ -131,4 +132,5 @@ class InvalidMetadataTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py index 93a5fdf9ff..00949e2236 100644 --- a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py +++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py @@ -15,6 +15,7 @@ import itertools import threading import unittest +import logging import grpc @@ -271,4 +272,5 @@ class InvocationDefectsTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_logging_test.py b/src/python/grpcio_tests/tests/unit/_logging_test.py new file mode 100644 index 0000000000..80b1f1b3c1 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_logging_test.py @@ -0,0 +1,73 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Test of gRPC Python's interaction with the python logging module""" + +import unittest +import six +from six.moves import reload_module +import logging +import grpc +import functools +import sys + + +def patch_stderr(f): + + @functools.wraps(f) + def _impl(*args, **kwargs): + old_stderr = sys.stderr + sys.stderr = six.StringIO() + try: + f(*args, **kwargs) + finally: + sys.stderr = old_stderr + + return _impl + + +def isolated_logging(f): + + @functools.wraps(f) + def _impl(*args, **kwargs): + reload_module(logging) + reload_module(grpc) + try: + f(*args, **kwargs) + finally: + reload_module(logging) + + return _impl + + +class LoggingTest(unittest.TestCase): + + @isolated_logging + def test_logger_not_occupied(self): + self.assertEqual(0, len(logging.getLogger().handlers)) + + @patch_stderr + @isolated_logging + def test_handler_found(self): + self.assertEqual(0, len(sys.stderr.getvalue())) + + @isolated_logging + def test_can_configure_logger(self): + intended_stream = six.StringIO() + logging.basicConfig(stream=intended_stream) + self.assertEqual(1, len(logging.getLogger().handlers)) + self.assertIs(logging.getLogger().handlers[0].stream, intended_stream) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py b/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py index ca10bd4dab..0dafab827a 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py @@ -15,6 +15,7 @@ import threading import unittest +import logging import grpc @@ -656,4 +657,5 @@ class MetadataCodeDetailsTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py index 5908421011..777ab683e3 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py @@ -15,6 +15,7 @@ import unittest import weakref +import logging import grpc from grpc import _channel @@ -237,4 +238,5 @@ class MetadataTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py index a708d8d862..f6d4fcbd0a 100644 --- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -15,6 +15,7 @@ import socket import time +import logging import unittest import grpc @@ -100,4 +101,5 @@ class ReconnectTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py b/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py index df4b129018..4fead8fcd5 100644 --- a/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py +++ b/src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py @@ -15,6 +15,7 @@ import threading import unittest +import logging import grpc from grpc import _channel @@ -253,4 +254,5 @@ class ResourceExhaustedTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_rpc_test.py b/src/python/grpcio_tests/tests/unit/_rpc_test.py index 34e7831a98..a768d6c7c1 100644 --- a/src/python/grpcio_tests/tests/unit/_rpc_test.py +++ b/src/python/grpcio_tests/tests/unit/_rpc_test.py @@ -16,6 +16,7 @@ import itertools import threading import unittest +import logging from concurrent import futures import grpc @@ -846,4 +847,5 @@ class RPCTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py index 0d78034b7b..e733a59a5b 100644 --- a/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py +++ b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py @@ -35,6 +35,7 @@ import os import six import threading import unittest +import logging from concurrent import futures @@ -518,4 +519,5 @@ class ServerSSLCertReloadTestCertConfigReuse(_ServerSSLCertReloadTest): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_server_test.py b/src/python/grpcio_tests/tests/unit/_server_test.py index acf4a17921..2c8205f365 100644 --- a/src/python/grpcio_tests/tests/unit/_server_test.py +++ b/src/python/grpcio_tests/tests/unit/_server_test.py @@ -14,6 +14,7 @@ from concurrent import futures import unittest +import logging import grpc @@ -49,4 +50,5 @@ class ServerTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/_session_cache_test.py b/src/python/grpcio_tests/tests/unit/_session_cache_test.py index b4e4670fa7..9223a6da03 100644 --- a/src/python/grpcio_tests/tests/unit/_session_cache_test.py +++ b/src/python/grpcio_tests/tests/unit/_session_cache_test.py @@ -15,6 +15,7 @@ import pickle import unittest +import logging import grpc from grpc import _channel @@ -142,4 +143,5 @@ class SSLSessionCacheTest(unittest.TestCase): if __name__ == '__main__': + logging.basicConfig() unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/unit/resources.py b/src/python/grpcio_tests/tests/unit/resources.py index 51a8979f58..6efd870fc8 100644 --- a/src/python/grpcio_tests/tests/unit/resources.py +++ b/src/python/grpcio_tests/tests/unit/resources.py @@ -14,8 +14,7 @@ """Constants and functions for data used in testing.""" import os - -import pkg_resources +import pkgutil _ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem' _PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key' @@ -23,94 +22,92 @@ _CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem' def test_root_certificates(): - return pkg_resources.resource_string(__name__, - _ROOT_CERTIFICATES_RESOURCE_PATH) + return pkgutil.get_data(__name__, _ROOT_CERTIFICATES_RESOURCE_PATH) def private_key(): - return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH) + return pkgutil.get_data(__name__, _PRIVATE_KEY_RESOURCE_PATH) def certificate_chain(): - return pkg_resources.resource_string(__name__, - _CERTIFICATE_CHAIN_RESOURCE_PATH) + return pkgutil.get_data(__name__, _CERTIFICATE_CHAIN_RESOURCE_PATH) def cert_hier_1_root_ca_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/certs/ca.cert.pem') def cert_hier_1_intermediate_ca_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem' ) def cert_hier_1_client_1_key(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/intermediate/private/client.key.pem' ) def cert_hier_1_client_1_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem' ) def cert_hier_1_server_1_key(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem' ) def cert_hier_1_server_1_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem' ) def cert_hier_2_root_ca_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/certs/ca.cert.pem') def cert_hier_2_intermediate_ca_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem' ) def cert_hier_2_client_1_key(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/intermediate/private/client.key.pem' ) def cert_hier_2_client_1_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem' ) def cert_hier_2_server_1_key(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem' ) def cert_hier_2_server_1_cert(): - return pkg_resources.resource_string( + return pkgutil.get_data( __name__, 'credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem' ) diff --git a/test/core/client_channel/uri_fuzzer_test.cc b/test/core/client_channel/uri_fuzzer_test.cc index ee38453166..a88e2ac5cf 100644 --- a/test/core/client_channel/uri_fuzzer_test.cc +++ b/test/core/client_channel/uri_fuzzer_test.cc @@ -23,8 +23,8 @@ #include <grpc/grpc.h> #include <grpc/support/alloc.h> -#include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/uri/uri_parser.h" bool squelch = true; bool leak_check = true; diff --git a/test/core/client_channel/uri_parser_test.cc b/test/core/client_channel/uri_parser_test.cc index 254bfddfb3..ec4f755dda 100644 --- a/test/core/client_channel/uri_parser_test.cc +++ b/test/core/client_channel/uri_parser_test.cc @@ -16,7 +16,7 @@ * */ -#include "src/core/ext/filters/client_channel/uri_parser.h" +#include "src/core/lib/uri/uri_parser.h" #include <string.h> diff --git a/test/core/debug/BUILD b/test/core/debug/BUILD new file mode 100644 index 0000000000..1592472532 --- /dev/null +++ b/test/core/debug/BUILD @@ -0,0 +1,34 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package") + +grpc_package(name = "test/core/debug") + +licenses(["notice"]) # Apache v2 + +grpc_cc_test( + name = "stats_test", + srcs = ["stats_test.cc"], + external_deps = [ + "gtest", + ], + language = "C++", + deps = [ + "//:gpr", + "//:grpc", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", + ], +) diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 7c61b7910b..922783aa0d 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -29,6 +29,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/time.h> +#include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/gpr/string.h" #include "test/core/end2end/cq_verifier.h" @@ -238,7 +239,6 @@ static void test_channelz(grpc_end2end_test_config config) { json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); - gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); @@ -250,7 +250,6 @@ static void test_channelz(grpc_end2end_test_config config) { json = channelz_server->RenderJsonString(); GPR_ASSERT(json != nullptr); - gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); @@ -292,7 +291,6 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { char* json = channelz_channel->RenderJsonString(); GPR_ASSERT(json != nullptr); - gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\"")); GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); @@ -300,7 +298,6 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { json = channelz_server->RenderJsonString(); GPR_ASSERT(json != nullptr); - gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Server created\"")); GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); diff --git a/test/core/end2end/tests/streaming_error_response.cc b/test/core/end2end/tests/streaming_error_response.cc index 4c357e077e..713975a33f 100644 --- a/test/core/end2end/tests/streaming_error_response.cc +++ b/test/core/end2end/tests/streaming_error_response.cc @@ -89,7 +89,8 @@ static void end_test(grpc_end2end_test_fixture* f) { } /* Client sends a request with payload, server reads then returns status. */ -static void test(grpc_end2end_test_config config, bool request_status_early) { +static void test(grpc_end2end_test_config config, bool request_status_early, + bool recv_message_separately) { grpc_call* c; grpc_call* s; grpc_slice response_payload1_slice = grpc_slice_from_copied_string("hello"); @@ -116,6 +117,7 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { int was_cancelled = 2; gpr_timespec deadline = five_seconds_from_now(); + GPR_ASSERT(!recv_message_separately || request_status_early); c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq, grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr); @@ -136,9 +138,11 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { op->op = GRPC_OP_RECV_INITIAL_METADATA; op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; op++; - op->op = GRPC_OP_RECV_MESSAGE; - op->data.recv_message.recv_message = &response_payload1_recv; - op++; + if (!recv_message_separately) { + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload1_recv; + op++; + } if (request_status_early) { op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; @@ -168,10 +172,24 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { nullptr); GPR_ASSERT(GRPC_CALL_OK == error); + if (recv_message_separately) { + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_RECV_MESSAGE; + op->data.recv_message.recv_message = &response_payload1_recv; + op++; + error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + } + CQ_EXPECT_COMPLETION(cqv, tag(102), 1); if (!request_status_early) { CQ_EXPECT_COMPLETION(cqv, tag(1), 1); } + if (recv_message_separately) { + CQ_EXPECT_COMPLETION(cqv, tag(4), 1); + } cq_verify(cqv); memset(ops, 0, sizeof(ops)); @@ -265,8 +283,9 @@ static void test(grpc_end2end_test_config config, bool request_status_early) { } void streaming_error_response(grpc_end2end_test_config config) { - test(config, false); - test(config, true); + test(config, false, false); + test(config, true, false); + test(config, true, true); } void streaming_error_response_pre_init(void) {} diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc index c8d88aa72c..9a4541bb7d 100644 --- a/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc +++ b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc @@ -19,14 +19,14 @@ #include <grpc/grpc.h> #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" -#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" +#include "src/core/tsi/alts/handshaker/alts_shared_resource.h" #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" +#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" #include "src/core/tsi/transport_security.h" #include "src/core/tsi/transport_security_interface.h" #include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h" #define ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME "Hello Google" -#define ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL "lame" #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME "bigtable.google.api.com" #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1 "A@google.com" #define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2 "B@google.com" @@ -37,37 +37,22 @@ const size_t kMaxRpcVersionMinor = 2; const size_t kMinRpcVersionMajor = 2; const size_t kMinRpcVersionMinor = 1; +using grpc_core::internal::alts_handshaker_client_get_closure_for_testing; +using grpc_core::internal:: + alts_handshaker_client_get_initial_metadata_for_testing; +using grpc_core::internal:: + alts_handshaker_client_get_recv_buffer_addr_for_testing; +using grpc_core::internal::alts_handshaker_client_get_send_buffer_for_testing; using grpc_core::internal::alts_handshaker_client_set_grpc_caller_for_testing; typedef struct alts_handshaker_client_test_config { grpc_channel* channel; grpc_completion_queue* cq; alts_handshaker_client* client; + alts_handshaker_client* server; grpc_slice out_frame; } alts_handshaker_client_test_config; -static alts_tsi_event* alts_tsi_event_create_for_testing(bool is_client) { - alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e))); - grpc_metadata_array_init(&e->initial_metadata); - grpc_metadata_array_init(&e->trailing_metadata); - e->options = is_client ? grpc_alts_credentials_client_options_create() - : grpc_alts_credentials_server_options_create(); - if (is_client) { - grpc_alts_credentials_client_options_add_target_service_account( - e->options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1); - grpc_alts_credentials_client_options_add_target_service_account( - e->options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2); - } - grpc_gcp_rpc_protocol_versions* versions = &e->options->rpc_versions; - GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max( - versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor)); - GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min( - versions, kMinRpcVersionMajor, kMinRpcVersionMinor)); - e->target_name = - grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME); - return e; -} - static void validate_rpc_protocol_versions( grpc_gcp_rpc_protocol_versions* versions) { GPR_ASSERT(versions != nullptr); @@ -101,11 +86,11 @@ static void validate_target_identities( /** * Validate if grpc operation data is correctly populated with the fields of - * ALTS TSI event. + * ALTS handshaker client. */ -static bool validate_op(alts_tsi_event* event, const grpc_op* op, size_t nops, - bool is_start) { - GPR_ASSERT(event != nullptr && op != nullptr && nops != 0); +static bool validate_op(alts_handshaker_client* c, const grpc_op* op, + size_t nops, bool is_start) { + GPR_ASSERT(c != nullptr && op != nullptr && nops != 0); bool ok = true; grpc_op* start_op = const_cast<grpc_op*>(op); if (is_start) { @@ -113,23 +98,22 @@ static bool validate_op(alts_tsi_event* event, const grpc_op* op, size_t nops, ok &= (op->data.send_initial_metadata.count == 0); op++; GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum); - ok &= (op->op == GRPC_OP_RECV_INITIAL_METADATA); ok &= (op->data.recv_initial_metadata.recv_initial_metadata == - &event->initial_metadata); + alts_handshaker_client_get_initial_metadata_for_testing(c)); op++; GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum); } ok &= (op->op == GRPC_OP_SEND_MESSAGE); - ok &= (op->data.send_message.send_message == event->send_buffer); + ok &= (op->data.send_message.send_message == + alts_handshaker_client_get_send_buffer_for_testing(c)); op++; GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum); - ok &= (op->op == GRPC_OP_RECV_MESSAGE); - ok &= (op->data.recv_message.recv_message == &event->recv_buffer); + ok &= (op->data.recv_message.recv_message == + alts_handshaker_client_get_recv_buffer_addr_for_testing(c)); op++; GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum); - return ok; } @@ -152,7 +136,7 @@ static grpc_gcp_handshaker_req* deserialize_handshaker_req( */ static grpc_call_error check_must_not_be_called(grpc_call* call, const grpc_op* ops, size_t nops, - void* tag) { + grpc_closure* tag) { GPR_ASSERT(0); } @@ -164,10 +148,14 @@ static grpc_call_error check_must_not_be_called(grpc_call* call, */ static grpc_call_error check_client_start_success(grpc_call* call, const grpc_op* op, - size_t nops, void* tag) { - alts_tsi_event* event = static_cast<alts_tsi_event*>(tag); - grpc_gcp_handshaker_req* req = - deserialize_handshaker_req(CLIENT_START_REQ, event->send_buffer); + size_t nops, + grpc_closure* closure) { + alts_handshaker_client* client = + static_cast<alts_handshaker_client*>(closure->cb_arg); + GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure); + grpc_gcp_handshaker_req* req = deserialize_handshaker_req( + CLIENT_START_REQ, + alts_handshaker_client_get_send_buffer_for_testing(client)); GPR_ASSERT(req->client_start.handshake_security_protocol == grpc_gcp_HandshakeProtocol_ALTS); const void* data = (static_cast<repeated_field*>( @@ -194,7 +182,7 @@ static grpc_call_error check_client_start_success(grpc_call* call, GRPC_SLICE_LENGTH(*target_name)) == 0); GPR_ASSERT(GRPC_SLICE_LENGTH(*target_name) == strlen(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME)); - GPR_ASSERT(validate_op(event, op, nops, true /* is_start */)); + GPR_ASSERT(validate_op(client, op, nops, true /* is_start */)); grpc_gcp_handshaker_req_destroy(req); return GRPC_CALL_OK; } @@ -207,10 +195,14 @@ static grpc_call_error check_client_start_success(grpc_call* call, */ static grpc_call_error check_server_start_success(grpc_call* call, const grpc_op* op, - size_t nops, void* tag) { - alts_tsi_event* event = static_cast<alts_tsi_event*>(tag); - grpc_gcp_handshaker_req* req = - deserialize_handshaker_req(SERVER_START_REQ, event->send_buffer); + size_t nops, + grpc_closure* closure) { + alts_handshaker_client* client = + static_cast<alts_handshaker_client*>(closure->cb_arg); + GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure); + grpc_gcp_handshaker_req* req = deserialize_handshaker_req( + SERVER_START_REQ, + alts_handshaker_client_get_send_buffer_for_testing(client)); const void* data = (static_cast<repeated_field*>( req->server_start.application_protocols.arg)) ->data; @@ -231,7 +223,7 @@ static grpc_call_error check_server_start_success(grpc_call* call, ALTS_RECORD_PROTOCOL, GRPC_SLICE_LENGTH(*record_protocol)) == 0); validate_rpc_protocol_versions(&req->server_start.rpc_versions); - GPR_ASSERT(validate_op(event, op, nops, true /* is_start */)); + GPR_ASSERT(validate_op(client, op, nops, true /* is_start */)); grpc_gcp_handshaker_req_destroy(req); return GRPC_CALL_OK; } @@ -242,16 +234,18 @@ static grpc_call_error check_server_start_success(grpc_call* call, * and op is correctly populated. */ static grpc_call_error check_next_success(grpc_call* call, const grpc_op* op, - size_t nops, void* tag) { - alts_tsi_event* event = static_cast<alts_tsi_event*>(tag); - grpc_gcp_handshaker_req* req = - deserialize_handshaker_req(NEXT_REQ, event->send_buffer); + size_t nops, grpc_closure* closure) { + alts_handshaker_client* client = + static_cast<alts_handshaker_client*>(closure->cb_arg); + GPR_ASSERT(alts_handshaker_client_get_closure_for_testing(client) == closure); + grpc_gcp_handshaker_req* req = deserialize_handshaker_req( + NEXT_REQ, alts_handshaker_client_get_send_buffer_for_testing(client)); grpc_slice* in_bytes = static_cast<grpc_slice*>(req->next.in_bytes.arg); GPR_ASSERT(in_bytes != nullptr); GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*in_bytes), ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME, GRPC_SLICE_LENGTH(*in_bytes)) == 0); - GPR_ASSERT(validate_op(event, op, nops, false /* is_start */)); + GPR_ASSERT(validate_op(client, op, nops, false /* is_start */)); grpc_gcp_handshaker_req_destroy(req); return GRPC_CALL_OK; } @@ -262,21 +256,54 @@ static grpc_call_error check_next_success(grpc_call* call, const grpc_op* op, */ static grpc_call_error check_grpc_call_failure(grpc_call* call, const grpc_op* op, size_t nops, - void* tag) { + grpc_closure* tag) { return GRPC_CALL_ERROR; } +static grpc_alts_credentials_options* create_credentials_options( + bool is_client) { + grpc_alts_credentials_options* options = + is_client ? grpc_alts_credentials_client_options_create() + : grpc_alts_credentials_server_options_create(); + if (is_client) { + grpc_alts_credentials_client_options_add_target_service_account( + options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1); + grpc_alts_credentials_client_options_add_target_service_account( + options, ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2); + } + grpc_gcp_rpc_protocol_versions* versions = &options->rpc_versions; + GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max( + versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor)); + GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min( + versions, kMinRpcVersionMajor, kMinRpcVersionMinor)); + return options; +} + static alts_handshaker_client_test_config* create_config() { alts_handshaker_client_test_config* config = static_cast<alts_handshaker_client_test_config*>( gpr_zalloc(sizeof(*config))); config->channel = grpc_insecure_channel_create( - ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL, nullptr, nullptr); + ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, nullptr, nullptr); config->cq = grpc_completion_queue_create_for_next(nullptr); + grpc_alts_credentials_options* client_options = + create_credentials_options(true /* is_client */); + grpc_alts_credentials_options* server_options = + create_credentials_options(false /* is_client */); + config->server = alts_grpc_handshaker_client_create( + nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, + nullptr, server_options, + grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME), + nullptr, nullptr, nullptr, nullptr, false); config->client = alts_grpc_handshaker_client_create( - config->channel, config->cq, - ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL); + nullptr, config->channel, ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, + nullptr, client_options, + grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME), + nullptr, nullptr, nullptr, nullptr, true); GPR_ASSERT(config->client != nullptr); + GPR_ASSERT(config->server != nullptr); + grpc_alts_credentials_options_destroy(client_options); + grpc_alts_credentials_options_destroy(server_options); config->out_frame = grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME); return config; @@ -289,6 +316,7 @@ static void destroy_config(alts_handshaker_client_test_config* config) { grpc_completion_queue_destroy(config->cq); grpc_channel_destroy(config->channel); alts_handshaker_client_destroy(config->client); + alts_handshaker_client_destroy(config->server); grpc_slice_unref(config->out_frame); gpr_free(config); } @@ -296,73 +324,50 @@ static void destroy_config(alts_handshaker_client_test_config* config) { static void schedule_request_invalid_arg_test() { /* Initialization. */ alts_handshaker_client_test_config* config = create_config(); - alts_tsi_event* event = nullptr; - /* Tests. */ alts_handshaker_client_set_grpc_caller_for_testing(config->client, check_must_not_be_called); - event = alts_tsi_event_create_for_testing(true /* is_client */); /* Check client_start. */ - GPR_ASSERT(alts_handshaker_client_start_client(nullptr, event) == - TSI_INVALID_ARGUMENT); - GPR_ASSERT(alts_handshaker_client_start_client(config->client, nullptr) == + GPR_ASSERT(alts_handshaker_client_start_client(nullptr) == TSI_INVALID_ARGUMENT); - /* Check server_start. */ - GPR_ASSERT(alts_handshaker_client_start_server( - config->client, event, nullptr) == TSI_INVALID_ARGUMENT); - GPR_ASSERT(alts_handshaker_client_start_server(config->client, nullptr, - &config->out_frame) == + GPR_ASSERT(alts_handshaker_client_start_server(config->server, nullptr) == TSI_INVALID_ARGUMENT); - GPR_ASSERT(alts_handshaker_client_start_server( - nullptr, event, &config->out_frame) == TSI_INVALID_ARGUMENT); - - /* Check next. */ - GPR_ASSERT(alts_handshaker_client_next(config->client, event, nullptr) == + GPR_ASSERT(alts_handshaker_client_start_server(nullptr, &config->out_frame) == TSI_INVALID_ARGUMENT); - GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr, - &config->out_frame) == + /* Check next. */ + GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr) == TSI_INVALID_ARGUMENT); - GPR_ASSERT(alts_handshaker_client_next(nullptr, event, &config->out_frame) == + GPR_ASSERT(alts_handshaker_client_next(nullptr, &config->out_frame) == TSI_INVALID_ARGUMENT); - /* Check shutdown. */ alts_handshaker_client_shutdown(nullptr); - /* Cleanup. */ - alts_tsi_event_destroy(event); destroy_config(config); } static void schedule_request_success_test() { /* Initialization. */ alts_handshaker_client_test_config* config = create_config(); - alts_tsi_event* event = nullptr; - /* Check client_start success. */ alts_handshaker_client_set_grpc_caller_for_testing( config->client, check_client_start_success); - event = alts_tsi_event_create_for_testing(true /* is_client. */); - GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) == - TSI_OK); - alts_tsi_event_destroy(event); - + GPR_ASSERT(alts_handshaker_client_start_client(config->client) == TSI_OK); /* Check server_start success. */ alts_handshaker_client_set_grpc_caller_for_testing( - config->client, check_server_start_success); - event = alts_tsi_event_create_for_testing(false /* is_client. */); - GPR_ASSERT(alts_handshaker_client_start_server(config->client, event, + config->server, check_server_start_success); + GPR_ASSERT(alts_handshaker_client_start_server(config->server, &config->out_frame) == TSI_OK); - alts_tsi_event_destroy(event); - - /* Check next success. */ + /* Check client next success. */ alts_handshaker_client_set_grpc_caller_for_testing(config->client, check_next_success); - event = alts_tsi_event_create_for_testing(true /* is_client. */); - GPR_ASSERT(alts_handshaker_client_next(config->client, event, - &config->out_frame) == TSI_OK); - alts_tsi_event_destroy(event); - + GPR_ASSERT(alts_handshaker_client_next(config->client, &config->out_frame) == + TSI_OK); + /* Check server next success. */ + alts_handshaker_client_set_grpc_caller_for_testing(config->server, + check_next_success); + GPR_ASSERT(alts_handshaker_client_next(config->server, &config->out_frame) == + TSI_OK); /* Cleanup. */ destroy_config(config); } @@ -370,30 +375,22 @@ static void schedule_request_success_test() { static void schedule_request_grpc_call_failure_test() { /* Initialization. */ alts_handshaker_client_test_config* config = create_config(); - alts_tsi_event* event = nullptr; - /* Check client_start failure. */ alts_handshaker_client_set_grpc_caller_for_testing(config->client, check_grpc_call_failure); - event = alts_tsi_event_create_for_testing(true /* is_client. */); - GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) == + GPR_ASSERT(alts_handshaker_client_start_client(config->client) == TSI_INTERNAL_ERROR); - alts_tsi_event_destroy(event); - /* Check server_start failure. */ - event = alts_tsi_event_create_for_testing(false /* is_client. */); - GPR_ASSERT(alts_handshaker_client_start_server(config->client, event, - &config->out_frame) == + alts_handshaker_client_set_grpc_caller_for_testing(config->server, + check_grpc_call_failure); + GPR_ASSERT(alts_handshaker_client_start_server( + config->server, &config->out_frame) == TSI_INTERNAL_ERROR); + /* Check client next failure. */ + GPR_ASSERT(alts_handshaker_client_next(config->client, &config->out_frame) == + TSI_INTERNAL_ERROR); + /* Check server next failure. */ + GPR_ASSERT(alts_handshaker_client_next(config->server, &config->out_frame) == TSI_INTERNAL_ERROR); - alts_tsi_event_destroy(event); - - /* Check next failure. */ - event = alts_tsi_event_create_for_testing(true /* is_cleint. */); - GPR_ASSERT( - alts_handshaker_client_next(config->client, event, &config->out_frame) == - TSI_INTERNAL_ERROR); - alts_tsi_event_destroy(event); - /* Cleanup. */ destroy_config(config); } @@ -401,13 +398,13 @@ static void schedule_request_grpc_call_failure_test() { int main(int argc, char** argv) { /* Initialization. */ grpc_init(); - + grpc_alts_shared_resource_dedicated_init(); /* Tests. */ schedule_request_invalid_arg_test(); schedule_request_success_test(); schedule_request_grpc_call_failure_test(); - /* Cleanup. */ + grpc_alts_shared_resource_dedicated_shutdown(); grpc_shutdown(); return 0; } diff --git a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc index e9eb7e175f..316ff13816 100644 --- a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc +++ b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc @@ -24,7 +24,7 @@ #include "src/core/lib/gprpp/thd.h" #include "src/core/tsi/alts/handshaker/alts_handshaker_client.h" -#include "src/core/tsi/alts/handshaker/alts_tsi_event.h" +#include "src/core/tsi/alts/handshaker/alts_shared_resource.h" #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" #include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h" @@ -43,12 +43,18 @@ #define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MAJOR 2 #define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MINOR 1 +using grpc_core::internal::alts_handshaker_client_check_fields_for_testing; +using grpc_core::internal::alts_handshaker_client_get_handshaker_for_testing; using grpc_core::internal:: - alts_tsi_handshaker_get_has_sent_start_message_for_testing; + alts_handshaker_client_get_recv_buffer_addr_for_testing; +using grpc_core::internal::alts_handshaker_client_set_cb_for_testing; +using grpc_core::internal::alts_handshaker_client_set_fields_for_testing; +using grpc_core::internal::alts_handshaker_client_set_recv_bytes_for_testing; +using grpc_core::internal::alts_handshaker_client_set_vtable_for_testing; +using grpc_core::internal::alts_tsi_handshaker_get_client_for_testing; using grpc_core::internal::alts_tsi_handshaker_get_is_client_for_testing; -using grpc_core::internal::alts_tsi_handshaker_get_recv_bytes_for_testing; -using grpc_core::internal::alts_tsi_handshaker_set_client_for_testing; -using grpc_core::internal::alts_tsi_handshaker_set_recv_bytes_for_testing; +using grpc_core::internal::alts_tsi_handshaker_set_client_vtable_for_testing; +static bool should_handshaker_client_api_succeed = true; /* ALTS mock notification. */ typedef struct notification { @@ -57,12 +63,6 @@ typedef struct notification { bool notified; } notification; -/* ALTS mock handshaker client. */ -typedef struct alts_mock_handshaker_client { - alts_handshaker_client base; - bool used_for_success_test; -} alts_mock_handshaker_client; - /* Type of ALTS handshaker response. */ typedef enum { INVALID, @@ -73,10 +73,7 @@ typedef enum { SERVER_NEXT, } alts_handshaker_response_type; -static alts_tsi_event* client_start_event; -static alts_tsi_event* client_next_event; -static alts_tsi_event* server_start_event; -static alts_tsi_event* server_next_event; +static alts_handshaker_client* cb_event = nullptr; static notification caller_to_tsi_notification; static notification tsi_to_caller_notification; @@ -311,89 +308,69 @@ static void on_server_next_success_cb(tsi_result status, void* user_data, signal(&tsi_to_caller_notification); } -static tsi_result mock_client_start(alts_handshaker_client* self, - alts_tsi_event* event) { - alts_mock_handshaker_client* client = - reinterpret_cast<alts_mock_handshaker_client*>(self); - if (!client->used_for_success_test) { - alts_tsi_event_destroy(event); +static tsi_result mock_client_start(alts_handshaker_client* client) { + if (!should_handshaker_client_api_succeed) { return TSI_INTERNAL_ERROR; } - GPR_ASSERT(event->cb == on_client_start_success_cb); - GPR_ASSERT(event->user_data == nullptr); - GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing( - event->handshaker)); + alts_handshaker_client_check_fields_for_testing( + client, on_client_start_success_cb, nullptr, false, nullptr); /* Populate handshaker response for client_start request. */ - event->recv_buffer = generate_handshaker_response(CLIENT_START); - client_start_event = event; + grpc_byte_buffer** recv_buffer_ptr = + alts_handshaker_client_get_recv_buffer_addr_for_testing(client); + *recv_buffer_ptr = generate_handshaker_response(CLIENT_START); + cb_event = client; signal(&caller_to_tsi_notification); return TSI_OK; } static void mock_shutdown(alts_handshaker_client* self) {} -static tsi_result mock_server_start(alts_handshaker_client* self, - alts_tsi_event* event, +static tsi_result mock_server_start(alts_handshaker_client* client, grpc_slice* bytes_received) { - alts_mock_handshaker_client* client = - reinterpret_cast<alts_mock_handshaker_client*>(self); - if (!client->used_for_success_test) { - alts_tsi_event_destroy(event); + if (!should_handshaker_client_api_succeed) { return TSI_INTERNAL_ERROR; } - GPR_ASSERT(event->cb == on_server_start_success_cb); - GPR_ASSERT(event->user_data == nullptr); + alts_handshaker_client_check_fields_for_testing( + client, on_server_start_success_cb, nullptr, false, nullptr); grpc_slice slice = grpc_empty_slice(); GPR_ASSERT(grpc_slice_cmp(*bytes_received, slice) == 0); - GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing( - event->handshaker)); /* Populate handshaker response for server_start request. */ - event->recv_buffer = generate_handshaker_response(SERVER_START); - server_start_event = event; + grpc_byte_buffer** recv_buffer_ptr = + alts_handshaker_client_get_recv_buffer_addr_for_testing(client); + *recv_buffer_ptr = generate_handshaker_response(SERVER_START); + cb_event = client; grpc_slice_unref(slice); signal(&caller_to_tsi_notification); return TSI_OK; } -static tsi_result mock_next(alts_handshaker_client* self, alts_tsi_event* event, +static tsi_result mock_next(alts_handshaker_client* client, grpc_slice* bytes_received) { - alts_mock_handshaker_client* client = - reinterpret_cast<alts_mock_handshaker_client*>(self); - if (!client->used_for_success_test) { - alts_tsi_event_destroy(event); + if (!should_handshaker_client_api_succeed) { return TSI_INTERNAL_ERROR; } - bool is_client = - alts_tsi_handshaker_get_is_client_for_testing(event->handshaker); - if (is_client) { - GPR_ASSERT(event->cb == on_client_next_success_cb); - } else { - GPR_ASSERT(event->cb == on_server_next_success_cb); - } - GPR_ASSERT(event->user_data == nullptr); + alts_tsi_handshaker* handshaker = + alts_handshaker_client_get_handshaker_for_testing(client); + bool is_client = alts_tsi_handshaker_get_is_client_for_testing(handshaker); + tsi_handshaker_on_next_done_cb cb = + is_client ? on_client_next_success_cb : on_server_next_success_cb; + alts_handshaker_client_set_cb_for_testing(client, cb); + alts_handshaker_client_set_recv_bytes_for_testing(client, bytes_received); + alts_handshaker_client_check_fields_for_testing(client, cb, nullptr, true, + bytes_received); GPR_ASSERT(bytes_received != nullptr); GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*bytes_received), ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES, GRPC_SLICE_LENGTH(*bytes_received)) == 0); - GPR_ASSERT(grpc_slice_cmp(alts_tsi_handshaker_get_recv_bytes_for_testing( - event->handshaker), - *bytes_received) == 0); - GPR_ASSERT(alts_tsi_handshaker_get_has_sent_start_message_for_testing( - event->handshaker)); /* Populate handshaker response for next request. */ grpc_slice out_frame = grpc_slice_from_static_string(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME); - if (is_client) { - event->recv_buffer = generate_handshaker_response(CLIENT_NEXT); - } else { - event->recv_buffer = generate_handshaker_response(SERVER_NEXT); - } - alts_tsi_handshaker_set_recv_bytes_for_testing(event->handshaker, &out_frame); - if (is_client) { - client_next_event = event; - } else { - server_next_event = event; - } + grpc_byte_buffer** recv_buffer_ptr = + alts_handshaker_client_get_recv_buffer_addr_for_testing(client); + *recv_buffer_ptr = is_client ? generate_handshaker_response(CLIENT_NEXT) + : generate_handshaker_response(SERVER_NEXT); + alts_handshaker_client_set_recv_bytes_for_testing(client, &out_frame); + cb_event = client; signal(&caller_to_tsi_notification); grpc_slice_unref(out_frame); return TSI_OK; @@ -401,38 +378,27 @@ static tsi_result mock_next(alts_handshaker_client* self, alts_tsi_event* event, static void mock_destruct(alts_handshaker_client* client) {} -static const alts_handshaker_client_vtable vtable = { - mock_client_start, mock_server_start, mock_next, mock_shutdown, - mock_destruct}; - -static alts_handshaker_client* alts_mock_handshaker_client_create( - bool used_for_success_test) { - alts_mock_handshaker_client* client = - static_cast<alts_mock_handshaker_client*>(gpr_zalloc(sizeof(*client))); - client->base.vtable = &vtable; - client->used_for_success_test = used_for_success_test; - return &client->base; -} +static alts_handshaker_client_vtable vtable = {mock_client_start, + mock_server_start, mock_next, + mock_shutdown, mock_destruct}; -static tsi_handshaker* create_test_handshaker(bool used_for_success_test, - bool is_client) { +static tsi_handshaker* create_test_handshaker(bool is_client) { tsi_handshaker* handshaker = nullptr; - alts_handshaker_client* client = - alts_mock_handshaker_client_create(used_for_success_test); grpc_alts_credentials_options* options = grpc_alts_credentials_client_options_create(); - alts_tsi_handshaker_create(options, "target_name", "lame", is_client, nullptr, - &handshaker); + alts_tsi_handshaker_create(options, "target_name", + ALTS_HANDSHAKER_SERVICE_URL_FOR_TESTING, is_client, + nullptr, &handshaker); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); - alts_tsi_handshaker_set_client_for_testing(alts_handshaker, client); + alts_tsi_handshaker_set_client_vtable_for_testing(alts_handshaker, &vtable); grpc_alts_credentials_options_destroy(options); return handshaker; } static void check_handshaker_next_invalid_input() { /* Initialization. */ - tsi_handshaker* handshaker = create_test_handshaker(true, true); + tsi_handshaker* handshaker = create_test_handshaker(true); /* Check nullptr handshaker. */ GPR_ASSERT(tsi_handshaker_next(nullptr, nullptr, 0, nullptr, nullptr, nullptr, check_must_not_be_called, @@ -447,8 +413,7 @@ static void check_handshaker_next_invalid_input() { static void check_handshaker_shutdown_invalid_input() { /* Initialization. */ - tsi_handshaker* handshaker = create_test_handshaker( - false /* used_for_success_test */, true /* is_client */); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */); /* Check nullptr handshaker. */ tsi_handshaker_shutdown(nullptr); /* Cleanup. */ @@ -460,10 +425,10 @@ static void check_handshaker_next_success() { * Create handshakers for which internal mock client is going to do * correctness check. */ - tsi_handshaker* client_handshaker = create_test_handshaker( - true /* used_for_success_test */, true /* is_client */); - tsi_handshaker* server_handshaker = create_test_handshaker( - true /* used_for_success_test */, false /* is_client */); + tsi_handshaker* client_handshaker = + create_test_handshaker(true /* is_client */); + tsi_handshaker* server_handshaker = + create_test_handshaker(false /* is_client */); /* Client start. */ GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr, nullptr, nullptr, on_client_start_success_cb, @@ -494,9 +459,7 @@ static void check_handshaker_next_success() { } static void check_handshaker_next_with_shutdown() { - /* Initialization. */ - tsi_handshaker* handshaker = create_test_handshaker( - true /* used_for_success_test */, true /* is_client*/); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client*/); /* next(success) -- shutdown(success) -- next (fail) */ GPR_ASSERT(tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr, on_client_start_success_cb, @@ -514,20 +477,18 @@ static void check_handshaker_next_with_shutdown() { } static void check_handle_response_with_shutdown(void* unused) { - /* Client start. */ wait(&caller_to_tsi_notification); - alts_tsi_event_dispatch_to_handshaker(client_start_event, true /* is_ok */); - alts_tsi_event_destroy(client_start_event); + alts_handshaker_client_handle_response(cb_event, true /* is_ok */); } static void check_handshaker_next_failure() { /** * Create handshakers for which internal mock client is always going to fail. */ - tsi_handshaker* client_handshaker = create_test_handshaker( - false /* used_for_success_test */, true /* is_client */); - tsi_handshaker* server_handshaker = create_test_handshaker( - false /* used_for_success_test */, false /* is_client */); + tsi_handshaker* client_handshaker = + create_test_handshaker(true /* is_client */); + tsi_handshaker* server_handshaker = + create_test_handshaker(false /* is_client */); /* Client start. */ GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr, nullptr, nullptr, check_must_not_be_called, @@ -578,34 +539,46 @@ static void on_failed_grpc_call_cb(tsi_result status, void* user_data, } static void check_handle_response_invalid_input() { + /* Initialization. */ + notification_init(&caller_to_tsi_notification); + notification_init(&tsi_to_caller_notification); /** * Create a handshaker at the client side, for which internal mock client is * always going to fail. */ - tsi_handshaker* handshaker = create_test_handshaker( - false /* used_for_success_test */, true /* is_client */); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */); + tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr, + on_client_start_success_cb, nullptr); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); - grpc_byte_buffer recv_buffer; + grpc_slice slice = grpc_empty_slice(); + grpc_byte_buffer* recv_buffer = grpc_raw_byte_buffer_create(&slice, 1); + alts_handshaker_client* client = + alts_tsi_handshaker_get_client_for_testing(alts_handshaker); /* Check nullptr handshaker. */ - alts_tsi_handshaker_handle_response(nullptr, &recv_buffer, GRPC_STATUS_OK, - nullptr, on_invalid_input_cb, nullptr, - true); + alts_handshaker_client_set_fields_for_testing(client, nullptr, + on_invalid_input_cb, nullptr, + recv_buffer, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, true); /* Check nullptr recv_bytes. */ - alts_tsi_handshaker_handle_response(alts_handshaker, nullptr, GRPC_STATUS_OK, - nullptr, on_invalid_input_cb, nullptr, - true); + alts_handshaker_client_set_fields_for_testing(client, alts_handshaker, + on_invalid_input_cb, nullptr, + nullptr, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, true); /* Check failed grpc call made to handshaker service. */ - alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer, - GRPC_STATUS_UNKNOWN, nullptr, - on_failed_grpc_call_cb, nullptr, true); - - alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer, - GRPC_STATUS_OK, nullptr, - on_failed_grpc_call_cb, nullptr, false); - + alts_handshaker_client_set_fields_for_testing( + client, alts_handshaker, on_failed_grpc_call_cb, nullptr, recv_buffer, + GRPC_STATUS_UNKNOWN); + alts_handshaker_client_handle_response(client, true); + alts_handshaker_client_set_fields_for_testing(client, alts_handshaker, + on_failed_grpc_call_cb, nullptr, + recv_buffer, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, false); /* Cleanup. */ + grpc_slice_unref(slice); tsi_handshaker_destroy(handshaker); + notification_destroy(&caller_to_tsi_notification); + notification_destroy(&tsi_to_caller_notification); } static void on_invalid_resp_cb(tsi_result status, void* user_data, @@ -620,41 +593,45 @@ static void on_invalid_resp_cb(tsi_result status, void* user_data, } static void check_handle_response_invalid_resp() { + /* Initialization. */ + notification_init(&caller_to_tsi_notification); + notification_init(&tsi_to_caller_notification); /** * Create a handshaker at the client side, for which internal mock client is * always going to fail. */ - tsi_handshaker* handshaker = create_test_handshaker( - false /* used_for_success_test */, true /* is_client */); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */); + tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr, + on_client_start_success_cb, nullptr); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); + alts_handshaker_client* client = + alts_tsi_handshaker_get_client_for_testing(alts_handshaker); /* Tests. */ grpc_byte_buffer* recv_buffer = generate_handshaker_response(INVALID); - alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer, - GRPC_STATUS_OK, nullptr, - on_invalid_resp_cb, nullptr, true); + alts_handshaker_client_set_fields_for_testing(client, alts_handshaker, + on_invalid_resp_cb, nullptr, + recv_buffer, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, true); /* Cleanup. */ - grpc_byte_buffer_destroy(recv_buffer); tsi_handshaker_destroy(handshaker); + notification_destroy(&caller_to_tsi_notification); + notification_destroy(&tsi_to_caller_notification); } static void check_handle_response_success(void* unused) { /* Client start. */ wait(&caller_to_tsi_notification); - alts_tsi_event_dispatch_to_handshaker(client_start_event, true /* is_ok */); - alts_tsi_event_destroy(client_start_event); + alts_handshaker_client_handle_response(cb_event, true /* is_ok */); /* Client next. */ wait(&caller_to_tsi_notification); - alts_tsi_event_dispatch_to_handshaker(client_next_event, true /* is_ok */); - alts_tsi_event_destroy(client_next_event); + alts_handshaker_client_handle_response(cb_event, true /* is_ok */); /* Server start. */ wait(&caller_to_tsi_notification); - alts_tsi_event_dispatch_to_handshaker(server_start_event, true /* is_ok */); - alts_tsi_event_destroy(server_start_event); + alts_handshaker_client_handle_response(cb_event, true /* is_ok */); /* Server next. */ wait(&caller_to_tsi_notification); - alts_tsi_event_dispatch_to_handshaker(server_next_event, true /* is_ok */); - alts_tsi_event_destroy(server_next_event); + alts_handshaker_client_handle_response(cb_event, true /* is_ok */); } static void on_failed_resp_cb(tsi_result status, void* user_data, @@ -669,22 +646,30 @@ static void on_failed_resp_cb(tsi_result status, void* user_data, } static void check_handle_response_failure() { + /* Initialization. */ + notification_init(&caller_to_tsi_notification); + notification_init(&tsi_to_caller_notification); /** * Create a handshaker at the client side, for which internal mock client is * always going to fail. */ - tsi_handshaker* handshaker = create_test_handshaker( - false /* used_for_success_test */, true /* is_client */); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */); + tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr, + on_client_start_success_cb, nullptr); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); + alts_handshaker_client* client = + alts_tsi_handshaker_get_client_for_testing(alts_handshaker); /* Tests. */ grpc_byte_buffer* recv_buffer = generate_handshaker_response(FAILED); - alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer, - GRPC_STATUS_OK, nullptr, - on_failed_resp_cb, nullptr, true); - grpc_byte_buffer_destroy(recv_buffer); + alts_handshaker_client_set_fields_for_testing(client, alts_handshaker, + on_failed_resp_cb, nullptr, + recv_buffer, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, true /* is_ok*/); /* Cleanup. */ tsi_handshaker_destroy(handshaker); + notification_destroy(&caller_to_tsi_notification); + notification_destroy(&tsi_to_caller_notification); } static void on_shutdown_resp_cb(tsi_result status, void* user_data, @@ -699,26 +684,38 @@ static void on_shutdown_resp_cb(tsi_result status, void* user_data, } static void check_handle_response_after_shutdown() { - tsi_handshaker* handshaker = create_test_handshaker( - true /* used_for_success_test */, true /* is_client */); + /* Initialization. */ + notification_init(&caller_to_tsi_notification); + notification_init(&tsi_to_caller_notification); + tsi_handshaker* handshaker = create_test_handshaker(true /* is_client */); + tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr, nullptr, + on_client_start_success_cb, nullptr); alts_tsi_handshaker* alts_handshaker = reinterpret_cast<alts_tsi_handshaker*>(handshaker); + alts_handshaker_client* client = + alts_tsi_handshaker_get_client_for_testing(alts_handshaker); + grpc_byte_buffer** recv_buffer_ptr = + alts_handshaker_client_get_recv_buffer_addr_for_testing(client); + grpc_byte_buffer_destroy(*recv_buffer_ptr); + /* Tests. */ tsi_handshaker_shutdown(handshaker); grpc_byte_buffer* recv_buffer = generate_handshaker_response(CLIENT_START); - alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer, - GRPC_STATUS_OK, nullptr, - on_shutdown_resp_cb, nullptr, true); - grpc_byte_buffer_destroy(recv_buffer); + alts_handshaker_client_set_fields_for_testing(client, alts_handshaker, + on_shutdown_resp_cb, nullptr, + recv_buffer, GRPC_STATUS_OK); + alts_handshaker_client_handle_response(client, true); /* Cleanup. */ tsi_handshaker_destroy(handshaker); + notification_destroy(&caller_to_tsi_notification); + notification_destroy(&tsi_to_caller_notification); } void check_handshaker_next_fails_after_shutdown() { /* Initialization. */ notification_init(&caller_to_tsi_notification); notification_init(&tsi_to_caller_notification); - client_start_event = nullptr; + cb_event = nullptr; /* Tests. */ grpc_core::Thread thd("alts_tsi_handshaker_test", &check_handle_response_with_shutdown, nullptr); @@ -734,10 +731,6 @@ void check_handshaker_success() { /* Initialization. */ notification_init(&caller_to_tsi_notification); notification_init(&tsi_to_caller_notification); - client_start_event = nullptr; - client_next_event = nullptr; - server_start_event = nullptr; - server_next_event = nullptr; /* Tests. */ grpc_core::Thread thd("alts_tsi_handshaker_test", &check_handle_response_success, nullptr); @@ -752,17 +745,21 @@ void check_handshaker_success() { int main(int argc, char** argv) { /* Initialization. */ grpc_init(); + grpc_alts_shared_resource_dedicated_init(); /* Tests. */ + should_handshaker_client_api_succeed = true; check_handshaker_success(); check_handshaker_next_invalid_input(); - check_handshaker_shutdown_invalid_input(); check_handshaker_next_fails_after_shutdown(); + check_handle_response_after_shutdown(); + should_handshaker_client_api_succeed = false; + check_handshaker_shutdown_invalid_input(); check_handshaker_next_failure(); check_handle_response_invalid_input(); check_handle_response_invalid_resp(); check_handle_response_failure(); - check_handle_response_after_shutdown(); /* Cleanup. */ + grpc_alts_shared_resource_dedicated_shutdown(); grpc_shutdown(); return 0; } diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 93e1e68654..fdc67969d9 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -33,6 +33,7 @@ #include <grpcpp/impl/codegen/method_handler_impl.h> #include <grpcpp/impl/codegen/proto_utils.h> #include <grpcpp/impl/codegen/rpc_method.h> +#include <grpcpp/impl/codegen/server_callback.h> #include <grpcpp/impl/codegen/service_type.h> #include <grpcpp/impl/codegen/status.h> #include <grpcpp/impl/codegen/stub_options.h> @@ -308,6 +309,80 @@ class ServiceA final { }; typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<WithAsyncMethod_MethodA3<WithAsyncMethod_MethodA4<Service > > > > AsyncService; template <class BaseClass> + class ExperimentalWithCallbackMethod_MethodA1 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithCallbackMethod_MethodA1() { + ::grpc::Service::experimental().MarkMethodCallback(0, + new ::grpc::internal::CallbackUnaryHandler< ExperimentalWithCallbackMethod_MethodA1<BaseClass>, ::grpc::testing::Request, ::grpc::testing::Response>( + [this](::grpc::ServerContext* context, + const ::grpc::testing::Request* request, + ::grpc::testing::Response* response, + ::grpc::experimental::ServerCallbackRpcController* controller) { + this->MethodA1(context, request, response, controller); + }, this)); + } + ~ExperimentalWithCallbackMethod_MethodA1() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual void MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); } + }; + template <class BaseClass> + class ExperimentalWithCallbackMethod_MethodA2 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithCallbackMethod_MethodA2() { + } + ~ExperimentalWithCallbackMethod_MethodA2() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template <class BaseClass> + class ExperimentalWithCallbackMethod_MethodA3 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithCallbackMethod_MethodA3() { + } + ~ExperimentalWithCallbackMethod_MethodA3() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template <class BaseClass> + class ExperimentalWithCallbackMethod_MethodA4 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithCallbackMethod_MethodA4() { + } + ~ExperimentalWithCallbackMethod_MethodA4() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + typedef ExperimentalWithCallbackMethod_MethodA1<ExperimentalWithCallbackMethod_MethodA2<ExperimentalWithCallbackMethod_MethodA3<ExperimentalWithCallbackMethod_MethodA4<Service > > > > ExperimentalCallbackService; + template <class BaseClass> class WithGenericMethod_MethodA1 : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service *service) {} @@ -456,6 +531,79 @@ class ServiceA final { } }; template <class BaseClass> + class ExperimentalWithRawCallbackMethod_MethodA1 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithRawCallbackMethod_MethodA1() { + ::grpc::Service::experimental().MarkMethodRawCallback(0, + new ::grpc::internal::CallbackUnaryHandler< ExperimentalWithRawCallbackMethod_MethodA1<BaseClass>, ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + [this](::grpc::ServerContext* context, + const ::grpc::ByteBuffer* request, + ::grpc::ByteBuffer* response, + ::grpc::experimental::ServerCallbackRpcController* controller) { + this->MethodA1(context, request, response, controller); + }, this)); + } + ~ExperimentalWithRawCallbackMethod_MethodA1() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual void MethodA1(::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); } + }; + template <class BaseClass> + class ExperimentalWithRawCallbackMethod_MethodA2 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithRawCallbackMethod_MethodA2() { + } + ~ExperimentalWithRawCallbackMethod_MethodA2() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template <class BaseClass> + class ExperimentalWithRawCallbackMethod_MethodA3 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithRawCallbackMethod_MethodA3() { + } + ~ExperimentalWithRawCallbackMethod_MethodA3() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template <class BaseClass> + class ExperimentalWithRawCallbackMethod_MethodA4 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithRawCallbackMethod_MethodA4() { + } + ~ExperimentalWithRawCallbackMethod_MethodA4() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template <class BaseClass> class WithStreamedUnaryMethod_MethodA1 : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service *service) {} @@ -591,6 +739,32 @@ class ServiceB final { }; typedef WithAsyncMethod_MethodB1<Service > AsyncService; template <class BaseClass> + class ExperimentalWithCallbackMethod_MethodB1 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithCallbackMethod_MethodB1() { + ::grpc::Service::experimental().MarkMethodCallback(0, + new ::grpc::internal::CallbackUnaryHandler< ExperimentalWithCallbackMethod_MethodB1<BaseClass>, ::grpc::testing::Request, ::grpc::testing::Response>( + [this](::grpc::ServerContext* context, + const ::grpc::testing::Request* request, + ::grpc::testing::Response* response, + ::grpc::experimental::ServerCallbackRpcController* controller) { + this->MethodB1(context, request, response, controller); + }, this)); + } + ~ExperimentalWithCallbackMethod_MethodB1() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual void MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); } + }; + typedef ExperimentalWithCallbackMethod_MethodB1<Service > ExperimentalCallbackService; + template <class BaseClass> class WithGenericMethod_MethodB1 : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service *service) {} @@ -628,6 +802,31 @@ class ServiceB final { } }; template <class BaseClass> + class ExperimentalWithRawCallbackMethod_MethodB1 : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + ExperimentalWithRawCallbackMethod_MethodB1() { + ::grpc::Service::experimental().MarkMethodRawCallback(0, + new ::grpc::internal::CallbackUnaryHandler< ExperimentalWithRawCallbackMethod_MethodB1<BaseClass>, ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + [this](::grpc::ServerContext* context, + const ::grpc::ByteBuffer* request, + ::grpc::ByteBuffer* response, + ::grpc::experimental::ServerCallbackRpcController* controller) { + this->MethodB1(context, request, response, controller); + }, this)); + } + ~ExperimentalWithRawCallbackMethod_MethodB1() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status MethodB1(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual void MethodB1(::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, ::grpc::experimental::ServerCallbackRpcController* controller) { controller->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); } + }; + template <class BaseClass> class WithStreamedUnaryMethod_MethodB1 : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service *service) {} diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc index 5f25278534..f04ffe4f2d 100644 --- a/test/cpp/end2end/channelz_service_test.cc +++ b/test/cpp/end2end/channelz_service_test.cc @@ -651,6 +651,28 @@ TEST_F(ChannelzServerTest, GetServerSocketsTest) { EXPECT_EQ(get_server_sockets_response.socket_ref_size(), 1); } +TEST_F(ChannelzServerTest, GetServerListenSocketsTest) { + ResetStubs(); + ConfigureProxy(1); + GetServersRequest get_server_request; + GetServersResponse get_server_response; + get_server_request.set_start_server_id(0); + ClientContext get_server_context; + Status s = channelz_stub_->GetServers(&get_server_context, get_server_request, + &get_server_response); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); + EXPECT_EQ(get_server_response.server_size(), 1); + EXPECT_EQ(get_server_response.server(0).listen_socket_size(), 1); + GetSocketRequest get_socket_request; + GetSocketResponse get_socket_response; + get_socket_request.set_socket_id( + get_server_response.server(0).listen_socket(0).socket_id()); + ClientContext get_socket_context; + s = channelz_stub_->GetSocket(&get_socket_context, get_socket_request, + &get_socket_response); + EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message(); +} + } // namespace testing } // namespace grpc diff --git a/test/cpp/end2end/client_callback_end2end_test.cc b/test/cpp/end2end/client_callback_end2end_test.cc index 62a85641c7..7ffc610ce2 100644 --- a/test/cpp/end2end/client_callback_end2end_test.cc +++ b/test/cpp/end2end/client_callback_end2end_test.cc @@ -41,13 +41,38 @@ namespace grpc { namespace testing { namespace { -class ClientCallbackEnd2endTest : public ::testing::Test { +class TestScenario { + public: + TestScenario(bool serve_callback) : callback_server(serve_callback) {} + void Log() const; + bool callback_server; +}; + +static std::ostream& operator<<(std::ostream& out, + const TestScenario& scenario) { + return out << "TestScenario{callback_server=" + << (scenario.callback_server ? "true" : "false") << "}"; +} + +void TestScenario::Log() const { + std::ostringstream out; + out << *this; + gpr_log(GPR_DEBUG, "%s", out.str().c_str()); +} + +class ClientCallbackEnd2endTest + : public ::testing::TestWithParam<TestScenario> { protected: - ClientCallbackEnd2endTest() {} + ClientCallbackEnd2endTest() { GetParam().Log(); } void SetUp() override { ServerBuilder builder; - builder.RegisterService(&service_); + + if (!GetParam().callback_server) { + builder.RegisterService(&service_); + } else { + builder.RegisterService(&callback_service_); + } server_ = builder.BuildAndStart(); is_server_started_ = true; @@ -151,37 +176,38 @@ class ClientCallbackEnd2endTest : public ::testing::Test { std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; std::unique_ptr<grpc::GenericStub> generic_stub_; TestServiceImpl service_; + CallbackTestServiceImpl callback_service_; std::unique_ptr<Server> server_; }; -TEST_F(ClientCallbackEnd2endTest, SimpleRpc) { +TEST_P(ClientCallbackEnd2endTest, SimpleRpc) { ResetStub(); SendRpcs(1, false); } -TEST_F(ClientCallbackEnd2endTest, SequentialRpcs) { +TEST_P(ClientCallbackEnd2endTest, SequentialRpcs) { ResetStub(); SendRpcs(10, false); } -TEST_F(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) { +TEST_P(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) { ResetStub(); SendRpcs(10, true); } -TEST_F(ClientCallbackEnd2endTest, SequentialGenericRpcs) { +TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcs) { ResetStub(); SendRpcsGeneric(10, false); } #if GRPC_ALLOW_EXCEPTIONS -TEST_F(ClientCallbackEnd2endTest, ExceptingRpc) { +TEST_P(ClientCallbackEnd2endTest, ExceptingRpc) { ResetStub(); SendRpcsGeneric(10, true); } #endif -TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) { +TEST_P(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) { ResetStub(); std::vector<std::thread> threads; threads.reserve(10); @@ -193,7 +219,7 @@ TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) { } } -TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) { +TEST_P(ClientCallbackEnd2endTest, MultipleRpcs) { ResetStub(); std::vector<std::thread> threads; threads.reserve(10); @@ -205,7 +231,7 @@ TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) { } } -TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) { +TEST_P(ClientCallbackEnd2endTest, CancelRpcBeforeStart) { ResetStub(); EchoRequest request; EchoResponse response; @@ -230,6 +256,11 @@ TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) { } } +TestScenario scenarios[] = {TestScenario{false}, TestScenario{true}}; + +INSTANTIATE_TEST_CASE_P(ClientCallbackEnd2endTest, ClientCallbackEnd2endTest, + ::testing::ValuesIn(scenarios)); + } // namespace } // namespace testing } // namespace grpc diff --git a/test/cpp/end2end/client_interceptors_end2end_test.cc b/test/cpp/end2end/client_interceptors_end2end_test.cc index c36417de37..0b34ec93ae 100644 --- a/test/cpp/end2end/client_interceptors_end2end_test.cc +++ b/test/cpp/end2end/client_interceptors_end2end_test.cc @@ -556,6 +556,106 @@ TEST_F(ClientInterceptorsStreamingEnd2endTest, BidiStreamingTest) { EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); } +class ClientGlobalInterceptorEnd2endTest : public ::testing::Test { + protected: + ClientGlobalInterceptorEnd2endTest() { + int port = grpc_pick_unused_port_or_die(); + + ServerBuilder builder; + server_address_ = "localhost:" + std::to_string(port); + builder.AddListeningPort(server_address_, InsecureServerCredentials()); + builder.RegisterService(&service_); + server_ = builder.BuildAndStart(); + } + + ~ClientGlobalInterceptorEnd2endTest() { server_->Shutdown(); } + + std::string server_address_; + TestServiceImpl service_; + std::unique_ptr<Server> server_; +}; + +TEST_F(ClientGlobalInterceptorEnd2endTest, DummyGlobalInterceptor) { + // We should ideally be registering a global interceptor only once per + // process, but for the purposes of testing, it should be fine to modify the + // registered global interceptor when there are no ongoing gRPC operations + DummyInterceptorFactory global_factory; + experimental::RegisterGlobalClientInterceptorFactory(&global_factory); + ChannelArguments args; + DummyInterceptor::Reset(); + auto creators = std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>( + new std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>()); + // Add 20 dummy interceptors + for (auto i = 0; i < 20; i++) { + creators->push_back(std::unique_ptr<DummyInterceptorFactory>( + new DummyInterceptorFactory())); + } + auto channel = experimental::CreateCustomChannelWithInterceptors( + server_address_, InsecureChannelCredentials(), args, std::move(creators)); + MakeCall(channel); + // Make sure all 20 dummy interceptors were run with the global interceptor + EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 21); + // Reset the global interceptor. This is again 'safe' because there are no + // other ongoing gRPC operations + experimental::RegisterGlobalClientInterceptorFactory(nullptr); +} + +TEST_F(ClientGlobalInterceptorEnd2endTest, LoggingGlobalInterceptor) { + // We should ideally be registering a global interceptor only once per + // process, but for the purposes of testing, it should be fine to modify the + // registered global interceptor when there are no ongoing gRPC operations + LoggingInterceptorFactory global_factory; + experimental::RegisterGlobalClientInterceptorFactory(&global_factory); + ChannelArguments args; + DummyInterceptor::Reset(); + auto creators = std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>( + new std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>()); + // Add 20 dummy interceptors + for (auto i = 0; i < 20; i++) { + creators->push_back(std::unique_ptr<DummyInterceptorFactory>( + new DummyInterceptorFactory())); + } + auto channel = experimental::CreateCustomChannelWithInterceptors( + server_address_, InsecureChannelCredentials(), args, std::move(creators)); + MakeCall(channel); + // Make sure all 20 dummy interceptors were run + EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); + // Reset the global interceptor. This is again 'safe' because there are no + // other ongoing gRPC operations + experimental::RegisterGlobalClientInterceptorFactory(nullptr); +} + +TEST_F(ClientGlobalInterceptorEnd2endTest, HijackingGlobalInterceptor) { + // We should ideally be registering a global interceptor only once per + // process, but for the purposes of testing, it should be fine to modify the + // registered global interceptor when there are no ongoing gRPC operations + HijackingInterceptorFactory global_factory; + experimental::RegisterGlobalClientInterceptorFactory(&global_factory); + ChannelArguments args; + DummyInterceptor::Reset(); + auto creators = std::unique_ptr<std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>( + new std::vector< + std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>()); + // Add 20 dummy interceptors + for (auto i = 0; i < 20; i++) { + creators->push_back(std::unique_ptr<DummyInterceptorFactory>( + new DummyInterceptorFactory())); + } + auto channel = experimental::CreateCustomChannelWithInterceptors( + server_address_, InsecureChannelCredentials(), args, std::move(creators)); + MakeCall(channel); + // Make sure all 20 dummy interceptors were run + EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); + // Reset the global interceptor. This is again 'safe' because there are no + // other ongoing gRPC operations + experimental::RegisterGlobalClientInterceptorFactory(nullptr); +} + } // namespace } // namespace testing } // namespace grpc diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc index 3c3a5d9cd4..605356724f 100644 --- a/test/cpp/end2end/test_service_impl.cc +++ b/test/cpp/end2end/test_service_impl.cc @@ -165,6 +165,138 @@ Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request, return Status::OK; } +void CallbackTestServiceImpl::Echo( + ServerContext* context, const EchoRequest* request, EchoResponse* response, + experimental::ServerCallbackRpcController* controller) { + // A bit of sleep to make sure that short deadline tests fail + if (request->has_param() && request->param().server_sleep_us() > 0) { + // Set an alarm for that much time + alarm_.experimental().Set( + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), + gpr_time_from_micros(request->param().server_sleep_us(), + GPR_TIMESPAN)), + [this, context, request, response, controller](bool) { + EchoNonDelayed(context, request, response, controller); + }); + } else { + EchoNonDelayed(context, request, response, controller); + } +} + +void CallbackTestServiceImpl::EchoNonDelayed( + ServerContext* context, const EchoRequest* request, EchoResponse* response, + experimental::ServerCallbackRpcController* controller) { + if (request->has_param() && request->param().server_die()) { + gpr_log(GPR_ERROR, "The request should not reach application handler."); + GPR_ASSERT(0); + } + if (request->has_param() && request->param().has_expected_error()) { + const auto& error = request->param().expected_error(); + controller->Finish(Status(static_cast<StatusCode>(error.code()), + error.error_message(), + error.binary_error_details())); + } + int server_try_cancel = GetIntValueFromMetadata( + kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL); + if (server_try_cancel > DO_NOT_CANCEL) { + // Since this is a unary RPC, by the time this server handler is called, + // the 'request' message is already read from the client. So the scenarios + // in server_try_cancel don't make much sense. Just cancel the RPC as long + // as server_try_cancel is not DO_NOT_CANCEL + EXPECT_FALSE(context->IsCancelled()); + context->TryCancel(); + gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request"); + // Now wait until it's really canceled + + std::function<void(bool)> recurrence = [this, context, controller, + &recurrence](bool) { + if (!context->IsCancelled()) { + alarm_.experimental().Set( + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_micros(1000, GPR_TIMESPAN)), + recurrence); + } else { + controller->Finish(Status::CANCELLED); + } + }; + recurrence(true); + return; + } + + response->set_message(request->message()); + MaybeEchoDeadline(context, request, response); + if (host_) { + response->mutable_param()->set_host(*host_); + } + if (request->has_param() && request->param().client_cancel_after_us()) { + { + std::unique_lock<std::mutex> lock(mu_); + signal_client_ = true; + } + std::function<void(bool)> recurrence = [this, context, request, controller, + &recurrence](bool) { + if (!context->IsCancelled()) { + alarm_.experimental().Set( + gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_micros(request->param().client_cancel_after_us(), + GPR_TIMESPAN)), + recurrence); + } else { + controller->Finish(Status::CANCELLED); + } + }; + recurrence(true); + return; + } else if (request->has_param() && + request->param().server_cancel_after_us()) { + alarm_.experimental().Set( + gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_micros(request->param().client_cancel_after_us(), + GPR_TIMESPAN)), + [controller](bool) { controller->Finish(Status::CANCELLED); }); + return; + } else if (!request->has_param() || + !request->param().skip_cancelled_check()) { + EXPECT_FALSE(context->IsCancelled()); + } + + if (request->has_param() && request->param().echo_metadata()) { + const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata = + context->client_metadata(); + for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator + iter = client_metadata.begin(); + iter != client_metadata.end(); ++iter) { + context->AddTrailingMetadata(ToString(iter->first), + ToString(iter->second)); + } + // Terminate rpc with error and debug info in trailer. + if (request->param().debug_info().stack_entries_size() || + !request->param().debug_info().detail().empty()) { + grpc::string serialized_debug_info = + request->param().debug_info().SerializeAsString(); + context->AddTrailingMetadata(kDebugInfoTrailerKey, serialized_debug_info); + controller->Finish(Status::CANCELLED); + } + } + if (request->has_param() && + (request->param().expected_client_identity().length() > 0 || + request->param().check_auth_context())) { + CheckServerAuthContext(context, + request->param().expected_transport_security_type(), + request->param().expected_client_identity()); + } + if (request->has_param() && request->param().response_message_length() > 0) { + response->set_message( + grpc::string(request->param().response_message_length(), '\0')); + } + if (request->has_param() && request->param().echo_peer()) { + response->mutable_param()->set_peer(context->peer()); + } + controller->Finish(Status::OK); +} + // Unimplemented is left unimplemented to test the returned error. Status TestServiceImpl::RequestStream(ServerContext* context, @@ -332,7 +464,8 @@ Status TestServiceImpl::BidiStream( return Status::OK; } -int TestServiceImpl::GetIntValueFromMetadata( +namespace { +int GetIntValueFromMetadataHelper( const char* key, const std::multimap<grpc::string_ref, grpc::string_ref>& metadata, int default_value) { @@ -344,6 +477,21 @@ int TestServiceImpl::GetIntValueFromMetadata( return default_value; } +}; // namespace + +int TestServiceImpl::GetIntValueFromMetadata( + const char* key, + const std::multimap<grpc::string_ref, grpc::string_ref>& metadata, + int default_value) { + return GetIntValueFromMetadataHelper(key, metadata, default_value); +} + +int CallbackTestServiceImpl::GetIntValueFromMetadata( + const char* key, + const std::multimap<grpc::string_ref, grpc::string_ref>& metadata, + int default_value) { + return GetIntValueFromMetadataHelper(key, metadata, default_value); +} void TestServiceImpl::ServerTryCancel(ServerContext* context) { EXPECT_FALSE(context->IsCancelled()); diff --git a/test/cpp/end2end/test_service_impl.h b/test/cpp/end2end/test_service_impl.h index 052543a03e..ddfe94487e 100644 --- a/test/cpp/end2end/test_service_impl.h +++ b/test/cpp/end2end/test_service_impl.h @@ -22,6 +22,7 @@ #include <mutex> #include <grpc/grpc.h> +#include <grpcpp/alarm.h> #include <grpcpp/server_context.h> #include "src/proto/grpc/testing/echo.grpc.pb.h" @@ -78,7 +79,39 @@ class TestServiceImpl : public ::grpc::testing::EchoTestService::Service { void ServerTryCancel(ServerContext* context); + bool signal_client_; + std::mutex mu_; + std::unique_ptr<grpc::string> host_; +}; + +class CallbackTestServiceImpl + : public ::grpc::testing::EchoTestService::ExperimentalCallbackService { + public: + CallbackTestServiceImpl() : signal_client_(false), host_() {} + explicit CallbackTestServiceImpl(const grpc::string& host) + : signal_client_(false), host_(new grpc::string(host)) {} + + void Echo(ServerContext* context, const EchoRequest* request, + EchoResponse* response, + experimental::ServerCallbackRpcController* controller) override; + + // Unimplemented is left unimplemented to test the returned error. + bool signal_client() { + std::unique_lock<std::mutex> lock(mu_); + return signal_client_; + } + private: + void EchoNonDelayed(ServerContext* context, const EchoRequest* request, + EchoResponse* response, + experimental::ServerCallbackRpcController* controller); + + int GetIntValueFromMetadata( + const char* key, + const std::multimap<grpc::string_ref, grpc::string_ref>& metadata, + int default_value); + + Alarm alarm_; bool signal_client_; std::mutex mu_; std::unique_ptr<grpc::string> host_; diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc index 1f7831096c..446dc93edb 100644 --- a/test/cpp/microbenchmarks/bm_call_create.cc +++ b/test/cpp/microbenchmarks/bm_call_create.cc @@ -468,7 +468,7 @@ class NoOp { class SendEmptyMetadata { public: - SendEmptyMetadata() { + SendEmptyMetadata() : op_payload_(nullptr) { memset(&op_, 0, sizeof(op_)); op_.on_complete = GRPC_CLOSURE_INIT(&closure_, DoNothing, nullptr, grpc_schedule_on_exec_ctx); diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc index ba4b57ad22..85d233dd26 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc @@ -778,8 +778,7 @@ static void free_timeout(void* p) { gpr_free(p); } // Benchmark the current on_initial_header implementation static void OnInitialHeader(void* user_data, grpc_mdelem md) { // Setup for benchmark. This will bloat the absolute values of this benchmark - grpc_chttp2_incoming_metadata_buffer buffer; - grpc_chttp2_incoming_metadata_buffer_init(&buffer, (gpr_arena*)user_data); + grpc_chttp2_incoming_metadata_buffer buffer((gpr_arena*)user_data); bool seen_error = false; // Below here is the code we actually care about benchmarking @@ -822,7 +821,6 @@ static void OnInitialHeader(void* user_data, grpc_mdelem md) { GPR_ASSERT(0); } } - grpc_chttp2_incoming_metadata_buffer_destroy(&buffer); } // Benchmark timeout handling diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc index 189923a841..f7ae16e61d 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc @@ -262,7 +262,7 @@ static void BM_StreamCreateDestroy(benchmark::State& state) { Fixture f(grpc::ChannelArguments(), true); Stream s(&f); grpc_transport_stream_op_batch op; - grpc_transport_stream_op_batch_payload op_payload; + grpc_transport_stream_op_batch_payload op_payload(nullptr); memset(&op, 0, sizeof(op)); op.cancel_stream = true; op.payload = &op_payload; @@ -308,8 +308,7 @@ static void BM_StreamCreateSendInitialMetadataDestroy(benchmark::State& state) { Fixture f(grpc::ChannelArguments(), true); Stream s(&f); grpc_transport_stream_op_batch op; - grpc_transport_stream_op_batch_payload op_payload; - memset(&op_payload, 0, sizeof(op_payload)); + grpc_transport_stream_op_batch_payload op_payload(nullptr); std::unique_ptr<Closure> start; std::unique_ptr<Closure> done; @@ -360,8 +359,7 @@ static void BM_TransportEmptyOp(benchmark::State& state) { Stream s(&f); s.Init(state); grpc_transport_stream_op_batch op; - grpc_transport_stream_op_batch_payload op_payload; - memset(&op_payload, 0, sizeof(op_payload)); + grpc_transport_stream_op_batch_payload op_payload(nullptr); auto reset_op = [&]() { memset(&op, 0, sizeof(op)); op.payload = &op_payload; @@ -393,8 +391,7 @@ static void BM_TransportStreamSend(benchmark::State& state) { auto s = std::unique_ptr<Stream>(new Stream(&f)); s->Init(state); grpc_transport_stream_op_batch op; - grpc_transport_stream_op_batch_payload op_payload; - memset(&op_payload, 0, sizeof(op_payload)); + grpc_transport_stream_op_batch_payload op_payload(nullptr); auto reset_op = [&]() { memset(&op, 0, sizeof(op)); op.payload = &op_payload; @@ -526,8 +523,7 @@ static void BM_TransportStreamRecv(benchmark::State& state) { Fixture f(grpc::ChannelArguments(), true); Stream s(&f); s.Init(state); - grpc_transport_stream_op_batch_payload op_payload; - memset(&op_payload, 0, sizeof(op_payload)); + grpc_transport_stream_op_batch_payload op_payload(nullptr); grpc_transport_stream_op_batch op; grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_stream; grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384); diff --git a/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py new file mode 100644 index 0000000000..4d03ef49ba --- /dev/null +++ b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py @@ -0,0 +1,63 @@ +# Copyright 2018 The gRPC Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Patches the compile() to allow enable parallel compilation of C/C++. + +build_ext has lots of C/C++ files and normally them one by one. +Enabling parallel build helps a lot. +""" + +import distutils.ccompiler +import os + +try: + BUILD_EXT_COMPILER_JOBS = int( + os.environ.get('GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS', '1')) +except ValueError: + BUILD_EXT_COMPILER_JOBS = 1 + + +# monkey-patch for parallel compilation +def _parallel_compile(self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None): + # setup the same way as distutils.ccompiler.CCompiler + # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564 + macros, objects, extra_postargs, pp_opts, build = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + + def _compile_single_file(obj): + try: + src, ext = build[obj] + except KeyError: + return + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + + # run compilation of individual files in parallel + import multiprocessing.pool + multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map( + _compile_single_file, objects) + return objects + + +def monkeypatch_compile_maybe(): + """Monkeypatching is dumb, but the build speed gain is worth it.""" + if BUILD_EXT_COMPILER_JOBS > 1: + distutils.ccompiler.CCompiler.compile = _parallel_compile diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py index c13dfe9ade..64c468cbf7 100644 --- a/tools/distrib/python/grpcio_tools/setup.py +++ b/tools/distrib/python/grpcio_tools/setup.py @@ -34,9 +34,12 @@ from setuptools.command import build_ext os.chdir(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.abspath('.')) +import _parallel_compile_patch import protoc_lib_deps import grpc_version +_parallel_compile_patch.monkeypatch_compile_maybe() + CLASSIFIERS = [ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index f2bb5df7d3..392113c284 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -971,6 +971,7 @@ include/grpcpp/impl/codegen/rpc_method.h \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ +include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -1008,6 +1009,7 @@ include/grpcpp/support/client_callback.h \ include/grpcpp/support/config.h \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ +include/grpcpp/support/server_callback.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ include/grpcpp/support/status_code_enum.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 81d74cd972..a96683883c 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -973,6 +973,7 @@ include/grpcpp/impl/codegen/rpc_method.h \ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ +include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ @@ -1010,6 +1011,7 @@ include/grpcpp/support/client_callback.h \ include/grpcpp/support/config.h \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ +include/grpcpp/support/server_callback.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ include/grpcpp/support/status_code_enum.h \ @@ -1181,9 +1183,11 @@ src/core/lib/transport/status_metadata.h \ src/core/lib/transport/timeout_encoding.h \ src/core/lib/transport/transport.h \ src/core/lib/transport/transport_impl.h \ +src/core/lib/uri/uri_parser.h \ src/cpp/README.md \ src/cpp/client/channel_cc.cc \ src/cpp/client/client_context.cc \ +src/cpp/client/client_interceptor.cc \ src/cpp/client/create_channel.cc \ src/cpp/client/create_channel_internal.cc \ src/cpp/client/create_channel_internal.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 437253c01b..791318bf36 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -962,8 +962,6 @@ src/core/ext/filters/client_channel/subchannel.cc \ src/core/ext/filters/client_channel/subchannel.h \ src/core/ext/filters/client_channel/subchannel_index.cc \ src/core/ext/filters/client_channel/subchannel_index.h \ -src/core/ext/filters/client_channel/uri_parser.cc \ -src/core/ext/filters/client_channel/uri_parser.h \ src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/deadline/deadline_filter.h \ src/core/ext/filters/http/client/http_client_filter.cc \ @@ -1478,6 +1476,8 @@ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport.h \ src/core/lib/transport/transport_impl.h \ src/core/lib/transport/transport_op_string.cc \ +src/core/lib/uri/uri_parser.cc \ +src/core/lib/uri/uri_parser.h \ src/core/plugin_registry/grpc_plugin_registry.cc \ src/core/tsi/README.md \ src/core/tsi/alts/crypt/aes_gcm.cc \ @@ -1501,8 +1501,8 @@ src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \ src/core/tsi/alts/handshaker/alts_handshaker_service_api.h \ src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \ src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h \ -src/core/tsi/alts/handshaker/alts_tsi_event.cc \ -src/core/tsi/alts/handshaker/alts_tsi_event.h \ +src/core/tsi/alts/handshaker/alts_shared_resource.cc \ +src/core/tsi/alts/handshaker/alts_shared_resource.h \ src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \ src/core/tsi/alts/handshaker/alts_tsi_handshaker.h \ src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h \ diff --git a/tools/gcp/utils/big_query_utils.py b/tools/gcp/utils/big_query_utils.py index 3e811ca2bf..6e9cda376b 100755 --- a/tools/gcp/utils/big_query_utils.py +++ b/tools/gcp/utils/big_query_utils.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import print_function + import argparse import json import uuid @@ -50,11 +52,11 @@ def create_dataset(biq_query, project_id, dataset_id): dataset_req.execute(num_retries=NUM_RETRIES) except HttpError as http_error: if http_error.resp.status == 409: - print 'Warning: The dataset %s already exists' % dataset_id + print('Warning: The dataset %s already exists' % dataset_id) else: # Note: For more debugging info, print "http_error.content" - print 'Error in creating dataset: %s. Err: %s' % (dataset_id, - http_error) + print('Error in creating dataset: %s. Err: %s' % (dataset_id, + http_error)) is_success = False return is_success @@ -122,13 +124,13 @@ def create_table2(big_query, table_req = big_query.tables().insert( projectId=project_id, datasetId=dataset_id, body=body) res = table_req.execute(num_retries=NUM_RETRIES) - print 'Successfully created %s "%s"' % (res['kind'], res['id']) + print('Successfully created %s "%s"' % (res['kind'], res['id'])) except HttpError as http_error: if http_error.resp.status == 409: - print 'Warning: Table %s already exists' % table_id + print('Warning: Table %s already exists' % table_id) else: - print 'Error in creating table: %s. Err: %s' % (table_id, - http_error) + print('Error in creating table: %s. Err: %s' % (table_id, + http_error)) is_success = False return is_success @@ -154,9 +156,9 @@ def patch_table(big_query, project_id, dataset_id, table_id, fields_schema): tableId=table_id, body=body) res = table_req.execute(num_retries=NUM_RETRIES) - print 'Successfully patched %s "%s"' % (res['kind'], res['id']) + print('Successfully patched %s "%s"' % (res['kind'], res['id'])) except HttpError as http_error: - print 'Error in creating table: %s. Err: %s' % (table_id, http_error) + print('Error in creating table: %s. Err: %s' % (table_id, http_error)) is_success = False return is_success @@ -172,10 +174,10 @@ def insert_rows(big_query, project_id, dataset_id, table_id, rows_list): body=body) res = insert_req.execute(num_retries=NUM_RETRIES) if res.get('insertErrors', None): - print 'Error inserting rows! Response: %s' % res + print('Error inserting rows! Response: %s' % res) is_success = False except HttpError as http_error: - print 'Error inserting rows to the table %s' % table_id + print('Error inserting rows to the table %s' % table_id) is_success = False return is_success @@ -189,8 +191,8 @@ def sync_query_job(big_query, project_id, query, timeout=5000): projectId=project_id, body=query_data).execute(num_retries=NUM_RETRIES) except HttpError as http_error: - print 'Query execute job failed with error: %s' % http_error - print http_error.content + print('Query execute job failed with error: %s' % http_error) + print(http_error.content) return query_job diff --git a/tools/internal_ci/README.md b/tools/internal_ci/README.md index e80e342dcd..af582c471e 100644 --- a/tools/internal_ci/README.md +++ b/tools/internal_ci/README.md @@ -1,6 +1,7 @@ -# Internal continuous integration +# Kokoro CI job configurations and testing scripts -gRPC's externally facing testing is managed by Jenkins CI (see `tools/jenkins` -directory). Nevertheless, some of the tests are better suited for being run -on internal infrastructure and using an internal CI system. Configuration for -such tests is under this directory. +gRPC uses a continous integration tool called "Kokoro" (a.k.a "internal CI") +for running majority of its open source tests. +This directory contains the external part of kokoro test job configurations +(the actual job definitions live in an internal repository) and the shell +scripts that act as entry points to exectute the actual tests. diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index 4b7477db14..2362b370d5 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -57,25 +57,25 @@ source $HOME/.rvm/scripts/rvm set -e # rvm commands are very verbose time rvm install 2.5.0 rvm use 2.5.0 --default -gem install bundler --no-ri --no-doc -gem install cocoapods --version 1.3.1 --no-ri --no-doc -gem install rake-compiler --no-ri --no-doc +time gem install bundler --no-ri --no-doc +time gem install cocoapods --version 1.3.1 --no-ri --no-doc +time gem install rake-compiler --no-ri --no-doc rvm osx-ssl-certs status all rvm osx-ssl-certs update all set -ex # cocoapods export LANG=en_US.UTF-8 -pod repo update # needed by python +time pod repo update # needed by python # python -pip install virtualenv --user python -pip install -U Mako six tox setuptools twisted pyyaml --user python +time pip install virtualenv --user python +time pip install -U Mako six tox setuptools twisted pyyaml --user python export PYTHONPATH=/Library/Python/3.4/site-packages # Install Python 3.7 -curl -O https://www.python.org/ftp/python/3.7.0/python-3.7.0-macosx10.9.pkg -sudo installer -pkg ./python-3.7.0-macosx10.9.pkg -target / +time curl -O https://www.python.org/ftp/python/3.7.0/python-3.7.0-macosx10.9.pkg +time sudo installer -pkg ./python-3.7.0-macosx10.9.pkg -target / # set xcode version for Obj-C tests sudo xcode-select -switch /Applications/Xcode_9.2.app/Contents/Developer/ @@ -88,7 +88,7 @@ export DOTNET_CLI_TELEMETRY_OPTOUT=true # TODO(jtattermusch): better debugging of clock skew, remove once not needed date -git submodule update --init +time git submodule update --init # Store intermediate build files of ObjC tests into /tmpfs mkdir /tmpfs/Build-ios-binary-size diff --git a/tools/internal_ci/macos/grpc_basictests_dbg.cfg b/tools/internal_ci/macos/grpc_basictests_dbg.cfg index e6f9c7ec87..1c7ed26d64 100644 --- a/tools/internal_ci/macos/grpc_basictests_dbg.cfg +++ b/tools/internal_ci/macos/grpc_basictests_dbg.cfg @@ -27,5 +27,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos dbg --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" + value: "-f basictests macos dbg --exclude objc --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" } diff --git a/tools/internal_ci/macos/grpc_basictests_opt.cfg b/tools/internal_ci/macos/grpc_basictests_opt.cfg index f2a83fe95a..f46ebaa786 100644 --- a/tools/internal_ci/macos/grpc_basictests_opt.cfg +++ b/tools/internal_ci/macos/grpc_basictests_opt.cfg @@ -27,5 +27,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos opt --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" + value: "-f basictests macos opt --exclude objc --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" } diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg index c759397b78..c91c033916 100644 --- a/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg @@ -27,5 +27,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos dbg --internal_ci -j 1 --inner_jobs 4 --max_time=3600" + value: "-f basictests macos dbg --exclude objc --internal_ci -j 1 --inner_jobs 4 --max_time=3600" } diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg index 4d68341405..532234fa84 100644 --- a/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg @@ -27,5 +27,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests macos opt --internal_ci -j 1 --inner_jobs 4 --max_time=3600" + value: "-f basictests macos opt --exclude objc --internal_ci -j 1 --inner_jobs 4 --max_time=3600" } diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat index d277668c94..795e80dc40 100644 --- a/tools/run_tests/artifacts/build_artifact_python.bat +++ b/tools/run_tests/artifacts/build_artifact_python.bat @@ -22,6 +22,10 @@ pip install -rrequirements.txt set GRPC_PYTHON_BUILD_WITH_CYTHON=1 +@rem Allow build_ext to build C/C++ files in parallel +@rem by enabling a monkeypatch. It speeds up the build a lot. +set GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=2 + mkdir -p %ARTIFACTS_OUT% set ARTIFACT_DIR=%cd%\%ARTIFACTS_OUT% diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh index 2878005bb2..9a2e0f739f 100755 --- a/tools/run_tests/artifacts/build_artifact_python.sh +++ b/tools/run_tests/artifacts/build_artifact_python.sh @@ -22,6 +22,10 @@ export PYTHON=${PYTHON:-python} export PIP=${PIP:-pip} export AUDITWHEEL=${AUDITWHEEL:-auditwheel} +# Allow build_ext to build C/C++ files in parallel +# by enabling a monkeypatch. It speeds up the build a lot. +export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=2 + mkdir -p "${ARTIFACTS_OUT}" ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}" diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index ade814a844..1bbacc41f0 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -9142,7 +9142,7 @@ "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h", "src/core/tsi/alts/frame_protector/frame_handler.h", "src/core/tsi/alts/handshaker/alts_handshaker_client.h", - "src/core/tsi/alts/handshaker/alts_tsi_event.h", + "src/core/tsi/alts/handshaker/alts_shared_resource.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h", "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h", @@ -9173,8 +9173,8 @@ "src/core/tsi/alts/frame_protector/frame_handler.h", "src/core/tsi/alts/handshaker/alts_handshaker_client.cc", "src/core/tsi/alts/handshaker/alts_handshaker_client.h", - "src/core/tsi/alts/handshaker/alts_tsi_event.cc", - "src/core/tsi/alts/handshaker/alts_tsi_event.h", + "src/core/tsi/alts/handshaker/alts_shared_resource.cc", + "src/core/tsi/alts/handshaker/alts_shared_resource.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc", "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h", "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h", @@ -9654,7 +9654,8 @@ "src/core/lib/transport/status_metadata.cc", "src/core/lib/transport/timeout_encoding.cc", "src/core/lib/transport/transport.cc", - "src/core/lib/transport/transport_op_string.cc" + "src/core/lib/transport/transport_op_string.cc", + "src/core/lib/uri/uri_parser.cc" ], "third_party": false, "type": "filegroup" @@ -9811,7 +9812,8 @@ "src/core/lib/transport/status_metadata.h", "src/core/lib/transport/timeout_encoding.h", "src/core/lib/transport/transport.h", - "src/core/lib/transport/transport_impl.h" + "src/core/lib/transport/transport_impl.h", + "src/core/lib/uri/uri_parser.h" ], "is_filegroup": true, "language": "c", @@ -9962,7 +9964,8 @@ "src/core/lib/transport/status_metadata.h", "src/core/lib/transport/timeout_encoding.h", "src/core/lib/transport/transport.h", - "src/core/lib/transport/transport_impl.h" + "src/core/lib/transport/transport_impl.h", + "src/core/lib/uri/uri_parser.h" ], "third_party": false, "type": "filegroup" @@ -10040,8 +10043,7 @@ "src/core/ext/filters/client_channel/resolver_registry.h", "src/core/ext/filters/client_channel/retry_throttle.h", "src/core/ext/filters/client_channel/subchannel.h", - "src/core/ext/filters/client_channel/subchannel_index.h", - "src/core/ext/filters/client_channel/uri_parser.h" + "src/core/ext/filters/client_channel/subchannel_index.h" ], "is_filegroup": true, "language": "c", @@ -10089,9 +10091,7 @@ "src/core/ext/filters/client_channel/subchannel.cc", "src/core/ext/filters/client_channel/subchannel.h", "src/core/ext/filters/client_channel/subchannel_index.cc", - "src/core/ext/filters/client_channel/subchannel_index.h", - "src/core/ext/filters/client_channel/uri_parser.cc", - "src/core/ext/filters/client_channel/uri_parser.h" + "src/core/ext/filters/client_channel/subchannel_index.h" ], "third_party": false, "type": "filegroup" @@ -11227,6 +11227,7 @@ "include/grpcpp/impl/codegen/rpc_service_method.h", "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", + "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", @@ -11302,6 +11303,7 @@ "include/grpcpp/impl/codegen/rpc_service_method.h", "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", + "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", @@ -11451,6 +11453,7 @@ "include/grpcpp/support/config.h", "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", + "include/grpcpp/support/server_callback.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", "include/grpcpp/support/status_code_enum.h", @@ -11555,6 +11558,7 @@ "include/grpcpp/support/config.h", "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", + "include/grpcpp/support/server_callback.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", "include/grpcpp/support/status_code_enum.h", @@ -11564,6 +11568,7 @@ "include/grpcpp/support/time.h", "src/cpp/client/channel_cc.cc", "src/cpp/client/client_context.cc", + "src/cpp/client/client_interceptor.cc", "src/cpp/client/create_channel.cc", "src/cpp/client/create_channel_internal.cc", "src/cpp/client/create_channel_internal.h", diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh index 6990244e51..eb3ea9e1f5 100755 --- a/tools/run_tests/helper_scripts/build_python.sh +++ b/tools/run_tests/helper_scripts/build_python.sh @@ -80,6 +80,8 @@ function toolchain() { fi } +# TODO(jtattermusch): this adds dependency on grealpath on mac +# (brew install coreutils) for little reason. # Command to invoke the linux command `realpath` or equivalent. function script_realpath() { # Find `realpath` @@ -112,6 +114,10 @@ export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS" export GRPC_PYTHON_BUILD_WITH_CYTHON=1 export LANG=en_US.UTF-8 +# Allow build_ext to build C/C++ files in parallel +# by enabling a monkeypatch. It speeds up the build a lot. +export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=4 + # If ccache is available on Linux, use it. if [ "$(is_linux)" ]; then # We're not on Darwin (Mac OS X) diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py index b732e1e03e..578712c393 100755 --- a/tools/run_tests/python_utils/jobset.py +++ b/tools/run_tests/python_utils/jobset.py @@ -13,8 +13,6 @@ # limitations under the License. """Run a group of subprocesses and then finish.""" -from __future__ import print_function - import logging import multiprocessing import os @@ -118,7 +116,7 @@ def eintr_be_gone(fn): while True: try: return fn() - except IOError, e: + except IOError as e: if e.errno != errno.EINTR: raise @@ -144,7 +142,7 @@ def message(tag, msg, explanatory_text=None, do_newline=False): if do_newline or explanatory_text is not None else '')) sys.stdout.flush() return - except IOError, e: + except IOError as e: if e.errno != errno.EINTR: raise diff --git a/tools/run_tests/python_utils/port_server.py b/tools/run_tests/python_utils/port_server.py index 83e09c09d0..243eef6827 100755 --- a/tools/run_tests/python_utils/port_server.py +++ b/tools/run_tests/python_utils/port_server.py @@ -14,15 +14,17 @@ # limitations under the License. """Manage TCP ports for unit tests; started by run_tests.py""" +from __future__ import print_function + import argparse -from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from six.moves.BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from six.moves.socketserver import ThreadingMixIn import hashlib import os import socket import sys import time import random -from SocketServer import ThreadingMixIn import threading import platform @@ -32,7 +34,7 @@ import platform _MY_VERSION = 20 if len(sys.argv) == 2 and sys.argv[1] == 'dump_version': - print _MY_VERSION + print(_MY_VERSION) sys.exit(0) argp = argparse.ArgumentParser(description='Server for httpcli_test') @@ -47,7 +49,7 @@ if args.logfile is not None: sys.stderr = open(args.logfile, 'w') sys.stdout = sys.stderr -print 'port server running on port %d' % args.port +print('port server running on port %d' % args.port) pool = [] in_use = {} @@ -74,7 +76,7 @@ def can_connect(port): try: s.connect(('localhost', port)) return True - except socket.error, e: + except socket.error as e: return False finally: s.close() @@ -86,7 +88,7 @@ def can_bind(port, proto): try: s.bind(('localhost', port)) return True - except socket.error, e: + except socket.error as e: return False finally: s.close() @@ -95,7 +97,7 @@ def can_bind(port, proto): def refill_pool(max_timeout, req): """Scan for ports not marked for being in use""" chk = [ - port for port in list(range(1025, 32766)) + port for port in range(1025, 32766) if port not in cronet_restricted_ports ] random.shuffle(chk) diff --git a/tools/run_tests/python_utils/report_utils.py b/tools/run_tests/python_utils/report_utils.py index b2a256ce29..8d8dedb929 100644 --- a/tools/run_tests/python_utils/report_utils.py +++ b/tools/run_tests/python_utils/report_utils.py @@ -13,8 +13,6 @@ # limitations under the License. """Generate XML and HTML test reports.""" -from __future__ import print_function - try: from mako.runtime import Context from mako.template import Template diff --git a/tools/run_tests/python_utils/start_port_server.py b/tools/run_tests/python_utils/start_port_server.py index 37995acbdf..0a32bf4418 100644 --- a/tools/run_tests/python_utils/start_port_server.py +++ b/tools/run_tests/python_utils/start_port_server.py @@ -12,8 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import urllib -import jobset +from __future__ import print_function + +from . import jobset + +import six.moves.urllib.request as request import logging import os import socket @@ -33,8 +36,8 @@ def start_port_server(): # otherwise, leave it up try: version = int( - urllib.urlopen('http://localhost:%d/version_number' % - _PORT_SERVER_PORT).read()) + request.urlopen('http://localhost:%d/version_number' % + _PORT_SERVER_PORT).read()) logging.info('detected port server running version %d', version) running = True except Exception as e: @@ -51,7 +54,7 @@ def start_port_server(): running = (version >= current_version) if not running: logging.info('port_server version mismatch: killing the old one') - urllib.urlopen( + request.urlopen( 'http://localhost:%d/quitquitquit' % _PORT_SERVER_PORT).read() time.sleep(1) if not running: @@ -92,7 +95,7 @@ def start_port_server(): # try one final time: maybe another build managed to start one time.sleep(1) try: - urllib.urlopen( + request.urlopen( 'http://localhost:%d/get' % _PORT_SERVER_PORT).read() logging.info( 'last ditch attempt to contact port server succeeded') @@ -101,11 +104,11 @@ def start_port_server(): logging.exception( 'final attempt to contact port server failed') port_log = open(logfile, 'r').read() - print port_log + print(port_log) sys.exit(1) try: port_server_url = 'http://localhost:%d/get' % _PORT_SERVER_PORT - urllib.urlopen(port_server_url).read() + request.urlopen(port_server_url).read() logging.info('port server is up and ready') break except socket.timeout: diff --git a/tools/run_tests/python_utils/watch_dirs.py b/tools/run_tests/python_utils/watch_dirs.py index d2ad303a07..f2f1c006df 100755 --- a/tools/run_tests/python_utils/watch_dirs.py +++ b/tools/run_tests/python_utils/watch_dirs.py @@ -15,13 +15,14 @@ import os import time +from six import string_types class DirWatcher(object): """Helper to watch a (set) of directories for modifications.""" def __init__(self, paths): - if isinstance(paths, basestring): + if isinstance(paths, string_types): paths = [paths] self._done = False self.paths = list(paths) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 5722a88182..ff6682c3cf 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -63,17 +63,17 @@ _SKIP_ADVANCED = [ 'unimplemented_service' ] +_SKIP_SPECIAL_STATUS_MESSAGE = ['special_status_message'] + _TEST_TIMEOUT = 3 * 60 # disable this test on core-based languages, # see https://github.com/grpc/grpc/issues/9779 _SKIP_DATA_FRAME_PADDING = ['data_frame_padding'] -# report suffix is important for reports to get picked up by internal CI -_INTERNAL_CL_XML_REPORT = 'sponge_log.xml' - -# report suffix is important for reports to get picked up by internal CI -_XML_REPORT = 'report.xml' +# report suffix "sponge_log.xml" is important for reports to get picked up by internal CI +_DOCKER_BUILD_XML_REPORT = 'interop_docker_build/sponge_log.xml' +_TESTS_XML_REPORT = 'interop_test/sponge_log.xml' class CXXLanguage: @@ -100,7 +100,7 @@ class CXXLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_DATA_FRAME_PADDING + return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return [] @@ -129,7 +129,7 @@ class CSharpLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _SKIP_COMPRESSION @@ -158,7 +158,7 @@ class CSharpCoreCLRLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _SKIP_COMPRESSION @@ -188,10 +188,10 @@ class DartLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_COMPRESSION + return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): - return _SKIP_COMPRESSION + return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE def __str__(self): return 'dart' @@ -248,7 +248,7 @@ class JavaOkHttpClient: return {} def unimplemented_test_cases(self): - return _SKIP_DATA_FRAME_PADDING + return _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def __str__(self): return 'javaokhttp' @@ -309,7 +309,7 @@ class Http2Server: return {} def unimplemented_test_cases(self): - return _TEST_CASES + _SKIP_DATA_FRAME_PADDING + return _TEST_CASES + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _TEST_CASES @@ -339,7 +339,7 @@ class Http2Client: return {} def unimplemented_test_cases(self): - return _TEST_CASES + return _TEST_CASES + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _TEST_CASES @@ -431,7 +431,7 @@ class PHPLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return [] @@ -456,7 +456,7 @@ class PHP7Language: return {} def unimplemented_test_cases(self): - return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return [] @@ -491,7 +491,7 @@ class ObjcLanguage: # cmdline argument. Here we return all but one test cases as unimplemented, # and depend upon ObjC test's behavior that it runs all cases even when # we tell it to run just one. - return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _SKIP_COMPRESSION @@ -526,7 +526,7 @@ class RubyLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + return _SKIP_SERVER_COMPRESSION + _SKIP_DATA_FRAME_PADDING + _SKIP_SPECIAL_STATUS_MESSAGE def unimplemented_test_cases_server(self): return _SKIP_COMPRESSION @@ -610,7 +610,7 @@ _TEST_CASES = [ 'custom_metadata', 'status_code_and_message', 'unimplemented_method', 'client_compressed_unary', 'server_compressed_unary', 'client_compressed_streaming', 'server_compressed_streaming', - 'unimplemented_service' + 'unimplemented_service', 'special_status_message' ] _AUTH_TEST_CASES = [ @@ -1161,8 +1161,9 @@ argp.add_argument( default=False, action='store_const', const=True, - help=('Put reports into subdirectories to improve ' - 'presentation of results by Internal CI.')) + help=( + '(Deprecated, has no effect) Put reports into subdirectories to improve ' + 'presentation of results by Internal CI.')) argp.add_argument( '--bq_result_table', default='', @@ -1251,8 +1252,12 @@ if args.use_docker: if args.verbose: print('Jobs to run: \n%s\n' % '\n'.join(str(j) for j in build_jobs)) - num_failures, _ = jobset.run( + num_failures, build_resultset = jobset.run( build_jobs, newline_on_success=True, maxjobs=args.jobs) + + report_utils.render_junit_xml_report(build_resultset, + _DOCKER_BUILD_XML_REPORT) + if num_failures == 0: jobset.message( 'SUCCESS', @@ -1315,7 +1320,7 @@ try: for language in languages: for test_case in _TEST_CASES: if not test_case in language.unimplemented_test_cases(): - if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION: + if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE: tls_test_job = cloud_to_prod_jobspec( language, test_case, @@ -1517,10 +1522,7 @@ try: write_cmdlog_maybe(server_manual_cmd_log, 'interop_server_cmds.sh') write_cmdlog_maybe(client_manual_cmd_log, 'interop_client_cmds.sh') - xml_report_name = _XML_REPORT - if args.internal_ci: - xml_report_name = _INTERNAL_CL_XML_REPORT - report_utils.render_junit_xml_report(resultset, xml_report_name) + report_utils.render_junit_xml_report(resultset, _TESTS_XML_REPORT) for name, job in resultset.items(): if "http2" in name: diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 44151f49fb..62bb6da7a7 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -1512,7 +1512,7 @@ if args.travis: _FORCE_ENVIRON_FOR_WRAPPERS = {'GRPC_TRACE': 'api'} if 'all' in args.language: - lang_list = _LANGUAGES.keys() + lang_list = list(_LANGUAGES.keys()) else: lang_list = args.language # We don't support code coverage on some languages @@ -1719,9 +1719,9 @@ def _has_epollexclusive(): try: subprocess.check_call(binary) return True - except subprocess.CalledProcessError, e: + except subprocess.CalledProcessError as e: return False - except OSError, e: + except OSError as e: # For languages other than C and Windows the binary won't exist return False |