aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yash Tibrewal <yashkt@google.com>2018-11-16 10:58:12 -0800
committerGravatar Yash Tibrewal <yashkt@google.com>2018-11-16 11:11:04 -0800
commitfc332d2c9247832af90792a59ff6d391e84bc8ae (patch)
tree4bd1db687960ca851f87d237a36f55190ac52f27
parent0eb9a3e783237cd46c8ba6d3b33228f537cafbfc (diff)
parent9cfacc48ee2e9f8db083d578c84881551734b1f0 (diff)
Merge master
-rw-r--r--.bazelrc3
-rw-r--r--.clang-tidy4
-rw-r--r--.clang_complete1
-rw-r--r--.github/CODEOWNERS8
-rw-r--r--.github/ISSUE_TEMPLATE.md2
-rw-r--r--.github/lock.yml2
-rw-r--r--AUTHORS1
-rw-r--r--BUILD161
-rw-r--r--BUILDING.md4
-rw-r--r--CMakeLists.txt1861
-rw-r--r--Makefile604
-rw-r--r--PYTHON-MANIFEST.in1
-rw-r--r--WORKSPACE5
-rw-r--r--bazel/OWNERS2
-rw-r--r--bazel/grpc_build_system.bzl329
-rw-r--r--bazel/grpc_deps.bzl10
-rw-r--r--build.yaml284
-rw-r--r--build_config.rb2
-rw-r--r--cmake/OWNERS2
-rw-r--r--config.m428
-rw-r--r--config.w3228
-rw-r--r--doc/PROTOCOL-HTTP2.md2
-rw-r--r--doc/connectivity-semantics-and-api.md11
-rw-r--r--doc/core/combiner-explainer.md (renamed from doc/combiner-explainer.md)0
-rw-r--r--doc/core/epoll-polling-engine.md (renamed from doc/epoll-polling-engine.md)0
-rw-r--r--doc/core/grpc-client-server-polling-engine-usage.md32
-rw-r--r--doc/core/grpc-cq.md64
-rw-r--r--doc/core/grpc-polling-engines.md154
-rw-r--r--doc/core/images/new_epoll_impl.png (renamed from doc/images/new_epoll_impl.png)bin53699 -> 53699 bytes
-rw-r--r--doc/core/images/old_epoll_impl.png (renamed from doc/images/old_epoll_impl.png)bin45342 -> 45342 bytes
-rw-r--r--doc/environment_variables.md11
-rw-r--r--doc/g_stands_for.md4
-rw-r--r--doc/images/grpc-call-channel-cq.pngbin0 -> 46078 bytes
-rw-r--r--doc/images/grpc-client-lb-pss.pngbin0 -> 56397 bytes
-rw-r--r--doc/images/grpc-cq.pngbin0 -> 41659 bytes
-rw-r--r--doc/images/grpc-epoll1.pngbin0 -> 36205 bytes
-rw-r--r--doc/images/grpc-epollex.pngbin0 -> 52651 bytes
-rw-r--r--doc/images/grpc-ps-pss-fd.pngbin0 -> 24969 bytes
-rw-r--r--doc/images/grpc-pss.pngbin0 -> 31518 bytes
-rw-r--r--doc/images/grpc-server-cq-fds.pngbin0 -> 42096 bytes
-rw-r--r--doc/interop-test-descriptions.md5
-rw-r--r--doc/naming.md64
-rw-r--r--doc/python/sphinx/conf.py102
-rw-r--r--doc/python/sphinx/glossary.rst16
-rw-r--r--doc/python/sphinx/grpc.rst169
-rw-r--r--doc/python/sphinx/grpc_health_checking.rst7
-rw-r--r--doc/python/sphinx/grpc_reflection.rst19
-rw-r--r--doc/python/sphinx/grpc_testing.rst7
-rw-r--r--doc/python/sphinx/index.rst24
-rw-r--r--doc/server-reflection.md1
-rw-r--r--doc/ssl-performance.md5
-rw-r--r--doc/statuscodes.md2
-rw-r--r--etc/roots.pem23
-rw-r--r--examples/csharp/Helloworld/Greeter/Greeter.csproj2
-rw-r--r--examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj2
-rw-r--r--examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj2
-rw-r--r--examples/csharp/Helloworld/README.md8
-rw-r--r--examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj2
-rw-r--r--examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj2
-rw-r--r--examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj2
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld.podspec66
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj399
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h25
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m37
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json58
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json6
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard717
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements5
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/Info.plist32
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/ViewController.h25
-rw-r--r--examples/objective-c/helloworld_macos/HelloWorld/ViewController.m37
-rw-r--r--examples/objective-c/helloworld_macos/Podfile9
-rw-r--r--examples/objective-c/helloworld_macos/README.md6
-rw-r--r--examples/objective-c/helloworld_macos/main.m43
-rw-r--r--examples/python/helloworld/greeter_client_with_options.py44
-rw-r--r--examples/python/interceptors/default_value/default_value_client_interceptor.py2
-rw-r--r--gRPC-C++.podspec49
-rw-r--r--gRPC-Core.podspec75
-rw-r--r--gRPC-ProtoRPC.podspec2
-rw-r--r--gRPC-RxLibrary.podspec2
-rw-r--r--gRPC.podspec2
-rw-r--r--grpc.def6
-rw-r--r--grpc.gemspec42
-rw-r--r--grpc.gyp76
-rw-r--r--include/grpc/grpc.h26
-rw-r--r--include/grpc/grpc_posix.h8
-rw-r--r--include/grpc/grpc_security.h4
-rw-r--r--include/grpc/grpc_security_constants.h43
-rw-r--r--include/grpc/impl/codegen/grpc_types.h31
-rw-r--r--include/grpc/impl/codegen/port_platform.h1
-rw-r--r--include/grpcpp/alarm.h27
-rw-r--r--include/grpcpp/channel.h31
-rw-r--r--include/grpcpp/create_channel.h21
-rw-r--r--include/grpcpp/create_channel_posix.h17
-rw-r--r--include/grpcpp/generic/generic_stub.h23
-rw-r--r--include/grpcpp/impl/codegen/async_stream.h102
-rw-r--r--include/grpcpp/impl/codegen/async_unary_call.h15
-rw-r--r--include/grpcpp/impl/codegen/byte_buffer.h14
-rw-r--r--include/grpcpp/impl/codegen/call.h669
-rw-r--r--include/grpcpp/impl/codegen/call_op_set.h919
-rw-r--r--include/grpcpp/impl/codegen/call_op_set_interface.h59
-rw-r--r--include/grpcpp/impl/codegen/callback_common.h200
-rw-r--r--include/grpcpp/impl/codegen/channel_interface.h32
-rw-r--r--include/grpcpp/impl/codegen/client_callback.h95
-rw-r--r--include/grpcpp/impl/codegen/client_context.h26
-rw-r--r--include/grpcpp/impl/codegen/client_interceptor.h127
-rw-r--r--include/grpcpp/impl/codegen/client_unary_call.h2
-rw-r--r--include/grpcpp/impl/codegen/completion_queue.h59
-rw-r--r--include/grpcpp/impl/codegen/completion_queue_tag.h23
-rw-r--r--include/grpcpp/impl/codegen/config_protobuf.h12
-rw-r--r--include/grpcpp/impl/codegen/core_codegen.h3
-rw-r--r--include/grpcpp/impl/codegen/core_codegen_interface.h12
-rw-r--r--include/grpcpp/impl/codegen/intercepted_channel.h80
-rw-r--r--include/grpcpp/impl/codegen/interceptor.h133
-rw-r--r--include/grpcpp/impl/codegen/interceptor_common.h458
-rw-r--r--include/grpcpp/impl/codegen/metadata_map.h71
-rw-r--r--include/grpcpp/impl/codegen/method_handler_impl.h83
-rw-r--r--include/grpcpp/impl/codegen/rpc_service_method.h74
-rw-r--r--include/grpcpp/impl/codegen/server_callback.h200
-rw-r--r--include/grpcpp/impl/codegen/server_context.h50
-rw-r--r--include/grpcpp/impl/codegen/server_interceptor.h99
-rw-r--r--include/grpcpp/impl/codegen/server_interface.h94
-rw-r--r--include/grpcpp/impl/codegen/service_type.h58
-rw-r--r--include/grpcpp/impl/codegen/sync_stream.h20
-rw-r--r--include/grpcpp/opencensus.h4
-rw-r--r--include/grpcpp/security/credentials.h32
-rw-r--r--include/grpcpp/server.h57
-rw-r--r--include/grpcpp/server_builder.h26
-rw-r--r--include/grpcpp/support/client_callback.h24
-rw-r--r--include/grpcpp/support/server_callback.h24
-rw-r--r--package.xml46
-rw-r--r--requirements.bazel.txt5
-rw-r--r--setup.py23
-rw-r--r--src/compiler/cpp_generator.cc352
-rw-r--r--src/compiler/ruby_generator.cc12
-rw-r--r--src/core/ext/filters/client_channel/OWNERS2
-rw-r--r--src/core/ext/filters/client_channel/README.md18
-rw-r--r--src/core/ext/filters/client_channel/client_channel.cc461
-rw-r--r--src/core/ext/filters/client_channel/client_channel.h8
-rw-r--r--src/core/ext/filters/client_channel/client_channel_channelz.cc73
-rw-r--r--src/core/ext/filters/client_channel/client_channel_channelz.h63
-rw-r--r--src/core/ext/filters/client_channel/connector.h3
-rw-r--r--src/core/ext/filters/client_channel/health/health.pb.c (renamed from src/cpp/server/health/health.pb.c)3
-rw-r--r--src/core/ext/filters/client_channel/health/health.pb.h (renamed from src/cpp/server/health/health.pb.h)7
-rw-r--r--src/core/ext/filters/client_channel/health/health_check_client.cc652
-rw-r--r--src/core/ext/filters/client_channel/health/health_check_client.h173
-rw-r--r--src/core/ext/filters/client_channel/http_connect_handshaker.cc3
-rw-r--r--src/core/ext/filters/client_channel/http_proxy.cc2
-rw-r--r--src/core/ext/filters/client_channel/lb_policy.h22
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc26
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc37
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc64
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc24
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/subchannel_list.h62
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds.cc1828
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds.h36
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc (renamed from src/core/lib/iomgr/ev_epollsig_linux.h)21
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h36
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc107
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc85
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h72
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc307
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h89
-rw-r--r--src/core/ext/filters/client_channel/lb_policy_factory.h8
-rw-r--r--src/core/ext/filters/client_channel/parse_address.cc31
-rw-r--r--src/core/ext/filters/client_channel/parse_address.h5
-rw-r--r--src/core/ext/filters/client_channel/resolver.h13
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc30
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc157
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h17
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc5
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc5
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc70
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc12
-rw-r--r--src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc18
-rw-r--r--src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h5
-rw-r--r--src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc7
-rw-r--r--src/core/ext/filters/client_channel/resolver_factory.h2
-rw-r--r--src/core/ext/filters/client_channel/subchannel.cc510
-rw-r--r--src/core/ext/filters/client_channel/subchannel.h27
-rw-r--r--src/core/ext/filters/client_channel/subchannel_index.cc3
-rw-r--r--src/core/ext/filters/client_channel/subchannel_index.h5
-rw-r--r--src/core/ext/filters/deadline/deadline_filter.cc42
-rw-r--r--src/core/ext/filters/deadline/deadline_filter.h22
-rw-r--r--src/core/ext/filters/http/client/http_client_filter.cc75
-rw-r--r--src/core/ext/filters/http/client_authority_filter.cc5
-rw-r--r--src/core/ext/filters/http/message_compress/message_compress_filter.cc44
-rw-r--r--src/core/ext/filters/http/server/http_server_filter.cc99
-rw-r--r--src/core/ext/filters/load_reporting/server_load_reporting_filter.cc2
-rw-r--r--src/core/ext/filters/max_age/max_age_filter.cc3
-rw-r--r--src/core/ext/filters/message_size/message_size_filter.cc141
-rw-r--r--src/core/ext/transport/chttp2/client/chttp2_connector.cc21
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc2
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.cc66
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc2
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.cc790
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.h5
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.cc18
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h22
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.cc2
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.cc70
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.cc29
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.cc12
-rw-r--r--src/core/ext/transport/chttp2/transport/incoming_metadata.h21
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h206
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.cc145
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.cc6
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.cc155
-rw-r--r--src/core/ext/transport/inproc/inproc_transport.cc580
-rw-r--r--src/core/lib/channel/channel_stack.cc9
-rw-r--r--src/core/lib/channel/channel_stack.h8
-rw-r--r--src/core/lib/channel/channel_stack_builder.cc16
-rw-r--r--src/core/lib/channel/channel_stack_builder.h8
-rw-r--r--src/core/lib/channel/channel_trace.cc111
-rw-r--r--src/core/lib/channel/channel_trace.h55
-rw-r--r--src/core/lib/channel/channelz.cc428
-rw-r--r--src/core/lib/channel/channelz.h253
-rw-r--r--src/core/lib/channel/channelz_registry.cc250
-rw-r--r--src/core/lib/channel/channelz_registry.h81
-rw-r--r--src/core/lib/channel/context.h8
-rw-r--r--src/core/lib/channel/handshaker.cc13
-rw-r--r--src/core/lib/channel/handshaker.h15
-rw-r--r--src/core/lib/channel/handshaker_factory.cc5
-rw-r--r--src/core/lib/channel/handshaker_factory.h2
-rw-r--r--src/core/lib/channel/handshaker_registry.cc8
-rw-r--r--src/core/lib/channel/handshaker_registry.h1
-rw-r--r--src/core/lib/gpr/arena.cc121
-rw-r--r--src/core/lib/gpr/arena.h2
-rw-r--r--src/core/lib/gpr/mpscq.h6
-rw-r--r--src/core/lib/gpr/sync_posix.cc42
-rw-r--r--src/core/lib/gprpp/inlined_vector.h8
-rw-r--r--src/core/lib/gprpp/ref_counted.h58
-rw-r--r--src/core/lib/gprpp/ref_counted_ptr.h11
-rw-r--r--src/core/lib/http/httpcli_security_connector.cc11
-rw-r--r--src/core/lib/iomgr/call_combiner.cc2
-rw-r--r--src/core/lib/iomgr/call_combiner.h4
-rw-r--r--src/core/lib/iomgr/closure.h1
-rw-r--r--src/core/lib/iomgr/error.cc74
-rw-r--r--src/core/lib/iomgr/error.h41
-rw-r--r--src/core/lib/iomgr/error_internal.h2
-rw-r--r--src/core/lib/iomgr/ev_epoll1_linux.cc14
-rw-r--r--src/core/lib/iomgr/ev_epollex_linux.cc4
-rw-r--r--src/core/lib/iomgr/ev_epollsig_linux.cc1743
-rw-r--r--src/core/lib/iomgr/ev_posix.cc15
-rw-r--r--src/core/lib/iomgr/exec_ctx.h7
-rw-r--r--src/core/lib/iomgr/internal_errqueue.cc4
-rw-r--r--src/core/lib/iomgr/internal_errqueue.h21
-rw-r--r--src/core/lib/iomgr/polling_entity.h8
-rw-r--r--src/core/lib/iomgr/port.h11
-rw-r--r--src/core/lib/iomgr/resource_quota.cc74
-rw-r--r--src/core/lib/iomgr/resource_quota.h27
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.cc96
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.h7
-rw-r--r--src/core/lib/iomgr/tcp_client_custom.cc17
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.cc5
-rw-r--r--src/core/lib/iomgr/tcp_posix.cc16
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_common.cc3
-rw-r--r--src/core/lib/iomgr/timer_generic.cc25
-rw-r--r--src/core/lib/iomgr/timer_heap.cc4
-rw-r--r--src/core/lib/iomgr/timer_heap.h6
-rw-r--r--src/core/lib/iomgr/timer_manager.cc33
-rw-r--r--src/core/lib/iomgr/timer_manager.h4
-rw-r--r--src/core/lib/iomgr/wakeup_fd_eventfd.cc7
-rw-r--r--src/core/lib/security/context/security_context.cc33
-rw-r--r--src/core/lib/security/context/security_context.h46
-rw-r--r--src/core/lib/security/credentials/alts/alts_credentials.cc2
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc3
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc3
-rw-r--r--src/core/lib/security/credentials/credentials.h4
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.cc1
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.cc93
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.h5
-rw-r--r--src/core/lib/security/credentials/local/local_credentials.cc2
-rw-r--r--src/core/lib/security/credentials/plugin/plugin_credentials.cc3
-rw-r--r--src/core/lib/security/credentials/ssl/ssl_credentials.h2
-rw-r--r--src/core/lib/security/security_connector/alts/alts_security_connector.cc (renamed from src/core/lib/security/security_connector/alts_security_connector.cc)19
-rw-r--r--src/core/lib/security/security_connector/alts/alts_security_connector.h (renamed from src/core/lib/security/security_connector/alts_security_connector.h)6
-rw-r--r--src/core/lib/security/security_connector/fake/fake_security_connector.cc310
-rw-r--r--src/core/lib/security/security_connector/fake/fake_security_connector.h42
-rw-r--r--src/core/lib/security/security_connector/local/local_security_connector.cc (renamed from src/core/lib/security/security_connector/local_security_connector.cc)7
-rw-r--r--src/core/lib/security/security_connector/local/local_security_connector.h (renamed from src/core/lib/security/security_connector/local_security_connector.h)6
-rw-r--r--src/core/lib/security/security_connector/security_connector.cc1043
-rw-r--r--src/core/lib/security/security_connector/security_connector.h120
-rw-r--r--src/core/lib/security/security_connector/ssl/ssl_security_connector.cc474
-rw-r--r--src/core/lib/security/security_connector/ssl/ssl_security_connector.h77
-rw-r--r--src/core/lib/security/security_connector/ssl_utils.cc345
-rw-r--r--src/core/lib/security/security_connector/ssl_utils.h93
-rw-r--r--src/core/lib/security/transport/client_auth_filter.cc45
-rw-r--r--src/core/lib/security/transport/secure_endpoint.cc92
-rw-r--r--src/core/lib/security/transport/security_handshaker.cc13
-rw-r--r--src/core/lib/security/transport/server_auth_filter.cc115
-rw-r--r--src/core/lib/slice/slice.cc8
-rw-r--r--src/core/lib/slice/slice_internal.h5
-rw-r--r--src/core/lib/surface/call.cc570
-rw-r--r--src/core/lib/surface/call.h5
-rw-r--r--src/core/lib/surface/channel.cc66
-rw-r--r--src/core/lib/surface/channel.h7
-rw-r--r--src/core/lib/surface/completion_queue.cc47
-rw-r--r--src/core/lib/surface/completion_queue.h19
-rw-r--r--src/core/lib/surface/completion_queue_factory.cc6
-rw-r--r--src/core/lib/surface/init.cc1
-rw-r--r--src/core/lib/surface/init_secure.cc2
-rw-r--r--src/core/lib/surface/server.cc218
-rw-r--r--src/core/lib/surface/server.h22
-rw-r--r--src/core/lib/surface/version.cc4
-rw-r--r--src/core/lib/transport/error_utils.cc6
-rw-r--r--src/core/lib/transport/metadata.cc23
-rw-r--r--src/core/lib/transport/metadata.h8
-rw-r--r--src/core/lib/transport/metadata_batch.cc5
-rw-r--r--src/core/lib/transport/metadata_batch.h8
-rw-r--r--src/core/lib/transport/static_metadata.cc519
-rw-r--r--src/core/lib/transport/static_metadata.h399
-rw-r--r--src/core/lib/transport/transport.h70
-rw-r--r--src/core/lib/uri/uri_parser.cc (renamed from src/core/ext/filters/client_channel/uri_parser.cc)2
-rw-r--r--src/core/lib/uri/uri_parser.h (renamed from src/core/ext/filters/client_channel/uri_parser.h)6
-rw-r--r--src/core/plugin_registry/grpc_cronet_plugin_registry.cc4
-rw-r--r--src/core/plugin_registry/grpc_plugin_registry.cc8
-rw-r--r--src/core/plugin_registry/grpc_unsecure_plugin_registry.cc4
-rw-r--r--src/core/tsi/alts/handshaker/alts_handshaker_client.cc442
-rw-r--r--src/core/tsi/alts/handshaker/alts_handshaker_client.h82
-rw-r--r--src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc4
-rw-r--r--src/core/tsi/alts/handshaker/alts_shared_resource.cc83
-rw-r--r--src/core/tsi/alts/handshaker/alts_shared_resource.h73
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_event.cc73
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_event.h93
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc304
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker.h55
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h48
-rw-r--r--src/core/tsi/alts/handshaker/alts_tsi_utils.cc4
-rw-r--r--src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc4
-rw-r--r--src/core/tsi/alts_transport_security.cc63
-rw-r--r--src/core/tsi/alts_transport_security.h47
-rw-r--r--src/core/tsi/ssl/session_cache/ssl_session_cache.cc3
-rw-r--r--src/core/tsi/ssl_transport_security.cc4
-rw-r--r--src/core/tsi/transport_security.cc19
-rw-r--r--src/core/tsi/transport_security.h3
-rw-r--r--src/cpp/client/channel_cc.cc104
-rw-r--r--src/cpp/client/client_context.cc12
-rw-r--r--src/cpp/client/client_interceptor.cc34
-rw-r--r--src/cpp/client/create_channel.cc42
-rw-r--r--src/cpp/client/create_channel_internal.cc10
-rw-r--r--src/cpp/client/create_channel_internal.h8
-rw-r--r--src/cpp/client/create_channel_posix.cc28
-rw-r--r--src/cpp/client/cronet_credentials.cc19
-rw-r--r--src/cpp/client/generic_stub.cc14
-rw-r--r--src/cpp/client/insecure_credentials.cc11
-rw-r--r--src/cpp/client/secure_credentials.cc19
-rw-r--r--src/cpp/client/secure_credentials.h6
-rw-r--r--src/cpp/common/alarm.cc47
-rw-r--r--src/cpp/common/completion_queue_cc.cc10
-rw-r--r--src/cpp/common/core_codegen.cc7
-rw-r--r--src/cpp/common/version_cc.cc2
-rw-r--r--src/cpp/ext/filters/census/context.cc12
-rw-r--r--src/cpp/ext/filters/census/server_filter.cc2
-rw-r--r--src/cpp/server/channelz/channelz_service.cc111
-rw-r--r--src/cpp/server/channelz/channelz_service.h21
-rw-r--r--src/cpp/server/health/default_health_check_service.cc475
-rw-r--r--src/cpp/server/health/default_health_check_service.h234
-rw-r--r--src/cpp/server/secure_server_credentials.cc7
-rw-r--r--src/cpp/server/server_builder.cc38
-rw-r--r--src/cpp/server/server_cc.cc541
-rw-r--r--src/cpp/server/server_context.cc235
-rw-r--r--src/csharp/.editorconfig23
-rw-r--r--src/csharp/BUILD-INTEGRATION.md357
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs20
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs37
-rw-r--r--src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs119
-rw-r--r--src/csharp/Grpc.Core.Tests/FakeCredentials.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs75
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs23
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallerTest.cs105
-rw-r--r--src/csharp/Grpc.Core.Tests/MetadataTest.cs19
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs1
-rw-r--r--src/csharp/Grpc.Core/Channel.cs12
-rw-r--r--src/csharp/Grpc.Core/ChannelCredentials.cs39
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs56
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs20
-rw-r--r--src/csharp/Grpc.Core/DeserializationContext.cs46
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs234
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs34
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/MarshalUtils.cs7
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs7
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs6
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs40
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs126
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs52
-rw-r--r--src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/RpcException.cs20
-rw-r--r--src/csharp/Grpc.Core/SerializationContext.cs34
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs98
-rwxr-xr-xsrc/csharp/Grpc.Core/Version.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs143
-rw-r--r--src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj2
-rw-r--r--src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs85
-rw-r--r--src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs88
-rw-r--r--src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs146
-rw-r--r--src/csharp/Grpc.Tools.Tests/GeneratorTest.cs55
-rw-r--r--src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj78
-rw-r--r--src/csharp/Grpc.Tools.Tests/NUnitMain.cs33
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs76
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs179
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs51
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs139
-rw-r--r--src/csharp/Grpc.Tools.Tests/Utils.cs46
-rw-r--r--src/csharp/Grpc.Tools.nuspec33
-rw-r--r--src/csharp/Grpc.Tools/Common.cs114
-rw-r--r--src/csharp/Grpc.Tools/DepFileUtil.cs273
-rw-r--r--src/csharp/Grpc.Tools/GeneratorServices.cs194
-rw-r--r--src/csharp/Grpc.Tools/Grpc.Tools.csproj101
-rw-r--r--src/csharp/Grpc.Tools/ProtoCompile.cs441
-rw-r--r--src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs86
-rw-r--r--src/csharp/Grpc.Tools/ProtoReadDependencies.cs78
-rw-r--r--src/csharp/Grpc.Tools/ProtoToolsPlatform.cs63
-rw-r--r--src/csharp/Grpc.Tools/build/Grpc.Tools.props11
-rw-r--r--src/csharp/Grpc.Tools/build/Grpc.Tools.targets11
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml30
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/README3
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props6
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets48
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props24
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets384
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml99
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/README1
-rw-r--r--src/csharp/Grpc.Tools/build/native/Grpc.Tools.props17
-rw-r--r--src/csharp/Grpc.sln12
-rw-r--r--src/csharp/README.md1
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat4
-rw-r--r--src/csharp/build_unitypackage.bat2
-rw-r--r--src/csharp/doc/README.md19
-rwxr-xr-xsrc/csharp/doc/generate_reference_docs.sh38
-rw-r--r--src/csharp/doc/integration.md-fig.1-classic.pngbin0 -> 15266 bytes
-rw-r--r--src/csharp/doc/integration.md-fig.2-sdk.pngbin0 -> 15863 bytes
-rw-r--r--src/csharp/experimental/README.md4
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c11
-rw-r--r--src/csharp/tests.json12
-rw-r--r--src/objective-c/!ProtoCompiler-gRPCPlugin.podspec2
-rw-r--r--src/objective-c/BoringSSL-GRPC.podspec5
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m5
-rw-r--r--src/objective-c/GRPCClient/private/NSError+GRPC.h2
-rw-r--r--src/objective-c/GRPCClient/private/NSError+GRPC.m20
-rw-r--r--src/objective-c/GRPCClient/private/version.h2
-rw-r--r--src/objective-c/tests/CronetUnitTests/CronetUnitTests.m2
-rw-r--r--src/objective-c/tests/InteropTests.m2
-rw-r--r--src/objective-c/tests/Podfile1
-rw-r--r--src/objective-c/tests/Tests.xcodeproj/project.pbxproj257
-rw-r--r--src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme92
-rw-r--r--src/objective-c/tests/UnitTests/Info.plist22
-rw-r--r--src/objective-c/tests/UnitTests/UnitTests.m62
-rwxr-xr-xsrc/objective-c/tests/run_tests.sh10
-rw-r--r--src/objective-c/tests/version.h4
-rw-r--r--src/php/composer.json2
-rw-r--r--src/php/ext/grpc/version.h2
-rw-r--r--src/php/tests/unit_tests/ChannelTest.php4
-rw-r--r--src/proto/grpc/channelz/channelz.proto13
-rw-r--r--src/proto/grpc/health/v1/BUILD8
-rw-r--r--src/proto/grpc/health/v1/health.proto20
-rw-r--r--src/proto/grpc/reflection/v1alpha/BUILD8
-rw-r--r--src/proto/grpc/testing/BUILD34
-rw-r--r--src/proto/grpc/testing/control.proto6
-rw-r--r--src/proto/grpc/testing/proto2/BUILD.bazel30
-rw-r--r--src/python/.gitignore1
-rw-r--r--src/python/grpcio/_parallel_compile_patch.py63
-rw-r--r--src/python/grpcio/commands.py69
-rw-r--r--src/python/grpcio/grpc/BUILD.bazel3
-rw-r--r--src/python/grpcio/grpc/__init__.py128
-rw-r--r--src/python/grpcio/grpc/_channel.py129
-rw-r--r--src/python/grpcio/grpc/_common.py13
-rw-r--r--src/python/grpcio/grpc/_cython/BUILD.bazel4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi10
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi6
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi8
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pyx1
-rw-r--r--src/python/grpcio/grpc/_grpcio_metadata.py2
-rw-r--r--src/python/grpcio/grpc/_interceptor.py126
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py21
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel33
-rw-r--r--src/python/grpcio_health_checking/grpc_version.py2
-rw-r--r--src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel34
-rw-r--r--src/python/grpcio_reflection/grpc_version.py2
-rw-r--r--src/python/grpcio_testing/grpc_testing/_channel/_invocation.py1
-rw-r--r--src/python/grpcio_testing/grpc_testing/_server/_rpc.py1
-rw-r--r--src/python/grpcio_testing/grpc_testing/_time.py1
-rw-r--r--src/python/grpcio_testing/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/commands.py6
-rw-r--r--src/python/grpcio_tests/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/tests/_sanity/_sanity_test.py4
-rw-r--r--src/python/grpcio_tests/tests/health_check/BUILD.bazel15
-rw-r--r--src/python/grpcio_tests/tests/interop/BUILD.bazel101
-rw-r--r--src/python/grpcio_tests/tests/interop/credentials/BUILD.bazel9
-rw-r--r--src/python/grpcio_tests/tests/interop/methods.py19
-rw-r--r--src/python/grpcio_tests/tests/interop/resources.py11
-rw-r--r--src/python/grpcio_tests/tests/interop/server.py1
-rw-r--r--src/python/grpcio_tests/tests/reflection/BUILD.bazel21
-rw-r--r--src/python/grpcio_tests/tests/testing/BUILD.bazel30
-rw-r--r--src/python/grpcio_tests/tests/tests.json3
-rw-r--r--src/python/grpcio_tests/tests/unit/BUILD.bazel84
-rw-r--r--src/python/grpcio_tests/tests/unit/_api_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_auth_context_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_auth_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_args_test.py18
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_close_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_compression_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_credentials_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel46
-rw-r--r--src/python/grpcio_tests/tests/unit/_empty_message_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_error_message_encoding_test.py86
-rw-r--r--src/python/grpcio_tests/tests/unit/_exit_scenarios.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_exit_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_interceptor_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_invocation_defects_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_logging_test.py80
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_flags_test.py251
-rw-r--r--src/python/grpcio_tests/tests/unit/_metadata_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_reconnect_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_resource_exhausted_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_rpc_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_server_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_session_cache_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/beta/BUILD.bazel75
-rw-r--r--src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel10
-rw-r--r--src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel11
-rw-r--r--src/python/grpcio_tests/tests/unit/resources.py35
-rw-r--r--src/python/grpcio_tests/tests/unit/test_common.py26
-rw-r--r--src/ruby/ext/grpc/rb_call.c1
-rw-r--r--src/ruby/ext/grpc/rb_channel.c3
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c32
-rw-r--r--src/ruby/ext/grpc/rb_grpc.h2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c12
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h24
-rw-r--r--src/ruby/ext/grpc/rb_server.c2
-rw-r--r--src/ruby/lib/grpc/errors.rb1
-rw-r--r--src/ruby/lib/grpc/generic/rpc_desc.rb6
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb2
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rwxr-xr-xsrc/ruby/pb/test/client.rb20
-rw-r--r--src/ruby/spec/channel_spec.rb44
-rw-r--r--src/ruby/spec/client_auth_spec.rb10
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb22
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb6
-rw-r--r--src/ruby/spec/pb/codegen/grpc/testing/package_options.proto28
-rw-r--r--src/ruby/spec/pb/codegen/package_option_spec.rb52
-rw-r--r--src/ruby/spec/support/services.rb50
-rw-r--r--src/ruby/tools/version.rb2
-rw-r--r--templates/CMakeLists.txt.template37
-rw-r--r--templates/Makefile.template4
-rw-r--r--templates/README.md39
-rw-r--r--templates/gRPC-C++.podspec.template3
-rw-r--r--templates/gRPC-Core.podspec.template3
-rw-r--r--templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template2
-rwxr-xr-xtemplates/src/csharp/build_packages_dotnetcli.bat.template2
-rw-r--r--templates/src/objective-c/BoringSSL-GRPC.podspec.template5
-rw-r--r--templates/tools/dockerfile/apt_get_python_27.include3
-rw-r--r--templates/tools/dockerfile/bazel.include7
-rw-r--r--templates/tools/dockerfile/csharp_deps.include7
-rw-r--r--templates/tools/dockerfile/debian_testing_repo.include3
-rw-r--r--templates/tools/dockerfile/gcp_api_libraries.include2
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template2
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template2
-rwxr-xr-xtemplates/tools/dockerfile/java_build_interop.sh.include8
-rw-r--r--templates/tools/dockerfile/python_stretch.include9
-rw-r--r--templates/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile.template17
-rw-r--r--templates/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile.template (renamed from templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template)19
-rw-r--r--templates/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile.template20
-rw-r--r--templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template20
-rw-r--r--templates/tools/run_tests/generated/lb_interop_test_scenarios.json.template6
-rw-r--r--test/.clang-tidy (renamed from test/cpp/util/.clang-tidy)0
-rw-r--r--test/core/bad_client/bad_client.cc2
-rw-r--r--test/core/channel/channel_stack_test.cc2
-rw-r--r--test/core/channel/channel_trace_test.cc223
-rw-r--r--test/core/channel/channelz_registry_test.cc159
-rw-r--r--test/core/channel/channelz_test.cc324
-rw-r--r--test/core/client_channel/parse_address_test.cc14
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc5
-rw-r--r--test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc117
-rw-r--r--test/core/client_channel/resolvers/fake_resolver_test.cc58
-rw-r--r--test/core/client_channel/uri_fuzzer_test.cc2
-rw-r--r--test/core/client_channel/uri_parser_test.cc2
-rw-r--r--test/core/compression/BUILD2
-rw-r--r--test/core/debug/BUILD34
-rw-r--r--test/core/end2end/BUILD19
-rwxr-xr-xtest/core/end2end/end2end_test.sh2
-rw-r--r--test/core/end2end/fixtures/h2_sockpair+trace.cc2
-rw-r--r--test/core/end2end/fixtures/h2_sockpair.cc2
-rw-r--r--test/core/end2end/fixtures/h2_sockpair_1byte.cc2
-rw-r--r--test/core/end2end/fixtures/http_proxy_fixture.cc18
-rw-r--r--test/core/end2end/fixtures/proxy.cc17
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer.cc7
-rw-r--r--test/core/end2end/fuzzers/hpack.dictionary65
-rw-r--r--test/core/end2end/fuzzers/server_fuzzer.cc2
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py2
-rwxr-xr-xtest/core/end2end/generate_tests.bzl664
-rw-r--r--test/core/end2end/goaway_server_test.cc10
-rw-r--r--test/core/end2end/inproc_callback_test.cc31
-rw-r--r--test/core/end2end/tests/channelz.cc87
-rw-r--r--test/core/end2end/tests/filter_status_code.cc26
-rw-r--r--test/core/end2end/tests/keepalive_timeout.cc2
-rw-r--r--test/core/end2end/tests/retry_streaming.cc64
-rw-r--r--test/core/end2end/tests/simple_request.cc13
-rw-r--r--test/core/end2end/tests/streaming_error_response.cc31
-rw-r--r--test/core/gprpp/inlined_vector_test.cc26
-rw-r--r--test/core/gprpp/ref_counted_test.cc47
-rw-r--r--test/core/handshake/readahead_handshaker_server_ssl.cc1
-rw-r--r--test/core/iomgr/BUILD32
-rw-r--r--test/core/iomgr/buffer_list_test.cc4
-rw-r--r--test/core/iomgr/error_test.cc11
-rw-r--r--test/core/iomgr/ev_epollsig_linux_test.cc321
-rw-r--r--test/core/iomgr/pollset_set_test.cc447
-rw-r--r--test/core/iomgr/resolve_address_test.cc43
-rw-r--r--test/core/iomgr/tcp_client_posix_test.cc2
-rw-r--r--test/core/iomgr/tcp_client_uv_test.cc29
-rw-r--r--test/core/iomgr/tcp_server_uv_test.cc40
-rw-r--r--test/core/iomgr/timer_list_test.cc4
-rw-r--r--test/core/memory_usage/BUILD60
-rw-r--r--test/core/memory_usage/memory_usage_test.cc4
-rw-r--r--test/core/memory_usage/server.cc2
-rw-r--r--test/core/security/alts_security_connector_test.cc2
-rw-r--r--test/core/security/credentials_test.cc13
-rw-r--r--test/core/security/linux_system_roots_test.cc6
-rw-r--r--test/core/security/security_connector_test.cc2
-rw-r--r--test/core/security/ssl_server_fuzzer.cc7
-rw-r--r--test/core/surface/completion_queue_test.cc25
-rw-r--r--test/core/surface/public_headers_must_be_c89.c5
-rw-r--r--test/core/transport/chttp2/hpack_encoder_test.cc2
-rw-r--r--test/core/transport/chttp2/settings_timeout_test.cc2
-rw-r--r--test/core/transport/metadata_test.cc5
-rw-r--r--test/core/tsi/alts/fake_handshaker/BUILD5
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc31
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h29
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc53
-rw-r--r--test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc225
-rw-r--r--test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc305
-rw-r--r--test/core/tsi/fake_transport_security_test.cc1
-rw-r--r--test/core/tsi/ssl_transport_security_test.cc6
-rw-r--r--test/core/util/port_isolated_runtime_environment.cc31
-rw-r--r--test/core/util/ubsan_suppressions.txt14
-rw-r--r--test/cpp/client/client_channel_stress_test.cc2
-rw-r--r--test/cpp/codegen/compiler_test_golden249
-rw-r--r--test/cpp/common/alarm_test.cc106
-rw-r--r--test/cpp/end2end/BUILD74
-rw-r--r--test/cpp/end2end/async_end2end_test.cc110
-rw-r--r--test/cpp/end2end/channelz_service_test.cc373
-rw-r--r--test/cpp/end2end/client_callback_end2end_test.cc283
-rw-r--r--test/cpp/end2end/client_interceptors_end2end_test.cc667
-rw-r--r--test/cpp/end2end/client_lb_end2end_test.cc296
-rw-r--r--test/cpp/end2end/end2end_test.cc84
-rw-r--r--test/cpp/end2end/grpclb_end2end_test.cc8
-rw-r--r--test/cpp/end2end/health_service_end2end_test.cc76
-rw-r--r--test/cpp/end2end/interceptors_util.cc151
-rw-r--r--test/cpp/end2end/interceptors_util.h279
-rw-r--r--test/cpp/end2end/server_interceptors_end2end_test.cc583
-rw-r--r--test/cpp/end2end/test_service_impl.cc150
-rw-r--r--test/cpp/end2end/test_service_impl.h33
-rw-r--r--test/cpp/interop/BUILD21
-rw-r--r--test/cpp/interop/client.cc8
-rw-r--r--test/cpp/interop/client_helper.h2
-rw-r--r--test/cpp/interop/interop_client.cc32
-rw-r--r--test/cpp/interop/interop_client.h2
-rw-r--r--test/cpp/interop/stress_interop_client.cc2
-rw-r--r--test/cpp/microbenchmarks/BUILD9
-rw-r--r--test/cpp/microbenchmarks/bm_call_create.cc9
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_hpack.cc72
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_transport.cc14
-rw-r--r--test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc2
-rw-r--r--test/cpp/microbenchmarks/fullstack_fixtures.h5
-rw-r--r--test/cpp/microbenchmarks/helpers.cc2
-rw-r--r--test/cpp/microbenchmarks/helpers.h1
-rw-r--r--test/cpp/naming/address_sorting_test.cc52
-rwxr-xr-xtest/cpp/naming/utils/dns_server.py15
-rwxr-xr-xtest/cpp/naming/utils/run_dns_server_for_lb_interop_tests.py109
-rwxr-xr-xtest/cpp/naming/utils/tcp_connect.py3
-rw-r--r--test/cpp/performance/writes_per_rpc_test.cc4
-rw-r--r--test/cpp/qps/BUILD69
-rw-r--r--test/cpp/qps/client.h54
-rw-r--r--test/cpp/qps/client_callback.cc219
-rw-r--r--test/cpp/qps/driver.cc6
-rw-r--r--test/cpp/qps/driver.h3
-rwxr-xr-xtest/cpp/qps/gen_build_yaml.py123
-rw-r--r--test/cpp/qps/histogram.h5
-rw-r--r--test/cpp/qps/inproc_sync_unary_ping_pong_test.cc2
-rwxr-xr-xtest/cpp/qps/json_run_localhost_scenario_gen.py39
-rw-r--r--test/cpp/qps/json_run_localhost_scenarios.bzl3
-rw-r--r--test/cpp/qps/qps_benchmark_script.bzl80
-rw-r--r--test/cpp/qps/qps_json_driver.cc19
-rwxr-xr-xtest/cpp/qps/qps_json_driver_scenario_gen.py39
-rw-r--r--test/cpp/qps/qps_json_driver_scenarios.bzl3
-rw-r--r--test/cpp/qps/qps_openloop_test.cc2
-rw-r--r--test/cpp/qps/qps_worker.cc4
-rw-r--r--test/cpp/qps/secure_sync_unary_ping_pong_test.cc2
-rw-r--r--test/cpp/qps/server.h1
-rw-r--r--test/cpp/qps/server_async.cc1
-rw-r--r--test/cpp/qps/server_callback.cc96
-rw-r--r--test/cpp/util/BUILD21
-rw-r--r--test/cpp/util/byte_buffer_proto_helper.h7
-rw-r--r--test/cpp/util/channel_trace_proto_helper.cc18
-rw-r--r--test/cpp/util/channel_trace_proto_helper.h4
-rw-r--r--test/cpp/util/cli_credentials.cc106
-rw-r--r--test/cpp/util/cli_credentials.h3
-rw-r--r--test/cpp/util/grpc_tool.cc67
-rw-r--r--test/cpp/util/grpc_tool_test.cc397
-rw-r--r--test/cpp/util/proto_file_parser.cc67
-rw-r--r--test/cpp/util/proto_file_parser.h52
-rwxr-xr-xtest/distrib/csharp/run_distrib_test.sh3
m---------third_party/boringssl-with-bazel0
-rw-r--r--tools/bazel.rc76
-rwxr-xr-x[-rw-r--r--]tools/buildgen/generate_build_additions.sh3
-rwxr-xr-xtools/codegen/core/gen_static_metadata.py132
-rwxr-xr-xtools/distrib/check_copyright.py4
-rwxr-xr-xtools/distrib/check_include_guards.py1
-rwxr-xr-xtools/distrib/check_nanopb_output.sh18
-rw-r--r--tools/distrib/python/grpcio_tools/MANIFEST.in1
-rw-r--r--tools/distrib/python/grpcio_tools/_parallel_compile_patch.py63
-rw-r--r--tools/distrib/python/grpcio_tools/grpc_version.py2
-rw-r--r--tools/distrib/python/grpcio_tools/setup.py3
-rw-r--r--tools/dockerfile/OWNERS2
-rw-r--r--tools/dockerfile/grpc_artifact_linux_x64/Dockerfile21
-rw-r--r--tools/dockerfile/grpc_artifact_linux_x86/Dockerfile16
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile7
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile7
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh6
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile2
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_go/Dockerfile2
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh8
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh8
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_php/build_interop.sh9
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh9
-rw-r--r--tools/dockerfile/interoptest/lb_interop_fake_servers/Dockerfile34
-rw-r--r--tools/dockerfile/interoptest/lb_interop_fake_servers/build_interop.sh35
-rw-r--r--tools/dockerfile/test/bazel/Dockerfile7
-rw-r--r--tools/dockerfile/test/csharp_jessie_x64/Dockerfile9
-rw-r--r--tools/dockerfile/test/cxx_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/cxx_jessie_x86/Dockerfile2
-rw-r--r--tools/dockerfile/test/cxx_sanitizers_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/fuzzer/Dockerfile2
-rw-r--r--tools/dockerfile/test/multilang_jessie_x64/Dockerfile9
-rw-r--r--tools/dockerfile/test/node_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/php7_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/php_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/python_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile69
-rw-r--r--tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile (renamed from tools/dockerfile/test/python_pyenv_x64/Dockerfile)57
-rw-r--r--tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile72
-rw-r--r--tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile72
-rw-r--r--tools/dockerfile/test/ruby_jessie_x64/Dockerfile2
-rw-r--r--tools/dockerfile/test/sanity/Dockerfile2
-rw-r--r--tools/doxygen/Doxyfile.c++16
-rw-r--r--tools/doxygen/Doxyfile.c++.internal26
-rw-r--r--tools/doxygen/Doxyfile.core9
-rw-r--r--tools/doxygen/Doxyfile.core.internal47
-rwxr-xr-xtools/gce/create_interop_worker.sh50
-rwxr-xr-xtools/gce/create_linux_kokoro_performance_worker.sh9
-rwxr-xr-xtools/gce/create_linux_kokoro_performance_worker_from_image.sh (renamed from tools/gce/create_linux_worker.sh)32
-rwxr-xr-xtools/gce/create_linux_performance_worker.sh53
-rw-r--r--tools/gce/jenkins_master.pub1
-rw-r--r--tools/gce/kokoro_performance.pub3
-rwxr-xr-xtools/gce/linux_kokoro_performance_worker_init.sh84
-rwxr-xr-xtools/gce/linux_performance_worker_init.sh184
-rwxr-xr-xtools/gce/linux_worker_init.sh78
-rwxr-xr-xtools/gcp/utils/big_query_utils.py28
-rw-r--r--tools/internal_ci/README.md11
-rwxr-xr-xtools/internal_ci/helper_scripts/delete_nonartifacts.sh2
-rw-r--r--tools/internal_ci/helper_scripts/prepare_build_grpclb_interop_rc33
-rw-r--r--tools/internal_ci/helper_scripts/prepare_build_macos_rc29
-rwxr-xr-x[-rw-r--r--]tools/internal_ci/linux/grpc_asan_on_foundry.sh5
-rw-r--r--tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_basictests_multilang.cfg2
-rwxr-xr-xtools/internal_ci/linux/grpc_bazel_on_foundry_base.sh41
-rw-r--r--tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh4
-rw-r--r--tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh4
-rw-r--r--tools/internal_ci/linux/grpc_build_artifacts.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_build_artifacts_extra.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_build_artifacts_extra_release.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_build_packages.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_coverage.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_distribtests.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_distribtests_standalone.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_e2e_performance_singlevm.cfg25
-rwxr-xr-xtools/internal_ci/linux/grpc_e2e_performance_singlevm.sh29
-rw-r--r--tools/internal_ci/linux/grpc_full_performance_master.cfg2
-rwxr-xr-xtools/internal_ci/linux/grpc_full_performance_master.sh2
-rw-r--r--tools/internal_ci/linux/grpc_full_performance_release.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_interop_alts.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_interop_matrix.cfg8
-rwxr-xr-xtools/internal_ci/linux/grpc_interop_matrix.sh2
-rw-r--r--tools/internal_ci/linux/grpc_interop_tocloud.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_interop_toprod.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_msan_on_foundry.sh62
-rwxr-xr-xtools/internal_ci/linux/grpc_performance_profile_daily.sh4
-rw-r--r--tools/internal_ci/linux/grpc_portability.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_portability_build_only.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_publish_packages.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_pull_request_sanity.cfg2
-rwxr-xr-xtools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh2
-rwxr-xr-xtools/internal_ci/linux/grpc_run_grpclb_interop_tests.sh26
-rw-r--r--tools/internal_ci/linux/grpc_sanity.cfg2
-rw-r--r--tools/internal_ci/linux/grpc_tsan_on_foundry.sh5
-rw-r--r--tools/internal_ci/linux/grpc_ubsan_on_foundry.sh59
-rw-r--r--tools/internal_ci/linux/grpclb_in_dns_interop.cfg25
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh5
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_c_dbg.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_c_opt.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_cpp_dbg.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_cpp_opt.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh4
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh4
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_interop_alts.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_interop_matrix_adhoc.cfg30
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_interop_tocloud.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_microbenchmark_diff.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh18
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_sanity.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_trickle_diff.cfg2
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh5
-rw-r--r--tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh53
-rwxr-xr-xtools/internal_ci/linux/run_performance_profile_hourly.sh4
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg2
-rw-r--r--tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg2
-rw-r--r--tools/internal_ci/macos/grpc_basictests_dbg.cfg4
-rw-r--r--tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg31
-rw-r--r--tools/internal_ci/macos/grpc_basictests_objc_opt.cfg31
-rw-r--r--tools/internal_ci/macos/grpc_basictests_opt.cfg4
-rw-r--r--tools/internal_ci/macos/grpc_build_artifacts.cfg2
-rw-r--r--tools/internal_ci/macos/grpc_distribtests.cfg2
-rw-r--r--tools/internal_ci/macos/grpc_interop.cfg2
-rw-r--r--tools/internal_ci/macos/grpc_interop_toprod.cfg2
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg4
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg31
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg31
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg4
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_interop.cfg2
-rw-r--r--tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_basictests.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_basictests_dbg.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_basictests_opt.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_build_artifacts.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_build_packages.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_distribtests.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_distribtests_standalone.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_portability.cfg2
-rw-r--r--tools/internal_ci/windows/grpc_portability_build_only.cfg2
-rw-r--r--tools/internal_ci/windows/pull_request/grpc_basictests.cfg2
-rw-r--r--tools/internal_ci/windows/pull_request/grpc_basictests_dbg.cfg2
-rw-r--r--tools/internal_ci/windows/pull_request/grpc_basictests_opt.cfg2
-rw-r--r--tools/internal_ci/windows/pull_request/grpc_portability.cfg2
-rw-r--r--tools/interop_matrix/client_matrix.py55
-rwxr-xr-xtools/interop_matrix/run_interop_matrix_tests.py224
-rw-r--r--tools/remote_build/README.md33
-rw-r--r--tools/remote_build/kokoro.bazelrc38
-rw-r--r--tools/remote_build/manual.bazelrc45
-rw-r--r--tools/remote_build/rbe_common.bazelrc85
-rw-r--r--tools/run_tests/artifacts/artifact_targets.py35
-rw-r--r--tools/run_tests/artifacts/build_artifact_csharp.bat29
-rwxr-xr-xtools/run_tests/artifacts/build_artifact_csharp.sh14
-rw-r--r--tools/run_tests/artifacts/build_artifact_python.bat4
-rwxr-xr-xtools/run_tests/artifacts/build_artifact_python.sh5
-rwxr-xr-xtools/run_tests/artifacts/build_package_python.sh14
-rw-r--r--tools/run_tests/generated/lb_interop_test_scenarios.json1167
-rw-r--r--tools/run_tests/generated/sources_and_headers.json362
-rw-r--r--tools/run_tests/generated/tests.json1075
-rwxr-xr-xtools/run_tests/helper_scripts/build_python.sh29
-rw-r--r--tools/run_tests/helper_scripts/pre_build_csharp.bat4
-rwxr-xr-xtools/run_tests/helper_scripts/pre_build_csharp.sh11
-rwxr-xr-xtools/run_tests/lb_interop_tests/gen_build_yaml.py347
-rwxr-xr-xtools/run_tests/performance/build_performance.sh23
-rwxr-xr-xtools/run_tests/performance/remote_host_prepare.sh3
-rwxr-xr-xtools/run_tests/performance/run_qps_driver.sh2
-rw-r--r--tools/run_tests/performance/scenario_config.py52
-rwxr-xr-xtools/run_tests/python_utils/dockerjob.py27
-rwxr-xr-xtools/run_tests/python_utils/jobset.py29
-rwxr-xr-xtools/run_tests/python_utils/port_server.py16
-rw-r--r--tools/run_tests/python_utils/report_utils.py2
-rw-r--r--tools/run_tests/python_utils/start_port_server.py19
-rw-r--r--tools/run_tests/python_utils/upload_rbe_results.py19
-rw-r--r--tools/run_tests/python_utils/upload_test_results.py17
-rwxr-xr-xtools/run_tests/python_utils/watch_dirs.py3
-rwxr-xr-xtools/run_tests/run_grpclb_interop_tests.py609
-rwxr-xr-xtools/run_tests/run_interop_tests.py97
-rwxr-xr-xtools/run_tests/run_performance_tests.py24
-rwxr-xr-xtools/run_tests/run_tests.py66
-rwxr-xr-xtools/run_tests/run_tests_matrix.py37
-rwxr-xr-xtools/run_tests/sanity/check_qps_scenario_changes.py33
-rwxr-xr-xtools/run_tests/sanity/check_submodules.sh2
-rwxr-xr-xtools/run_tests/sanity/core_banned_functions.py4
-rw-r--r--tools/run_tests/sanity/sanity_tests.yaml1
919 files changed, 40431 insertions, 13964 deletions
diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 0000000000..bc31c54e94
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,3 @@
+# load bazelrc from the legacy location
+# as recommended in https://github.com/bazelbuild/bazel/issues/6319
+import %workspace%/tools/bazel.rc
diff --git a/.clang-tidy b/.clang-tidy
index fbf0b6541e..d217441792 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,6 +1,6 @@
---
-Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*'
-WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*'
+Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*,bugprone-*'
+WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*,bugprone-*'
CheckOptions:
- key: readability-function-size.StatementThreshold
value: '450'
diff --git a/.clang_complete b/.clang_complete
index aa77554f4e..1448b01342 100644
--- a/.clang_complete
+++ b/.clang_complete
@@ -14,4 +14,5 @@
-Ithird_party/cares
-Ithird_party/googletest/googletest/include
-Ithird_party/googletest/googlemock/include
+-Ithird_party/nanopb
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c28eb974f8..0a7141c1be 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,8 +2,8 @@
# Uses OWNERS files in different modules throughout the
# repository as the source of truth for module ownership.
/**/OWNERS @markdroth @nicolasnoble @a11r
-/bazel/** @nicolasnoble @dgquintas @a11r @vjpai
-/cmake/** @jtattermusch @nicolasnoble @mehrdada
-/src/core/ext/filters/client_channel/** @markdroth @dgquintas @AspirinSJL
-/tools/dockerfile/** @jtattermusch @mehrdada @nicolasnoble
+/bazel/** @nicolasnoble @jtattermusch @a11r @vjpai
+/cmake/** @jtattermusch @nicolasnoble @apolcyn
+/src/core/ext/filters/client_channel/** @markdroth @apolcyn @AspirinSJL
+/tools/dockerfile/** @jtattermusch @apolcyn @nicolasnoble
/tools/run_tests/performance/** @ncteisen @apolcyn @jtattermusch
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 5b2ac80df6..d31aea6c73 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -26,6 +26,8 @@ If possible, provide a recipe for reproducing the error. Try being specific and
### What did you see instead?
Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs).
+
+See https://github.com/grpc/grpc/blob/master/TROUBLESHOOTING.md for how to diagnose problems better.
### Anything else we should know about your project / environment?
diff --git a/.github/lock.yml b/.github/lock.yml
new file mode 100644
index 0000000000..119e4840be
--- /dev/null
+++ b/.github/lock.yml
@@ -0,0 +1,2 @@
+daysUntilLock: 90
+lockComment: false
diff --git a/AUTHORS b/AUTHORS
index e491a9e7f7..3e130afda2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,2 @@
Google Inc.
+WeWork Companies Inc.
diff --git a/BUILD b/BUILD
index b38e598ea4..3e3ae484f7 100644
--- a/BUILD
+++ b/BUILD
@@ -64,11 +64,11 @@ config_setting(
)
# This should be updated along with build.yaml
-g_stands_for = "glider"
+g_stands_for = "gizmo"
core_version = "6.0.0-dev"
-version = "1.15.0-dev"
+version = "1.17.0-dev"
GPR_PUBLIC_HDRS = [
"include/grpc/support/alloc.h",
@@ -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",
@@ -131,7 +132,6 @@ GRPCXX_SRCS = [
"src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc",
"src/cpp/server/health/default_health_check_service.cc",
- "src/cpp/server/health/health.pb.c",
"src/cpp/server/health/health_check_service.cc",
"src/cpp/server/health/health_check_service_server_builder_option.cc",
"src/cpp/server/server_builder.cc",
@@ -151,7 +151,6 @@ GRPCXX_HDRS = [
"src/cpp/common/channel_filter.h",
"src/cpp/server/dynamic_thread_pool.h",
"src/cpp/server/health/default_health_check_service.h",
- "src/cpp/server/health/health.pb.h",
"src/cpp/server/thread_pool_interface.h",
"src/cpp/thread_manager/thread_manager.h",
]
@@ -243,9 +242,11 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "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",
@@ -278,6 +279,7 @@ grpc_cc_library(
deps = [
"grpc_common",
"grpc_lb_policy_grpclb",
+ "grpc_lb_policy_xds",
],
)
@@ -293,6 +295,7 @@ grpc_cc_library(
deps = [
"grpc_common",
"grpc_lb_policy_grpclb_secure",
+ "grpc_lb_policy_xds_secure",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_secure",
@@ -706,7 +709,6 @@ grpc_cc_library(
"src/core/lib/iomgr/error.cc",
"src/core/lib/iomgr/ev_epoll1_linux.cc",
"src/core/lib/iomgr/ev_epollex_linux.cc",
- "src/core/lib/iomgr/ev_epollsig_linux.cc",
"src/core/lib/iomgr/ev_poll_posix.cc",
"src/core/lib/iomgr/ev_posix.cc",
"src/core/lib/iomgr/ev_windows.cc",
@@ -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",
@@ -847,8 +850,8 @@ grpc_cc_library(
"src/core/lib/http/format_request.h",
"src/core/lib/http/httpcli.h",
"src/core/lib/http/parser.h",
- "src/core/lib/iomgr/buffer_list.h",
"src/core/lib/iomgr/block_annotate.h",
+ "src/core/lib/iomgr/buffer_list.h",
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
@@ -858,7 +861,6 @@ grpc_cc_library(
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -955,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",
@@ -1039,6 +1042,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/client_channel_factory.cc",
"src/core/ext/filters/client_channel/client_channel_plugin.cc",
"src/core/ext/filters/client_channel/connector.cc",
+ "src/core/ext/filters/client_channel/health/health_check_client.cc",
"src/core/ext/filters/client_channel/http_connect_handshaker.cc",
"src/core/ext/filters/client_channel/http_proxy.cc",
"src/core/ext/filters/client_channel/lb_policy.cc",
@@ -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",
@@ -1061,6 +1064,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/client_channel_channelz.h",
"src/core/ext/filters/client_channel/client_channel_factory.h",
"src/core/ext/filters/client_channel/connector.h",
+ "src/core/ext/filters/client_channel/health/health_check_client.h",
"src/core/ext/filters/client_channel/http_connect_handshaker.h",
"src/core/ext/filters/client_channel/http_proxy.h",
"src/core/ext/filters/client_channel/lb_policy.h",
@@ -1076,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 = [
@@ -1088,6 +1091,7 @@ grpc_cc_library(
"orphanable",
"ref_counted",
"ref_counted_ptr",
+ "health_proto",
],
)
@@ -1200,6 +1204,38 @@ grpc_cc_library(
)
grpc_cc_library(
+ name = "health_proto",
+ srcs = [
+ "src/core/ext/filters/client_channel/health/health.pb.c",
+ ],
+ hdrs = [
+ "src/core/ext/filters/client_channel/health/health.pb.h",
+ ],
+ external_deps = [
+ "nanopb",
+ ],
+ language = "c++",
+)
+
+grpc_cc_library(
+ name = "grpclb_proto",
+ srcs = [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ ],
+ hdrs = [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+ ],
+ external_deps = [
+ "nanopb",
+ ],
+ language = "c++",
+)
+
+grpc_cc_library(
name = "grpc_lb_policy_grpclb",
srcs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc",
@@ -1207,9 +1243,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
@@ -1217,9 +1250,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
],
external_deps = [
"nanopb",
@@ -1229,6 +1259,7 @@ grpc_cc_library(
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
],
)
@@ -1240,9 +1271,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
@@ -1250,9 +1278,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
],
external_deps = [
"nanopb",
@@ -1263,6 +1288,60 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
+ ],
+)
+
+grpc_cc_library(
+ name = "grpc_lb_policy_xds",
+ srcs = [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ ],
+ hdrs = [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h",
+ ],
+ external_deps = [
+ "nanopb",
+ ],
+ language = "c++",
+ deps = [
+ "grpc_base",
+ "grpc_client_channel",
+ "grpc_resolver_fake",
+ "grpclb_proto",
+ ],
+)
+
+grpc_cc_library(
+ name = "grpc_lb_policy_xds_secure",
+ srcs = [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ ],
+ hdrs = [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h",
+ ],
+ external_deps = [
+ "nanopb",
+ ],
+ language = "c++",
+ deps = [
+ "grpc_base",
+ "grpc_client_channel",
+ "grpc_resolver_fake",
+ "grpc_secure",
+ "grpclb_proto",
],
)
@@ -1504,11 +1583,14 @@ grpc_cc_library(
"src/core/lib/security/credentials/oauth2/oauth2_credentials.cc",
"src/core/lib/security/credentials/plugin/plugin_credentials.cc",
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
- "src/core/lib/security/security_connector/alts_security_connector.cc",
+ "src/core/lib/security/security_connector/alts/alts_security_connector.cc",
+ "src/core/lib/security/security_connector/fake/fake_security_connector.cc",
"src/core/lib/security/security_connector/load_system_roots_fallback.cc",
"src/core/lib/security/security_connector/load_system_roots_linux.cc",
- "src/core/lib/security/security_connector/local_security_connector.cc",
+ "src/core/lib/security/security_connector/local/local_security_connector.cc",
"src/core/lib/security/security_connector/security_connector.cc",
+ "src/core/lib/security/security_connector/ssl_utils.cc",
+ "src/core/lib/security/security_connector/ssl/ssl_security_connector.cc",
"src/core/lib/security/transport/client_auth_filter.cc",
"src/core/lib/security/transport/secure_endpoint.cc",
"src/core/lib/security/transport/security_handshaker.cc",
@@ -1520,6 +1602,7 @@ grpc_cc_library(
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
@@ -1534,11 +1617,14 @@ grpc_cc_library(
"src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
- "src/core/lib/security/security_connector/alts_security_connector.h",
+ "src/core/lib/security/security_connector/alts/alts_security_connector.h",
+ "src/core/lib/security/security_connector/fake/fake_security_connector.h",
"src/core/lib/security/security_connector/load_system_roots.h",
"src/core/lib/security/security_connector/load_system_roots_linux.h",
- "src/core/lib/security/security_connector/local_security_connector.h",
+ "src/core/lib/security/security_connector/local/local_security_connector.h",
"src/core/lib/security/security_connector/security_connector.h",
+ "src/core/lib/security/security_connector/ssl_utils.h",
+ "src/core/lib/security/security_connector/ssl/ssl_security_connector.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_handshaker.h",
@@ -1551,9 +1637,9 @@ grpc_cc_library(
deps = [
"alts_util",
"grpc_base",
+ "grpc_shadow_boringssl",
"grpc_transport_chttp2_alpn",
"tsi",
- "grpc_shadow_boringssl",
],
)
@@ -1815,8 +1901,8 @@ grpc_cc_library(
deps = [
"gpr",
"grpc_base",
- "tsi_interface",
"grpc_shadow_boringssl",
+ "tsi_interface",
],
)
@@ -1875,10 +1961,9 @@ 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",
"src/core/tsi/fake_transport_security.cc",
"src/core/tsi/local_transport_security.cc",
"src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc",
@@ -1889,11 +1974,10 @@ 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",
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.h",
"src/core/tsi/ssl/session_cache/ssl_session.h",
@@ -1911,9 +1995,9 @@ grpc_cc_library(
"alts_util",
"gpr",
"grpc_base",
+ "grpc_shadow_boringssl",
"grpc_transport_chttp2_client_insecure",
"tsi_interface",
- "grpc_shadow_boringssl",
],
)
@@ -1926,6 +2010,7 @@ grpc_cc_library(
deps = [
"grpc",
"grpc++_codegen_base",
+ "health_proto",
],
)
@@ -1938,6 +2023,7 @@ grpc_cc_library(
deps = [
"grpc++_codegen_base",
"grpc_unsecure",
+ "health_proto",
],
)
@@ -1981,8 +2067,13 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
+ "include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
"include/grpcpp/impl/codegen/completion_queue_tag.h",
@@ -1990,13 +2081,18 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
+ "include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"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",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
@@ -2139,7 +2235,6 @@ grpc_cc_library(
"src/cpp/ext/filters/census/channel_filter.cc",
"src/cpp/ext/filters/census/client_filter.cc",
"src/cpp/ext/filters/census/context.cc",
- "src/core/ext/filters/census/grpc_context.cc",
"src/cpp/ext/filters/census/grpc_plugin.cc",
"src/cpp/ext/filters/census/measures.cc",
"src/cpp/ext/filters/census/rpc_encoding.cc",
diff --git a/BUILDING.md b/BUILDING.md
index 81edb68e43..615b371db6 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -132,8 +132,8 @@ you will be able to browse and build the code.
> @rem Run from grpc directory after cloning the repo with --recursive or updating submodules.
> md .build
> cd .build
-> cmake .. -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=Release
-> cmake --build .
+> cmake .. -G "Visual Studio 14 2015"
+> cmake --build . --config Release
```
## cmake: Windows, Using Ninja (faster build, supports boringssl's assembly optimizations).
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af2341c299..4ccb31e641 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@
cmake_minimum_required(VERSION 2.8)
set(PACKAGE_NAME "grpc")
-set(PACKAGE_VERSION "1.15.0-dev")
+set(PACKAGE_VERSION "1.17.0-dev")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -40,6 +40,7 @@ set(gRPC_INSTALL_SHAREDIR "share/grpc" CACHE STRING "Installation directory for
option(gRPC_BUILD_TESTS "Build tests" OFF)
option(gRPC_BUILD_CODEGEN "Build codegen" ON)
option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON)
+option(gRPC_BACKWARDS_COMPATIBILITY_MODE "Build libraries that are binary compatible across a larger number of OS and libc versions" OFF)
set(gRPC_INSTALL_default ON)
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -115,6 +116,25 @@ else()
set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf")
endif()
+if(gRPC_BACKWARDS_COMPATIBILITY_MODE)
+ add_definitions(-DGPR_BACKWARDS_COMPATIBILITY_MODE)
+ if (_gRPC_PLATFORM_MAC)
+ # some C++11 constructs not supported before OS X 10.9
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
+ endif()
+endif()
+
+if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
+ # C core has C++ source code, but should not depend on libstc++ (for better portability).
+ # We need to use a few tricks to convince cmake to do that.
+ # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc
+ set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
+ # Exceptions and RTTI must be off to avoid dependency on libstdc++
+ set(_gRPC_CORE_NOSTDCXX_FLAGS -fno-exceptions -fno-rtti)
+else()
+ set(_gRPC_CORE_NOSTDCXX_FLAGS "")
+endif()
+
include(cmake/zlib.cmake)
include(cmake/cares.cmake)
include(cmake/protobuf.cmake)
@@ -254,9 +274,6 @@ add_dependencies(buildtests_c error_test)
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_c ev_epollex_linux_test)
endif()
-if(_gRPC_PLATFORM_LINUX)
-add_dependencies(buildtests_c ev_epollsig_linux_test)
-endif()
add_dependencies(buildtests_c fake_resolver_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c fake_transport_security_test)
@@ -312,10 +329,10 @@ add_dependencies(buildtests_c grpc_jwt_verifier_test)
add_dependencies(buildtests_c grpc_security_connector_test)
add_dependencies(buildtests_c grpc_ssl_credentials_test)
if(_gRPC_PLATFORM_LINUX)
-add_dependencies(buildtests_c handshake_client)
+add_dependencies(buildtests_c handshake_client_ssl)
endif()
if(_gRPC_PLATFORM_LINUX)
-add_dependencies(buildtests_c handshake_server)
+add_dependencies(buildtests_c handshake_server_ssl)
endif()
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_c handshake_server_with_readahead_handshaker)
@@ -343,10 +360,10 @@ add_dependencies(buildtests_c json_stream_error_test)
add_dependencies(buildtests_c json_test)
add_dependencies(buildtests_c lame_client_test)
add_dependencies(buildtests_c load_file_test)
-add_dependencies(buildtests_c memory_profile_client)
-add_dependencies(buildtests_c memory_profile_server)
+add_dependencies(buildtests_c memory_usage_client)
+add_dependencies(buildtests_c memory_usage_server)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_dependencies(buildtests_c memory_profile_test)
+add_dependencies(buildtests_c memory_usage_test)
endif()
add_dependencies(buildtests_c message_compress_test)
add_dependencies(buildtests_c minimal_stack_is_minimal_test)
@@ -356,13 +373,11 @@ add_dependencies(buildtests_c no_server_test)
add_dependencies(buildtests_c num_external_connectivity_watchers_test)
add_dependencies(buildtests_c parse_address_test)
add_dependencies(buildtests_c percent_encoding_test)
-if(_gRPC_PLATFORM_LINUX)
-add_dependencies(buildtests_c pollset_set_test)
-endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c resolve_address_posix_test)
endif()
-add_dependencies(buildtests_c resolve_address_test)
+add_dependencies(buildtests_c resolve_address_using_ares_resolver_test)
+add_dependencies(buildtests_c resolve_address_using_native_resolver_test)
add_dependencies(buildtests_c resource_quota_test)
add_dependencies(buildtests_c secure_channel_create_test)
add_dependencies(buildtests_c secure_endpoint_test)
@@ -474,7 +489,6 @@ add_dependencies(buildtests_c h2_sockpair_1byte_nosec_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c h2_uds_nosec_test)
endif()
-add_dependencies(buildtests_c inproc_nosec_test)
add_dependencies(buildtests_c alts_credentials_fuzzer_one_entry)
add_dependencies(buildtests_c api_fuzzer_one_entry)
add_dependencies(buildtests_c client_fuzzer_one_entry)
@@ -565,11 +579,13 @@ add_dependencies(buildtests_cxx check_gcp_environment_linux_test)
add_dependencies(buildtests_cxx check_gcp_environment_windows_test)
add_dependencies(buildtests_cxx chttp2_settings_timeout_test)
add_dependencies(buildtests_cxx cli_call_test)
+add_dependencies(buildtests_cxx client_callback_end2end_test)
add_dependencies(buildtests_cxx client_channel_stress_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx client_crash_test)
endif()
add_dependencies(buildtests_cxx client_crash_test_server)
+add_dependencies(buildtests_cxx client_interceptors_end2end_test)
add_dependencies(buildtests_cxx client_lb_end2end_test)
add_dependencies(buildtests_cxx codegen_test_full)
add_dependencies(buildtests_cxx codegen_test_minimal)
@@ -650,6 +666,7 @@ add_dependencies(buildtests_cxx server_crash_test)
endif()
add_dependencies(buildtests_cxx server_crash_test_client)
add_dependencies(buildtests_cxx server_early_return_test)
+add_dependencies(buildtests_cxx server_interceptors_end2end_test)
add_dependencies(buildtests_cxx server_request_call_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx slice_hash_table_test)
@@ -715,7 +732,12 @@ target_include_directories(address_sorting
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(address_sorting PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(address_sorting PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(address_sorting
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -762,7 +784,12 @@ target_include_directories(alts_test_util
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(alts_test_util PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(alts_test_util PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(alts_test_util
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -838,7 +865,12 @@ target_include_directories(gpr
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(gpr PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(gpr
${_gRPC_ALLTARGETS_LIBRARIES}
)
@@ -928,7 +960,12 @@ target_include_directories(gpr_test_util
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_test_util PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(gpr_test_util PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(gpr_test_util
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
@@ -973,7 +1010,6 @@ add_library(grpc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1090,6 +1126,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
@@ -1137,11 +1174,14 @@ add_library(grpc
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
- src/core/lib/security/security_connector/alts_security_connector.cc
+ src/core/lib/security/security_connector/alts/alts_security_connector.cc
+ src/core/lib/security/security_connector/fake/fake_security_connector.cc
src/core/lib/security/security_connector/load_system_roots_fallback.cc
src/core/lib/security/security_connector/load_system_roots_linux.cc
- src/core/lib/security/security_connector/local_security_connector.cc
+ src/core/lib/security/security_connector/local/local_security_connector.cc
src/core/lib/security/security_connector/security_connector.cc
+ src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
+ src/core/lib/security/security_connector/ssl_utils.cc
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/secure_endpoint.cc
src/core/lib/security/transport/security_handshaker.cc
@@ -1160,7 +1200,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
@@ -1196,6 +1236,7 @@ add_library(grpc
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -1210,9 +1251,8 @@ 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/tsi/alts_transport_security.cc
+ src/core/ext/filters/client_channel/health/health.pb.c
src/core/tsi/fake_transport_security.cc
src/core/tsi/local_transport_security.cc
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1231,10 +1271,14 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -1280,7 +1324,12 @@ target_include_directories(grpc
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_SSL_LIBRARIES}
@@ -1382,7 +1431,6 @@ add_library(grpc_cronet
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1499,6 +1547,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
@@ -1539,6 +1588,7 @@ add_library(grpc_cronet
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -1553,8 +1603,11 @@ 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
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/core/lib/http/httpcli_security_connector.cc
src/core/lib/security/context/security_context.cc
src/core/lib/security/credentials/alts/alts_credentials.cc
@@ -1572,11 +1625,14 @@ add_library(grpc_cronet
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
src/core/lib/security/credentials/plugin/plugin_credentials.cc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
- src/core/lib/security/security_connector/alts_security_connector.cc
+ src/core/lib/security/security_connector/alts/alts_security_connector.cc
+ src/core/lib/security/security_connector/fake/fake_security_connector.cc
src/core/lib/security/security_connector/load_system_roots_fallback.cc
src/core/lib/security/security_connector/load_system_roots_linux.cc
- src/core/lib/security/security_connector/local_security_connector.cc
+ src/core/lib/security/security_connector/local/local_security_connector.cc
src/core/lib/security/security_connector/security_connector.cc
+ src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
+ src/core/lib/security/security_connector/ssl_utils.cc
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/secure_endpoint.cc
src/core/lib/security/transport/security_handshaker.cc
@@ -1595,7 +1651,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
@@ -1616,15 +1672,11 @@ add_library(grpc_cronet
src/core/tsi/alts/handshaker/altscontext.pb.c
src/core/tsi/alts/handshaker/handshaker.pb.c
src/core/tsi/alts/handshaker/transport_security_common.pb.c
- third_party/nanopb/pb_common.c
- third_party/nanopb/pb_decode.c
- third_party/nanopb/pb_encode.c
src/core/tsi/transport_security.cc
src/core/ext/transport/chttp2/client/insecure/channel_create.cc
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
src/core/ext/transport/chttp2/client/authority.cc
src/core/ext/transport/chttp2/client/chttp2_connector.cc
- src/core/tsi/alts_transport_security.cc
src/core/tsi/fake_transport_security.cc
src/core/tsi/local_transport_security.cc
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1659,7 +1711,12 @@ target_include_directories(grpc_cronet
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_cronet PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc_cronet PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc_cronet
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_SSL_LIBRARIES}
@@ -1777,7 +1834,6 @@ add_library(grpc_test_util
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1894,6 +1950,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
@@ -1902,6 +1959,7 @@ add_library(grpc_test_util
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -1916,8 +1974,11 @@ 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
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/core/ext/transport/chttp2/transport/bin_decoder.cc
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
@@ -1972,7 +2033,12 @@ target_include_directories(grpc_test_util
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_test_util PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc_test_util PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc_test_util
${_gRPC_ALLTARGETS_LIBRARIES}
gpr_test_util
@@ -2088,7 +2154,6 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -2205,6 +2270,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
@@ -2213,6 +2279,7 @@ add_library(grpc_test_util_unsecure
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -2227,8 +2294,11 @@ 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
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/core/ext/transport/chttp2/transport/bin_decoder.cc
src/core/ext/transport/chttp2/transport/bin_encoder.cc
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
@@ -2283,7 +2353,12 @@ target_include_directories(grpc_test_util_unsecure
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_test_util_unsecure PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc_test_util_unsecure PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc_test_util_unsecure
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
@@ -2378,7 +2453,6 @@ add_library(grpc_unsecure
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -2495,6 +2569,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
@@ -2538,6 +2613,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -2552,8 +2628,11 @@ 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
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/core/ext/transport/inproc/inproc_plugin.cc
src/core/ext/transport/inproc/inproc_transport.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -2575,9 +2654,10 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
- third_party/nanopb/pb_common.c
- third_party/nanopb/pb_decode.c
- third_party/nanopb/pb_encode.c
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/census/grpc_context.cc
@@ -2613,7 +2693,12 @@ target_include_directories(grpc_unsecure
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_unsecure PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc_unsecure PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc_unsecure
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_ZLIB_LIBRARIES}
@@ -2706,7 +2791,12 @@ target_include_directories(reconnect_server
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(reconnect_server PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(reconnect_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(reconnect_server
${_gRPC_ALLTARGETS_LIBRARIES}
test_tcp_server
@@ -2748,7 +2838,12 @@ target_include_directories(test_tcp_server
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(test_tcp_server PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(test_tcp_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(test_tcp_server
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
@@ -2771,6 +2866,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
@@ -2789,7 +2885,6 @@ add_library(grpc++
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/dynamic_thread_pool.cc
src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health.pb.c
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/server_builder.cc
@@ -2802,6 +2897,10 @@ add_library(grpc++
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
+ src/core/ext/filters/client_channel/health/health.pb.c
+ third_party/nanopb/pb_common.c
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/cpp/codegen/codegen_init.cc
)
@@ -2830,7 +2929,6 @@ target_include_directories(grpc++
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_SSL_LIBRARIES}
@@ -2923,9 +3021,11 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ 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
@@ -3020,8 +3120,13 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
+ include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -3029,13 +3134,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
+ include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
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
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -3111,7 +3221,6 @@ target_include_directories(grpc++_core_stats
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_core_stats
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -3129,6 +3238,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
@@ -3147,7 +3257,6 @@ add_library(grpc++_cronet
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/dynamic_thread_pool.cc
src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health.pb.c
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/server_builder.cc
@@ -3160,6 +3269,10 @@ add_library(grpc++_cronet
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
+ src/core/ext/filters/client_channel/health/health.pb.c
+ third_party/nanopb/pb_common.c
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/cpp/codegen/codegen_init.cc
src/core/ext/transport/chttp2/client/insecure/channel_create.cc
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
@@ -3222,7 +3335,6 @@ add_library(grpc++_cronet
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -3339,6 +3451,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
@@ -3352,6 +3465,7 @@ add_library(grpc++_cronet
src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/connector.cc
+ src/core/ext/filters/client_channel/health/health_check_client.cc
src/core/ext/filters/client_channel/http_connect_handshaker.cc
src/core/ext/filters/client_channel/http_proxy.cc
src/core/ext/filters/client_channel/lb_policy.cc
@@ -3366,7 +3480,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
@@ -3399,7 +3512,6 @@ target_include_directories(grpc++_cronet
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_cronet
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_SSL_LIBRARIES}
@@ -3493,9 +3605,11 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ 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
@@ -3590,8 +3704,13 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
+ include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -3599,13 +3718,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
+ include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
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
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -3671,7 +3795,6 @@ target_include_directories(grpc++_error_details
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_error_details
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_PROTOBUF_LIBRARIES}
@@ -3743,7 +3866,6 @@ target_include_directories(grpc++_proto_reflection_desc_db
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_proto_reflection_desc_db
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -3803,7 +3925,6 @@ target_include_directories(grpc++_reflection
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_reflection
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -3867,7 +3988,6 @@ target_include_directories(grpc++_test_config
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_test_config
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -3954,7 +4074,6 @@ target_include_directories(grpc++_test_util
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_test_util
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4000,8 +4119,13 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
+ include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -4009,13 +4133,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
+ include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
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
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -4132,7 +4261,6 @@ target_include_directories(grpc++_test_util_unsecure
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_test_util_unsecure
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4178,8 +4306,13 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
+ include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -4187,13 +4320,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
+ include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
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
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -4248,6 +4386,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
@@ -4266,7 +4405,6 @@ add_library(grpc++_unsecure
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/dynamic_thread_pool.cc
src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health.pb.c
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/server_builder.cc
@@ -4279,6 +4417,10 @@ add_library(grpc++_unsecure
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
+ src/core/ext/filters/client_channel/health/health.pb.c
+ third_party/nanopb/pb_common.c
+ third_party/nanopb/pb_decode.c
+ third_party/nanopb/pb_encode.c
src/cpp/codegen/codegen_init.cc
)
@@ -4307,7 +4449,6 @@ target_include_directories(grpc++_unsecure
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc++_unsecure
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_PROTOBUF_LIBRARIES}
@@ -4399,9 +4540,11 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ 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
@@ -4496,8 +4639,13 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/call_op_set.h
+ include/grpcpp/impl/codegen/call_op_set_interface.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
+ include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -4505,13 +4653,18 @@ foreach(_hdr
include/grpcpp/impl/codegen/core_codegen_interface.h
include/grpcpp/impl/codegen/create_auth_context.h
include/grpcpp/impl/codegen/grpc_library.h
+ include/grpcpp/impl/codegen/intercepted_channel.h
+ include/grpcpp/impl/codegen/interceptor.h
+ include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
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
include/grpcpp/impl/codegen/service_type.h
include/grpcpp/impl/codegen/slice.h
@@ -4573,7 +4726,6 @@ target_include_directories(grpc_benchmark
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc_benchmark
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4633,7 +4785,6 @@ target_include_directories(grpc_cli_libs
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc_cli_libs
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4691,7 +4842,6 @@ target_include_directories(grpc_plugin_support
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpc_plugin_support
${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
${_gRPC_PROTOBUF_LIBRARIES}
@@ -4757,7 +4907,6 @@ target_include_directories(grpcpp_channelz
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(grpcpp_channelz
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4842,7 +4991,6 @@ target_include_directories(http2_client_main
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(http2_client_main
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4899,7 +5047,6 @@ target_include_directories(interop_client_helper
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(interop_client_helper
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -4971,7 +5118,6 @@ target_include_directories(interop_client_main
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(interop_client_main
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5023,7 +5169,6 @@ target_include_directories(interop_server_helper
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(interop_server_helper
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5093,7 +5238,6 @@ target_include_directories(interop_server_lib
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(interop_server_lib
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5145,7 +5289,6 @@ target_include_directories(interop_server_main
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(interop_server_main
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5188,6 +5331,7 @@ add_library(qps
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/worker_service.grpc.pb.h
test/cpp/qps/benchmark_config.cc
test/cpp/qps/client_async.cc
+ test/cpp/qps/client_callback.cc
test/cpp/qps/client_sync.cc
test/cpp/qps/driver.cc
test/cpp/qps/parse_json.cc
@@ -5195,6 +5339,7 @@ add_library(qps
test/cpp/qps/qps_worker.cc
test/cpp/qps/report.cc
test/cpp/qps/server_async.cc
+ test/cpp/qps/server_callback.cc
test/cpp/qps/server_sync.cc
test/cpp/qps/usage_timer.cc
)
@@ -5249,7 +5394,6 @@ target_include_directories(qps
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
-
target_link_libraries(qps
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5293,7 +5437,12 @@ target_include_directories(grpc_csharp_ext
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_csharp_ext PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(grpc_csharp_ext PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(grpc_csharp_ext
${_gRPC_ALLTARGETS_LIBRARIES}
grpc
@@ -5341,7 +5490,12 @@ target_include_directories(bad_client_test
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(bad_client_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util_unsecure
@@ -5382,7 +5536,12 @@ target_include_directories(bad_ssl_test_server
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bad_ssl_test_server PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(bad_ssl_test_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(bad_ssl_test_server
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
@@ -5502,7 +5661,12 @@ target_include_directories(end2end_tests
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(end2end_tests PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(end2end_tests PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(end2end_tests
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
@@ -5622,7 +5786,12 @@ target_include_directories(end2end_nosec_tests
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(end2end_nosec_tests PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(end2end_nosec_tests PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
target_link_libraries(end2end_nosec_tests
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util_unsecure
@@ -5662,6 +5831,12 @@ target_link_libraries(algorithm_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(algorithm_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(algorithm_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5689,6 +5864,12 @@ target_link_libraries(alloc_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(alloc_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(alloc_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5718,6 +5899,12 @@ target_link_libraries(alpn_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(alpn_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(alpn_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5745,6 +5932,12 @@ target_link_libraries(arena_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(arena_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(arena_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5773,6 +5966,12 @@ target_link_libraries(avl_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(avl_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(avl_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5803,6 +6002,12 @@ target_link_libraries(bad_server_response_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bad_server_response_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(bad_server_response_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5830,6 +6035,12 @@ target_link_libraries(bin_decoder_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bin_decoder_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(bin_decoder_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5857,6 +6068,12 @@ target_link_libraries(bin_encoder_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bin_encoder_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(bin_encoder_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
@@ -5887,6 +6104,12 @@ target_link_libraries(buffer_list_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(buffer_list_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(buffer_list_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -5917,6 +6140,12 @@ target_link_libraries(channel_create_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(channel_create_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(channel_create_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
add_executable(check_epollexclusive
@@ -5943,6 +6172,12 @@ target_link_libraries(check_epollexclusive
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(check_epollexclusive PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(check_epollexclusive PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
if (gRPC_BUILD_TESTS)
add_executable(chttp2_hpack_encoder_test
@@ -5971,6 +6206,12 @@ target_link_libraries(chttp2_hpack_encoder_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(chttp2_hpack_encoder_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(chttp2_hpack_encoder_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6000,6 +6241,12 @@ target_link_libraries(chttp2_stream_map_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(chttp2_stream_map_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(chttp2_stream_map_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6029,6 +6276,12 @@ target_link_libraries(chttp2_varint_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(chttp2_varint_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(chttp2_varint_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6057,6 +6310,12 @@ target_link_libraries(cmdline_test
grpc_test_util
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(cmdline_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(cmdline_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6086,6 +6345,12 @@ target_link_libraries(combiner_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(combiner_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(combiner_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6115,6 +6380,12 @@ target_link_libraries(compression_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(compression_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(compression_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6144,6 +6415,12 @@ target_link_libraries(concurrent_connectivity_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(concurrent_connectivity_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(concurrent_connectivity_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6173,6 +6450,12 @@ target_link_libraries(connection_refused_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(connection_refused_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(connection_refused_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6200,6 +6483,12 @@ target_link_libraries(context_list_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(context_list_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(context_list_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6229,6 +6518,12 @@ target_link_libraries(dns_resolver_connectivity_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(dns_resolver_connectivity_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(dns_resolver_connectivity_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6258,6 +6553,12 @@ target_link_libraries(dns_resolver_cooldown_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(dns_resolver_cooldown_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(dns_resolver_cooldown_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6287,6 +6588,12 @@ target_link_libraries(dns_resolver_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(dns_resolver_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(dns_resolver_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -6317,6 +6624,12 @@ target_link_libraries(dualstack_socket_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(dualstack_socket_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(dualstack_socket_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6347,6 +6660,12 @@ target_link_libraries(endpoint_pair_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(endpoint_pair_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(endpoint_pair_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6376,6 +6695,12 @@ target_link_libraries(error_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(error_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(error_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
@@ -6406,36 +6731,11 @@ target_link_libraries(ev_epollex_linux_test
gpr
)
-endif()
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX)
-
-add_executable(ev_epollsig_linux_test
- test/core/iomgr/ev_epollsig_linux_test.cc
-)
-
-
-target_include_directories(ev_epollsig_linux_test
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
- PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
- PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
- PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
- PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
- PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
- PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
- PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
- PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
-)
-
-target_link_libraries(ev_epollsig_linux_test
- ${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
- grpc
- gpr_test_util
- gpr
-)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(ev_epollex_linux_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(ev_epollex_linux_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
endif()
endif (gRPC_BUILD_TESTS)
@@ -6467,6 +6767,12 @@ target_link_libraries(fake_resolver_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fake_resolver_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fake_resolver_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -6497,6 +6803,12 @@ target_link_libraries(fake_transport_security_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fake_transport_security_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fake_transport_security_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6528,6 +6840,12 @@ target_link_libraries(fd_conservation_posix_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fd_conservation_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fd_conservation_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6559,6 +6877,12 @@ target_link_libraries(fd_posix_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fd_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fd_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6589,6 +6913,12 @@ target_link_libraries(fling_client
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fling_client PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fling_client PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6618,6 +6948,12 @@ target_link_libraries(fling_server
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fling_server PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fling_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -6648,6 +6984,12 @@ target_link_libraries(fling_stream_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fling_stream_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fling_stream_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6679,6 +7021,12 @@ target_link_libraries(fling_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fling_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fling_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6708,6 +7056,12 @@ target_link_libraries(fork_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(fork_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(fork_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6739,6 +7093,12 @@ target_link_libraries(goaway_server_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(goaway_server_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(goaway_server_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6767,6 +7127,12 @@ target_link_libraries(gpr_cpu_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_cpu_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_cpu_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6794,6 +7160,12 @@ target_link_libraries(gpr_env_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_env_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_env_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6821,6 +7193,12 @@ target_link_libraries(gpr_host_port_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_host_port_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_host_port_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6848,6 +7226,12 @@ target_link_libraries(gpr_log_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_log_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_log_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6875,6 +7259,12 @@ target_link_libraries(gpr_manual_constructor_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_manual_constructor_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_manual_constructor_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6902,6 +7292,12 @@ target_link_libraries(gpr_mpscq_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_mpscq_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_mpscq_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6929,6 +7325,12 @@ target_link_libraries(gpr_spinlock_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_spinlock_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_spinlock_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6956,6 +7358,12 @@ target_link_libraries(gpr_string_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_string_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_string_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -6983,6 +7391,12 @@ target_link_libraries(gpr_sync_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_sync_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_sync_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7010,6 +7424,12 @@ target_link_libraries(gpr_thd_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_thd_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_thd_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7037,6 +7457,12 @@ target_link_libraries(gpr_time_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_time_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_time_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7064,6 +7490,12 @@ target_link_libraries(gpr_tls_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_tls_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_tls_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7091,6 +7523,12 @@ target_link_libraries(gpr_useful_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(gpr_useful_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(gpr_useful_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7120,6 +7558,12 @@ target_link_libraries(grpc_auth_context_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_auth_context_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_auth_context_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7149,6 +7593,12 @@ target_link_libraries(grpc_b64_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_b64_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_b64_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7178,6 +7628,12 @@ target_link_libraries(grpc_byte_buffer_reader_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_byte_buffer_reader_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_byte_buffer_reader_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7207,6 +7663,12 @@ target_link_libraries(grpc_channel_args_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_channel_args_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_channel_args_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7236,6 +7698,12 @@ target_link_libraries(grpc_channel_stack_builder_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_channel_stack_builder_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_channel_stack_builder_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7265,6 +7733,12 @@ target_link_libraries(grpc_channel_stack_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_channel_stack_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_channel_stack_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7294,6 +7768,12 @@ target_link_libraries(grpc_completion_queue_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_completion_queue_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_completion_queue_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7323,6 +7803,12 @@ target_link_libraries(grpc_completion_queue_threading_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_completion_queue_threading_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_completion_queue_threading_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
add_executable(grpc_create_jwt
@@ -7351,6 +7837,12 @@ target_link_libraries(grpc_create_jwt
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_create_jwt PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_create_jwt PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
if (gRPC_BUILD_TESTS)
add_executable(grpc_credentials_test
@@ -7379,6 +7871,12 @@ target_link_libraries(grpc_credentials_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_credentials_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_credentials_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7408,6 +7906,12 @@ target_link_libraries(grpc_fetch_oauth2
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_fetch_oauth2 PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_fetch_oauth2 PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7437,6 +7941,12 @@ target_link_libraries(grpc_ipv6_loopback_available_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_ipv6_loopback_available_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_ipv6_loopback_available_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -7467,6 +7977,12 @@ target_link_libraries(grpc_json_token_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_json_token_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_json_token_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7497,6 +8013,12 @@ target_link_libraries(grpc_jwt_verifier_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_jwt_verifier_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_jwt_verifier_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
add_executable(grpc_print_google_default_creds_token
@@ -7524,6 +8046,12 @@ target_link_libraries(grpc_print_google_default_creds_token
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_print_google_default_creds_token PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_print_google_default_creds_token PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
if (gRPC_BUILD_TESTS)
add_executable(grpc_security_connector_test
@@ -7552,6 +8080,12 @@ target_link_libraries(grpc_security_connector_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_security_connector_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_security_connector_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7581,6 +8115,12 @@ target_link_libraries(grpc_ssl_credentials_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_ssl_credentials_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_ssl_credentials_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
add_executable(grpc_verify_jwt
@@ -7608,15 +8148,21 @@ target_link_libraries(grpc_verify_jwt
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(grpc_verify_jwt PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(grpc_verify_jwt PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
-add_executable(handshake_client
+add_executable(handshake_client_ssl
test/core/handshake/client_ssl.cc
)
-target_include_directories(handshake_client
+target_include_directories(handshake_client_ssl
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -7629,7 +8175,7 @@ target_include_directories(handshake_client
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(handshake_client
+target_link_libraries(handshake_client_ssl
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
@@ -7638,18 +8184,24 @@ target_link_libraries(handshake_client
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(handshake_client_ssl PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(handshake_client_ssl PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
-add_executable(handshake_server
+add_executable(handshake_server_ssl
test/core/handshake/server_ssl.cc
test/core/handshake/server_ssl_common.cc
)
-target_include_directories(handshake_server
+target_include_directories(handshake_server_ssl
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -7662,7 +8214,7 @@ target_include_directories(handshake_server
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(handshake_server
+target_link_libraries(handshake_server_ssl
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
@@ -7671,6 +8223,12 @@ target_link_libraries(handshake_server
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(handshake_server_ssl PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(handshake_server_ssl PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7704,6 +8262,12 @@ target_link_libraries(handshake_server_with_readahead_handshaker
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(handshake_server_with_readahead_handshaker PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(handshake_server_with_readahead_handshaker PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7736,6 +8300,12 @@ target_link_libraries(handshake_verify_peer_options
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(handshake_verify_peer_options PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(handshake_verify_peer_options PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7764,6 +8334,12 @@ target_link_libraries(histogram_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(histogram_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(histogram_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7793,6 +8369,12 @@ target_link_libraries(hpack_parser_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(hpack_parser_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(hpack_parser_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7822,6 +8404,12 @@ target_link_libraries(hpack_table_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(hpack_table_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(hpack_table_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7851,6 +8439,12 @@ target_link_libraries(http_parser_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(http_parser_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(http_parser_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7880,6 +8474,12 @@ target_link_libraries(httpcli_format_request_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(httpcli_format_request_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(httpcli_format_request_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -7910,6 +8510,12 @@ target_link_libraries(httpcli_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(httpcli_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(httpcli_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7941,6 +8547,12 @@ target_link_libraries(httpscli_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(httpscli_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(httpscli_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -7971,6 +8583,12 @@ target_link_libraries(init_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(init_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(init_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8000,6 +8618,12 @@ target_link_libraries(inproc_callback_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(inproc_callback_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(inproc_callback_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8029,6 +8653,12 @@ target_link_libraries(invalid_call_argument_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(invalid_call_argument_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(invalid_call_argument_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8058,6 +8688,12 @@ target_link_libraries(json_rewrite
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(json_rewrite PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(json_rewrite PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8087,6 +8723,12 @@ target_link_libraries(json_rewrite_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(json_rewrite_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(json_rewrite_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8116,6 +8758,12 @@ target_link_libraries(json_stream_error_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(json_stream_error_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(json_stream_error_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8145,6 +8793,12 @@ target_link_libraries(json_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(json_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(json_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8174,6 +8828,12 @@ target_link_libraries(lame_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(lame_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(lame_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8203,15 +8863,21 @@ target_link_libraries(load_file_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(load_file_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(load_file_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(memory_profile_client
+add_executable(memory_usage_client
test/core/memory_usage/client.cc
)
-target_include_directories(memory_profile_client
+target_include_directories(memory_usage_client
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8224,7 +8890,7 @@ target_include_directories(memory_profile_client
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(memory_profile_client
+target_link_libraries(memory_usage_client
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8232,15 +8898,21 @@ target_link_libraries(memory_profile_client
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(memory_usage_client PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(memory_usage_client PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(memory_profile_server
+add_executable(memory_usage_server
test/core/memory_usage/server.cc
)
-target_include_directories(memory_profile_server
+target_include_directories(memory_usage_server
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8253,7 +8925,7 @@ target_include_directories(memory_profile_server
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(memory_profile_server
+target_link_libraries(memory_usage_server
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8261,16 +8933,22 @@ target_link_libraries(memory_profile_server
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(memory_usage_server PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(memory_usage_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_executable(memory_profile_test
+add_executable(memory_usage_test
test/core/memory_usage/memory_usage_test.cc
)
-target_include_directories(memory_profile_test
+target_include_directories(memory_usage_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8283,7 +8961,7 @@ target_include_directories(memory_profile_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(memory_profile_test
+target_link_libraries(memory_usage_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8291,6 +8969,12 @@ target_link_libraries(memory_profile_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(memory_usage_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(memory_usage_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8321,6 +9005,12 @@ target_link_libraries(message_compress_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(message_compress_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(message_compress_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8350,6 +9040,12 @@ target_link_libraries(minimal_stack_is_minimal_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(minimal_stack_is_minimal_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(minimal_stack_is_minimal_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8379,6 +9075,12 @@ target_link_libraries(multiple_server_queues_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(multiple_server_queues_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(multiple_server_queues_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8406,6 +9108,12 @@ target_link_libraries(murmur_hash_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(murmur_hash_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(murmur_hash_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8435,6 +9143,12 @@ target_link_libraries(no_server_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(no_server_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(no_server_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8464,6 +9178,12 @@ target_link_libraries(num_external_connectivity_watchers_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(num_external_connectivity_watchers_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(num_external_connectivity_watchers_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8493,6 +9213,12 @@ target_link_libraries(parse_address_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(parse_address_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(parse_address_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8522,16 +9248,22 @@ target_link_libraries(percent_encoding_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(percent_encoding_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(percent_encoding_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_executable(pollset_set_test
- test/core/iomgr/pollset_set_test.cc
+add_executable(resolve_address_posix_test
+ test/core/iomgr/resolve_address_posix_test.cc
)
-target_include_directories(pollset_set_test
+target_include_directories(resolve_address_posix_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8544,7 +9276,7 @@ target_include_directories(pollset_set_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(pollset_set_test
+target_link_libraries(resolve_address_posix_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8552,17 +9284,22 @@ target_link_libraries(pollset_set_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(resolve_address_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(resolve_address_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_executable(resolve_address_posix_test
- test/core/iomgr/resolve_address_posix_test.cc
+add_executable(resolve_address_using_ares_resolver_test
+ test/core/iomgr/resolve_address_test.cc
)
-target_include_directories(resolve_address_posix_test
+target_include_directories(resolve_address_using_ares_resolver_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8575,7 +9312,7 @@ target_include_directories(resolve_address_posix_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(resolve_address_posix_test
+target_link_libraries(resolve_address_using_ares_resolver_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8583,16 +9320,21 @@ target_link_libraries(resolve_address_posix_test
gpr
)
-endif()
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(resolve_address_using_ares_resolver_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(resolve_address_using_ares_resolver_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(resolve_address_test
+add_executable(resolve_address_using_native_resolver_test
test/core/iomgr/resolve_address_test.cc
)
-target_include_directories(resolve_address_test
+target_include_directories(resolve_address_using_native_resolver_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8605,7 +9347,7 @@ target_include_directories(resolve_address_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(resolve_address_test
+target_link_libraries(resolve_address_using_native_resolver_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8613,6 +9355,12 @@ target_link_libraries(resolve_address_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(resolve_address_using_native_resolver_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(resolve_address_using_native_resolver_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8642,6 +9390,12 @@ target_link_libraries(resource_quota_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(resource_quota_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(resource_quota_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8671,6 +9425,12 @@ target_link_libraries(secure_channel_create_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(secure_channel_create_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(secure_channel_create_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8700,6 +9460,12 @@ target_link_libraries(secure_endpoint_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(secure_endpoint_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(secure_endpoint_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8729,6 +9495,12 @@ target_link_libraries(sequential_connectivity_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(sequential_connectivity_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(sequential_connectivity_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8758,6 +9530,12 @@ target_link_libraries(server_chttp2_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(server_chttp2_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(server_chttp2_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8787,6 +9565,12 @@ target_link_libraries(server_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(server_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(server_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8816,6 +9600,12 @@ target_link_libraries(slice_buffer_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(slice_buffer_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(slice_buffer_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8845,6 +9635,12 @@ target_link_libraries(slice_string_helpers_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(slice_string_helpers_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(slice_string_helpers_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8874,6 +9670,12 @@ target_link_libraries(slice_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(slice_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(slice_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8903,6 +9705,12 @@ target_link_libraries(sockaddr_resolver_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(sockaddr_resolver_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(sockaddr_resolver_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8932,6 +9740,12 @@ target_link_libraries(sockaddr_utils_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(sockaddr_utils_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(sockaddr_utils_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -8962,6 +9776,12 @@ target_link_libraries(socket_utils_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(socket_utils_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(socket_utils_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -8993,6 +9813,12 @@ target_link_libraries(ssl_transport_security_test
grpc
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(ssl_transport_security_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(ssl_transport_security_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9023,6 +9849,12 @@ target_link_libraries(status_conversion_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(status_conversion_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(status_conversion_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9052,6 +9884,12 @@ target_link_libraries(stream_compression_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(stream_compression_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(stream_compression_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9081,6 +9919,12 @@ target_link_libraries(stream_owned_slice_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(stream_owned_slice_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(stream_owned_slice_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -9111,6 +9955,12 @@ target_link_libraries(tcp_client_posix_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(tcp_client_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(tcp_client_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9141,6 +9991,12 @@ target_link_libraries(tcp_client_uv_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(tcp_client_uv_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(tcp_client_uv_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -9171,6 +10027,12 @@ target_link_libraries(tcp_posix_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(tcp_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(tcp_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9202,6 +10064,12 @@ target_link_libraries(tcp_server_posix_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(tcp_server_posix_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(tcp_server_posix_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9232,6 +10100,12 @@ target_link_libraries(tcp_server_uv_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(tcp_server_uv_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(tcp_server_uv_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9261,6 +10135,12 @@ target_link_libraries(time_averaged_stats_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(time_averaged_stats_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(time_averaged_stats_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9290,6 +10170,12 @@ target_link_libraries(timeout_encoding_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(timeout_encoding_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(timeout_encoding_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9319,6 +10205,12 @@ target_link_libraries(timer_heap_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(timer_heap_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(timer_heap_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9348,6 +10240,12 @@ target_link_libraries(timer_list_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(timer_list_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(timer_list_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9377,6 +10275,12 @@ target_link_libraries(transport_connectivity_state_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(transport_connectivity_state_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(transport_connectivity_state_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9406,6 +10310,12 @@ target_link_libraries(transport_metadata_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(transport_metadata_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(transport_metadata_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -9436,6 +10346,12 @@ target_link_libraries(transport_security_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(transport_security_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(transport_security_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9467,6 +10383,12 @@ target_link_libraries(udp_server_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(udp_server_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(udp_server_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9497,6 +10419,12 @@ target_link_libraries(uri_parser_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(uri_parser_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(uri_parser_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -9527,6 +10455,12 @@ target_link_libraries(wakeup_fd_cv_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(wakeup_fd_cv_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(wakeup_fd_cv_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9568,6 +10502,7 @@ target_link_libraries(alarm_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9605,6 +10540,7 @@ target_link_libraries(alts_counter_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9643,6 +10579,7 @@ target_link_libraries(alts_crypt_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9680,6 +10617,7 @@ target_link_libraries(alts_crypter_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9717,6 +10655,7 @@ target_link_libraries(alts_frame_handler_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9755,6 +10694,7 @@ target_link_libraries(alts_frame_protector_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9792,6 +10732,7 @@ target_link_libraries(alts_grpc_record_protocol_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9829,6 +10770,7 @@ target_link_libraries(alts_handshaker_client_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9866,6 +10808,7 @@ target_link_libraries(alts_handshaker_service_api_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9903,6 +10846,7 @@ target_link_libraries(alts_iovec_record_protocol_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9939,6 +10883,7 @@ target_link_libraries(alts_security_connector_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -9976,6 +10921,7 @@ target_link_libraries(alts_tsi_handshaker_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10013,6 +10959,7 @@ target_link_libraries(alts_tsi_utils_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10050,6 +10997,7 @@ target_link_libraries(alts_zero_copy_grpc_protector_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10090,6 +11038,7 @@ target_link_libraries(async_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10130,6 +11079,7 @@ target_link_libraries(auth_property_iterator_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10168,6 +11118,7 @@ target_link_libraries(backoff_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10208,6 +11159,7 @@ target_link_libraries(bdp_estimator_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -10252,6 +11204,7 @@ target_link_libraries(bm_arena
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10297,6 +11250,7 @@ target_link_libraries(bm_call_create
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10342,6 +11296,7 @@ target_link_libraries(bm_channel
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10387,6 +11342,7 @@ target_link_libraries(bm_chttp2_hpack
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10432,6 +11388,7 @@ target_link_libraries(bm_chttp2_transport
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10477,6 +11434,7 @@ target_link_libraries(bm_closure
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10522,6 +11480,7 @@ target_link_libraries(bm_cq
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10567,6 +11526,7 @@ target_link_libraries(bm_cq_multiple_threads
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10612,6 +11572,7 @@ target_link_libraries(bm_error
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10657,6 +11618,7 @@ target_link_libraries(bm_fullstack_streaming_ping_pong
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10702,6 +11664,7 @@ target_link_libraries(bm_fullstack_streaming_pump
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10747,6 +11710,7 @@ target_link_libraries(bm_fullstack_trickle
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10792,6 +11756,7 @@ target_link_libraries(bm_fullstack_unary_ping_pong
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10837,6 +11802,7 @@ target_link_libraries(bm_metadata
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10882,6 +11848,7 @@ target_link_libraries(bm_pollset
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10921,6 +11888,7 @@ target_link_libraries(byte_stream_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10958,6 +11926,7 @@ target_link_libraries(channel_arguments_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -10995,6 +11964,7 @@ target_link_libraries(channel_filter_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11042,6 +12012,7 @@ target_link_libraries(channel_trace_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11082,6 +12053,7 @@ target_link_libraries(channelz_registry_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11130,6 +12102,7 @@ target_link_libraries(channelz_service_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11177,6 +12150,7 @@ target_link_libraries(channelz_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11213,6 +12187,7 @@ target_link_libraries(check_gcp_environment_linux_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11249,6 +12224,7 @@ target_link_libraries(check_gcp_environment_windows_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11287,6 +12263,7 @@ target_link_libraries(chttp2_settings_timeout_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11328,6 +12305,48 @@ target_link_libraries(cli_call_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(client_callback_end2end_test
+ test/cpp/end2end/client_callback_end2end_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(client_callback_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(client_callback_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11375,6 +12394,7 @@ target_link_libraries(client_channel_stress_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -11416,6 +12436,7 @@ target_link_libraries(client_crash_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11457,6 +12478,49 @@ target_link_libraries(client_crash_test_server
${_gRPC_GFLAGS_LIBRARIES}
)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(client_interceptors_end2end_test
+ test/cpp/end2end/client_interceptors_end2end_test.cc
+ test/cpp/end2end/interceptors_util.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(client_interceptors_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(client_interceptors_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11497,6 +12561,7 @@ target_link_libraries(client_lb_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11584,6 +12649,7 @@ target_link_libraries(codegen_test_full
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11671,6 +12737,7 @@ target_link_libraries(codegen_test_minimal
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11708,6 +12775,7 @@ target_link_libraries(credentials_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11747,6 +12815,7 @@ target_link_libraries(cxx_byte_buffer_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11786,6 +12855,7 @@ target_link_libraries(cxx_slice_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11822,6 +12892,7 @@ target_link_libraries(cxx_string_ref_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11861,11 +12932,13 @@ target_link_libraries(cxx_time_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(end2end_test
test/cpp/end2end/end2end_test.cc
+ test/cpp/end2end/interceptors_util.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
@@ -11901,6 +12974,7 @@ target_link_libraries(end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11944,6 +13018,7 @@ target_link_libraries(error_details_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -11984,6 +13059,7 @@ target_link_libraries(exception_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12024,6 +13100,7 @@ target_link_libraries(filter_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12064,6 +13141,7 @@ target_link_libraries(generic_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12108,6 +13186,7 @@ target_link_libraries(golden_file_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12144,6 +13223,7 @@ target_link_libraries(grpc_alts_credentials_options_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12184,6 +13264,7 @@ target_link_libraries(grpc_cli
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_CODEGEN)
@@ -12214,6 +13295,7 @@ target_link_libraries(grpc_cpp_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_cpp_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12252,6 +13334,7 @@ target_link_libraries(grpc_csharp_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_csharp_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12298,6 +13381,7 @@ target_link_libraries(grpc_linux_system_roots_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_CODEGEN)
@@ -12328,6 +13412,7 @@ target_link_libraries(grpc_node_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_node_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12366,6 +13451,7 @@ target_link_libraries(grpc_objective_c_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_objective_c_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12404,6 +13490,7 @@ target_link_libraries(grpc_php_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_php_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12442,6 +13529,7 @@ target_link_libraries(grpc_python_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_python_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12480,6 +13568,7 @@ target_link_libraries(grpc_ruby_plugin
)
+
if (gRPC_INSTALL)
install(TARGETS grpc_ruby_plugin EXPORT gRPCTargets
RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
@@ -12545,6 +13634,7 @@ target_link_libraries(grpc_tool_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12590,6 +13680,7 @@ target_link_libraries(grpclb_api_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12637,6 +13728,7 @@ target_link_libraries(grpclb_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12676,6 +13768,7 @@ target_link_libraries(h2_ssl_cert_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12715,6 +13808,7 @@ target_link_libraries(h2_ssl_session_reuse_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12755,6 +13849,7 @@ target_link_libraries(health_service_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -12795,6 +13890,7 @@ target_link_libraries(http2_client
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12836,6 +13932,7 @@ target_link_libraries(hybrid_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12875,6 +13972,7 @@ target_link_libraries(inlined_vector_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -12919,6 +14017,7 @@ target_link_libraries(inproc_sync_unary_ping_pong_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -12963,6 +14062,7 @@ target_link_libraries(interop_client
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13008,6 +14108,7 @@ target_link_libraries(interop_server
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13049,6 +14150,7 @@ target_link_libraries(interop_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13092,6 +14194,7 @@ target_link_libraries(json_run_localhost
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13132,6 +14235,7 @@ target_link_libraries(memory_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13177,6 +14281,7 @@ target_link_libraries(metrics_client
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13217,6 +14322,7 @@ target_link_libraries(mock_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13257,6 +14363,7 @@ target_link_libraries(nonblocking_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13292,6 +14399,7 @@ target_link_libraries(noop-benchmark
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13331,6 +14439,7 @@ target_link_libraries(orphanable_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13373,6 +14482,7 @@ target_link_libraries(proto_server_reflection_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13409,6 +14519,7 @@ target_link_libraries(proto_utils_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -13452,6 +14563,7 @@ target_link_libraries(qps_interarrival_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13496,6 +14608,7 @@ target_link_libraries(qps_json_driver
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -13540,6 +14653,7 @@ target_link_libraries(qps_openloop_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13584,6 +14698,7 @@ target_link_libraries(qps_worker
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13624,6 +14739,7 @@ target_link_libraries(raw_end2end_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13686,6 +14802,7 @@ target_link_libraries(reconnect_interop_client
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13750,6 +14867,7 @@ target_link_libraries(reconnect_interop_server
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13789,6 +14907,7 @@ target_link_libraries(ref_counted_ptr_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13828,6 +14947,7 @@ target_link_libraries(ref_counted_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13866,6 +14986,7 @@ target_link_libraries(retry_throttle_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13906,6 +15027,7 @@ target_link_libraries(secure_auth_context_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -13950,6 +15072,7 @@ target_link_libraries(secure_sync_unary_ping_pong_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -13991,6 +15114,7 @@ target_link_libraries(server_builder_plugin_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14045,6 +15169,7 @@ target_link_libraries(server_builder_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_POSIX)
@@ -14100,6 +15225,7 @@ target_link_libraries(server_builder_with_socket_mutator_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14140,6 +15266,7 @@ target_link_libraries(server_context_test_spouse_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -14181,6 +15308,7 @@ target_link_libraries(server_crash_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14222,6 +15350,7 @@ target_link_libraries(server_crash_test_client
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14262,6 +15391,49 @@ target_link_libraries(server_early_return_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(server_interceptors_end2end_test
+ test/cpp/end2end/interceptors_util.cc
+ test/cpp/end2end/server_interceptors_end2end_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(server_interceptors_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(server_interceptors_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14316,6 +15488,7 @@ target_link_libraries(server_request_call_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14356,6 +15529,7 @@ target_link_libraries(shutdown_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14394,6 +15568,7 @@ target_link_libraries(slice_hash_table_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14432,6 +15607,7 @@ target_link_libraries(slice_weak_hash_table_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14471,6 +15647,7 @@ target_link_libraries(stats_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14506,6 +15683,7 @@ target_link_libraries(status_metadata_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14541,6 +15719,7 @@ target_link_libraries(status_util_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -14582,6 +15761,7 @@ target_link_libraries(streaming_throughput_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14655,6 +15835,7 @@ target_link_libraries(stress_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14693,6 +15874,7 @@ target_link_libraries(thread_manager_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14733,6 +15915,7 @@ target_link_libraries(thread_stress_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14773,6 +15956,7 @@ target_link_libraries(transport_pid_controller_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14810,6 +15994,7 @@ target_link_libraries(transport_security_common_api_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -14851,6 +16036,7 @@ target_link_libraries(writes_per_rpc_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -14879,6 +16065,7 @@ target_link_libraries(public_headers_must_be_c89
gpr
)
+
endif (gRPC_BUILD_TESTS)
add_executable(gen_hpack_tables
@@ -14906,6 +16093,7 @@ target_link_libraries(gen_hpack_tables
)
+
add_executable(gen_legal_metadata_characters
tools/codegen/core/gen_legal_metadata_characters.cc
)
@@ -14929,6 +16117,7 @@ target_link_libraries(gen_legal_metadata_characters
)
+
add_executable(gen_percent_encoding_tables
tools/codegen/core/gen_percent_encoding_tables.cc
)
@@ -14951,6 +16140,7 @@ target_link_libraries(gen_percent_encoding_tables
${_gRPC_ALLTARGETS_LIBRARIES}
)
+
if (gRPC_BUILD_TESTS)
add_executable(badreq_bad_client_test
@@ -14981,6 +16171,12 @@ target_link_libraries(badreq_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(badreq_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(badreq_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15012,6 +16208,12 @@ target_link_libraries(connection_prefix_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(connection_prefix_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(connection_prefix_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15043,6 +16245,12 @@ target_link_libraries(duplicate_header_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(duplicate_header_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(duplicate_header_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15074,6 +16282,12 @@ target_link_libraries(head_of_line_blocking_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(head_of_line_blocking_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(head_of_line_blocking_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15105,6 +16319,12 @@ target_link_libraries(headers_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(headers_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(headers_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15136,6 +16356,12 @@ target_link_libraries(initial_settings_frame_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(initial_settings_frame_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(initial_settings_frame_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15167,6 +16393,12 @@ target_link_libraries(large_metadata_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(large_metadata_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(large_metadata_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15198,6 +16430,12 @@ target_link_libraries(server_registered_method_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(server_registered_method_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(server_registered_method_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15229,6 +16467,12 @@ target_link_libraries(simple_request_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(simple_request_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(simple_request_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15260,6 +16504,12 @@ target_link_libraries(unknown_frame_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(unknown_frame_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(unknown_frame_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15291,6 +16541,12 @@ target_link_libraries(window_overflow_bad_client_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(window_overflow_bad_client_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(window_overflow_bad_client_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -15322,6 +16578,12 @@ target_link_libraries(bad_ssl_cert_server
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bad_ssl_cert_server PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(bad_ssl_cert_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15353,6 +16615,12 @@ target_link_libraries(bad_ssl_cert_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(bad_ssl_cert_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(bad_ssl_cert_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15384,6 +16652,12 @@ target_link_libraries(h2_census_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_census_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_census_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15414,6 +16688,12 @@ target_link_libraries(h2_compress_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_compress_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_compress_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15444,6 +16724,12 @@ target_link_libraries(h2_fakesec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_fakesec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_fakesec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -15475,6 +16761,12 @@ target_link_libraries(h2_fd_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_fd_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_fd_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15506,6 +16798,12 @@ target_link_libraries(h2_full_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
@@ -15537,6 +16835,12 @@ target_link_libraries(h2_full+pipe_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+pipe_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+pipe_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15568,6 +16872,12 @@ target_link_libraries(h2_full+trace_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+trace_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+trace_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15598,6 +16908,12 @@ target_link_libraries(h2_full+workarounds_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+workarounds_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+workarounds_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15628,6 +16944,12 @@ target_link_libraries(h2_http_proxy_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_http_proxy_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_http_proxy_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -15659,6 +16981,12 @@ target_link_libraries(h2_local_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_local_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_local_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15690,6 +17018,12 @@ target_link_libraries(h2_oauth2_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_oauth2_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_oauth2_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15720,6 +17054,12 @@ target_link_libraries(h2_proxy_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_proxy_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_proxy_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15750,6 +17090,12 @@ target_link_libraries(h2_sockpair_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15780,6 +17126,12 @@ target_link_libraries(h2_sockpair+trace_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair+trace_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair+trace_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15810,6 +17162,12 @@ target_link_libraries(h2_sockpair_1byte_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair_1byte_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair_1byte_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15840,6 +17198,12 @@ target_link_libraries(h2_ssl_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_ssl_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_ssl_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15870,6 +17234,12 @@ target_link_libraries(h2_ssl_proxy_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_ssl_proxy_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_ssl_proxy_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -15901,6 +17271,12 @@ target_link_libraries(h2_uds_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_uds_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_uds_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15932,6 +17308,12 @@ target_link_libraries(inproc_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(inproc_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(inproc_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15962,6 +17344,12 @@ target_link_libraries(h2_census_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_census_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_census_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -15992,6 +17380,12 @@ target_link_libraries(h2_compress_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_compress_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_compress_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -16023,6 +17417,12 @@ target_link_libraries(h2_fd_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_fd_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_fd_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16054,6 +17454,12 @@ target_link_libraries(h2_full_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
@@ -16085,6 +17491,12 @@ target_link_libraries(h2_full+pipe_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+pipe_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+pipe_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16116,6 +17528,12 @@ target_link_libraries(h2_full+trace_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+trace_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+trace_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16146,6 +17564,12 @@ target_link_libraries(h2_full+workarounds_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_full+workarounds_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_full+workarounds_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16176,6 +17600,12 @@ target_link_libraries(h2_http_proxy_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_http_proxy_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_http_proxy_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16206,6 +17636,12 @@ target_link_libraries(h2_proxy_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_proxy_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_proxy_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16236,6 +17672,12 @@ target_link_libraries(h2_sockpair_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16266,6 +17708,12 @@ target_link_libraries(h2_sockpair+trace_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair+trace_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair+trace_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16296,6 +17744,12 @@ target_link_libraries(h2_sockpair_1byte_nosec_test
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_sockpair_1byte_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_sockpair_1byte_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -16327,37 +17781,13 @@ target_link_libraries(h2_uds_nosec_test
gpr
)
-endif()
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
-add_executable(inproc_nosec_test
- test/core/end2end/fixtures/inproc.cc
-)
-
-
-target_include_directories(inproc_nosec_test
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
- PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
- PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
- PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
- PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
- PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
- PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
- PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
- PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
-)
-
-target_link_libraries(inproc_nosec_test
- ${_gRPC_ALLTARGETS_LIBRARIES}
- end2end_nosec_tests
- grpc_test_util_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
-)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(h2_uds_nosec_test PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(h2_uds_nosec_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16399,6 +17829,7 @@ target_link_libraries(resolver_component_test_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16440,6 +17871,7 @@ target_link_libraries(resolver_component_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -16482,6 +17914,7 @@ target_link_libraries(resolver_component_tests_runner_invoker_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16525,6 +17958,7 @@ target_link_libraries(resolver_component_tests_runner_invoker
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16567,6 +18001,7 @@ target_link_libraries(address_sorting_test_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16608,6 +18043,7 @@ target_link_libraries(address_sorting_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16649,6 +18085,7 @@ target_link_libraries(cancel_ares_query_test
${_gRPC_GFLAGS_LIBRARIES}
)
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16679,6 +18116,12 @@ target_link_libraries(alts_credentials_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(alts_credentials_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(alts_credentials_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16709,6 +18152,12 @@ target_link_libraries(api_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(api_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(api_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16739,6 +18188,12 @@ target_link_libraries(client_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(client_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(client_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16769,6 +18224,12 @@ target_link_libraries(hpack_parser_fuzzer_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(hpack_parser_fuzzer_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(hpack_parser_fuzzer_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16799,6 +18260,12 @@ target_link_libraries(http_request_fuzzer_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(http_request_fuzzer_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(http_request_fuzzer_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16829,6 +18296,12 @@ target_link_libraries(http_response_fuzzer_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(http_response_fuzzer_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(http_response_fuzzer_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16859,6 +18332,12 @@ target_link_libraries(json_fuzzer_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(json_fuzzer_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(json_fuzzer_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16889,6 +18368,12 @@ target_link_libraries(nanopb_fuzzer_response_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(nanopb_fuzzer_response_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(nanopb_fuzzer_response_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16919,6 +18404,12 @@ target_link_libraries(nanopb_fuzzer_serverlist_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(nanopb_fuzzer_serverlist_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(nanopb_fuzzer_serverlist_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16949,6 +18440,12 @@ target_link_libraries(percent_decode_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(percent_decode_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(percent_decode_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -16979,6 +18476,12 @@ target_link_libraries(percent_encode_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(percent_encode_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(percent_encode_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -17009,6 +18512,12 @@ target_link_libraries(server_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(server_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(server_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -17039,6 +18548,12 @@ target_link_libraries(ssl_server_fuzzer_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(ssl_server_fuzzer_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(ssl_server_fuzzer_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
@@ -17069,6 +18584,12 @@ target_link_libraries(uri_fuzzer_test_one_entry
gpr
)
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(uri_fuzzer_test_one_entry PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(uri_fuzzer_test_one_entry PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ endif()
+
endif (gRPC_BUILD_TESTS)
diff --git a/Makefile b/Makefile
index a4755683f0..6dc9fe6ed1 100644
--- a/Makefile
+++ b/Makefile
@@ -352,6 +352,7 @@ CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
CXXFLAGS += -stdlib=libc++
endif
+CXXFLAGS += -Wnon-virtual-dtor
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
COREFLAGS += -fno-rtti -fno-exceptions
LDFLAGS += -g
@@ -436,9 +437,9 @@ E = @echo
Q = @
endif
-CORE_VERSION = 6.0.0-dev
-CPP_VERSION = 1.15.0-dev
-CSHARP_VERSION = 1.15.0-dev
+CORE_VERSION = 7.0.0-dev
+CPP_VERSION = 1.17.0-dev
+CSHARP_VERSION = 1.17.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -486,7 +487,7 @@ SHARED_EXT_CORE = dll
SHARED_EXT_CPP = dll
SHARED_EXT_CSHARP = dll
SHARED_PREFIX =
-SHARED_VERSION_CORE = -6
+SHARED_VERSION_CORE = -7
SHARED_VERSION_CPP = -1
SHARED_VERSION_CSHARP = -1
else ifeq ($(SYSTEM),Darwin)
@@ -791,7 +792,7 @@ PC_DESCRIPTION = high performance general RPC framework without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
-PC_LIB = -lgrpc
+PC_LIB = -lgrpc_unsecure
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
PROTOBUF_PKG_CONFIG = false
@@ -862,7 +863,7 @@ PC_DESCRIPTION = C++ wrapper for gRPC without SSL
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
-PC_LIB = -lgrpc++
+PC_LIB = -lgrpc++_unsecure
GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)
ifeq ($(MAKECMDGOALS),clean)
@@ -998,7 +999,6 @@ dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
error_test: $(BINDIR)/$(CONFIG)/error_test
ev_epollex_linux_test: $(BINDIR)/$(CONFIG)/ev_epollex_linux_test
-ev_epollsig_linux_test: $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test
fake_resolver_test: $(BINDIR)/$(CONFIG)/fake_resolver_test
fake_transport_security_test: $(BINDIR)/$(CONFIG)/fake_transport_security_test
fd_conservation_posix_test: $(BINDIR)/$(CONFIG)/fd_conservation_posix_test
@@ -1040,8 +1040,8 @@ grpc_print_google_default_creds_token: $(BINDIR)/$(CONFIG)/grpc_print_google_def
grpc_security_connector_test: $(BINDIR)/$(CONFIG)/grpc_security_connector_test
grpc_ssl_credentials_test: $(BINDIR)/$(CONFIG)/grpc_ssl_credentials_test
grpc_verify_jwt: $(BINDIR)/$(CONFIG)/grpc_verify_jwt
-handshake_client: $(BINDIR)/$(CONFIG)/handshake_client
-handshake_server: $(BINDIR)/$(CONFIG)/handshake_server
+handshake_client_ssl: $(BINDIR)/$(CONFIG)/handshake_client_ssl
+handshake_server_ssl: $(BINDIR)/$(CONFIG)/handshake_server_ssl
handshake_server_with_readahead_handshaker: $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker
handshake_verify_peer_options: $(BINDIR)/$(CONFIG)/handshake_verify_peer_options
histogram_test: $(BINDIR)/$(CONFIG)/histogram_test
@@ -1065,9 +1065,9 @@ json_test: $(BINDIR)/$(CONFIG)/json_test
lame_client_test: $(BINDIR)/$(CONFIG)/lame_client_test
load_file_test: $(BINDIR)/$(CONFIG)/load_file_test
low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
-memory_profile_client: $(BINDIR)/$(CONFIG)/memory_profile_client
-memory_profile_server: $(BINDIR)/$(CONFIG)/memory_profile_server
-memory_profile_test: $(BINDIR)/$(CONFIG)/memory_profile_test
+memory_usage_client: $(BINDIR)/$(CONFIG)/memory_usage_client
+memory_usage_server: $(BINDIR)/$(CONFIG)/memory_usage_server
+memory_usage_test: $(BINDIR)/$(CONFIG)/memory_usage_test
message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
minimal_stack_is_minimal_test: $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test
multiple_server_queues_test: $(BINDIR)/$(CONFIG)/multiple_server_queues_test
@@ -1080,9 +1080,9 @@ parse_address_test: $(BINDIR)/$(CONFIG)/parse_address_test
percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer
percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer
percent_encoding_test: $(BINDIR)/$(CONFIG)/percent_encoding_test
-pollset_set_test: $(BINDIR)/$(CONFIG)/pollset_set_test
resolve_address_posix_test: $(BINDIR)/$(CONFIG)/resolve_address_posix_test
-resolve_address_test: $(BINDIR)/$(CONFIG)/resolve_address_test
+resolve_address_using_ares_resolver_test: $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test
+resolve_address_using_native_resolver_test: $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test
resource_quota_test: $(BINDIR)/$(CONFIG)/resource_quota_test
secure_channel_create_test: $(BINDIR)/$(CONFIG)/secure_channel_create_test
secure_endpoint_test: $(BINDIR)/$(CONFIG)/secure_endpoint_test
@@ -1161,9 +1161,11 @@ check_gcp_environment_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linu
check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test
cli_call_test: $(BINDIR)/$(CONFIG)/cli_call_test
+client_callback_end2end_test: $(BINDIR)/$(CONFIG)/client_callback_end2end_test
client_channel_stress_test: $(BINDIR)/$(CONFIG)/client_channel_stress_test
client_crash_test: $(BINDIR)/$(CONFIG)/client_crash_test
client_crash_test_server: $(BINDIR)/$(CONFIG)/client_crash_test_server
+client_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test
client_lb_end2end_test: $(BINDIR)/$(CONFIG)/client_lb_end2end_test
codegen_test_full: $(BINDIR)/$(CONFIG)/codegen_test_full
codegen_test_minimal: $(BINDIR)/$(CONFIG)/codegen_test_minimal
@@ -1229,6 +1231,7 @@ server_context_test_spouse_test: $(BINDIR)/$(CONFIG)/server_context_test_spouse_
server_crash_test: $(BINDIR)/$(CONFIG)/server_crash_test
server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
+server_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
@@ -1343,7 +1346,6 @@ h2_sockpair_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_nosec_test
h2_sockpair+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test
h2_sockpair_1byte_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test
h2_uds_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds_nosec_test
-inproc_nosec_test: $(BINDIR)/$(CONFIG)/inproc_nosec_test
resolver_component_test_unsecure: $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure
resolver_component_test: $(BINDIR)/$(CONFIG)/resolver_component_test
resolver_component_tests_runner_invoker_unsecure: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure
@@ -1454,7 +1456,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/endpoint_pair_test \
$(BINDIR)/$(CONFIG)/error_test \
$(BINDIR)/$(CONFIG)/ev_epollex_linux_test \
- $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test \
$(BINDIR)/$(CONFIG)/fake_resolver_test \
$(BINDIR)/$(CONFIG)/fake_transport_security_test \
$(BINDIR)/$(CONFIG)/fd_conservation_posix_test \
@@ -1493,8 +1494,8 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test \
$(BINDIR)/$(CONFIG)/grpc_security_connector_test \
$(BINDIR)/$(CONFIG)/grpc_ssl_credentials_test \
- $(BINDIR)/$(CONFIG)/handshake_client \
- $(BINDIR)/$(CONFIG)/handshake_server \
+ $(BINDIR)/$(CONFIG)/handshake_client_ssl \
+ $(BINDIR)/$(CONFIG)/handshake_server_ssl \
$(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker \
$(BINDIR)/$(CONFIG)/handshake_verify_peer_options \
$(BINDIR)/$(CONFIG)/histogram_test \
@@ -1513,9 +1514,9 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/json_test \
$(BINDIR)/$(CONFIG)/lame_client_test \
$(BINDIR)/$(CONFIG)/load_file_test \
- $(BINDIR)/$(CONFIG)/memory_profile_client \
- $(BINDIR)/$(CONFIG)/memory_profile_server \
- $(BINDIR)/$(CONFIG)/memory_profile_test \
+ $(BINDIR)/$(CONFIG)/memory_usage_client \
+ $(BINDIR)/$(CONFIG)/memory_usage_server \
+ $(BINDIR)/$(CONFIG)/memory_usage_test \
$(BINDIR)/$(CONFIG)/message_compress_test \
$(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test \
$(BINDIR)/$(CONFIG)/multiple_server_queues_test \
@@ -1524,9 +1525,9 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test \
$(BINDIR)/$(CONFIG)/parse_address_test \
$(BINDIR)/$(CONFIG)/percent_encoding_test \
- $(BINDIR)/$(CONFIG)/pollset_set_test \
$(BINDIR)/$(CONFIG)/resolve_address_posix_test \
- $(BINDIR)/$(CONFIG)/resolve_address_test \
+ $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test \
+ $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test \
$(BINDIR)/$(CONFIG)/resource_quota_test \
$(BINDIR)/$(CONFIG)/secure_channel_create_test \
$(BINDIR)/$(CONFIG)/secure_endpoint_test \
@@ -1604,7 +1605,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test \
$(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uds_nosec_test \
- $(BINDIR)/$(CONFIG)/inproc_nosec_test \
$(BINDIR)/$(CONFIG)/alts_credentials_fuzzer_one_entry \
$(BINDIR)/$(CONFIG)/api_fuzzer_one_entry \
$(BINDIR)/$(CONFIG)/client_fuzzer_one_entry \
@@ -1667,9 +1667,11 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
$(BINDIR)/$(CONFIG)/cli_call_test \
+ $(BINDIR)/$(CONFIG)/client_callback_end2end_test \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
+ $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/client_lb_end2end_test \
$(BINDIR)/$(CONFIG)/codegen_test_full \
$(BINDIR)/$(CONFIG)/codegen_test_minimal \
@@ -1728,6 +1730,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_crash_test \
$(BINDIR)/$(CONFIG)/server_crash_test_client \
$(BINDIR)/$(CONFIG)/server_early_return_test \
+ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@@ -1847,9 +1850,11 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
$(BINDIR)/$(CONFIG)/cli_call_test \
+ $(BINDIR)/$(CONFIG)/client_callback_end2end_test \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
+ $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/client_lb_end2end_test \
$(BINDIR)/$(CONFIG)/codegen_test_full \
$(BINDIR)/$(CONFIG)/codegen_test_minimal \
@@ -1908,6 +1913,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_crash_test \
$(BINDIR)/$(CONFIG)/server_crash_test_client \
$(BINDIR)/$(CONFIG)/server_early_return_test \
+ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
@@ -1990,8 +1996,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/error_test || ( echo test error_test failed ; exit 1 )
$(E) "[RUN] Testing ev_epollex_linux_test"
$(Q) $(BINDIR)/$(CONFIG)/ev_epollex_linux_test || ( echo test ev_epollex_linux_test failed ; exit 1 )
- $(E) "[RUN] Testing ev_epollsig_linux_test"
- $(Q) $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test || ( echo test ev_epollsig_linux_test failed ; exit 1 )
$(E) "[RUN] Testing fake_resolver_test"
$(Q) $(BINDIR)/$(CONFIG)/fake_resolver_test || ( echo test fake_resolver_test failed ; exit 1 )
$(E) "[RUN] Testing fake_transport_security_test"
@@ -2062,10 +2066,10 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/grpc_security_connector_test || ( echo test grpc_security_connector_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_ssl_credentials_test"
$(Q) $(BINDIR)/$(CONFIG)/grpc_ssl_credentials_test || ( echo test grpc_ssl_credentials_test failed ; exit 1 )
- $(E) "[RUN] Testing handshake_client"
- $(Q) $(BINDIR)/$(CONFIG)/handshake_client || ( echo test handshake_client failed ; exit 1 )
- $(E) "[RUN] Testing handshake_server"
- $(Q) $(BINDIR)/$(CONFIG)/handshake_server || ( echo test handshake_server failed ; exit 1 )
+ $(E) "[RUN] Testing handshake_client_ssl"
+ $(Q) $(BINDIR)/$(CONFIG)/handshake_client_ssl || ( echo test handshake_client_ssl failed ; exit 1 )
+ $(E) "[RUN] Testing handshake_server_ssl"
+ $(Q) $(BINDIR)/$(CONFIG)/handshake_server_ssl || ( echo test handshake_server_ssl failed ; exit 1 )
$(E) "[RUN] Testing handshake_server_with_readahead_handshaker"
$(Q) $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker || ( echo test handshake_server_with_readahead_handshaker failed ; exit 1 )
$(E) "[RUN] Testing handshake_verify_peer_options"
@@ -2100,8 +2104,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/lame_client_test || ( echo test lame_client_test failed ; exit 1 )
$(E) "[RUN] Testing load_file_test"
$(Q) $(BINDIR)/$(CONFIG)/load_file_test || ( echo test load_file_test failed ; exit 1 )
- $(E) "[RUN] Testing memory_profile_test"
- $(Q) $(BINDIR)/$(CONFIG)/memory_profile_test || ( echo test memory_profile_test failed ; exit 1 )
+ $(E) "[RUN] Testing memory_usage_test"
+ $(Q) $(BINDIR)/$(CONFIG)/memory_usage_test || ( echo test memory_usage_test failed ; exit 1 )
$(E) "[RUN] Testing message_compress_test"
$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
$(E) "[RUN] Testing minimal_stack_is_minimal_test"
@@ -2118,12 +2122,12 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/parse_address_test || ( echo test parse_address_test failed ; exit 1 )
$(E) "[RUN] Testing percent_encoding_test"
$(Q) $(BINDIR)/$(CONFIG)/percent_encoding_test || ( echo test percent_encoding_test failed ; exit 1 )
- $(E) "[RUN] Testing pollset_set_test"
- $(Q) $(BINDIR)/$(CONFIG)/pollset_set_test || ( echo test pollset_set_test failed ; exit 1 )
$(E) "[RUN] Testing resolve_address_posix_test"
$(Q) $(BINDIR)/$(CONFIG)/resolve_address_posix_test || ( echo test resolve_address_posix_test failed ; exit 1 )
- $(E) "[RUN] Testing resolve_address_test"
- $(Q) $(BINDIR)/$(CONFIG)/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 )
+ $(E) "[RUN] Testing resolve_address_using_ares_resolver_test"
+ $(Q) $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test || ( echo test resolve_address_using_ares_resolver_test failed ; exit 1 )
+ $(E) "[RUN] Testing resolve_address_using_native_resolver_test"
+ $(Q) $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test || ( echo test resolve_address_using_native_resolver_test failed ; exit 1 )
$(E) "[RUN] Testing resource_quota_test"
$(Q) $(BINDIR)/$(CONFIG)/resource_quota_test || ( echo test resource_quota_test failed ; exit 1 )
$(E) "[RUN] Testing secure_channel_create_test"
@@ -2306,10 +2310,14 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test || ( echo test chttp2_settings_timeout_test failed ; exit 1 )
$(E) "[RUN] Testing cli_call_test"
$(Q) $(BINDIR)/$(CONFIG)/cli_call_test || ( echo test cli_call_test failed ; exit 1 )
+ $(E) "[RUN] Testing client_callback_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/client_callback_end2end_test || ( echo test client_callback_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing client_channel_stress_test"
$(Q) $(BINDIR)/$(CONFIG)/client_channel_stress_test || ( echo test client_channel_stress_test failed ; exit 1 )
$(E) "[RUN] Testing client_crash_test"
$(Q) $(BINDIR)/$(CONFIG)/client_crash_test || ( echo test client_crash_test failed ; exit 1 )
+ $(E) "[RUN] Testing client_interceptors_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test || ( echo test client_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing client_lb_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/client_lb_end2end_test || ( echo test client_lb_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing codegen_test_full"
@@ -2400,6 +2408,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/server_crash_test || ( echo test server_crash_test failed ; exit 1 )
$(E) "[RUN] Testing server_early_return_test"
$(Q) $(BINDIR)/$(CONFIG)/server_early_return_test || ( echo test server_early_return_test failed ; exit 1 )
+ $(E) "[RUN] Testing server_interceptors_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test || ( echo test server_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing server_request_call_test"
$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
$(E) "[RUN] Testing shutdown_test"
@@ -3005,7 +3015,7 @@ install-shared_c: shared_c strip-shared_c install-pkg-config_c
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libaddress_sorting.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libaddress_sorting.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libaddress_sorting.so.7
$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libaddress_sorting.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -3014,7 +3024,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgpr.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.7
$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -3023,7 +3033,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -3032,7 +3042,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_cronet.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -3041,7 +3051,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_unsecure.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so
endif
ifneq ($(SYSTEM),MINGW32)
@@ -3058,7 +3068,7 @@ install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-con
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3067,7 +3077,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_cronet.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3076,7 +3086,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_error_details.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_error_details.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3085,7 +3095,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_reflection.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3094,7 +3104,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_unsecure.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so
endif
$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
@@ -3103,7 +3113,7 @@ endif
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpcpp_channelz$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpcpp_channelz.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpcpp_channelz$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpcpp_channelz.so
endif
ifneq ($(SYSTEM),MINGW32)
@@ -3120,7 +3130,7 @@ install-shared_csharp: shared_csharp strip-shared_csharp
ifeq ($(SYSTEM),MINGW32)
$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a $(prefix)/lib/libgrpc_csharp_ext.a
else ifneq ($(SYSTEM),Darwin)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.6
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so
endif
ifneq ($(SYSTEM),MINGW32)
@@ -3211,8 +3221,8 @@ $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE):
ifeq ($(SYSTEM),Darwin)
$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
else
- $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libaddress_sorting.so.6 -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
- $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so.6
+ $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libaddress_sorting.so.7 -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+ $(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so.7
$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so
endif
endif
@@ -3406,8 +3416,8 @@ $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OB
ifeq ($(SYSTEM),Darwin)
$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
else
- $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.6 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
- $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.6
+ $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.7 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+ $(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.7
$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
endif
endif
@@ -3478,7 +3488,6 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -3595,6 +3604,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 \
@@ -3642,11 +3652,14 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
- src/core/lib/security/security_connector/alts_security_connector.cc \
+ src/core/lib/security/security_connector/alts/alts_security_connector.cc \
+ src/core/lib/security/security_connector/fake/fake_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
- src/core/lib/security/security_connector/local_security_connector.cc \
+ src/core/lib/security/security_connector/local/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
+ src/core/lib/security/security_connector/ssl/ssl_security_connector.cc \
+ src/core/lib/security/security_connector/ssl_utils.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
@@ -3665,7 +3678,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 \
@@ -3701,6 +3714,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -3715,9 +3729,8 @@ 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/tsi/alts_transport_security.cc \
+ src/core/ext/filters/client_channel/health/health.pb.c \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -3736,10 +3749,14 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
@@ -3835,8 +3852,8 @@ $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_
ifeq ($(SYSTEM),Darwin)
$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
else
- $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
- $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.6
+ $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.7 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+ $(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
endif
endif
@@ -3886,7 +3903,6 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4003,6 +4019,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 \
@@ -4043,6 +4060,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -4057,8 +4075,11 @@ 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 \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/core/lib/http/httpcli_security_connector.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/alts/alts_credentials.cc \
@@ -4076,11 +4097,14 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
- src/core/lib/security/security_connector/alts_security_connector.cc \
+ src/core/lib/security/security_connector/alts/alts_security_connector.cc \
+ src/core/lib/security/security_connector/fake/fake_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
- src/core/lib/security/security_connector/local_security_connector.cc \
+ src/core/lib/security/security_connector/local/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
+ src/core/lib/security/security_connector/ssl/ssl_security_connector.cc \
+ src/core/lib/security/security_connector/ssl_utils.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
@@ -4099,7 +4123,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 \
@@ -4120,15 +4144,11 @@ LIBGRPC_CRONET_SRC = \
src/core/tsi/alts/handshaker/altscontext.pb.c \
src/core/tsi/alts/handshaker/handshaker.pb.c \
src/core/tsi/alts/handshaker/transport_security_common.pb.c \
- third_party/nanopb/pb_common.c \
- third_party/nanopb/pb_decode.c \
- third_party/nanopb/pb_encode.c \
src/core/tsi/transport_security.cc \
src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
src/core/ext/transport/chttp2/client/authority.cc \
src/core/ext/transport/chttp2/client/chttp2_connector.cc \
- src/core/tsi/alts_transport_security.cc \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -4202,8 +4222,8 @@ $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(L
ifeq ($(SYSTEM),Darwin)
$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
else
- $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.6
+ $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.7 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
endif
endif
@@ -4279,7 +4299,6 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4396,6 +4415,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 \
@@ -4404,6 +4424,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -4418,8 +4439,11 @@ 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 \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/core/ext/transport/chttp2/transport/bin_decoder.cc \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
@@ -4581,7 +4605,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4698,6 +4721,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 \
@@ -4706,6 +4730,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -4720,8 +4745,11 @@ 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 \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/core/ext/transport/chttp2/transport/bin_decoder.cc \
src/core/ext/transport/chttp2/transport/bin_encoder.cc \
src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
@@ -4849,7 +4877,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4966,6 +4993,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 \
@@ -5009,6 +5037,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -5023,8 +5052,11 @@ 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 \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/core/ext/transport/inproc/inproc_plugin.cc \
src/core/ext/transport/inproc/inproc_transport.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
@@ -5046,9 +5078,10 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
- third_party/nanopb/pb_common.c \
- third_party/nanopb/pb_decode.c \
- third_party/nanopb/pb_encode.c \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/census/grpc_context.cc \
@@ -5122,8 +5155,8 @@ $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $
ifeq ($(SYSTEM),Darwin)
$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
else
- $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
- $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.6
+ $(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.7 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+ $(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.7
$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
endif
endif
@@ -5222,6 +5255,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 \
@@ -5240,7 +5274,6 @@ LIBGRPC++_SRC = \
src/cpp/server/create_default_thread_pool.cc \
src/cpp/server/dynamic_thread_pool.cc \
src/cpp/server/health/default_health_check_service.cc \
- src/cpp/server/health/health.pb.c \
src/cpp/server/health/health_check_service.cc \
src/cpp/server/health/health_check_service_server_builder_option.cc \
src/cpp/server/server_builder.cc \
@@ -5253,6 +5286,10 @@ LIBGRPC++_SRC = \
src/cpp/util/status.cc \
src/cpp/util/string_ref.cc \
src/cpp/util/time_cc.cc \
+ src/core/ext/filters/client_channel/health/health.pb.c \
+ third_party/nanopb/pb_common.c \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/cpp/codegen/codegen_init.cc \
PUBLIC_HEADERS_CXX += \
@@ -5338,9 +5375,11 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ 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 \
@@ -5435,8 +5474,13 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+ include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -5444,13 +5488,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
+ include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -5588,6 +5637,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 \
@@ -5606,7 +5656,6 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/server/create_default_thread_pool.cc \
src/cpp/server/dynamic_thread_pool.cc \
src/cpp/server/health/default_health_check_service.cc \
- src/cpp/server/health/health.pb.c \
src/cpp/server/health/health_check_service.cc \
src/cpp/server/health/health_check_service_server_builder_option.cc \
src/cpp/server/server_builder.cc \
@@ -5619,6 +5668,10 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/util/status.cc \
src/cpp/util/string_ref.cc \
src/cpp/util/time_cc.cc \
+ src/core/ext/filters/client_channel/health/health.pb.c \
+ third_party/nanopb/pb_common.c \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/cpp/codegen/codegen_init.cc \
src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
@@ -5681,7 +5734,6 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -5798,6 +5850,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 \
@@ -5811,6 +5864,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -5825,7 +5879,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 \
@@ -5915,9 +5968,11 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ 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 \
@@ -6012,8 +6067,13 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+ include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -6021,13 +6081,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
+ include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6402,8 +6467,13 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+ include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -6411,13 +6481,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
+ include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6556,8 +6631,13 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+ include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -6565,13 +6645,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
+ include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -6665,6 +6750,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 \
@@ -6683,7 +6769,6 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/server/create_default_thread_pool.cc \
src/cpp/server/dynamic_thread_pool.cc \
src/cpp/server/health/default_health_check_service.cc \
- src/cpp/server/health/health.pb.c \
src/cpp/server/health/health_check_service.cc \
src/cpp/server/health/health_check_service_server_builder_option.cc \
src/cpp/server/server_builder.cc \
@@ -6696,6 +6781,10 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/util/status.cc \
src/cpp/util/string_ref.cc \
src/cpp/util/time_cc.cc \
+ src/core/ext/filters/client_channel/health/health.pb.c \
+ third_party/nanopb/pb_common.c \
+ third_party/nanopb/pb_decode.c \
+ third_party/nanopb/pb_encode.c \
src/cpp/codegen/codegen_init.cc \
PUBLIC_HEADERS_CXX += \
@@ -6781,9 +6870,11 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ 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 \
@@ -6878,8 +6969,13 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/call_op_set.h \
+ include/grpcpp/impl/codegen/call_op_set_interface.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+ include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -6887,13 +6983,18 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+ include/grpcpp/impl/codegen/intercepted_channel.h \
+ include/grpcpp/impl/codegen/interceptor.h \
+ include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -7501,6 +7602,7 @@ LIBQPS_SRC = \
$(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc \
test/cpp/qps/benchmark_config.cc \
test/cpp/qps/client_async.cc \
+ test/cpp/qps/client_callback.cc \
test/cpp/qps/client_sync.cc \
test/cpp/qps/driver.cc \
test/cpp/qps/parse_json.cc \
@@ -7508,6 +7610,7 @@ LIBQPS_SRC = \
test/cpp/qps/qps_worker.cc \
test/cpp/qps/report.cc \
test/cpp/qps/server_async.cc \
+ test/cpp/qps/server_callback.cc \
test/cpp/qps/server_sync.cc \
test/cpp/qps/usage_timer.cc \
@@ -7557,6 +7660,7 @@ endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/qps/benchmark_config.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_callback.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/parse_json.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
@@ -7564,6 +7668,7 @@ $(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_server_builder.o: $(GENDIR)/src/proto/grpc/
$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_callback.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
$(OBJDIR)/$(CONFIG)/test/cpp/qps/usage_timer.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.pb.cc $(GENDIR)/src/proto/grpc/testing/benchmark_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.pb.cc $(GENDIR)/src/proto/grpc/testing/report_qps_scenario_service.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.pb.cc $(GENDIR)/src/proto/grpc/testing/worker_service.grpc.pb.cc
@@ -11367,38 +11472,6 @@ endif
endif
-EV_EPOLLSIG_LINUX_TEST_SRC = \
- test/core/iomgr/ev_epollsig_linux_test.cc \
-
-EV_EPOLLSIG_LINUX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(EV_EPOLLSIG_LINUX_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/ev_epollsig_linux_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/ev_epollsig_linux_test: $(EV_EPOLLSIG_LINUX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(EV_EPOLLSIG_LINUX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/ev_epollsig_linux_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_ev_epollsig_linux_test: $(EV_EPOLLSIG_LINUX_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(EV_EPOLLSIG_LINUX_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
FAKE_RESOLVER_TEST_SRC = \
test/core/client_channel/resolvers/fake_resolver_test.cc \
@@ -12723,57 +12796,57 @@ endif
endif
-HANDSHAKE_CLIENT_SRC = \
+HANDSHAKE_CLIENT_SSL_SRC = \
test/core/handshake/client_ssl.cc \
-HANDSHAKE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HANDSHAKE_CLIENT_SRC))))
+HANDSHAKE_CLIENT_SSL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HANDSHAKE_CLIENT_SSL_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/handshake_client: openssl_dep_error
+$(BINDIR)/$(CONFIG)/handshake_client_ssl: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/handshake_client: $(HANDSHAKE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/handshake_client_ssl: $(HANDSHAKE_CLIENT_SSL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(HANDSHAKE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/handshake_client
+ $(Q) $(LD) $(LDFLAGS) $(HANDSHAKE_CLIENT_SSL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/handshake_client_ssl
endif
$(OBJDIR)/$(CONFIG)/test/core/handshake/client_ssl.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_handshake_client: $(HANDSHAKE_CLIENT_OBJS:.o=.dep)
+deps_handshake_client_ssl: $(HANDSHAKE_CLIENT_SSL_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(HANDSHAKE_CLIENT_OBJS:.o=.dep)
+-include $(HANDSHAKE_CLIENT_SSL_OBJS:.o=.dep)
endif
endif
-HANDSHAKE_SERVER_SRC = \
+HANDSHAKE_SERVER_SSL_SRC = \
test/core/handshake/server_ssl.cc \
test/core/handshake/server_ssl_common.cc \
-HANDSHAKE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HANDSHAKE_SERVER_SRC))))
+HANDSHAKE_SERVER_SSL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HANDSHAKE_SERVER_SSL_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/handshake_server: openssl_dep_error
+$(BINDIR)/$(CONFIG)/handshake_server_ssl: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/handshake_server: $(HANDSHAKE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/handshake_server_ssl: $(HANDSHAKE_SERVER_SSL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(HANDSHAKE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/handshake_server
+ $(Q) $(LD) $(LDFLAGS) $(HANDSHAKE_SERVER_SSL_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/handshake_server_ssl
endif
@@ -12781,11 +12854,11 @@ $(OBJDIR)/$(CONFIG)/test/core/handshake/server_ssl.o: $(LIBDIR)/$(CONFIG)/libgr
$(OBJDIR)/$(CONFIG)/test/core/handshake/server_ssl_common.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_handshake_server: $(HANDSHAKE_SERVER_OBJS:.o=.dep)
+deps_handshake_server_ssl: $(HANDSHAKE_SERVER_SSL_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(HANDSHAKE_SERVER_OBJS:.o=.dep)
+-include $(HANDSHAKE_SERVER_SSL_OBJS:.o=.dep)
endif
endif
@@ -13529,98 +13602,98 @@ endif
endif
-MEMORY_PROFILE_CLIENT_SRC = \
+MEMORY_USAGE_CLIENT_SRC = \
test/core/memory_usage/client.cc \
-MEMORY_PROFILE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_CLIENT_SRC))))
+MEMORY_USAGE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_USAGE_CLIENT_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/memory_profile_client: openssl_dep_error
+$(BINDIR)/$(CONFIG)/memory_usage_client: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/memory_usage_client: $(MEMORY_USAGE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_client
+ $(Q) $(LD) $(LDFLAGS) $(MEMORY_USAGE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_usage_client
endif
$(OBJDIR)/$(CONFIG)/test/core/memory_usage/client.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+deps_memory_usage_client: $(MEMORY_USAGE_CLIENT_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+-include $(MEMORY_USAGE_CLIENT_OBJS:.o=.dep)
endif
endif
-MEMORY_PROFILE_SERVER_SRC = \
+MEMORY_USAGE_SERVER_SRC = \
test/core/memory_usage/server.cc \
-MEMORY_PROFILE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_SERVER_SRC))))
+MEMORY_USAGE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_USAGE_SERVER_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/memory_profile_server: openssl_dep_error
+$(BINDIR)/$(CONFIG)/memory_usage_server: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/memory_usage_server: $(MEMORY_USAGE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_server
+ $(Q) $(LD) $(LDFLAGS) $(MEMORY_USAGE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_usage_server
endif
$(OBJDIR)/$(CONFIG)/test/core/memory_usage/server.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+deps_memory_usage_server: $(MEMORY_USAGE_SERVER_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+-include $(MEMORY_USAGE_SERVER_OBJS:.o=.dep)
endif
endif
-MEMORY_PROFILE_TEST_SRC = \
+MEMORY_USAGE_TEST_SRC = \
test/core/memory_usage/memory_usage_test.cc \
-MEMORY_PROFILE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_TEST_SRC))))
+MEMORY_USAGE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_USAGE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/memory_profile_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/memory_usage_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/memory_profile_test: $(MEMORY_PROFILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/memory_usage_test: $(MEMORY_USAGE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_test
+ $(Q) $(LD) $(LDFLAGS) $(MEMORY_USAGE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_usage_test
endif
$(OBJDIR)/$(CONFIG)/test/core/memory_usage/memory_usage_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_memory_profile_test: $(MEMORY_PROFILE_TEST_OBJS:.o=.dep)
+deps_memory_usage_test: $(MEMORY_USAGE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(MEMORY_PROFILE_TEST_OBJS:.o=.dep)
+-include $(MEMORY_USAGE_TEST_OBJS:.o=.dep)
endif
endif
@@ -14009,98 +14082,98 @@ endif
endif
-POLLSET_SET_TEST_SRC = \
- test/core/iomgr/pollset_set_test.cc \
+RESOLVE_ADDRESS_POSIX_TEST_SRC = \
+ test/core/iomgr/resolve_address_posix_test.cc \
-POLLSET_SET_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(POLLSET_SET_TEST_SRC))))
+RESOLVE_ADDRESS_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_POSIX_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/pollset_set_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_posix_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/pollset_set_test: $(POLLSET_SET_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(POLLSET_SET_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pollset_set_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_POSIX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resolve_address_posix_test
endif
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/pollset_set_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_posix_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_pollset_set_test: $(POLLSET_SET_TEST_OBJS:.o=.dep)
+deps_resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(POLLSET_SET_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
endif
endif
-RESOLVE_ADDRESS_POSIX_TEST_SRC = \
- test/core/iomgr/resolve_address_posix_test.cc \
+RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_SRC = \
+ test/core/iomgr/resolve_address_test.cc \
-RESOLVE_ADDRESS_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_POSIX_TEST_SRC))))
+RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/resolve_address_posix_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test: $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_POSIX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resolve_address_posix_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test
endif
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_posix_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
+deps_resolve_address_using_ares_resolver_test: $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS:.o=.dep)
endif
endif
-RESOLVE_ADDRESS_TEST_SRC = \
+RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_SRC = \
test/core/iomgr/resolve_address_test.cc \
-RESOLVE_ADDRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_TEST_SRC))))
+RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/resolve_address_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/resolve_address_test: $(RESOLVE_ADDRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test: $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resolve_address_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_resolve_address_test: $(RESOLVE_ADDRESS_TEST_OBJS:.o=.dep)
+deps_resolve_address_using_native_resolver_test: $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(RESOLVE_ADDRESS_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS:.o=.dep)
endif
endif
@@ -17118,6 +17191,49 @@ endif
endif
+CLIENT_CALLBACK_END2END_TEST_SRC = \
+ test/cpp/end2end/client_callback_end2end_test.cc \
+
+CLIENT_CALLBACK_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_CALLBACK_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: $(PROTOBUF_DEP) $(CLIENT_CALLBACK_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_CALLBACK_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_callback_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_callback_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_client_callback_end2end_test: $(CLIENT_CALLBACK_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CLIENT_CALLBACK_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CLIENT_CHANNEL_STRESS_TEST_SRC = \
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
test/cpp/client/client_channel_stress_test.cc \
@@ -17251,6 +17367,52 @@ endif
endif
+CLIENT_INTERCEPTORS_END2END_TEST_SRC = \
+ test/cpp/end2end/client_interceptors_end2end_test.cc \
+ test/cpp/end2end/interceptors_util.cc \
+
+CLIENT_INTERCEPTORS_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_INTERCEPTORS_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/client_interceptors_end2end_test: $(PROTOBUF_DEP) $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_interceptors_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_interceptors_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_client_interceptors_end2end_test: $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CLIENT_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CLIENT_LB_END2END_TEST_SRC = \
test/cpp/end2end/client_lb_end2end_test.cc \
@@ -17645,6 +17807,7 @@ endif
END2END_TEST_SRC = \
test/cpp/end2end/end2end_test.cc \
+ test/cpp/end2end/interceptors_util.cc \
END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(END2END_TEST_SRC))))
ifeq ($(NO_SECURE),true)
@@ -17677,6 +17840,8 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
deps_end2end_test: $(END2END_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
@@ -20036,6 +20201,52 @@ endif
endif
+SERVER_INTERCEPTORS_END2END_TEST_SRC = \
+ test/cpp/end2end/interceptors_util.cc \
+ test/cpp/end2end/server_interceptors_end2end_test.cc \
+
+SERVER_INTERCEPTORS_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_INTERCEPTORS_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test: $(PROTOBUF_DEP) $(SERVER_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(SERVER_INTERCEPTORS_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/interceptors_util.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/server_interceptors_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_server_interceptors_end2end_test: $(SERVER_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(SERVER_INTERCEPTORS_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
SERVER_REQUEST_CALL_TEST_SRC = \
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
@@ -23994,26 +24205,6 @@ ifneq ($(NO_DEPS),true)
endif
-INPROC_NOSEC_TEST_SRC = \
- test/core/end2end/fixtures/inproc.cc \
-
-INPROC_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INPROC_NOSEC_TEST_SRC))))
-
-
-$(BINDIR)/$(CONFIG)/inproc_nosec_test: $(INPROC_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
- $(E) "[LD] Linking $@"
- $(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(INPROC_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/inproc_nosec_test
-
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/inproc.o: $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_inproc_nosec_test: $(INPROC_NOSEC_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_DEPS),true)
--include $(INPROC_NOSEC_TEST_OBJS:.o=.dep)
-endif
-
-
RESOLVER_COMPONENT_TEST_UNSECURE_SRC = \
test/cpp/naming/resolver_component_test.cc \
@@ -24814,6 +25005,7 @@ ifneq ($(OPENSSL_DEP),)
# installing headers to their final destination on the drive. We need this
# otherwise parallel compilation will fail if a source is compiled first.
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc: $(OPENSSL_DEP)
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc: $(OPENSSL_DEP)
src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc: $(OPENSSL_DEP)
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc: $(OPENSSL_DEP)
src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc: $(OPENSSL_DEP)
@@ -24843,11 +25035,14 @@ src/core/lib/security/credentials/local/local_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP)
-src/core/lib/security/security_connector/alts_security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/alts/alts_security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/fake/fake_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/load_system_roots_fallback.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/load_system_roots_linux.cc: $(OPENSSL_DEP)
-src/core/lib/security/security_connector/local_security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/local/local_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/ssl/ssl_security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/ssl_utils.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/client_auth_filter.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/secure_endpoint.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/security_handshaker.cc: $(OPENSSL_DEP)
@@ -24870,7 +25065,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)
@@ -24882,7 +25077,6 @@ src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_p
src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc: $(OPENSSL_DEP)
src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc: $(OPENSSL_DEP)
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc: $(OPENSSL_DEP)
-src/core/tsi/alts_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/fake_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/local_transport_security.cc: $(OPENSSL_DEP)
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc: $(OPENSSL_DEP)
@@ -24929,6 +25123,7 @@ test/cpp/interop/server_helper.cc: $(OPENSSL_DEP)
test/cpp/microbenchmarks/helpers.cc: $(OPENSSL_DEP)
test/cpp/qps/benchmark_config.cc: $(OPENSSL_DEP)
test/cpp/qps/client_async.cc: $(OPENSSL_DEP)
+test/cpp/qps/client_callback.cc: $(OPENSSL_DEP)
test/cpp/qps/client_sync.cc: $(OPENSSL_DEP)
test/cpp/qps/driver.cc: $(OPENSSL_DEP)
test/cpp/qps/parse_json.cc: $(OPENSSL_DEP)
@@ -24936,6 +25131,7 @@ test/cpp/qps/qps_server_builder.cc: $(OPENSSL_DEP)
test/cpp/qps/qps_worker.cc: $(OPENSSL_DEP)
test/cpp/qps/report.cc: $(OPENSSL_DEP)
test/cpp/qps/server_async.cc: $(OPENSSL_DEP)
+test/cpp/qps/server_callback.cc: $(OPENSSL_DEP)
test/cpp/qps/server_sync.cc: $(OPENSSL_DEP)
test/cpp/qps/usage_timer.cc: $(OPENSSL_DEP)
test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index b30a1fbf90..c0de5289ee 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -9,6 +9,7 @@ graft third_party/boringssl
graft third_party/cares
graft third_party/nanopb
graft third_party/zlib
+include src/python/grpcio/_parallel_compile_patch.py
include src/python/grpcio/_spawn_patch.py
include src/python/grpcio/commands.py
include src/python/grpcio/grpc_version.py
diff --git a/WORKSPACE b/WORKSPACE
index 9a0c41977f..a547c24cbe 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -34,10 +34,11 @@ pip_import(
load("@grpc_python_dependencies//:requirements.bzl", "pip_install")
pip_install()
+# NOTE(https://github.com/pubref/rules_protobuf/pull/196): Switch to upstream repo after this gets merged.
git_repository(
name="org_pubref_rules_protobuf",
- remote="https://github.com/pubref/rules_protobuf",
- tag="v0.8.2",
+ remote="https://github.com/ghostwriternr/rules_protobuf",
+ tag="v0.8.2.1-alpha",
)
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories")
diff --git a/bazel/OWNERS b/bazel/OWNERS
index 613ba36be8..30813d1e7a 100644
--- a/bazel/OWNERS
+++ b/bazel/OWNERS
@@ -1,6 +1,6 @@
set noparent
@nicolasnoble
-@dgquintas
+@jtattermusch
@a11r
@vjpai
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 73147bf3ac..159ebd5d1f 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -24,178 +24,203 @@
#
# The set of pollers to test against if a test exercises polling
-POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
+POLLERS = ["epollex", "epoll1", "poll", "poll-cv"]
def if_not_windows(a):
- return select({
- "//:windows": [],
- "//:windows_msvc": [],
- "//conditions:default": a,
- })
+ return select({
+ "//:windows": [],
+ "//:windows_msvc": [],
+ "//conditions:default": a,
+ })
def _get_external_deps(external_deps):
- ret = []
- for dep in external_deps:
- if dep == "address_sorting":
- ret += ["//third_party/address_sorting"]
- elif dep == "cares":
- ret += select({"//:grpc_no_ares": [],
- "//conditions:default": ["//external:cares"],})
- else:
- ret += ["//external:" + dep]
- return ret
+ ret = []
+ for dep in external_deps:
+ if dep == "address_sorting":
+ ret += ["//third_party/address_sorting"]
+ elif dep == "cares":
+ ret += select({
+ "//:grpc_no_ares": [],
+ "//conditions:default": ["//external:cares"],
+ })
+ else:
+ ret += ["//external:" + dep]
+ return ret
def _maybe_update_cc_library_hdrs(hdrs):
- ret = []
- hdrs_to_update = {
- "third_party/objective_c/Cronet/bidirectional_stream_c.h": "//third_party:objective_c/Cronet/bidirectional_stream_c.h",
- }
- for h in hdrs:
- if h in hdrs_to_update.keys():
- ret.append(hdrs_to_update[h])
- else:
- ret.append(h)
- return ret
-
-def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
- external_deps = [], deps = [], standalone = False,
- language = "C++", testonly = False, visibility = None,
- alwayslink = 0, data = []):
- copts = []
- if language.upper() == "C":
- copts = if_not_windows(["-std=c99"])
- native.cc_library(
- name = name,
- srcs = srcs,
- defines = select({"//:grpc_no_ares": ["GRPC_ARES=0"],
- "//conditions:default": [],}) +
- select({"//:remote_execution": ["GRPC_PORT_ISOLATED_RUNTIME=1"],
- "//conditions:default": [],}) +
- select({"//:grpc_allow_exceptions": ["GRPC_ALLOW_EXCEPTIONS=1"],
- "//:grpc_disallow_exceptions":
- ["GRPC_ALLOW_EXCEPTIONS=0"],
- "//conditions:default": [],}),
- hdrs = _maybe_update_cc_library_hdrs(hdrs + public_hdrs),
- deps = deps + _get_external_deps(external_deps),
- copts = copts,
- visibility = visibility,
- testonly = testonly,
- linkopts = if_not_windows(["-pthread"]),
- includes = [
- "include"
- ],
- alwayslink = alwayslink,
- data = data,
- )
+ ret = []
+ hdrs_to_update = {
+ "third_party/objective_c/Cronet/bidirectional_stream_c.h": "//third_party:objective_c/Cronet/bidirectional_stream_c.h",
+ }
+ for h in hdrs:
+ if h in hdrs_to_update.keys():
+ ret.append(hdrs_to_update[h])
+ else:
+ ret.append(h)
+ return ret
+
+def grpc_cc_library(
+ name,
+ srcs = [],
+ public_hdrs = [],
+ hdrs = [],
+ external_deps = [],
+ deps = [],
+ standalone = False,
+ language = "C++",
+ testonly = False,
+ visibility = None,
+ alwayslink = 0,
+ data = []):
+ copts = []
+ if language.upper() == "C":
+ copts = if_not_windows(["-std=c99"])
+ native.cc_library(
+ name = name,
+ srcs = srcs,
+ defines = select({
+ "//:grpc_no_ares": ["GRPC_ARES=0"],
+ "//conditions:default": [],
+ }) +
+ select({
+ "//:remote_execution": ["GRPC_PORT_ISOLATED_RUNTIME=1"],
+ "//conditions:default": [],
+ }) +
+ select({
+ "//:grpc_allow_exceptions": ["GRPC_ALLOW_EXCEPTIONS=1"],
+ "//:grpc_disallow_exceptions": ["GRPC_ALLOW_EXCEPTIONS=0"],
+ "//conditions:default": [],
+ }),
+ hdrs = _maybe_update_cc_library_hdrs(hdrs + public_hdrs),
+ deps = deps + _get_external_deps(external_deps),
+ copts = copts,
+ visibility = visibility,
+ testonly = testonly,
+ linkopts = if_not_windows(["-pthread"]),
+ includes = [
+ "include",
+ ],
+ alwayslink = alwayslink,
+ data = data,
+ )
def grpc_proto_plugin(name, srcs = [], deps = []):
- native.cc_binary(
- name = name,
- srcs = srcs,
- deps = deps,
- )
+ native.cc_binary(
+ name = name,
+ srcs = srcs,
+ deps = deps,
+ )
load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library")
-def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = False,
- has_services = True, use_external = False, generate_mocks = False):
- cc_grpc_library(
- name = name,
- srcs = srcs,
- deps = deps,
- well_known_protos = well_known_protos,
- proto_only = not has_services,
- use_external = use_external,
- generate_mocks = generate_mocks,
- )
+def grpc_proto_library(
+ name,
+ srcs = [],
+ deps = [],
+ well_known_protos = False,
+ has_services = True,
+ use_external = False,
+ generate_mocks = False):
+ cc_grpc_library(
+ name = name,
+ srcs = srcs,
+ deps = deps,
+ well_known_protos = well_known_protos,
+ proto_only = not has_services,
+ use_external = use_external,
+ generate_mocks = generate_mocks,
+ )
def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate", tags = []):
- copts = []
- if language.upper() == "C":
- copts = if_not_windows(["-std=c99"])
- args = {
- 'name': name,
- 'srcs': srcs,
- 'args': args,
- 'data': data,
- 'deps': deps + _get_external_deps(external_deps),
- 'copts': copts,
- 'linkopts': if_not_windows(["-pthread"]),
- 'size': size,
- 'timeout': timeout,
- }
- if uses_polling:
- native.cc_test(testonly=True, tags=['manual'], **args)
- for poller in POLLERS:
- native.sh_test(
- name = name + '@poller=' + poller,
- data = [name],
- srcs = [
- '//test/core/util:run_with_poller_sh',
- ],
- size = size,
- timeout = timeout,
- args = [
- poller,
- '$(location %s)' % name,
- ] + args['args'],
- tags = tags,
- )
- else:
- native.cc_test(**args)
+ copts = []
+ if language.upper() == "C":
+ copts = if_not_windows(["-std=c99"])
+ args = {
+ "name": name,
+ "srcs": srcs,
+ "args": args,
+ "data": data,
+ "deps": deps + _get_external_deps(external_deps),
+ "copts": copts,
+ "linkopts": if_not_windows(["-pthread"]),
+ "size": size,
+ "timeout": timeout,
+ }
+ if uses_polling:
+ native.cc_test(testonly = True, tags = ["manual"], **args)
+ for poller in POLLERS:
+ native.sh_test(
+ name = name + "@poller=" + poller,
+ data = [name] + data,
+ srcs = [
+ "//test/core/util:run_with_poller_sh",
+ ],
+ size = size,
+ timeout = timeout,
+ args = [
+ poller,
+ "$(location %s)" % name,
+ ] + args["args"],
+ tags = tags,
+ )
+ else:
+ native.cc_test(**args)
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = []):
- copts = []
- if language.upper() == "C":
- copts = ["-std=c99"]
- native.cc_binary(
- name = name,
- srcs = srcs,
- args = args,
- data = data,
- testonly = testonly,
- linkshared = linkshared,
- deps = deps + _get_external_deps(external_deps),
- copts = copts,
- linkopts = if_not_windows(["-pthread"]) + linkopts,
- )
-
-def grpc_generate_one_off_targets(): pass
+ copts = []
+ if language.upper() == "C":
+ copts = ["-std=c99"]
+ native.cc_binary(
+ name = name,
+ srcs = srcs,
+ args = args,
+ data = data,
+ testonly = testonly,
+ linkshared = linkshared,
+ deps = deps + _get_external_deps(external_deps),
+ copts = copts,
+ linkopts = if_not_windows(["-pthread"]) + linkopts,
+ )
+
+def grpc_generate_one_off_targets():
+ pass
def grpc_sh_test(name, srcs, args = [], data = []):
- native.sh_test(
- name = name,
- srcs = srcs,
- args = args,
- data = data)
+ native.sh_test(
+ name = name,
+ srcs = srcs,
+ args = args,
+ data = data,
+ )
def grpc_sh_binary(name, srcs, data = []):
- native.sh_binary(
- name = name,
- srcs = srcs,
- data = data)
+ native.sh_binary(
+ name = name,
+ srcs = srcs,
+ data = data,
+ )
def grpc_py_binary(name, srcs, data = [], deps = [], external_deps = [], testonly = False):
- native.py_binary(
- name = name,
- srcs = srcs,
- testonly = testonly,
- data = data,
- deps = deps + _get_external_deps(external_deps)
- )
+ native.py_binary(
+ name = name,
+ srcs = srcs,
+ testonly = testonly,
+ data = data,
+ deps = deps + _get_external_deps(external_deps),
+ )
def grpc_package(name, visibility = "private", features = []):
- if visibility == "tests":
- visibility = ["//test:__subpackages__"]
- elif visibility == "public":
- visibility = ["//visibility:public"]
- elif visibility == "private":
- visibility = []
- else:
- fail("Unknown visibility " + visibility)
-
- if len(visibility) != 0:
- native.package(
- default_visibility = visibility,
- features = features
- )
+ if visibility == "tests":
+ visibility = ["//test:__subpackages__"]
+ elif visibility == "public":
+ visibility = ["//visibility:public"]
+ elif visibility == "private":
+ visibility = []
+ else:
+ fail("Unknown visibility " + visibility)
+
+ if len(visibility) != 0:
+ native.package(
+ default_visibility = visibility,
+ features = features,
+ )
diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl
index d7519b1453..8626817855 100644
--- a/bazel/grpc_deps.bzl
+++ b/bazel/grpc_deps.bzl
@@ -102,7 +102,7 @@ def grpc_deps():
native.http_archive(
name = "boringssl",
# on the chromium-stable-with-bazel branch
- url = "https://boringssl.googlesource.com/boringssl/+archive/dcd3e6e6ecddf059adb48fca45bc7346a108bdd9.tar.gz",
+ url = "https://boringssl.googlesource.com/boringssl/+archive/afc30d43eef92979b05776ec0963c9cede5fb80f.tar.gz",
)
if "com_github_madler_zlib" not in native.existing_rules():
@@ -169,12 +169,12 @@ def grpc_deps():
if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
native.http_archive(
name = "com_github_bazelbuild_bazeltoolchains",
- strip_prefix = "bazel-toolchains-4653c01284d8a4a536f8f9bb47b7d10f94c549e7",
+ strip_prefix = "bazel-toolchains-280edaa6f93623074513d2b426068de42e62ea4d",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/4653c01284d8a4a536f8f9bb47b7d10f94c549e7.tar.gz",
- "https://github.com/bazelbuild/bazel-toolchains/archive/4653c01284d8a4a536f8f9bb47b7d10f94c549e7.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/280edaa6f93623074513d2b426068de42e62ea4d.tar.gz",
+ "https://github.com/bazelbuild/bazel-toolchains/archive/280edaa6f93623074513d2b426068de42e62ea4d.tar.gz",
],
- sha256 = "1c4a532b396c698e6467a1548554571cb85fa091e472b05e398ebc836c315d77",
+ sha256 = "50c9df51f80cdf9ff8f2bc27620c155526b9ba67be95e8a686f32ff8898a06e2",
)
if "io_opencensus_cpp" not in native.existing_rules():
diff --git a/build.yaml b/build.yaml
index 47a75d23c1..f837ea90b6 100644
--- a/build.yaml
+++ b/build.yaml
@@ -12,9 +12,9 @@ settings:
'#08': Use "-preN" suffixes to identify pre-release versions
'#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here
- core_version: 6.0.0-dev
- g_stands_for: glider
- version: 1.15.0-dev
+ core_version: 7.0.0-dev
+ g_stands_for: gizmo
+ version: 1.17.0-dev
filegroups:
- name: alts_proto
headers:
@@ -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
@@ -266,7 +266,6 @@ filegroups:
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/ev_epoll1_linux.cc
- src/core/lib/iomgr/ev_epollex_linux.cc
- - src/core/lib/iomgr/ev_epollsig_linux.cc
- src/core/lib/iomgr/ev_poll_posix.cc
- src/core/lib/iomgr/ev_posix.cc
- src/core/lib/iomgr/ev_windows.cc
@@ -383,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:
@@ -446,7 +446,6 @@ filegroups:
- src/core/lib/iomgr/error_internal.h
- src/core/lib/iomgr/ev_epoll1_linux.h
- src/core/lib/iomgr/ev_epollex_linux.h
- - src/core/lib/iomgr/ev_epollsig_linux.h
- src/core/lib/iomgr/ev_poll_posix.h
- src/core/lib/iomgr/ev_posix.h
- src/core/lib/iomgr/exec_ctx.h
@@ -540,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:
@@ -574,6 +574,7 @@ filegroups:
- src/core/ext/filters/client_channel/client_channel_channelz.h
- src/core/ext/filters/client_channel/client_channel_factory.h
- src/core/ext/filters/client_channel/connector.h
+ - src/core/ext/filters/client_channel/health/health_check_client.h
- src/core/ext/filters/client_channel/http_connect_handshaker.h
- src/core/ext/filters/client_channel/http_proxy.h
- src/core/ext/filters/client_channel/lb_policy.h
@@ -589,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
@@ -598,6 +598,7 @@ filegroups:
- src/core/ext/filters/client_channel/client_channel_factory.cc
- src/core/ext/filters/client_channel/client_channel_plugin.cc
- src/core/ext/filters/client_channel/connector.cc
+ - src/core/ext/filters/client_channel/health/health_check_client.cc
- src/core/ext/filters/client_channel/http_connect_handshaker.cc
- src/core/ext/filters/client_channel/http_proxy.cc
- src/core/ext/filters/client_channel/lb_policy.cc
@@ -612,11 +613,11 @@ 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
- grpc_deadline_filter
+ - health_proto
- name: grpc_codegen
public_headers:
- include/grpc/impl/codegen/byte_buffer.h
@@ -657,24 +658,19 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
src:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
plugin: grpc_lb_policy_grpclb
uses:
- grpc_base
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_policy_grpclb_secure
headers:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
@@ -682,18 +678,12 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
src:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
plugin: grpc_lb_policy_grpclb
uses:
- grpc_base
@@ -701,6 +691,7 @@ filegroups:
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_policy_pick_first
src:
- src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -717,6 +708,43 @@ filegroups:
- grpc_base
- grpc_client_channel
- grpc_lb_subchannel_list
+- name: grpc_lb_policy_xds
+ headers:
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
+ src:
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
+ plugin: grpc_lb_policy_xds
+ uses:
+ - grpc_base
+ - grpc_client_channel
+ - nanopb
+ - grpc_resolver_fake
+ - grpclb_proto
+- name: grpc_lb_policy_xds_secure
+ headers:
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
+ src:
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
+ plugin: grpc_lb_policy_xds
+ uses:
+ - grpc_base
+ - grpc_secure
+ - grpc_client_channel
+ - nanopb
+ - grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_subchannel_list
headers:
- src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -784,6 +812,7 @@ filegroups:
- include/grpc/grpc_security.h
headers:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.h
- src/core/lib/security/context/security_context.h
- src/core/lib/security/credentials/alts/alts_credentials.h
- src/core/lib/security/credentials/composite/composite_credentials.h
@@ -798,11 +827,14 @@ filegroups:
- src/core/lib/security/credentials/oauth2/oauth2_credentials.h
- src/core/lib/security/credentials/plugin/plugin_credentials.h
- src/core/lib/security/credentials/ssl/ssl_credentials.h
- - src/core/lib/security/security_connector/alts_security_connector.h
+ - src/core/lib/security/security_connector/alts/alts_security_connector.h
+ - src/core/lib/security/security_connector/fake/fake_security_connector.h
- src/core/lib/security/security_connector/load_system_roots.h
- src/core/lib/security/security_connector/load_system_roots_linux.h
- - src/core/lib/security/security_connector/local_security_connector.h
+ - src/core/lib/security/security_connector/local/local_security_connector.h
- src/core/lib/security/security_connector/security_connector.h
+ - src/core/lib/security/security_connector/ssl/ssl_security_connector.h
+ - src/core/lib/security/security_connector/ssl_utils.h
- src/core/lib/security/transport/auth_filters.h
- src/core/lib/security/transport/secure_endpoint.h
- src/core/lib/security/transport/security_handshaker.h
@@ -827,11 +859,14 @@ filegroups:
- src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
- src/core/lib/security/credentials/plugin/plugin_credentials.cc
- src/core/lib/security/credentials/ssl/ssl_credentials.cc
- - src/core/lib/security/security_connector/alts_security_connector.cc
+ - src/core/lib/security/security_connector/alts/alts_security_connector.cc
+ - src/core/lib/security/security_connector/fake/fake_security_connector.cc
- src/core/lib/security/security_connector/load_system_roots_fallback.cc
- src/core/lib/security/security_connector/load_system_roots_linux.cc
- - src/core/lib/security/security_connector/local_security_connector.cc
+ - src/core/lib/security/security_connector/local/local_security_connector.cc
- src/core/lib/security/security_connector/security_connector.cc
+ - src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
+ - src/core/lib/security/security_connector/ssl_utils.cc
- src/core/lib/security/transport/client_auth_filter.cc
- src/core/lib/security/transport/secure_endpoint.cc
- src/core/lib/security/transport/security_handshaker.cc
@@ -1072,6 +1107,24 @@ filegroups:
uses:
- grpc_base
- grpc_server_backward_compatibility
+- name: grpclb_proto
+ headers:
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+ src:
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+ uses:
+ - nanopb
+- name: health_proto
+ headers:
+ - src/core/ext/filters/client_channel/health/health.pb.h
+ src:
+ - src/core/ext/filters/client_channel/health/health.pb.c
+ uses:
+ - nanopb
- name: nanopb
src:
- third_party/nanopb/pb_common.c
@@ -1095,7 +1148,6 @@ filegroups:
- grpc
- name: tsi
headers:
- - src/core/tsi/alts_transport_security.h
- src/core/tsi/fake_transport_security.h
- src/core/tsi/local_transport_security.h
- src/core/tsi/ssl/session_cache/ssl_session.h
@@ -1104,7 +1156,6 @@ filegroups:
- src/core/tsi/ssl_types.h
- src/core/tsi/transport_security_grpc.h
src:
- - src/core/tsi/alts_transport_security.cc
- src/core/tsi/fake_transport_security.cc
- src/core/tsi/local_transport_security.cc
- src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -1114,7 +1165,6 @@ filegroups:
- src/core/tsi/transport_security_grpc.cc
deps:
- gpr
- plugin: grpc_tsi_alts
secure: true
uses:
- tsi_interface
@@ -1171,8 +1221,13 @@ filegroups:
- include/grpcpp/impl/codegen/byte_buffer.h
- include/grpcpp/impl/codegen/call.h
- include/grpcpp/impl/codegen/call_hook.h
+ - include/grpcpp/impl/codegen/call_op_set.h
+ - include/grpcpp/impl/codegen/call_op_set_interface.h
+ - include/grpcpp/impl/codegen/callback_common.h
- include/grpcpp/impl/codegen/channel_interface.h
+ - include/grpcpp/impl/codegen/client_callback.h
- include/grpcpp/impl/codegen/client_context.h
+ - include/grpcpp/impl/codegen/client_interceptor.h
- include/grpcpp/impl/codegen/client_unary_call.h
- include/grpcpp/impl/codegen/completion_queue.h
- include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -1180,13 +1235,18 @@ filegroups:
- include/grpcpp/impl/codegen/core_codegen_interface.h
- include/grpcpp/impl/codegen/create_auth_context.h
- include/grpcpp/impl/codegen/grpc_library.h
+ - include/grpcpp/impl/codegen/intercepted_channel.h
+ - include/grpcpp/impl/codegen/interceptor.h
+ - include/grpcpp/impl/codegen/interceptor_common.h
- include/grpcpp/impl/codegen/metadata_map.h
- include/grpcpp/impl/codegen/method_handler_impl.h
- 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
- include/grpcpp/impl/codegen/service_type.h
- include/grpcpp/impl/codegen/slice.h
@@ -1299,9 +1359,11 @@ filegroups:
- include/grpcpp/support/async_unary_call.h
- include/grpcpp/support/byte_buffer.h
- include/grpcpp/support/channel_arguments.h
+ - 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
@@ -1314,12 +1376,12 @@ filegroups:
- src/cpp/common/channel_filter.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/health/default_health_check_service.h
- - src/cpp/server/health/health.pb.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
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
@@ -1338,7 +1400,6 @@ filegroups:
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/dynamic_thread_pool.cc
- src/cpp/server/health/default_health_check_service.cc
- - src/cpp/server/health/health.pb.c
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/server_builder.cc
@@ -1357,6 +1418,7 @@ filegroups:
- grpc_transport_inproc_headers
- grpc++_codegen_base
- nanopb_headers
+ - health_proto
- name: grpc++_config_proto
language: c++
public_headers:
@@ -1436,7 +1498,6 @@ libs:
filegroups:
- gpr_base
secure: false
- vs_project_guid: '{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}'
- name: gpr_test_util
build: private
language: c
@@ -1447,7 +1508,6 @@ libs:
deps:
- gpr
secure: false
- vs_project_guid: '{EAB0A629-17A9-44DB-B5FF-E91A721FE037}'
- name: grpc
build: all
language: c
@@ -1464,6 +1524,7 @@ libs:
- grpc_transport_chttp2_client_insecure
- grpc_transport_inproc
- grpc_lb_policy_grpclb_secure
+ - grpc_lb_policy_xds_secure
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
- grpc_resolver_dns_ares
@@ -1480,10 +1541,6 @@ libs:
- grpc_server_backward_compatibility
generate_plugin_registry: true
secure: true
- vs_packages:
- - grpc.dependencies.openssl
- - grpc.dependencies.zlib
- vs_project_guid: '{29D16885-7228-4C31-81ED-5F9187C7F2A9}'
- name: grpc_cronet
build: all
language: c
@@ -1500,27 +1557,6 @@ libs:
platforms:
- linux
secure: true
-- name: grpc_dll
- build: private
- language: c
- src: []
- deps:
- - gpr
- - grpc
- build_system:
- - visual_studio
- deps_linkage: static
- dll_def: grpc.def
- vs_config_type: DynamicLibrary
- vs_packages:
- - grpc.dependencies.openssl
- - grpc.dependencies.zlib
- vs_project_guid: '{A2F6CBBA-A553-41B3-A7DE-F26DECCC27F0}'
- vs_props:
- - zlib
- - openssl
- - winsock
- - global
- name: grpc_test_util
build: private
language: c
@@ -1539,7 +1575,6 @@ libs:
- grpc
filegroups:
- grpc_test_util_base
- vs_project_guid: '{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}'
- name: grpc_test_util_unsecure
build: private
language: c
@@ -1550,7 +1585,6 @@ libs:
filegroups:
- grpc_test_util_base
secure: false
- vs_project_guid: '{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}'
- name: grpc_unsecure
build: all
language: c
@@ -1570,6 +1604,7 @@ libs:
- grpc_resolver_sockaddr
- grpc_resolver_fake
- grpc_lb_policy_grpclb
+ - grpc_lb_policy_xds
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
- census
@@ -1581,7 +1616,6 @@ libs:
- grpc_server_backward_compatibility
generate_plugin_registry: true
secure: false
- vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
- name: reconnect_server
build: private
language: c
@@ -1635,7 +1669,6 @@ libs:
- grpc++_codegen_proto
- grpc++_codegen_base_src
secure: check
- vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}'
- name: grpc++_core_stats
build: private
language: c++
@@ -1681,7 +1714,6 @@ libs:
deps:
- grpc++
baselib: true
- vs_project_guid: '{9F58AD72-49E1-4D10-B826-9E190AB0AAC0}'
- name: grpc++_proto_reflection_desc_db
build: private
language: c++
@@ -1794,7 +1826,6 @@ libs:
- grpc++_codegen_base
- grpc++_codegen_base_src
secure: false
- vs_project_guid: '{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}'
- name: grpc_benchmark
build: test
language: c++
@@ -1869,9 +1900,6 @@ libs:
filegroups:
- grpc++_config_proto
secure: false
- vs_project_guid: '{B6E81D84-2ACB-41B8-8781-493A944C7817}'
- vs_props:
- - protoc
- name: grpcpp_channelz
build: all
language: c++
@@ -2000,6 +2028,7 @@ libs:
- src/proto/grpc/testing/worker_service.proto
- test/cpp/qps/benchmark_config.cc
- test/cpp/qps/client_async.cc
+ - test/cpp/qps/client_callback.cc
- test/cpp/qps/client_sync.cc
- test/cpp/qps/driver.cc
- test/cpp/qps/parse_json.cc
@@ -2007,6 +2036,7 @@ libs:
- test/cpp/qps/qps_worker.cc
- test/cpp/qps/report.cc
- test/cpp/qps/server_async.cc
+ - test/cpp/qps/server_callback.cc
- test/cpp/qps/server_sync.cc
- test/cpp/qps/usage_timer.cc
deps:
@@ -2026,16 +2056,6 @@ libs:
LDFLAGS: $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy)
deps_linkage: static
dll: only
- vs_config_type: DynamicLibrary
- vs_packages:
- - grpc.dependencies.openssl
- - grpc.dependencies.zlib
- vs_project_guid: '{D64C6D63-4458-4A88-AB38-35678384A7E4}'
- vs_props:
- - zlib
- - openssl
- - winsock
- - global
targets:
- name: algorithm_test
build: test
@@ -2378,21 +2398,6 @@ targets:
- uv
platforms:
- linux
-- name: ev_epollsig_linux_test
- cpu_cost: 3
- build: test
- language: c
- src:
- - test/core/iomgr/ev_epollsig_linux_test.cc
- deps:
- - grpc_test_util
- - grpc
- - gpr_test_util
- - gpr
- exclude_iomgrs:
- - uv
- platforms:
- - linux
- name: fake_resolver_test
build: test
language: c
@@ -2854,7 +2859,7 @@ targets:
filegroups:
- cmdline
uses_polling: false
-- name: handshake_client
+- name: handshake_client_ssl
build: test
language: c
src:
@@ -2869,7 +2874,7 @@ targets:
platforms:
- linux
secure: true
-- name: handshake_server
+- name: handshake_server_ssl
build: test
language: c
headers:
@@ -3168,7 +3173,7 @@ targets:
- mac
- linux
- posix
-- name: memory_profile_client
+- name: memory_usage_client
build: test
run: false
language: c
@@ -3180,7 +3185,7 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
-- name: memory_profile_server
+- name: memory_usage_server
build: test
run: false
language: c
@@ -3191,7 +3196,7 @@ targets:
- grpc
- gpr_test_util
- gpr
-- name: memory_profile_test
+- name: memory_usage_test
cpu_cost: 1.5
build: test
language: c
@@ -3344,11 +3349,11 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
-- name: pollset_set_test
+- name: resolve_address_posix_test
build: test
language: c
src:
- - test/core/iomgr/pollset_set_test.cc
+ - test/core/iomgr/resolve_address_posix_test.cc
deps:
- grpc_test_util
- grpc
@@ -3357,24 +3362,22 @@ targets:
exclude_iomgrs:
- uv
platforms:
+ - mac
- linux
-- name: resolve_address_posix_test
+ - posix
+- name: resolve_address_using_ares_resolver_test
build: test
language: c
src:
- - test/core/iomgr/resolve_address_posix_test.cc
+ - test/core/iomgr/resolve_address_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- exclude_iomgrs:
- - uv
- platforms:
- - mac
- - linux
- - posix
-- name: resolve_address_test
+ args:
+ - --resolver=ares
+- name: resolve_address_using_native_resolver_test
build: test
language: c
src:
@@ -3384,6 +3387,8 @@ targets:
- grpc
- gpr_test_util
- gpr
+ args:
+ - --resolver=native
- name: resource_quota_test
cpu_cost: 30
build: test
@@ -4476,8 +4481,23 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: client_callback_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ src:
+ - test/cpp/end2end/client_callback_end2end_test.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: client_channel_stress_test
gtest: false
+ cpu_cost: 10.0
build: test
language: c++
src:
@@ -4521,6 +4541,23 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: client_interceptors_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
+ src:
+ - test/cpp/end2end/client_interceptors_end2end_test.cc
+ - test/cpp/end2end/interceptors_util.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: client_lb_end2end_test
gtest: true
build: test
@@ -4640,8 +4677,11 @@ targets:
cpu_cost: 0.5
build: test
language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
src:
- test/cpp/end2end/end2end_test.cc
+ - test/cpp/end2end/interceptors_util.cc
deps:
- grpc++_test_util
- grpc_test_util
@@ -4741,8 +4781,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- vs_project_guid: '{7E51A25F-AC59-488F-906C-C60FAAE706AA}'
- name: grpc_csharp_plugin
build: protoc
language: c++
@@ -4751,8 +4789,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- vs_project_guid: '{3C813052-A49A-4662-B90A-1ADBEC7EE453}'
- name: grpc_linux_system_roots_test
gtest: true
build: test
@@ -4772,7 +4808,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- name: grpc_objective_c_plugin
build: protoc
language: c++
@@ -4781,8 +4816,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- vs_project_guid: '{19564640-CEE6-4921-ABA5-676ED79A36F6}'
- name: grpc_php_plugin
build: protoc
language: c++
@@ -4791,7 +4824,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- name: grpc_python_plugin
build: protoc
language: c++
@@ -4800,8 +4832,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- vs_project_guid: '{DF52D501-A6CF-4E6F-BA38-6EBE2E8DAFB2}'
- name: grpc_ruby_plugin
build: protoc
language: c++
@@ -4810,8 +4840,6 @@ targets:
deps:
- grpc_plugin_support
secure: false
- vs_config_type: Application
- vs_project_guid: '{069E9D05-B78B-4751-9252-D21EBAE7DE8E}'
- name: grpc_tool_test
gtest: true
build: test
@@ -5445,6 +5473,23 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: server_interceptors_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ headers:
+ - test/cpp/end2end/interceptors_util.h
+ src:
+ - test/cpp/end2end/interceptors_util.cc
+ - test/cpp/end2end/server_interceptors_end2end_test.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: server_request_call_test
gtest: true
build: test
@@ -5838,6 +5883,7 @@ defaults:
COREFLAGS: -fno-rtti -fno-exceptions
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
+ CXXFLAGS: -Wnon-virtual-dtor
LDFLAGS: -g
zlib:
CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration
diff --git a/build_config.rb b/build_config.rb
index 644c80fdb6..ab06a13747 100644
--- a/build_config.rb
+++ b/build_config.rb
@@ -13,5 +13,5 @@
# limitations under the License.
module GrpcBuildConfig
- CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-6.dll'
+ CORE_WINDOWS_DLL = '/tmp/libs/opt/grpc-7.dll'
end
diff --git a/cmake/OWNERS b/cmake/OWNERS
index 21981a7c55..a6181f6209 100644
--- a/cmake/OWNERS
+++ b/cmake/OWNERS
@@ -1,4 +1,4 @@
set noparent
@jtattermusch
@nicolasnoble
-@mehrdada
+@apolcyn
diff --git a/config.m4 b/config.m4
index 4f1405e235..ff4dfd45ee 100644
--- a/config.m4
+++ b/config.m4
@@ -118,7 +118,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -235,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 \
@@ -282,11 +282,14 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
- src/core/lib/security/security_connector/alts_security_connector.cc \
+ src/core/lib/security/security_connector/alts/alts_security_connector.cc \
+ src/core/lib/security/security_connector/fake/fake_security_connector.cc \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
- src/core/lib/security/security_connector/local_security_connector.cc \
+ src/core/lib/security/security_connector/local/local_security_connector.cc \
src/core/lib/security/security_connector/security_connector.cc \
+ src/core/lib/security/security_connector/ssl/ssl_security_connector.cc \
+ src/core/lib/security/security_connector/ssl_utils.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
@@ -305,7 +308,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 \
@@ -341,6 +344,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
+ src/core/ext/filters/client_channel/health/health_check_client.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_proxy.cc \
src/core/ext/filters/client_channel/lb_policy.cc \
@@ -355,9 +359,8 @@ 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/tsi/alts_transport_security.cc \
+ src/core/ext/filters/client_channel/health/health.pb.c \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/local_transport_security.cc \
src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
@@ -376,10 +379,14 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
@@ -665,11 +672,13 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/census)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/health)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/fake)
@@ -715,11 +724,16 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/plugin)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/ssl)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector/alts)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector/fake)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector/local)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector/ssl)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/transport)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/util)
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 9bd2e238f8..75ce9fa280 100644
--- a/config.w32
+++ b/config.w32
@@ -93,7 +93,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\error.cc " +
"src\\core\\lib\\iomgr\\ev_epoll1_linux.cc " +
"src\\core\\lib\\iomgr\\ev_epollex_linux.cc " +
- "src\\core\\lib\\iomgr\\ev_epollsig_linux.cc " +
"src\\core\\lib\\iomgr\\ev_poll_posix.cc " +
"src\\core\\lib\\iomgr\\ev_posix.cc " +
"src\\core\\lib\\iomgr\\ev_windows.cc " +
@@ -210,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 " +
@@ -257,11 +257,14 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\oauth2\\oauth2_credentials.cc " +
"src\\core\\lib\\security\\credentials\\plugin\\plugin_credentials.cc " +
"src\\core\\lib\\security\\credentials\\ssl\\ssl_credentials.cc " +
- "src\\core\\lib\\security\\security_connector\\alts_security_connector.cc " +
+ "src\\core\\lib\\security\\security_connector\\alts\\alts_security_connector.cc " +
+ "src\\core\\lib\\security\\security_connector\\fake\\fake_security_connector.cc " +
"src\\core\\lib\\security\\security_connector\\load_system_roots_fallback.cc " +
"src\\core\\lib\\security\\security_connector\\load_system_roots_linux.cc " +
- "src\\core\\lib\\security\\security_connector\\local_security_connector.cc " +
+ "src\\core\\lib\\security\\security_connector\\local\\local_security_connector.cc " +
"src\\core\\lib\\security\\security_connector\\security_connector.cc " +
+ "src\\core\\lib\\security\\security_connector\\ssl\\ssl_security_connector.cc " +
+ "src\\core\\lib\\security\\security_connector\\ssl_utils.cc " +
"src\\core\\lib\\security\\transport\\client_auth_filter.cc " +
"src\\core\\lib\\security\\transport\\secure_endpoint.cc " +
"src\\core\\lib\\security\\transport\\security_handshaker.cc " +
@@ -280,7 +283,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 " +
@@ -316,6 +319,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " +
"src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " +
"src\\core\\ext\\filters\\client_channel\\connector.cc " +
+ "src\\core\\ext\\filters\\client_channel\\health\\health_check_client.cc " +
"src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " +
"src\\core\\ext\\filters\\client_channel\\http_proxy.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy.cc " +
@@ -330,9 +334,8 @@ 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\\tsi\\alts_transport_security.cc " +
+ "src\\core\\ext\\filters\\client_channel\\health\\health.pb.c " +
"src\\core\\tsi\\fake_transport_security.cc " +
"src\\core\\tsi\\local_transport_security.cc " +
"src\\core\\tsi\\ssl\\session_cache\\ssl_session_boringssl.cc " +
@@ -351,10 +354,14 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_channel_secure.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_client_stats.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\load_balancer_api.cc " +
+ "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf\\duration.pb.c " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf\\timestamp.pb.c " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\load_balancer.pb.c " +
- "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_channel_secure.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_client_stats.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_load_balancer_api.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
@@ -670,6 +677,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\census");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\health");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto");
@@ -680,6 +688,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\xds");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares");
@@ -731,11 +740,16 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\plugin");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\ssl");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector\\alts");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector\\fake");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector\\local");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector\\ssl");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\transport");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\util");
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/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md
index bdd00ca363..a354dad863 100644
--- a/doc/PROTOCOL-HTTP2.md
+++ b/doc/PROTOCOL-HTTP2.md
@@ -92,7 +92,7 @@ The repeated sequence of **Length-Prefixed-Message** items is delivered in DATA
* **Length-Prefixed-Message** → Compressed-Flag Message-Length Message
* <a name="compressed-flag"></a>**Compressed-Flag** → 0 / 1 # encoded as 1 byte unsigned integer
-* **Message-Length** → {_length of Message_} # encoded as 4 byte unsigned integer
+* **Message-Length** → {_length of Message_} # encoded as 4 byte unsigned integer (big endian)
* **Message** → \*{binary octet}
A **Compressed-Flag** value of 1 indicates that the binary octet sequence of **Message** is compressed using the mechanism declared by the **Message-Encoding** header. A value of 0 indicates that no encoding of **Message** bytes has occurred. Compression contexts are NOT maintained over message boundaries, implementations must create a new context for each message in the stream. If the **Message-Encoding** header is omitted then the **Compressed-Flag** must be 0.
diff --git a/doc/connectivity-semantics-and-api.md b/doc/connectivity-semantics-and-api.md
index dc30fe5348..44fdf050c6 100644
--- a/doc/connectivity-semantics-and-api.md
+++ b/doc/connectivity-semantics-and-api.md
@@ -23,9 +23,10 @@ make progress on one of the steps involved in name resolution, TCP connection
establishment or TLS handshake. This may be used as the initial state for channels upon
creation.
-READY: The channel has successfully established a connection all the way
-through TLS handshake (or equivalent) and all subsequent attempt to communicate
-have succeeded (or are pending without any known failure ).
+READY: The channel has successfully established a connection all the way through
+TLS handshake (or equivalent) and protocol-level (HTTP/2, etc) handshaking, and
+all subsequent attempt to communicate have succeeded (or are pending without any
+known failure).
TRANSIENT_FAILURE: There has been some transient failure (such as a TCP 3-way
handshake timing out or a socket error). Channels in this state will eventually
@@ -52,8 +53,8 @@ immediately. Pending RPCs may continue running till the application cancels them
Channels may enter this state either because the application explicitly requested
a shutdown or if a non-recoverable error has happened during attempts to connect
communicate . (As of 6/12/2015, there are no known errors (while connecting or
-communicating) that are classified as non-recoverable)
-Channels that enter this state never leave this state.
+communicating) that are classified as non-recoverable.) Channels that enter this
+state never leave this state.
The following table lists the legal transitions from one state to another and
corresponding reasons. Empty cells denote disallowed transitions.
diff --git a/doc/combiner-explainer.md b/doc/core/combiner-explainer.md
index 9e9d077273..9e9d077273 100644
--- a/doc/combiner-explainer.md
+++ b/doc/core/combiner-explainer.md
diff --git a/doc/epoll-polling-engine.md b/doc/core/epoll-polling-engine.md
index 1f5d855743..1f5d855743 100644
--- a/doc/epoll-polling-engine.md
+++ b/doc/core/epoll-polling-engine.md
diff --git a/doc/core/grpc-client-server-polling-engine-usage.md b/doc/core/grpc-client-server-polling-engine-usage.md
new file mode 100644
index 0000000000..3a560e71a8
--- /dev/null
+++ b/doc/core/grpc-client-server-polling-engine-usage.md
@@ -0,0 +1,32 @@
+# Polling Engine Usage on gRPC client and Server
+
+_Author: Sree Kuchibhotla (@sreecha) - Sep 2018_
+
+
+This document talks about how polling engine is used in gRPC core (both on client and server code paths).
+
+## gRPC client
+
+### Relation between Call, Channel (sub-channels), Completion queue, `grpc_pollset`
+- A gRPC Call is tied to a channel (more specifically a sub-channel) and a completion queue for the lifetime of the call.
+- Once a _sub-channel_ is picked for the call, the file-descriptor (socket fd in case of TCP channels) is added to the pollset corresponding to call's completion queue. (Recall that as per [grpc-cq](grpc-cq.md), a completion queue has a pollset by default)
+
+![image](../images/grpc-call-channel-cq.png)
+
+
+### Making progress on Async `connect()` on sub-channels (`grpc_pollset_set` usecase)
+- A gRPC channel is created between a client and a 'target'. The 'target' may resolve in to one or more backend servers.
+- A sub-channel is the 'connection' from a client to the backend server
+- While establishing sub-cannels (i.e connections) to the backends, gRPC issues async [`connect()`](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/iomgr/tcp_client_posix.cc#L296) calls which may not complete right away. When the `connect()` eventually succeeds, the socket fd is make 'writable'
+ - This means that the polling engine must be monitoring all these sub-channel `fd`s for writable events and we need to make sure there is a polling thread that monitors all these fds
+ - To accomplish this, the `grpc_pollset_set` is used the following way (see picture below)
+
+![image](../images/grpc-client-lb-pss.png)
+
+## gRPC server
+
+- The listening fd (i.e., the socket fd corresponding to the server listening port) is added to each of the server completion queues. Note that in gRPC we use SO_REUSEPORT option and create multiple listening fds but all of them map to the same listening port
+- A new incoming channel is assigned to some server completion queue picked randomly (note that we currently [round-robin](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/iomgr/tcp_server_posix.cc#L231) over the server completion queues)
+
+![image](../images/grpc-server-cq-fds.png)
+
diff --git a/doc/core/grpc-cq.md b/doc/core/grpc-cq.md
new file mode 100644
index 0000000000..b485c35456
--- /dev/null
+++ b/doc/core/grpc-cq.md
@@ -0,0 +1,64 @@
+# gRPC Completion Queue
+
+_Author: Sree Kuchibhotla (@sreecha) - Sep 2018_
+
+Code: [completion_queue.cc](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/surface/completion_queue.cc)
+
+This document gives an overview of completion queue architecture and focuses mainly on the interaction between completion queue and the Polling engine layer.
+
+## Completion queue attributes
+Completion queue has two attributes
+
+ - Completion_type:
+ - GRPC_CQ_NEXT: grpc_completion_queue_next() can be called (but not grpc_completion_queue_pluck())
+ - GRPC_CQ_PLUCK: grpc_completion_queue_pluck() can be called (but not grpc_completion_queue_next())
+ - GRPC_CQ_CALLBACK: The tags in the queue are function pointers to callbacks. Also, neither next() nor pluck() can be called on this
+
+ - Polling_type:
+ - GRPC_CQ_NON_POLLING: Threads calling completion_queue_next/pluck do not do any polling
+ - GRPC_CQ_DEFAULT_POLLING: Threads calling completion_queue_next/pluck do polling
+ - GRPC_CQ_NON_LISTENING: Functionally similar to default polling except for a boolean attribute that states that the cq is non-listening. This is used by the grpc-server code to not associate any listening sockets with this completion-queue’s pollset
+
+
+## Details
+
+![image](../images/grpc-cq.png)
+
+
+### **grpc\_completion\_queue\_next()** & **grpc_completion_queue_pluck()** APIS
+
+
+``` C++
+grpc_completion_queue_next(cq, deadline)/pluck(cq, deadline, tag) {
+ while(true) {
+ \\ 1. If an event is queued in the completion queue, dequeue and return
+ \\ (in case of pluck() dequeue only if the tag is the one we are interested in)
+
+ \\ 2. If completion queue shutdown return
+
+ \\ 3. In case of pluck, add (tag, worker) pair to the tag<->worker map on the cq
+
+ \\ 4. Call grpc_pollset_work(cq’s-pollset, deadline) to do polling
+ \\ Note that if this function found some fds to be readable/writable/error,
+ \\ it would have scheduled those closures (which may queue completion events
+ \\ on SOME completion queue - not necessarily this one)
+ }
+}
+```
+
+### Queuing a completion event (i.e., "tag")
+
+``` C++
+grpc_cq_end_op(cq, tag) {
+ \\ 1. Queue the tag in the event queue
+
+ \\ 2. Find the pollset corresponding to the completion queue
+ \\ (i) If the cq is of type GRPC_CQ_NEXT, then KICK ANY worker
+ \\ i.e., call grpc_pollset_kick(pollset, nullptr)
+ \\ (ii) If the cq is of type GRPC_CQ_PLUCK, then search the tag<->worker
+ \\ map on the completion queue to find the worker. Then specifically
+ \\ kick that worker i.e call grpc_pollset_kick(pollset, worker)
+}
+
+```
+
diff --git a/doc/core/grpc-polling-engines.md b/doc/core/grpc-polling-engines.md
new file mode 100644
index 0000000000..f273913b1e
--- /dev/null
+++ b/doc/core/grpc-polling-engines.md
@@ -0,0 +1,154 @@
+# Polling Engines
+
+_Author: Sree Kuchibhotla (@sreecha) - Sep 2018_
+
+
+## Why do we need a 'polling engine' ?
+
+Polling engine component was created for the following reasons:
+
+- gRPC code deals with a bunch of file descriptors on which events like descriptor being readable/writable/error have to be monitored
+- gRPC code knows the actions to perform when such events happen
+ - For example:
+ - `grpc_endpoint` code calls `recvmsg` call when the fd is readable and `sendmsg` call when the fd is writable
+ - ` tcp_client` connect code issues async `connect` and finishes creating the client once the fd is writable (i.e when the `connect` actually finished)
+- gRPC needed some component that can "efficiently" do the above operations __using the threads provided by the applications (i.e., not create any new threads)__. Also by "efficiently" we mean optimized for latency and throughput
+
+
+## Polling Engine Implementations in gRPC
+There are multiple polling engine implementations depending on the OS and the OS version. Fortunately all of them expose the same interface
+
+- Linux:
+
+ - **`epollex`** (default but requires kernel version >= 4.5),
+ - `epoll1` (If `epollex` is not available and glibc version >= 2.9)
+ - `poll` (If kernel does not have epoll support)
+ - `poll-cv` (If explicitly configured)
+- Mac: **`poll`** (default), `poll-cv` (If explicitly configured)
+- Windows: (no name)
+- One-off polling engines:
+ - AppEngine platform: **`poll-cv`** (default)
+ - NodeJS : `libuv` polling engine implementation (requires different compile `#define`s)
+
+## Polling Engine Interface
+
+### Opaque Structures exposed by the polling engine
+The following are the **Opaque** structures exposed by Polling Engine interface (NOTE: Different polling engine implementations have different definitions of these structures)
+
+- **grpc_fd:** Structure representing a file descriptor
+- **grpc_pollset:** A set of one or more grpc_fds that are ‘polled’ for readable/writable/error events. One grpc_fd can be in multiple `grpc_pollset`s
+- **grpc_pollset_worker:** Structure representing a ‘polling thread’ - more specifically, the thread that calls `grpc_pollset_work()` API
+- **grpc_pollset_set:** A group of `grpc_fds`, `grpc_pollsets` and `grpc_pollset_sets` (yes, a `grpc_pollset_set` can contain other `grpc_pollset_sets`)
+
+### Polling engine API
+
+#### grpc_fd
+- **grpc\_fd\_notify\_on\_[read|write|error]**
+ - Signature: `grpc_fd_notify_on_(grpc_fd* fd, grpc_closure* closure)`
+ - Register a [closure](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/iomgr/closure.h#L67) to be called when the fd becomes readable/writable or has an error (In grpc parlance, we refer to this act as “arming the fd”)
+ - The closure is called exactly once per event. I.e once the fd becomes readable (or writable or error), the closure is fired and the fd is ‘unarmed’. To be notified again, the fd has to be armed again.
+
+- **grpc_fd_shutdown**
+ - Signature: `grpc_fd_shutdown(grpc_fd* fd)`
+ - Any current (or future) closures registered for readable/writable/error events are scheduled immediately with an error
+
+- **grpc_fd_orphan**
+ - Signature: `grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd, char* reason)`
+ - Release the `grpc_fd` structure and call `on_done` closure when the operation is complete
+ - If `release_fd` is set to `nullptr`, then `close()` the underlying fd as well. If not, put the underlying fd in `release_fd` (and do not call `close()`)
+ - `release_fd` set to non-null in cases where the underlying fd is NOT owned by grpc core (like for example the fds used by C-Ares DNS resolver )
+
+#### grpc_pollset
+
+- **grpc_pollset_add_fd **
+ - Signature: `grpc_pollset_add_fd(grpc_pollset* ps, grpc_fd *fd)`
+ - Add fd to pollset
+ > **NOTE**: There is no `grpc_pollset_remove_fd`. This is because calling `grpc_fd_orphan()` will effectively remove the fd from all the pollsets it’s a part of
+
+- ** grpc_pollset_work **
+ - Signature: `grpc_pollset_work(grpc_pollset* ps, grpc_pollset_worker** worker, grpc_millis deadline)`
+ > **NOTE**: `grpc_pollset_work()` requires the pollset mutex to be locked before calling it. Shortly after calling `grpc_pollset_work()`, the function populates the `*worker` pointer (among other things) and releases the mutex. Once `grpc_pollset_work()` returns, the `*worker` pointer is **invalid** and should not be used anymore. See the code in `completion_queue.cc` to see how this is used.
+ - Poll the fds in the pollset for events AND return when ANY of the following is true:
+ - Deadline expired
+ - Some fds in the pollset were found to be readable/writable/error and those associated closures were ‘scheduled’ (but not necessarily executed)
+ - worker is “kicked” (see `grpc_pollset_kick` for more details)
+
+- **grpc_pollset_kick**
+ - Signature: `grpc_pollset_kick(grpc_pollset* ps, grpc_pollset_worker* worker)`
+ - “Kick the worker” i.e Force the worker to return from grpc_pollset_work()
+ - If `worker == nullptr`, kick ANY worker active on that pollset
+
+#### grpc_pollset_set
+
+- **grpc\_pollset\_set\_[add|del]\_fd**
+ - Signature: `grpc_pollset_set_[add|del]_fd(grpc_pollset_set* pss, grpc_fd *fd)`
+Add/Remove fd to the `grpc_pollset_set`
+
+- **grpc\_pollset\_set_[add|del]\_pollset**
+ - Signature: `grpc_pollset_set_[add|del]_pollset(grpc_pollset_set* pss, grpc_pollset* ps)`
+ - What does adding a pollset to a pollset_set mean ?
+ - It means that calling `grpc_pollset_work()` on the pollset will also poll all the fds in the pollset_set i.e semantically, it is similar to adding all the fds inside pollset_set to the pollset.
+ - This guarantee is no longer true once the pollset is removed from the pollset_set
+
+- **grpc\_pollset\_set_[add|del]\_pollset\_set**
+ - Signature: `grpc_pollset_set_[add|del]_pollset_set(grpc_pollset_set* bag, grpc_pollset_set* item)`
+ - Semantically, this is similar to adding all the fds in the ‘bag’ pollset_set to the ‘item’ pollset_set
+
+
+#### Recap:
+
+__Relation between grpc_pollset_worker, grpc_pollset and grpc_fd:__
+
+![image](../images/grpc-ps-pss-fd.png)
+
+__grpc_pollset_set__
+
+![image](../images/grpc-pss.png)
+
+
+## Polling Engine Implementations
+
+### epoll1
+
+![image](../images/grpc-epoll1.png)
+
+Code at `src/core/lib/iomgr/ev_epoll1_posix.cc`
+
+- The logic to choose a designated poller is quite complicated. Pollsets are internally sharded into what are called `pollset_neighborhood` (a structure internal to `epoll1` polling engine implementation). `grpc_pollset_workers` that call `grpc_pollset_work` on a given pollset are all queued in a linked-list against the `grpc_pollset`. The head of the linked list is called "root worker"
+
+- There are as many neighborhoods as the number of cores. A pollset is put in a neighborhood based on the CPU core of the root worker thread. When picking the next designated poller, we always try to find another worker on the current pollset. If there are no more workers in the current pollset, a `pollset_neighborhood` listed is scanned to pick the next pollset and worker that could be the new designated poller.
+ - NOTE: There is room to tune this implementation. All we really need is good way to maintain a list of `grpc_pollset_workers` with a way to group them per-pollset (needed to implement `grpc_pollset_kick` semantics) and a way randomly select a new designated poller
+
+- See [`begin_worker()`](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/iomgr/ev_epoll1_linux.cc#L729) function to see how a designated poller is chosen. Similarly [`end_worker()`](https://github.com/grpc/grpc/blob/v1.15.1/src/core/lib/iomgr/ev_epoll1_linux.cc#L916) function is called by the worker that was just out of `epoll_wait()` and will have to choose a new designated poller)
+
+
+### epollex
+
+![image](../images/grpc-epollex.png)
+
+Code at `src/core/lib/iomgr/ev_epollex_posix.cc`
+
+- FDs are added to multiple epollsets with EPOLLEXCLUSIVE flag. This prevents multiple worker threads from waking up from polling whenever the fd is readable/writable
+
+- A few observations:
+
+ - If multiple pollsets are pointing to the same `Pollable`, then the `pollable` MUST be either empty or of type `PO_FD` (i.e single-fd)
+ - A multi-pollable has one-and-only-one incoming link from a pollset
+ - The same FD can be in multiple `Pollable`s (even if one of the `Pollable`s is of type PO_FD)
+ - There cannot be two `Pollable`s of type PO_FD for the same fd
+
+- Why do we need `Pollable` of type PO_FD and PO_EMTPY ?
+ - The main reason is the Sync client API
+ - We create one new completion queue per call. If we didn’t have PO_EMPTY and PO_FD type pollables, then every call on a given channel will effectively have to create a `Pollable` and hence an epollset. This is because every completion queue automatically creates a pollset and the channel fd will have to be put in that pollset. This clearly requires an epollset to put that fd. Creating an epollset per call (even if we delete the epollset once the call is completed) would mean a lot of sys calls to create/delete epoll fds. This is clearly not a good idea.
+ - With these new types of `Pollable`s, all pollsets (corresponding to the new per-call completion queue) will initially point to PO_EMPTY global epollset. Then once the channel fd is added to the pollset, the pollset will point to the `Pollable` of type PO_FD containing just that fd (i.e it will reuse the existing `Pollable`). This way, the epoll fd creation/deletion churn is avoided.
+
+
+### Other polling engine implementations (poll and windows polling engine)
+- **poll** polling engine: gRPC's `poll` polling engine is quite complicated. It uses the `poll()` function to do the polling (and hence it is for platforms like osx where epoll is not available)
+ - The implementation is further complicated by the fact that poll() is level triggered (just keep this in mind in case you wonder why the code at `src/core/lib/iomgr/ev_poll_posix.cc` is written a certain/seemingly complicated way :))
+
+- **Polling engine on Windows**: Windows polling engine looks nothing like other polling engines
+ - Unlike the grpc polling engines for Unix systems (epollex, epoll1 and poll) Windows endpoint implementation and polling engine implementations are very closely tied together
+ - Windows endpoint read/write API implementations use the Windows IO API which require specifying an [I/O completion port](https://docs.microsoft.com/en-us/windows/desktop/fileio/i-o-completion-ports)
+ - In Windows polling engine’s grpc_pollset_work() implementation, ONE of the threads is chosen to wait on the I/O completion port while other threads wait on a condition variable (much like the turnstile polling in epollex/epoll1)
+
diff --git a/doc/images/new_epoll_impl.png b/doc/core/images/new_epoll_impl.png
index 9ca1f49cbd..9ca1f49cbd 100644
--- a/doc/images/new_epoll_impl.png
+++ b/doc/core/images/new_epoll_impl.png
Binary files differ
diff --git a/doc/images/old_epoll_impl.png b/doc/core/images/old_epoll_impl.png
index 7ac3df8367..7ac3df8367 100644
--- a/doc/images/old_epoll_impl.png
+++ b/doc/core/images/old_epoll_impl.png
Binary files differ
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index b472f7e126..d1172e62f4 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -52,6 +52,7 @@ some configuration as environment variables that can be set.
traces epoll-fd creation/close calls for epollex polling engine
- glb - traces the grpclb load balancer
- handshaker - traces handshaking state
+ - health_check_client - traces health checking client code
- http - traces state in the http2 transport engine
- http2_stream_state - traces all http2 stream state mutations.
- http1 - traces HTTP/1.x operations performed by gRPC
@@ -139,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/doc/g_stands_for.md b/doc/g_stands_for.md
index b3ed9bd713..a5a8efb21c 100644
--- a/doc/g_stands_for.md
+++ b/doc/g_stands_for.md
@@ -14,4 +14,6 @@
- 1.12 'g' stands for ['glorious'](https://github.com/grpc/grpc/tree/v1.12.x)
- 1.13 'g' stands for ['gloriosa'](https://github.com/grpc/grpc/tree/v1.13.x)
- 1.14 'g' stands for ['gladiolus'](https://github.com/grpc/grpc/tree/v1.14.x)
-- 1.15 'g' stands for ['glider'](https://github.com/grpc/grpc/tree/master)
+- 1.15 'g' stands for ['glider'](https://github.com/grpc/grpc/tree/v1.15.x)
+- 1.16 'g' stands for ['gao'](https://github.com/grpc/grpc/tree/v1.16.x)
+- 1.17 'g' stands for ['gizmo'](https://github.com/grpc/grpc/tree/master)
diff --git a/doc/images/grpc-call-channel-cq.png b/doc/images/grpc-call-channel-cq.png
new file mode 100644
index 0000000000..d73b987ee9
--- /dev/null
+++ b/doc/images/grpc-call-channel-cq.png
Binary files differ
diff --git a/doc/images/grpc-client-lb-pss.png b/doc/images/grpc-client-lb-pss.png
new file mode 100644
index 0000000000..188e3654ec
--- /dev/null
+++ b/doc/images/grpc-client-lb-pss.png
Binary files differ
diff --git a/doc/images/grpc-cq.png b/doc/images/grpc-cq.png
new file mode 100644
index 0000000000..2d9e095862
--- /dev/null
+++ b/doc/images/grpc-cq.png
Binary files differ
diff --git a/doc/images/grpc-epoll1.png b/doc/images/grpc-epoll1.png
new file mode 100644
index 0000000000..3ab9a4c7d1
--- /dev/null
+++ b/doc/images/grpc-epoll1.png
Binary files differ
diff --git a/doc/images/grpc-epollex.png b/doc/images/grpc-epollex.png
new file mode 100644
index 0000000000..86dc0005b3
--- /dev/null
+++ b/doc/images/grpc-epollex.png
Binary files differ
diff --git a/doc/images/grpc-ps-pss-fd.png b/doc/images/grpc-ps-pss-fd.png
new file mode 100644
index 0000000000..790af7f1bc
--- /dev/null
+++ b/doc/images/grpc-ps-pss-fd.png
Binary files differ
diff --git a/doc/images/grpc-pss.png b/doc/images/grpc-pss.png
new file mode 100644
index 0000000000..3a0dd9c3ee
--- /dev/null
+++ b/doc/images/grpc-pss.png
Binary files differ
diff --git a/doc/images/grpc-server-cq-fds.png b/doc/images/grpc-server-cq-fds.png
new file mode 100644
index 0000000000..e52bfac81c
--- /dev/null
+++ b/doc/images/grpc-server-cq-fds.png
Binary files differ
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 3c33189196..1d6535d7ea 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -944,6 +944,11 @@ the experimental flag, `soak_iterations`.
This tests puts stress on several gRPC components; the resolver, the load
balancer, and the RPC hotpath.
+#### long_lived_channel
+
+The client performs a number of large_unary RPCs over a single long-lived
+channel with a fixed but configurable interval between each RPC.
+
### TODO Tests
#### High priority:
diff --git a/doc/naming.md b/doc/naming.md
index 676aa9f298..581c550567 100644
--- a/doc/naming.md
+++ b/doc/naming.md
@@ -14,34 +14,48 @@ be plugged in.
### Name Syntax
A fully qualified, self contained name used for gRPC channel construction
-uses the syntax:
-
-```
-scheme://authority/endpoint_name
-```
-
-Here, `scheme` indicates the name-system to be used. Currently, we
-support the following schemes:
-
-- `dns`
-
-- `ipv4` (IPv4 address)
-
-- `ipv6` (IPv6 address)
-
-- `unix` (path to unix domain socket -- unix systems only)
+uses URI syntax as defined in [RFC 3986](https://tools.ietf.org/html/rfc3986).
+
+The URI scheme indicates what resolver plugin to use. If no scheme
+prefix is specified or the scheme is unknown, the `dns` scheme is used
+by default.
+
+The URI path indicates the name to be resolved.
+
+Most gRPC implementations support the following URI schemes:
+
+- `dns:[//authority/]host[:port]` -- DNS (default)
+ - `host` is the host to resolve via DNS.
+ - `port` is the port to return for each address. If not specified,
+ 443 is used (but some implementations default to 80 for insecure
+ channels).
+ - `authority` indicates the DNS server to use, although this is only
+ supported by some implementations. (In C-core, the default DNS
+ resolver does not support this, but the c-ares based resolver
+ supports specifying this in the form "IP:port".)
+
+- `unix:path` or `unix://absolute_path` -- Unix domain sockets (Unix systems only)
+ - `path` indicates the location of the desired socket.
+ - In the first form, the path may be relative or absolute; in the
+ second form, the path must be absolute (i.e., there will actually be
+ three slashes, two prior to the path and another to begin the
+ absolute path).
+
+The following schemes are supported by the gRPC C-core implementation,
+but may not be supported in other languages:
+
+- `ipv4:address[:port][,address[:port],...]` -- IPv4 addresses
+ - Can specify multiple comma-delimited addresses of the form `address[:port]`:
+ - `address` is the IPv4 address to use.
+ - `port` is the port to use. If not specified, 443 is used.
+
+- `ipv6:address[:port][,address[:port],...]` -- IPv6 addresses
+ - Can specify multiple comma-delimited addresses of the form `address[:port]`:
+ - `address` is the IPv6 address to use.
+ - `port` is the port to use. If not specified, 443 is used.
In the future, additional schemes such as `etcd` could be added.
-The `authority` indicates some scheme-specific bootstrap information, e.g.,
-for DNS, the authority may include the IP[:port] of the DNS server to
-use. Often, a DNS name may be used as the authority, since the ability to
-resolve DNS names is already built into all gRPC client libraries.
-
-Finally, the `endpoint_name` indicates a concrete name to be looked up
-in a given name-system identified by the scheme and the authority. The
-syntax of the endpoint name is dictated by the scheme in use.
-
### Resolver Plugins
The gRPC client library will use the specified scheme to pick the right
diff --git a/doc/python/sphinx/conf.py b/doc/python/sphinx/conf.py
new file mode 100644
index 0000000000..1eb3a5de7f
--- /dev/null
+++ b/doc/python/sphinx/conf.py
@@ -0,0 +1,102 @@
+# 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.
+
+# -- Path setup --------------------------------------------------------------
+
+import os
+import sys
+PYTHON_FOLDER = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ '..', '..', '..', 'src', 'python')
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_health_checking'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_reflection'))
+sys.path.insert(0, os.path.join(PYTHON_FOLDER, 'grpcio_testing'))
+
+# -- Project information -----------------------------------------------------
+
+project = 'gRPC Python'
+copyright = '2018, The gRPC Authors'
+author = 'The gRPC Authors'
+
+# Import generated grpc_version after the path been modified
+import grpc_version
+version = ".".join(grpc_version.VERSION.split(".")[:3])
+release = grpc_version.VERSION
+
+# -- General configuration ---------------------------------------------------
+
+templates_path = ['_templates']
+source_suffix = ['.rst', '.md']
+master_doc = 'index'
+language = 'en'
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+pygments_style = None
+
+# --- Extensions Configuration -----------------------------------------------
+
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.napoleon',
+ 'sphinx.ext.coverage',
+]
+
+napoleon_google_docstring = True
+napoleon_numpy_docstring = True
+napoleon_include_special_with_doc = True
+
+autodoc_default_options = {
+ 'members': None,
+}
+
+autodoc_mock_imports = [
+ 'grpc._cython',
+ 'grpc_health.v1.health_pb2',
+ 'grpc_health.v1.health_pb2_grpc',
+ 'grpc_reflection.v1alpha.reflection_pb2',
+ 'grpc_reflection.v1alpha.reflection_pb2_grpc',
+]
+
+# -- HTML Configuration -------------------------------------------------
+
+html_theme = 'alabaster'
+html_theme_options = {
+ 'fixed_sidebar': True,
+ 'page_width': '1140px',
+ 'show_related': True,
+ 'analytics_id': 'UA-60127042-1',
+ 'description': grpc_version.VERSION,
+ 'show_powered_by': False,
+}
+
+# -- Options for manual page output ------------------------------------------
+
+man_pages = [(master_doc, 'grpcio', 'grpcio Documentation', [author], 1)]
+
+# -- Options for Texinfo output ----------------------------------------------
+
+texinfo_documents = [
+ (master_doc, 'grpcio', 'grpcio Documentation', author, 'grpcio',
+ 'One line description of project.', 'Miscellaneous'),
+]
+
+# -- Options for Epub output -------------------------------------------------
+
+epub_title = project
+epub_exclude_files = ['search.html']
+
+# -- Options for todo extension ----------------------------------------------
+
+todo_include_todos = True
diff --git a/doc/python/sphinx/glossary.rst b/doc/python/sphinx/glossary.rst
new file mode 100644
index 0000000000..dee5d16143
--- /dev/null
+++ b/doc/python/sphinx/glossary.rst
@@ -0,0 +1,16 @@
+Glossary
+================
+
+.. glossary::
+
+ metadatum
+ A key-value pair included in the HTTP header. It is a
+ 2-tuple where the first entry is the key and the
+ second is the value, i.e. (key, value). The metadata key is an ASCII str,
+ and must be a valid HTTP header name. The metadata value can be
+ either a valid HTTP ASCII str, or bytes. If bytes are provided,
+ the key must end with '-bin', i.e.
+ ``('binary-metadata-bin', b'\\x00\\xFF')``
+
+ metadata
+ A sequence of metadatum.
diff --git a/doc/python/sphinx/grpc.rst b/doc/python/sphinx/grpc.rst
new file mode 100644
index 0000000000..bd2df9596b
--- /dev/null
+++ b/doc/python/sphinx/grpc.rst
@@ -0,0 +1,169 @@
+gRPC
+=============
+
+.. module:: grpc
+
+Tutorial
+--------
+
+If you want to see gRPC in action first, visit the `Python Quickstart <https://grpc.io/docs/quickstart/python.html>`_.
+Or, if you would like dive in with more extensive usage of gRPC Python, check `gRPC Basics - Python <https://grpc.io/docs/tutorials/basic/python.html>`_ out.
+
+
+Example
+-------
+
+Go to `gRPC Python Examples <https://github.com/grpc/grpc/tree/master/examples/python>`_
+
+
+Module Contents
+---------------
+
+Create Client
+^^^^^^^^^^^^^
+
+.. autofunction:: insecure_channel
+.. autofunction:: secure_channel
+.. autofunction:: intercept_channel
+
+
+Create Client Credentials
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: ssl_channel_credentials
+.. autofunction:: metadata_call_credentials
+.. autofunction:: access_token_call_credentials
+.. autofunction:: composite_call_credentials
+.. autofunction:: composite_channel_credentials
+
+
+Create Server
+^^^^^^^^^^^^^
+
+.. autofunction:: server
+
+
+Create Server Credentials
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: ssl_server_credentials
+.. autofunction:: ssl_server_certificate_configuration
+.. autofunction:: dynamic_ssl_server_credentials
+
+
+RPC Method Handlers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: unary_unary_rpc_method_handler
+.. autofunction:: unary_stream_rpc_method_handler
+.. autofunction:: stream_unary_rpc_method_handler
+.. autofunction:: stream_stream_rpc_method_handler
+.. autofunction:: method_handlers_generic_handler
+
+
+Channel Ready Future
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: channel_ready_future
+
+
+Channel Connectivity
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ChannelConnectivity
+
+
+gRPC Status Code
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: StatusCode
+
+
+Channel Object
+^^^^^^^^^^^^^^
+
+.. autoclass:: Channel
+
+
+Server Object
+^^^^^^^^^^^^^
+
+.. autoclass:: Server
+
+
+Authentication & Authorization Objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ChannelCredentials
+.. autoclass:: CallCredentials
+.. autoclass:: AuthMetadataContext
+.. autoclass:: AuthMetadataPluginCallback
+.. autoclass:: AuthMetadataPlugin
+.. autoclass:: ServerCredentials
+.. autoclass:: ServerCertificateConfiguration
+
+
+gRPC Exceptions
+^^^^^^^^^^^^^^^
+
+.. autoexception:: RpcError
+
+
+Shared Context
+^^^^^^^^^^^^^^
+
+.. autoclass:: RpcContext
+
+
+Client-Side Context
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: Call
+
+
+Client-Side Interceptor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ClientCallDetails
+.. autoclass:: UnaryUnaryClientInterceptor
+.. autoclass:: UnaryStreamClientInterceptor
+.. autoclass:: StreamUnaryClientInterceptor
+.. autoclass:: StreamStreamClientInterceptor
+
+
+Service-Side Context
+^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ServicerContext
+
+
+Service-Side Handler
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: RpcMethodHandler
+.. autoclass:: HandlerCallDetails
+.. autoclass:: GenericRpcHandler
+.. autoclass:: ServiceRpcHandler
+
+
+Service-Side Interceptor
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: ServerInterceptor
+
+
+Multi-Callable Interfaces
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autoclass:: UnaryUnaryMultiCallable
+.. autoclass:: UnaryStreamMultiCallable
+.. autoclass:: StreamUnaryMultiCallable
+.. autoclass:: StreamStreamMultiCallable
+
+
+Future Interfaces
+^^^^^^^^^^^^^^^^^
+
+.. autoexception:: FutureTimeoutError
+.. autoexception:: FutureCancelledError
+.. autoclass:: Future
diff --git a/doc/python/sphinx/grpc_health_checking.rst b/doc/python/sphinx/grpc_health_checking.rst
new file mode 100644
index 0000000000..b344e34ac9
--- /dev/null
+++ b/doc/python/sphinx/grpc_health_checking.rst
@@ -0,0 +1,7 @@
+gRPC Health Checking
+====================
+
+Module Contents
+---------------
+
+.. autoclass:: grpc_health.v1.health.HealthServicer
diff --git a/doc/python/sphinx/grpc_reflection.rst b/doc/python/sphinx/grpc_reflection.rst
new file mode 100644
index 0000000000..043f2edb96
--- /dev/null
+++ b/doc/python/sphinx/grpc_reflection.rst
@@ -0,0 +1,19 @@
+gRPC Reflection
+====================
+
+What is gRPC reflection?
+---------------------------------------------
+
+Check this out `gRPC Python Server Reflection <https://github.com/grpc/grpc/blob/master/doc/python/server_reflection.md>`_
+
+
+Example
+-------
+
+Refer to the GitHub `reflection example <https://github.com/grpc/grpc/blob/master/examples/python/helloworld/greeter_server_with_reflection.py>`_
+
+
+Module Contents
+---------------
+
+.. automodule:: grpc_reflection.v1alpha.reflection
diff --git a/doc/python/sphinx/grpc_testing.rst b/doc/python/sphinx/grpc_testing.rst
new file mode 100644
index 0000000000..adfeb8b384
--- /dev/null
+++ b/doc/python/sphinx/grpc_testing.rst
@@ -0,0 +1,7 @@
+gRPC Testing
+====================
+
+Module Contents
+---------------
+
+.. automodule:: grpc_testing
diff --git a/doc/python/sphinx/index.rst b/doc/python/sphinx/index.rst
new file mode 100644
index 0000000000..322ca33e15
--- /dev/null
+++ b/doc/python/sphinx/index.rst
@@ -0,0 +1,24 @@
+Welcome to gRPC Python's documentation!
+=======================================
+
+Version: |version| Release: |release|
+
+API Reference
+=============
+
+.. toctree::
+ :caption: Contents:
+
+ grpc
+ grpc_health_checking
+ grpc_reflection
+ grpc_testing
+ glossary
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/server-reflection.md b/doc/server-reflection.md
index 3716dc5a21..0cc30a4eb0 100644
--- a/doc/server-reflection.md
+++ b/doc/server-reflection.md
@@ -161,6 +161,7 @@ which FileDescriptorProtos have been sent on a given stream, for a given value
of valid_host, and avoid sending them repeatedly for overlapping requests.
| message_request message | Result |
+| --------------------------- | ----------------------------------------------- |
| files_for_file_name | transitive closure of file name |
| files_for_symbol_name | transitive closure file containing symbol |
| file_containing_extension | transitive closure of file containing a given extension number of a given symbol |
diff --git a/doc/ssl-performance.md b/doc/ssl-performance.md
index 711b9dff09..20fe3cef08 100644
--- a/doc/ssl-performance.md
+++ b/doc/ssl-performance.md
@@ -25,7 +25,10 @@ In addition, we are shipping packages for language implementations. These packag
Language | From source | Platform | Uses assembly optimizations
---|---|---|---
-C# | n/a | all | :x:
+C# | n/a | Linux, 64bit | :heavy_check_mark:
+C# | n/a | Linux, 32bit | :x:
+C# | n/a | MacOS | :heavy_check_mark:
+C# | n/a | Windows | :heavy_check_mark:
Node.JS | n/a | Linux | :heavy_check_mark:
Node.JS | n/a | MacOS | :heavy_check_mark:
Node.JS | n/a | Windows | :x:
diff --git a/doc/statuscodes.md b/doc/statuscodes.md
index 06fbe5c8fe..547da05495 100644
--- a/doc/statuscodes.md
+++ b/doc/statuscodes.md
@@ -38,7 +38,7 @@ situations in which they are generated.
| Error parsing response proto | INTERNAL | Client|
| Error parsing request proto | INTERNAL | Server|
| Sent or received message was larger than configured limit | RESOURCE_EXHAUSTED | Both |
-| Keepalive watchdog times out | INTERNAL | Both |
+| Keepalive watchdog times out | UNAVAILABLE | Both |
The following status codes are never generated by the library:
- INVALID_ARGUMENT
diff --git a/etc/roots.pem b/etc/roots.pem
index c22dfe69f8..3e6bbcd76e 100644
--- a/etc/roots.pem
+++ b/etc/roots.pem
@@ -4317,3 +4317,26 @@ JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----
+
+# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
+# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
+# Label: "OISTE WISeKey Global Root GC CA"
+# Serial: 44084345621038548146064804565436152554
+# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23
+# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31
+# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
+CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
+bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
+Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
+BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
+ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
+b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
+eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
+p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
+rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
+57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
+Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
diff --git a/examples/csharp/Helloworld/Greeter/Greeter.csproj b/examples/csharp/Helloworld/Greeter/Greeter.csproj
index 1ca821320c..eba262565d 100644
--- a/examples/csharp/Helloworld/Greeter/Greeter.csproj
+++ b/examples/csharp/Helloworld/Greeter/Greeter.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>Greeter</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>Greeter</AssemblyName>
<PackageId>Greeter</PackageId>
diff --git a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
index d1ed040411..24a89d58c5 100644
--- a/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
+++ b/examples/csharp/Helloworld/GreeterClient/GreeterClient.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>GreeterClient</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>GreeterClient</AssemblyName>
<OutputType>Exe</OutputType>
diff --git a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
index 159fbd8a23..9ea1fa3817 100644
--- a/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
+++ b/examples/csharp/Helloworld/GreeterServer/GreeterServer.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>GreeterServer</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>GreeterServer</AssemblyName>
<OutputType>Exe</OutputType>
diff --git a/examples/csharp/Helloworld/README.md b/examples/csharp/Helloworld/README.md
index e603179438..4871132426 100644
--- a/examples/csharp/Helloworld/README.md
+++ b/examples/csharp/Helloworld/README.md
@@ -12,7 +12,7 @@ which have been already added to the project for you.
PREREQUISITES
-------------
-- The [.NET Core SDK](https://www.microsoft.com/net/core) (version 2+ is recommended)
+- The [.NET Core SDK 2.1+](https://www.microsoft.com/net/core)
You can also build the example directly using Visual Studio 2017, but it's not a requirement.
@@ -23,8 +23,6 @@ From the `examples/csharp/Helloworld` directory:
- `dotnet build Greeter.sln`
-(if you're using dotnet SDK 1.x you need to run `dotnet restore Greeter.sln` first)
-
Try it!
-------
@@ -32,14 +30,14 @@ Try it!
```
> cd GreeterServer
- > dotnet run -f netcoreapp1.0
+ > dotnet run -f netcoreapp2.1
```
- Run the client
```
> cd GreeterClient
- > dotnet run -f netcoreapp1.0
+ > dotnet run -f netcoreapp2.1
```
Tutorial
diff --git a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
index e1c44ecf3c..86346d1e14 100644
--- a/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
+++ b/examples/csharp/RouteGuide/RouteGuide/RouteGuide.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>RouteGuide</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>RouteGuide</AssemblyName>
<PackageId>RouteGuide</PackageId>
diff --git a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
index 96cc204ba3..c6dadf082b 100644
--- a/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
+++ b/examples/csharp/RouteGuide/RouteGuideClient/RouteGuideClient.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>RouteGuideClient</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>RouteGuideClient</AssemblyName>
<OutputType>Exe</OutputType>
diff --git a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
index aa6315bf81..005c87ca0c 100644
--- a/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
+++ b/examples/csharp/RouteGuide/RouteGuideServer/RouteGuideServer.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyTitle>RouteGuideServer</AssemblyTitle>
- <TargetFrameworks>netcoreapp1.0</TargetFrameworks>
+ <TargetFrameworks>netcoreapp2.1</TargetFrameworks>
<DebugType>portable</DebugType>
<AssemblyName>RouteGuideServer</AssemblyName>
<OutputType>Exe</OutputType>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld.podspec b/examples/objective-c/helloworld_macos/HelloWorld.podspec
new file mode 100644
index 0000000000..fc671ef4da
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld.podspec
@@ -0,0 +1,66 @@
+Pod::Spec.new do |s|
+ s.name = "HelloWorld"
+ s.version = "0.0.1"
+ s.license = "Apache License, Version 2.0"
+ s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+ s.homepage = "https://grpc.io/"
+ s.summary = "HelloWorld example"
+ s.source = { :git => 'https://github.com/grpc/grpc.git' }
+
+ s.ios.deployment_target = "7.1"
+ s.osx.deployment_target = "10.9"
+
+ # Base directory where the .proto files are.
+ src = "../../protos"
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"
+
+ # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
+ pods_root = 'Pods'
+
+ # Path where Cocoapods downloads protoc and the gRPC plugin.
+ protoc_dir = "#{pods_root}/!ProtoCompiler"
+ protoc = "#{protoc_dir}/protoc"
+ plugin = "#{pods_root}/!ProtoCompiler-gRPCPlugin/grpc_objective_c_plugin"
+
+ # Directory where the generated files will be placed.
+ dir = "#{pods_root}/#{s.name}"
+
+ s.prepare_command = <<-CMD
+ mkdir -p #{dir}
+ #{protoc} \
+ --plugin=protoc-gen-grpc=#{plugin} \
+ --objc_out=#{dir} \
+ --grpc_out=#{dir} \
+ -I #{src} \
+ -I #{protoc_dir} \
+ #{src}/helloworld.proto
+ CMD
+
+ # Files generated by protoc
+ s.subspec "Messages" do |ms|
+ ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
+ ms.header_mappings_dir = dir
+ ms.requires_arc = false
+ # The generated files depend on the protobuf runtime.
+ ms.dependency "Protobuf"
+ end
+
+ # Files generated by the gRPC plugin
+ s.subspec "Services" do |ss|
+ ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
+ ss.header_mappings_dir = dir
+ ss.requires_arc = true
+ # The generated files depend on the gRPC runtime, and on the files generated by protoc.
+ ss.dependency "gRPC-ProtoRPC"
+ ss.dependency "#{s.name}/Messages"
+ end
+
+ s.pod_target_xcconfig = {
+ # This is needed by all pods that depend on Protobuf:
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+ # This is needed by all pods that depend on gRPC-RxLibrary:
+ 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+ }
+end
diff --git a/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..06f06290d5
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj
@@ -0,0 +1,399 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 5EF711A4215174880077496F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A3215174880077496F /* AppDelegate.m */; };
+ 5EF711A7215174880077496F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A6215174880077496F /* ViewController.m */; };
+ 5EF711A9215174890077496F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711A8215174890077496F /* Assets.xcassets */; };
+ 5EF711AC215174890077496F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711AA215174890077496F /* Main.storyboard */; };
+ 5EF711AF215174890077496F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711AE215174890077496F /* main.m */; };
+ 827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
+ 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5EF7119F215174870077496F /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5EF711A2215174880077496F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 5EF711A3215174880077496F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 5EF711A5215174880077496F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ 5EF711A6215174880077496F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ 5EF711A8215174890077496F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ 5EF711AB215174890077496F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 5EF711AD215174890077496F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 5EF711AE215174890077496F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 5EF711B0215174890077496F /* HelloWorld.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HelloWorld.entitlements; sourceTree = "<group>"; };
+ CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5EF7119C215174870077496F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 5EF71196215174870077496F = {
+ isa = PBXGroup;
+ children = (
+ 5EF711AE215174890077496F /* main.m */,
+ 5EF711A1215174870077496F /* HelloWorld */,
+ 5EF711A0215174870077496F /* Products */,
+ 8D3EFBB796129582177142C4 /* Pods */,
+ A986548CB5622AF6CC3ECCCE /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 5EF711A0215174870077496F /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5EF7119F215174870077496F /* HelloWorld.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 5EF711A1215174870077496F /* HelloWorld */ = {
+ isa = PBXGroup;
+ children = (
+ 5EF711A2215174880077496F /* AppDelegate.h */,
+ 5EF711A3215174880077496F /* AppDelegate.m */,
+ 5EF711A5215174880077496F /* ViewController.h */,
+ 5EF711A6215174880077496F /* ViewController.m */,
+ 5EF711A8215174890077496F /* Assets.xcassets */,
+ 5EF711AA215174890077496F /* Main.storyboard */,
+ 5EF711AD215174890077496F /* Info.plist */,
+ 5EF711B0215174890077496F /* HelloWorld.entitlements */,
+ );
+ path = HelloWorld;
+ sourceTree = "<group>";
+ };
+ 8D3EFBB796129582177142C4 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */,
+ 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ A986548CB5622AF6CC3ECCCE /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 5EF7119E215174870077496F /* HelloWorld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */;
+ buildPhases = (
+ 3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */,
+ 5EF7119B215174870077496F /* Sources */,
+ 5EF7119C215174870077496F /* Frameworks */,
+ 5EF7119D215174870077496F /* Resources */,
+ DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = HelloWorld;
+ productName = HelloWorld;
+ productReference = 5EF7119F215174870077496F /* HelloWorld.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 5EF71197215174870077496F /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0930;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 5EF7119E215174870077496F = {
+ CreatedOnToolsVersion = 9.3;
+ SystemCapabilities = {
+ com.apple.Sandbox = {
+ enabled = 0;
+ };
+ };
+ };
+ };
+ };
+ buildConfigurationList = 5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 5EF71196215174870077496F;
+ productRefGroup = 5EF711A0215174870077496F /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 5EF7119E215174870077496F /* HelloWorld */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 5EF7119D215174870077496F /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5EF711A9215174890077496F /* Assets.xcassets in Resources */,
+ 5EF711AC215174890077496F /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-HelloWorld-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 5EF7119B215174870077496F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5EF711A7215174880077496F /* ViewController.m in Sources */,
+ 5EF711AF215174890077496F /* main.m in Sources */,
+ 5EF711A4215174880077496F /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 5EF711AA215174890077496F /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 5EF711AB215174890077496F /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 5EF711B1215174890077496F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ 5EF711B2215174890077496F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ 5EF711B4215174890077496F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 5EF711B5215174890077496F /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ INFOPLIST_FILE = HelloWorld/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5EF711B1215174890077496F /* Debug */,
+ 5EF711B2215174890077496F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5EF711B4215174890077496F /* Debug */,
+ 5EF711B5215174890077496F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 5EF71197215174870077496F /* Project object */;
+}
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h
new file mode 100644
index 0000000000..1b88e35d22
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+
+
+@end
+
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m
new file mode 100644
index 0000000000..7da5e1171b
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ // Insert code here to initialize your application
+}
+
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification {
+ // Insert code here to tear down your application
+}
+
+
+@end
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..2db2b1c7c6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..da4a164c91
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard b/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..3ed4144fba
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard
@@ -0,0 +1,717 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
+ </dependencies>
+ <scenes>
+ <!--Application-->
+ <scene sceneID="JPo-4y-FX3">
+ <objects>
+ <application id="hnw-xV-0zn" sceneMemberID="viewController">
+ <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
+ <items>
+ <menuItem title="HelloWorld" id="1Xt-HY-uBw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="HelloWorld" systemMenu="apple" id="uQy-DD-JDr">
+ <items>
+ <menuItem title="About HelloWorld" id="5kV-Vb-QxS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
+ <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
+ <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
+ <menuItem title="Services" id="NMo-om-nkz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
+ <menuItem title="Hide HelloWorld" keyEquivalent="h" id="Olw-nP-bQN">
+ <connections>
+ <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="Kd2-mp-pUS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
+ <menuItem title="Quit HelloWorld" keyEquivalent="q" id="4sb-4s-VLi">
+ <connections>
+ <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" id="dMs-cI-mzQ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="File" id="bib-Uj-vzu">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
+ <connections>
+ <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
+ <connections>
+ <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="tXI-mr-wws">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
+ <items>
+ <menuItem title="Clear Menu" id="vNY-rz-j42">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
+ <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
+ <connections>
+ <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
+ <connections>
+ <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
+ <connections>
+ <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
+ <connections>
+ <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
+ <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
+ <connections>
+ <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" id="5QF-Oa-p0T">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Edit" id="W48-6f-4Dl">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
+ <connections>
+ <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
+ <connections>
+ <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
+ <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
+ <connections>
+ <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
+ <connections>
+ <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
+ <connections>
+ <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="pa3-QI-u2k">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
+ <connections>
+ <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
+ <menuItem title="Find" id="4EN-yA-p0u">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Find" id="1b7-l0-nxx">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
+ <items>
+ <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
+ <connections>
+ <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
+ <connections>
+ <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
+ <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="9ic-FL-obx">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
+ <items>
+ <menuItem title="Show Substitutions" id="z6F-FW-3nz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
+ <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" id="hQb-2v-fYv">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Dashes" id="rgM-f4-ycn">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" id="cwL-P1-jid">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Data Detectors" id="tRr-pd-1PS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Text Replacement" id="HFQ-gK-NFA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Transformations" id="2oI-Rn-ZJC">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
+ <items>
+ <menuItem title="Make Upper Case" id="vmV-6d-7jI">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Make Lower Case" id="d9M-CD-aMd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Capitalize" id="UEZ-Bs-lqG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="xrE-MZ-jX0">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
+ <items>
+ <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" id="jxT-CU-nIS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Format" id="GEO-Iw-cKr">
+ <items>
+ <menuItem title="Font" id="Gi5-1S-RQB">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
+ <connections>
+ <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
+ <connections>
+ <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
+ <connections>
+ <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
+ <connections>
+ <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
+ <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
+ <connections>
+ <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
+ <connections>
+ <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
+ <menuItem title="Kern" id="jBQ-r6-VK2">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Kern" id="tlD-Oa-oAM">
+ <items>
+ <menuItem title="Use Default" id="GUa-eO-cwY">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="cDB-IK-hbR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Tighten" id="46P-cB-AYj">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Loosen" id="ogc-rX-tC1">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Ligatures" id="o6e-r0-MWq">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
+ <items>
+ <menuItem title="Use Default" id="agt-UL-0e3">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="J7y-lM-qPV">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use All" id="xQD-1f-W4t">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Baseline" id="OaQ-X3-Vso">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Baseline" id="ijk-EB-dga">
+ <items>
+ <menuItem title="Use Default" id="3Om-Ey-2VK">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Superscript" id="Rqc-34-cIF">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Subscript" id="I0S-gh-46l">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Raise" id="2h7-ER-AoG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Lower" id="1tx-W0-xDw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
+ <connections>
+ <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
+ <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Text" id="Fal-I4-PZk">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Text" id="d9c-me-L2H">
+ <items>
+ <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
+ <connections>
+ <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
+ <connections>
+ <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Justify" id="J5U-5w-g23">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
+ <connections>
+ <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
+ <menuItem title="Writing Direction" id="H1b-Si-o9J">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
+ <items>
+ <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="YGs-j5-SAR">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
+ </connections>
+ </menuItem>
+ <menuItem id="Lbh-J2-qVU">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
+ </connections>
+ </menuItem>
+ <menuItem id="jFq-tB-4Kx">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
+ <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="Nop-cj-93Q">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
+ </connections>
+ </menuItem>
+ <menuItem id="BgM-ve-c93">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
+ </connections>
+ </menuItem>
+ <menuItem id="RB4-Sm-HuC">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
+ <menuItem title="Show Ruler" id="vLm-3I-IUL">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" id="H8h-7b-M4v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="View" id="HyV-fh-RgO">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
+ <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" id="aUF-d1-5bR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
+ <connections>
+ <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="R4o-n2-Eq4">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
+ <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" id="wpr-3q-Mcd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
+ <items>
+ <menuItem title="HelloWorld Help" keyEquivalent="?" id="FKE-Sm-Kum">
+ <connections>
+ <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <connections>
+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
+ </connections>
+ </application>
+ <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider=""/>
+ <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
+ <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="0.0"/>
+ </scene>
+ <!--Window Controller-->
+ <scene sceneID="R2V-B0-nI4">
+ <objects>
+ <windowController id="B8D-0N-5wS" sceneMemberID="viewController">
+ <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="196" y="240" width="480" height="270"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
+ <connections>
+ <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
+ </connections>
+ </window>
+ <connections>
+ <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
+ </connections>
+ </windowController>
+ <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="250"/>
+ </scene>
+ <!--View Controller-->
+ <scene sceneID="hIz-AP-VOD">
+ <objects>
+ <viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </view>
+ </viewController>
+ <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="655"/>
+ </scene>
+ </scenes>
+</document>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements b/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements
new file mode 100644
index 0000000000..0c67376eba
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Info.plist b/examples/objective-c/helloworld_macos/HelloWorld/Info.plist
new file mode 100644
index 0000000000..f7bfdac9d6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2018 gRPC. All rights reserved.</string>
+ <key>NSMainStoryboardFile</key>
+ <string>Main</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h
new file mode 100644
index 0000000000..ff620dc426
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ViewController : NSViewController
+
+
+@end
+
diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m
new file mode 100644
index 0000000000..fc9e95f9a6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import "ViewController.h"
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Do any additional setup after loading the view.
+}
+
+
+- (void)setRepresentedObject:(id)representedObject {
+ [super setRepresentedObject:representedObject];
+
+ // Update the view, if already loaded.
+}
+
+
+@end
diff --git a/examples/objective-c/helloworld_macos/Podfile b/examples/objective-c/helloworld_macos/Podfile
new file mode 100644
index 0000000000..bf1488cba6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/Podfile
@@ -0,0 +1,9 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :macos, '10.9'
+
+install! 'cocoapods', :deterministic_uuids => false
+
+target 'HelloWorld' do
+ # Depend on the generated HelloWorld library.
+ pod 'HelloWorld', :path => '.'
+end
diff --git a/examples/objective-c/helloworld_macos/README.md b/examples/objective-c/helloworld_macos/README.md
new file mode 100644
index 0000000000..295701b5e6
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/README.md
@@ -0,0 +1,6 @@
+# gRPC Objective-C Mac OS Hello World Example
+
+A hello world example app on Mac OS. Note that Mac OS is not a first class supported platform of gRPC
+Objective-C library. This example is only for reference.
+
+Refer to [Hello World Example](../helloworld) for instructions on installation and running.
diff --git a/examples/objective-c/helloworld_macos/main.m b/examples/objective-c/helloworld_macos/main.m
new file mode 100644
index 0000000000..2a98ec4966
--- /dev/null
+++ b/examples/objective-c/helloworld_macos/main.m
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import <GRPCClient/GRPCCall+ChannelArg.h>
+#import <GRPCClient/GRPCCall+Tests.h>
+#import <HelloWorld/Helloworld.pbrpc.h>
+
+static NSString * const kHostAddress = @"localhost:50051";
+
+int main(int argc, const char * argv[]) {
+ @autoreleasepool {
+ [GRPCCall useInsecureConnectionsForHost:kHostAddress];
+ [GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
+
+ HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
+
+ HLWHelloRequest *request = [HLWHelloRequest message];
+ request.name = @"Objective-C";
+
+ [client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
+ NSLog(@"%@", response.message);
+ }];
+ }
+
+ return NSApplicationMain(argc, argv);
+}
diff --git a/examples/python/helloworld/greeter_client_with_options.py b/examples/python/helloworld/greeter_client_with_options.py
new file mode 100644
index 0000000000..7eda8c9066
--- /dev/null
+++ b/examples/python/helloworld/greeter_client_with_options.py
@@ -0,0 +1,44 @@
+# 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.
+"""The Python implementation of the GRPC helloworld.Greeter client with channel options and call timeout parameters."""
+
+from __future__ import print_function
+
+import grpc
+
+import helloworld_pb2
+import helloworld_pb2_grpc
+
+
+def run():
+ # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+ # used in circumstances in which the with statement does not fit the needs
+ # of the code.
+ #
+ # For more channel options, please see https://grpc.io/grpc/core/group__grpc__arg__keys.html
+ with grpc.insecure_channel(
+ target='localhost:50051',
+ options=[('grpc.lb_policy_name', 'pick_first'),
+ ('grpc.enable_retries', 0), ('grpc.keepalive_timeout_ms',
+ 10000)]) as channel:
+ stub = helloworld_pb2_grpc.GreeterStub(channel)
+ # Timeout in seconds.
+ # Please refer gRPC Python documents for more detail. https://grpc.io/grpc/python/grpc.html
+ response = stub.SayHello(
+ helloworld_pb2.HelloRequest(name='you'), timeout=10)
+ print("Greeter client received: " + response.message)
+
+
+if __name__ == '__main__':
+ run()
diff --git a/examples/python/interceptors/default_value/default_value_client_interceptor.py b/examples/python/interceptors/default_value/default_value_client_interceptor.py
index c549f2b861..c935b95491 100644
--- a/examples/python/interceptors/default_value/default_value_client_interceptor.py
+++ b/examples/python/interceptors/default_value/default_value_client_interceptor.py
@@ -13,8 +13,6 @@
# limitations under the License.
"""Interceptor that adds headers to outgoing requests."""
-import collections
-
import grpc
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 758717a0d2..0ebf5d99ce 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -23,7 +23,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-C++'
# TODO (mxyan): use version that match gRPC version when pod is stabilized
- # version = '1.15.0-dev'
+ # version = '1.17.0-dev'
version = '0.0.3'
s.version = version
s.summary = 'gRPC C++ library'
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
s.license = 'Apache License, Version 2.0'
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
- grpc_version = '1.15.0-dev'
+ grpc_version = '1.17.0-dev'
s.source = {
:git => 'https://github.com/grpc/grpc.git',
@@ -69,6 +69,9 @@ Pod::Spec.new do |s|
s.default_subspecs = 'Interface', 'Implementation'
+ # Certificates, to be able to establish TLS connections:
+ s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
+
s.header_mappings_dir = 'include/grpcpp'
s.subspec 'Interface' do |ss|
@@ -111,9 +114,11 @@ Pod::Spec.new do |s|
'include/grpcpp/support/async_unary_call.h',
'include/grpcpp/support/byte_buffer.h',
'include/grpcpp/support/channel_arguments.h',
+ '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',
@@ -127,8 +132,13 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/byte_buffer.h',
'include/grpcpp/impl/codegen/call.h',
'include/grpcpp/impl/codegen/call_hook.h',
+ 'include/grpcpp/impl/codegen/call_op_set.h',
+ 'include/grpcpp/impl/codegen/call_op_set_interface.h',
+ 'include/grpcpp/impl/codegen/callback_common.h',
'include/grpcpp/impl/codegen/channel_interface.h',
+ 'include/grpcpp/impl/codegen/client_callback.h',
'include/grpcpp/impl/codegen/client_context.h',
+ 'include/grpcpp/impl/codegen/client_interceptor.h',
'include/grpcpp/impl/codegen/client_unary_call.h',
'include/grpcpp/impl/codegen/completion_queue.h',
'include/grpcpp/impl/codegen/completion_queue_tag.h',
@@ -136,13 +146,18 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/core_codegen_interface.h',
'include/grpcpp/impl/codegen/create_auth_context.h',
'include/grpcpp/impl/codegen/grpc_library.h',
+ 'include/grpcpp/impl/codegen/intercepted_channel.h',
+ 'include/grpcpp/impl/codegen/interceptor.h',
+ 'include/grpcpp/impl/codegen/interceptor_common.h',
'include/grpcpp/impl/codegen/metadata_map.h',
'include/grpcpp/impl/codegen/method_handler_impl.h',
'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',
'include/grpcpp/impl/codegen/service_type.h',
'include/grpcpp/impl/codegen/slice.h',
@@ -168,7 +183,6 @@ Pod::Spec.new do |s|
'src/cpp/common/channel_filter.h',
'src/cpp/server/dynamic_thread_pool.h',
'src/cpp/server/health/default_health_check_service.h',
- 'src/cpp/server/health/health.pb.h',
'src/cpp/server/thread_pool_interface.h',
'src/cpp/thread_manager/thread_manager.h',
'src/cpp/client/insecure_credentials.cc',
@@ -181,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',
@@ -199,7 +214,6 @@ Pod::Spec.new do |s|
'src/cpp/server/create_default_thread_pool.cc',
'src/cpp/server/dynamic_thread_pool.cc',
'src/cpp/server/health/default_health_check_service.cc',
- 'src/cpp/server/health/health.pb.c',
'src/cpp/server/health/health_check_service.cc',
'src/cpp/server/health/health_check_service_server_builder_option.cc',
'src/cpp/server/server_builder.cc',
@@ -265,6 +279,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -279,11 +294,14 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
- 'src/core/lib/security/security_connector/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
- 'src/core/lib/security/security_connector/local_security_connector.h',
+ 'src/core/lib/security/security_connector/local/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.h',
+ 'src/core/lib/security/security_connector/ssl_utils.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
@@ -297,7 +315,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',
@@ -324,6 +342,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
+ 'src/core/ext/filters/client_channel/health/health_check_client.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
@@ -339,9 +358,8 @@ 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/tsi/alts_transport_security.h',
+ 'src/core/ext/filters/client_channel/health/health.pb.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -393,7 +411,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -487,15 +504,19 @@ 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',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
@@ -513,7 +534,6 @@ Pod::Spec.new do |s|
'src/cpp/common/channel_filter.h',
'src/cpp/server/dynamic_thread_pool.h',
'src/cpp/server/health/default_health_check_service.h',
- 'src/cpp/server/health/health.pb.h',
'src/cpp/server/thread_pool_interface.h',
'src/cpp/thread_manager/thread_manager.h',
'src/core/lib/gpr/alloc.h',
@@ -583,7 +603,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -677,8 +696,10 @@ 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/transport/inproc/inproc_transport.h',
+ 'src/core/ext/filters/client_channel/health/health.pb.h'
end
s.subspec 'Protobuf' do |ss|
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 1bd0dc1b52..780f36a3db 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -22,7 +22,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
- version = '1.15.0-dev'
+ version = '1.17.0-dev'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'https://grpc.io'
@@ -181,7 +181,7 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
- ss.dependency 'BoringSSL-GRPC', '0.0.1'
+ ss.dependency 'BoringSSL-GRPC', '0.0.2'
ss.dependency 'nanopb', '~> 0.3'
ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS'
@@ -277,6 +277,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -291,11 +292,14 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
- 'src/core/lib/security/security_connector/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
- 'src/core/lib/security/security_connector/local_security_connector.h',
+ 'src/core/lib/security/security_connector/local/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.h',
+ 'src/core/lib/security/security_connector/ssl_utils.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
@@ -309,7 +313,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',
@@ -336,6 +340,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
+ 'src/core/ext/filters/client_channel/health/health_check_client.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
@@ -351,9 +356,8 @@ 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/tsi/alts_transport_security.h',
+ 'src/core/ext/filters/client_channel/health/health.pb.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -405,7 +409,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -499,15 +502,19 @@ 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',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
@@ -551,7 +558,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -668,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',
@@ -715,11 +722,14 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
- 'src/core/lib/security/security_connector/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
- 'src/core/lib/security/security_connector/local_security_connector.cc',
+ 'src/core/lib/security/security_connector/local/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl_utils.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
@@ -738,7 +748,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',
@@ -771,6 +781,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -785,9 +796,8 @@ 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/tsi/alts_transport_security.cc',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
@@ -806,10 +816,14 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
@@ -882,6 +896,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -896,11 +911,14 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
- 'src/core/lib/security/security_connector/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.h',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.h',
'src/core/lib/security/security_connector/load_system_roots.h',
'src/core/lib/security/security_connector/load_system_roots_linux.h',
- 'src/core/lib/security/security_connector/local_security_connector.h',
+ 'src/core/lib/security/security_connector/local/local_security_connector.h',
'src/core/lib/security/security_connector/security_connector.h',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.h',
+ 'src/core/lib/security/security_connector/ssl_utils.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
@@ -914,7 +932,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',
@@ -941,6 +959,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
+ 'src/core/ext/filters/client_channel/health/health_check_client.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
@@ -956,9 +975,8 @@ 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/tsi/alts_transport_security.h',
+ 'src/core/ext/filters/client_channel/health/health.pb.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/local_transport_security.h',
'src/core/tsi/ssl/session_cache/ssl_session.h',
@@ -1010,7 +1028,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -1104,15 +1121,19 @@ 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',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
@@ -1201,6 +1222,9 @@ Pod::Spec.new do |s|
'test/core/util/tracer_util.cc',
'test/core/util/trickle_endpoint.cc',
'test/core/util/cmdline.cc',
+ 'third_party/nanopb/pb_common.c',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'test/core/end2end/data/ssl_test_data.h',
'test/core/security/oauth2_utils.h',
'test/core/end2end/cq_verifier.h',
@@ -1222,6 +1246,10 @@ Pod::Spec.new do |s|
'test/core/util/tracer_util.h',
'test/core/util/trickle_endpoint.h',
'test/core/util/cmdline.h',
+ 'third_party/nanopb/pb.h',
+ 'third_party/nanopb/pb_common.h',
+ 'third_party/nanopb/pb_decode.h',
+ 'third_party/nanopb/pb_encode.h',
'test/core/end2end/end2end_tests.cc',
'test/core/end2end/end2end_test_utils.cc',
'test/core/end2end/tests/authority_not_supported.cc',
@@ -1310,5 +1338,6 @@ Pod::Spec.new do |s|
s.prepare_command = <<-END_OF_COMMAND
find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
+ find src/core/ -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
end
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index 79ec679e3a..693b873d14 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
- version = '1.15.0-dev'
+ version = '1.17.0-dev'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'https://grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 7a461e270f..fd590023e1 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
- version = '1.15.0-dev'
+ version = '1.17.0-dev'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'https://grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index bf3f56bd54..5e513cb127 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -20,7 +20,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
- version = '1.15.0-dev'
+ version = '1.17.0-dev'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'https://grpc.io'
diff --git a/grpc.def b/grpc.def
index 72e3e90c62..b3466c004d 100644
--- a/grpc.def
+++ b/grpc.def
@@ -74,10 +74,14 @@ EXPORTS
grpc_resource_quota_set_max_threads
grpc_resource_quota_arg_vtable
grpc_channelz_get_top_channels
+ grpc_channelz_get_servers
+ grpc_channelz_get_server
+ grpc_channelz_get_server_sockets
grpc_channelz_get_channel
+ grpc_channelz_get_subchannel
+ grpc_channelz_get_socket
grpc_insecure_channel_create_from_fd
grpc_server_add_insecure_channel_from_fd
- grpc_use_signal
grpc_auth_property_iterator_next
grpc_auth_context_property_iterator
grpc_auth_context_peer_identity
diff --git a/grpc.gemspec b/grpc.gemspec
index 9a8d80823a..a72a584ae8 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -209,6 +209,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds.h )
s.files += %w( src/core/lib/security/context/security_context.h )
s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.h )
s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
@@ -223,11 +224,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.h )
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
- s.files += %w( src/core/lib/security/security_connector/alts_security_connector.h )
+ s.files += %w( src/core/lib/security/security_connector/alts/alts_security_connector.h )
+ s.files += %w( src/core/lib/security/security_connector/fake/fake_security_connector.h )
s.files += %w( src/core/lib/security/security_connector/load_system_roots.h )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_linux.h )
- s.files += %w( src/core/lib/security/security_connector/local_security_connector.h )
+ s.files += %w( src/core/lib/security/security_connector/local/local_security_connector.h )
s.files += %w( src/core/lib/security/security_connector/security_connector.h )
+ s.files += %w( src/core/lib/security/security_connector/ssl/ssl_security_connector.h )
+ s.files += %w( src/core/lib/security/security_connector/ssl_utils.h )
s.files += %w( src/core/lib/security/transport/auth_filters.h )
s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.h )
@@ -241,7 +245,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 )
@@ -272,6 +276,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/client_channel_channelz.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/filters/client_channel/connector.h )
+ s.files += %w( src/core/ext/filters/client_channel/health/health_check_client.h )
s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h )
s.files += %w( src/core/ext/filters/client_channel/http_proxy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
@@ -287,9 +292,8 @@ 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/tsi/alts_transport_security.h )
+ s.files += %w( src/core/ext/filters/client_channel/health/health.pb.h )
s.files += %w( src/core/tsi/fake_transport_security.h )
s.files += %w( src/core/tsi/local_transport_security.h )
s.files += %w( src/core/tsi/ssl/session_cache/ssl_session.h )
@@ -341,7 +345,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/error_internal.h )
s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.h )
s.files += %w( src/core/lib/iomgr/ev_epollex_linux.h )
- s.files += %w( src/core/lib/iomgr/ev_epollsig_linux.h )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.h )
s.files += %w( src/core/lib/iomgr/ev_posix.h )
s.files += %w( src/core/lib/iomgr/exec_ctx.h )
@@ -435,15 +438,19 @@ 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 )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
+ s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
- s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )
@@ -487,7 +494,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/error.cc )
s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.cc )
s.files += %w( src/core/lib/iomgr/ev_epollex_linux.cc )
- s.files += %w( src/core/lib/iomgr/ev_epollsig_linux.cc )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.cc )
s.files += %w( src/core/lib/iomgr/ev_posix.cc )
s.files += %w( src/core/lib/iomgr/ev_windows.cc )
@@ -604,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 )
@@ -651,11 +658,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.cc )
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.cc )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.cc )
- s.files += %w( src/core/lib/security/security_connector/alts_security_connector.cc )
+ s.files += %w( src/core/lib/security/security_connector/alts/alts_security_connector.cc )
+ s.files += %w( src/core/lib/security/security_connector/fake/fake_security_connector.cc )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_fallback.cc )
s.files += %w( src/core/lib/security/security_connector/load_system_roots_linux.cc )
- s.files += %w( src/core/lib/security/security_connector/local_security_connector.cc )
+ s.files += %w( src/core/lib/security/security_connector/local/local_security_connector.cc )
s.files += %w( src/core/lib/security/security_connector/security_connector.cc )
+ s.files += %w( src/core/lib/security/security_connector/ssl/ssl_security_connector.cc )
+ s.files += %w( src/core/lib/security/security_connector/ssl_utils.cc )
s.files += %w( src/core/lib/security/transport/client_auth_filter.cc )
s.files += %w( src/core/lib/security/transport/secure_endpoint.cc )
s.files += %w( src/core/lib/security/transport/security_handshaker.cc )
@@ -674,7 +684,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 )
@@ -710,6 +720,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc )
s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc )
s.files += %w( src/core/ext/filters/client_channel/connector.cc )
+ s.files += %w( src/core/ext/filters/client_channel/health/health_check_client.cc )
s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc )
s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc )
@@ -724,9 +735,8 @@ 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/tsi/alts_transport_security.cc )
+ s.files += %w( src/core/ext/filters/client_channel/health/health.pb.c )
s.files += %w( src/core/tsi/fake_transport_security.cc )
s.files += %w( src/core/tsi/local_transport_security.cc )
s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc )
@@ -745,10 +755,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc )
+ s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
- s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 8229b9689b..02992e763e 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -310,7 +310,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -427,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',
@@ -474,11 +474,14 @@
'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
- 'src/core/lib/security/security_connector/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
- 'src/core/lib/security/security_connector/local_security_connector.cc',
+ 'src/core/lib/security/security_connector/local/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl_utils.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
@@ -497,7 +500,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',
@@ -533,6 +536,7 @@
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -547,9 +551,8 @@
'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/tsi/alts_transport_security.cc',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
@@ -568,10 +571,14 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
@@ -594,16 +601,6 @@
],
},
{
- 'target_name': 'grpc_dll',
- 'type': 'static_library',
- 'dependencies': [
- 'gpr',
- 'grpc',
- ],
- 'sources': [
- ],
- },
- {
'target_name': 'grpc_test_util',
'type': 'static_library',
'dependencies': [
@@ -673,7 +670,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -790,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',
@@ -798,6 +795,7 @@
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -812,8 +810,11 @@
'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',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
@@ -909,7 +910,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -1026,6 +1026,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',
@@ -1034,6 +1035,7 @@
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -1048,8 +1050,11 @@
'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',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
@@ -1123,7 +1128,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -1240,6 +1244,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',
@@ -1283,6 +1288,7 @@
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -1297,8 +1303,11 @@
'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',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'src/core/ext/transport/inproc/inproc_plugin.cc',
'src/core/ext/transport/inproc/inproc_transport.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
@@ -1320,9 +1329,10 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'third_party/nanopb/pb_common.c',
- 'third_party/nanopb/pb_decode.c',
- 'third_party/nanopb/pb_encode.c',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/census/grpc_context.cc',
@@ -1379,6 +1389,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',
@@ -1397,7 +1408,6 @@
'src/cpp/server/create_default_thread_pool.cc',
'src/cpp/server/dynamic_thread_pool.cc',
'src/cpp/server/health/default_health_check_service.cc',
- 'src/cpp/server/health/health.pb.c',
'src/cpp/server/health/health_check_service.cc',
'src/cpp/server/health/health_check_service_server_builder_option.cc',
'src/cpp/server/server_builder.cc',
@@ -1410,6 +1420,10 @@
'src/cpp/util/status.cc',
'src/cpp/util/string_ref.cc',
'src/cpp/util/time_cc.cc',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
+ 'third_party/nanopb/pb_common.c',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'src/cpp/codegen/codegen_init.cc',
],
},
@@ -1526,6 +1540,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',
@@ -1544,7 +1559,6 @@
'src/cpp/server/create_default_thread_pool.cc',
'src/cpp/server/dynamic_thread_pool.cc',
'src/cpp/server/health/default_health_check_service.cc',
- 'src/cpp/server/health/health.pb.c',
'src/cpp/server/health/health_check_service.cc',
'src/cpp/server/health/health_check_service_server_builder_option.cc',
'src/cpp/server/server_builder.cc',
@@ -1557,6 +1571,10 @@
'src/cpp/util/status.cc',
'src/cpp/util/string_ref.cc',
'src/cpp/util/time_cc.cc',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
+ 'third_party/nanopb/pb_common.c',
+ 'third_party/nanopb/pb_decode.c',
+ 'third_party/nanopb/pb_encode.c',
'src/cpp/codegen/codegen_init.cc',
],
},
@@ -1735,6 +1753,7 @@
'src/proto/grpc/testing/worker_service.proto',
'test/cpp/qps/benchmark_config.cc',
'test/cpp/qps/client_async.cc',
+ 'test/cpp/qps/client_callback.cc',
'test/cpp/qps/client_sync.cc',
'test/cpp/qps/driver.cc',
'test/cpp/qps/parse_json.cc',
@@ -1742,6 +1761,7 @@
'test/cpp/qps/qps_worker.cc',
'test/cpp/qps/report.cc',
'test/cpp/qps/server_async.cc',
+ 'test/cpp/qps/server_callback.cc',
'test/cpp/qps/server_sync.cc',
'test/cpp/qps/usage_timer.cc',
],
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 4e50cd0bac..d3b74cabab 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -111,7 +111,8 @@ GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_pluck(
of GRPC_CQ_CALLBACK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING.
This function is experimental. */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_callback(
- void* shutdown_callback, void* reserved);
+ grpc_experimental_completion_queue_functor* shutdown_callback,
+ void* reserved);
/** Create a completion queue */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create(
@@ -247,10 +248,13 @@ GRPCAPI void* grpc_call_arena_alloc(grpc_call* call, size_t size);
appropriate to call grpc_completion_queue_next or
grpc_completion_queue_pluck consequent to the failed grpc_call_start_batch
call.
+ If a call to grpc_call_start_batch with an empty batch returns
+ GRPC_CALL_OK, the tag is put in the completion queue immediately.
THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
needs to be synchronized. As an optimization, you may synchronize batches
containing just send operations independently from batches containing just
- receive operations. */
+ receive operations. Access to grpc_call_start_batch with an empty batch is
+ thread-compatible. */
GRPCAPI grpc_call_error grpc_call_start_batch(grpc_call* call,
const grpc_op* ops, size_t nops,
void* tag, void* reserved);
@@ -499,10 +503,28 @@ GRPCAPI const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable(void);
The returned string is allocated and must be freed by the application. */
GRPCAPI char* grpc_channelz_get_top_channels(intptr_t start_channel_id);
+/* Gets all servers that exist in the process. */
+GRPCAPI char* grpc_channelz_get_servers(intptr_t start_server_id);
+
+/* Returns a single Server, or else a NOT_FOUND code. */
+GRPCAPI char* grpc_channelz_get_server(intptr_t server_id);
+
+/* Gets all server sockets that exist in the server. */
+GRPCAPI char* grpc_channelz_get_server_sockets(intptr_t server_id,
+ intptr_t start_socket_id);
+
/* Returns a single Channel, or else a NOT_FOUND code. The returned string
is allocated and must be freed by the application. */
GRPCAPI char* grpc_channelz_get_channel(intptr_t channel_id);
+/* Returns a single Subchannel, or else a NOT_FOUND code. The returned string
+ is allocated and must be freed by the application. */
+GRPCAPI char* grpc_channelz_get_subchannel(intptr_t subchannel_id);
+
+/* Returns a single Socket, or else a NOT_FOUND code. The returned string
+ is allocated and must be freed by the application. */
+GRPCAPI char* grpc_channelz_get_socket(intptr_t socket_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/grpc/grpc_posix.h b/include/grpc/grpc_posix.h
index 5f1ada5aaf..fbce5e13c1 100644
--- a/include/grpc/grpc_posix.h
+++ b/include/grpc/grpc_posix.h
@@ -52,14 +52,6 @@ GRPCAPI grpc_channel* grpc_insecure_channel_create_from_fd(
GRPCAPI void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
void* reserved, int fd);
-/** GRPC Core POSIX library may internally use signals to optimize some work.
- The library uses (SIGRTMIN + 6) signal by default. Use this API to instruct
- the library to use a different signal i.e 'signum' instead.
- Note:
- - To prevent GRPC library from using any signals, pass a 'signum' of -1
- - This API is optional but if called, it MUST be called before grpc_init() */
-GRPCAPI void grpc_use_signal(int signum);
-
#ifdef __cplusplus
}
#endif
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 02d87a493a..de90971cc5 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -532,14 +532,14 @@ typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
-grpc_alts_credentials_client_options_create();
+grpc_alts_credentials_client_options_create(void);
/**
* This method creates a grpc ALTS credentials server options instance.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
-grpc_alts_credentials_server_options_create();
+grpc_alts_credentials_server_options_create(void);
/**
* This method adds a target service account to grpc client's ALTS credentials
diff --git a/include/grpc/grpc_security_constants.h b/include/grpc/grpc_security_constants.h
index 944a1e927f..f935557f2d 100644
--- a/include/grpc/grpc_security_constants.h
+++ b/include/grpc/grpc_security_constants.h
@@ -57,46 +57,51 @@ typedef enum {
} grpc_ssl_certificate_config_reload_status;
typedef enum {
- /** Server does not request client certificate. A client can present a self
- signed or signed certificates if it wishes to do so and they would be
- accepted. */
+ /** Server does not request client certificate.
+ The certificate presented by the client is not checked by the server at
+ all. (A client may present a self signed or signed certificate or not
+ present a certificate at all and any of those option would be accepted) */
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
/** Server requests client certificate but does not enforce that the client
presents a certificate.
If the client presents a certificate, the client authentication is left to
- the application based on the metadata like certificate etc.
+ the application (the necessary metadata will be available to the
+ application via authentication context properties, see grpc_auth_context).
- The key cert pair should still be valid for the SSL connection to be
- established. */
+ The client's key certificate pair must be valid for the SSL connection to
+ be established. */
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY,
/** Server requests client certificate but does not enforce that the client
presents a certificate.
If the client presents a certificate, the client authentication is done by
- grpc framework (The client needs to either present a signed cert or skip no
- certificate for a successful connection).
+ the gRPC framework. (For a successful connection the client needs to either
+ present a certificate that can be verified against the root certificate
+ configured by the server or not present a certificate at all)
- The key cert pair should still be valid for the SSL connection to be
- established. */
+ The client's key certificate pair must be valid for the SSL connection to
+ be established. */
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY,
- /** Server requests client certificate but enforces that the client presents a
+ /** Server requests client certificate and enforces that the client presents a
certificate.
If the client presents a certificate, the client authentication is left to
- the application based on the metadata like certificate etc.
+ the application (the necessary metadata will be available to the
+ application via authentication context properties, see grpc_auth_context).
- The key cert pair should still be valid for the SSL connection to be
- established. */
+ The client's key certificate pair must be valid for the SSL connection to
+ be established. */
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY,
- /** Server requests client certificate but enforces that the client presents a
+ /** Server requests client certificate and enforces that the client presents a
certificate.
- The cerificate presented by the client is verified by grpc framework (The
- client needs to present signed certs for a successful connection).
+ The cerificate presented by the client is verified by the gRPC framework.
+ (For a successful connection the client needs to present a certificate that
+ can be verified against the root certificate configured by the server)
- The key cert pair should still be valid for the SSL connection to be
- established. */
+ The client's key certificate pair must be valid for the SSL connection to
+ be established. */
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
} grpc_ssl_client_certificate_request_type;
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index b5353c1dea..17a43fab0f 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -285,10 +285,12 @@ typedef struct {
#define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator"
/** The grpc_socket_factory instance to create and bind sockets. A pointer. */
#define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory"
-/** The maximum number of trace events to keep in the tracer for each channel or
- * subchannel. The default is 10. If set to 0, channel tracing is disabled. */
-#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
- "grpc.max_channel_trace_events_per_node"
+/** The maximum amount of memory used by trace events per channel trace node.
+ * Once the maximum is reached, subsequent events will evict the oldest events
+ * from the buffer. The unit for this knob is bytes. Setting it to zero causes
+ * channel tracing to be disabled. */
+#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE \
+ "grpc.max_channel_trace_event_memory_per_node"
/** If non-zero, gRPC library will track stats and information at at per channel
* level. Disabling channelz naturally disables channel tracing. The default
* is for channelz to be disabled. */
@@ -342,6 +344,12 @@ typedef struct {
"grpc.disable_client_authority_filter"
/** If set to zero, disables use of http proxies. Enabled by default. */
#define GRPC_ARG_ENABLE_HTTP_PROXY "grpc.enable_http_proxy"
+/** If set to non zero, surfaces the user agent string to the server. User
+ agent is surfaced by default. */
+#define GRPC_ARG_SURFACE_USER_AGENT "grpc.surface_user_agent"
+/** If set, inhibits health checking (which may be enabled via the
+ * service config.) */
+#define GRPC_ARG_INHIBIT_HEALTH_CHECKING "grpc.inhibit_health_checking"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
@@ -657,6 +665,19 @@ typedef enum {
GRPC_CQ_CALLBACK
} grpc_cq_completion_type;
+/** EXPERIMENTAL: Specifies an interface class to be used as a tag
+ for callback-based completion queues. This can be used directly,
+ as the first element of a struct in C, or as a base class in C++.
+ Its "run" value should be assigned to some non-member function, such as
+ a static method. */
+typedef struct grpc_experimental_completion_queue_functor {
+ /** The run member specifies a function that will be called when this
+ tag is extracted from the completion queue. Its arguments will be a
+ pointer to this functor and a boolean that indicates whether the
+ operation succeeded (non-zero) or failed (zero) */
+ void (*functor_run)(struct grpc_experimental_completion_queue_functor*, int);
+} grpc_experimental_completion_queue_functor;
+
/* The upgrade to version 2 is currently experimental. */
#define GRPC_CQ_CURRENT_VERSION 2
@@ -675,7 +696,7 @@ typedef struct grpc_completion_queue_attributes {
/* EXPERIMENTAL: START OF VERSION 2 CQ ATTRIBUTES */
/** When creating a callbackable CQ, pass in a functor to get invoked when
* shutdown is complete */
- void* cq_shutdown_cb;
+ grpc_experimental_completion_queue_functor* cq_shutdown_cb;
/* END OF VERSION 2 CQ ATTRIBUTES */
} grpc_completion_queue_attributes;
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 8d9bd83285..b2028a6305 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -174,6 +174,7 @@
#ifdef __GLIBC__
#define GPR_POSIX_CRASH_HANDLER 1
#define GPR_LINUX_PTHREAD_NAME 1
+#include <linux/version.h>
#else /* musl libc */
#define GPR_MUSL_LIBC_COMPAT 1
#endif
diff --git a/include/grpcpp/alarm.h b/include/grpcpp/alarm.h
index f484610a6e..365feb4eb9 100644
--- a/include/grpcpp/alarm.h
+++ b/include/grpcpp/alarm.h
@@ -21,6 +21,8 @@
#ifndef GRPCPP_ALARM_H
#define GRPCPP_ALARM_H
+#include <functional>
+
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
@@ -76,8 +78,33 @@ class Alarm : private GrpcLibraryCodegen {
/// has already fired has no effect.
void Cancel();
+ /// NOTE: class experimental_type is not part of the public API of this class
+ /// TODO(vjpai): Move these contents to the public API of Alarm when
+ /// they are no longer experimental
+ class experimental_type {
+ public:
+ explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
+
+ /// Set an alarm to invoke callback \a f. The argument to the callback
+ /// states whether the alarm expired at \a deadline (true) or was cancelled
+ /// (false)
+ template <typename T>
+ void Set(const T& deadline, std::function<void(bool)> f) {
+ alarm_->SetInternal(TimePoint<T>(deadline).raw_time(), std::move(f));
+ }
+
+ private:
+ Alarm* alarm_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
private:
void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
+ void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
internal::CompletionQueueTag* alarm_;
};
diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h
index fed02bf7bc..4502b94b17 100644
--- a/include/grpcpp/channel.h
+++ b/include/grpcpp/channel.h
@@ -20,10 +20,12 @@
#define GRPCPP_CHANNEL_H
#include <memory>
+#include <mutex>
#include <grpc/grpc.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
@@ -62,8 +64,15 @@ class Channel final : public ChannelInterface,
friend class internal::BlockingUnaryCallImpl;
friend void experimental::ChannelResetConnectionBackoff(Channel* channel);
friend std::shared_ptr<Channel> CreateChannelInternal(
- const grpc::string& host, grpc_channel* c_channel);
- Channel(const grpc::string& host, grpc_channel* c_channel);
+ const grpc::string& host, grpc_channel* c_channel,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+ friend class internal::InterceptedChannel;
+ Channel(const grpc::string& host, grpc_channel* c_channel,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
@@ -78,8 +87,26 @@ class Channel final : public ChannelInterface,
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
+ CompletionQueue* CallbackCQ() override;
+
+ internal::Call CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context, CompletionQueue* cq,
+ size_t interceptor_pos) override;
+
const grpc::string host_;
grpc_channel* const c_channel_; // owned
+
+ // mu_ protects callback_cq_ (the per-channel callbackable completion queue)
+ std::mutex mu_;
+
+ // callback_cq_ references the callbackable completion queue associated
+ // with this channel (if any). It is set on the first call to CallbackCQ().
+ // It is _not owned_ by the channel; ownership belongs with its internal
+ // shutdown callback tag (invoked when the CQ is fully shutdown).
+ CompletionQueue* callback_cq_ = nullptr;
+
+ std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
+ interceptor_creators_;
};
} // namespace grpc
diff --git a/include/grpcpp/create_channel.h b/include/grpcpp/create_channel.h
index 7a505a7127..43188d09e7 100644
--- a/include/grpcpp/create_channel.h
+++ b/include/grpcpp/create_channel.h
@@ -22,6 +22,7 @@
#include <memory>
#include <grpcpp/channel.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
@@ -53,6 +54,26 @@ std::shared_ptr<Channel> CreateCustomChannel(
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args);
+namespace experimental {
+/// Create a new \em custom \a Channel pointing to \a target with \a
+/// interceptors being invoked per call.
+///
+/// \warning For advanced use and testing ONLY. Override default channel
+/// arguments only if necessary.
+///
+/// \param target The URI of the endpoint to connect to.
+/// \param creds Credentials to use for the created channel. If it does not
+/// hold an object or is invalid, a lame channel (one on which all operations
+/// fail) is returned.
+/// \param args Options for channel creation.
+std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
+ const grpc::string& target,
+ const std::shared_ptr<ChannelCredentials>& creds,
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+} // namespace experimental
} // namespace grpc
#endif // GRPCPP_CREATE_CHANNEL_H
diff --git a/include/grpcpp/create_channel_posix.h b/include/grpcpp/create_channel_posix.h
index 9bf5acc45c..808514041b 100644
--- a/include/grpcpp/create_channel_posix.h
+++ b/include/grpcpp/create_channel_posix.h
@@ -45,6 +45,23 @@ std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
const grpc::string& target, int fd, const ChannelArguments& args);
+namespace experimental {
+
+/// Create a new \a Channel communicating over given file descriptor with custom
+/// channel arguments.
+///
+/// \param target The name of the target.
+/// \param fd The file descriptor representing a socket.
+/// \param args Options for channel creation.
+/// \param interceptor_creators Vector of interceptor factory objects.
+std::shared_ptr<Channel> CreateCustomInsecureChannelWithInterceptorsFromFd(
+ const grpc::string& target, int fd, const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+
+} // namespace experimental
+
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
} // namespace grpc
diff --git a/include/grpcpp/generic/generic_stub.h b/include/grpcpp/generic/generic_stub.h
index 92405a43fa..d509d9a520 100644
--- a/include/grpcpp/generic/generic_stub.h
+++ b/include/grpcpp/generic/generic_stub.h
@@ -19,9 +19,12 @@
#ifndef GRPCPP_GENERIC_GENERIC_STUB_H
#define GRPCPP_GENERIC_GENERIC_STUB_H
+#include <functional>
+
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/byte_buffer.h>
+#include <grpcpp/support/status.h>
namespace grpc {
@@ -62,6 +65,26 @@ class GenericStub final {
ClientContext* context, const grpc::string& method, CompletionQueue* cq,
void* tag);
+ /// NOTE: class experimental_type is not part of the public API of this class
+ /// TODO(vjpai): Move these contents to the public API of GenericStub when
+ /// they are no longer experimental
+ class experimental_type {
+ public:
+ explicit experimental_type(GenericStub* stub) : stub_(stub) {}
+
+ void UnaryCall(ClientContext* context, const grpc::string& method,
+ const ByteBuffer* request, ByteBuffer* response,
+ std::function<void(Status)> on_completion);
+
+ private:
+ GenericStub* stub_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
private:
std::shared_ptr<ChannelInterface> channel_;
};
diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h
index b2134590c3..bfb2df4f23 100644
--- a/include/grpcpp/impl/codegen/async_stream.h
+++ b/include/grpcpp/impl/codegen/async_stream.h
@@ -64,7 +64,7 @@ class ClientAsyncStreamingInterface {
/// earlier call to \a AsyncReaderInterface::Read that yielded a failed
/// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
///
- /// This function will return when either:
+ /// The tag will be returned when either:
/// - all incoming messages have been read and the server has returned
/// a status.
/// - the server has returned a non-OK status.
@@ -114,6 +114,9 @@ class AsyncWriterInterface {
/// queue BEFORE calling Write again.
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] tag The tag identifying the operation.
virtual void Write(const W& msg, void* tag) = 0;
@@ -127,6 +130,9 @@ class AsyncWriterInterface {
/// WriteOptions \a options is used to set the write options of this message.
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
@@ -144,6 +150,9 @@ class AsyncWriterInterface {
/// the flow control window size. If \a msg size is larger than the window
/// size, it will be sent on wire without buffering.
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
@@ -195,6 +204,13 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
assert(size == sizeof(ClientAsyncReader));
}
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
void StartCall(void* tag) override {
assert(!started_);
started_ = true;
@@ -260,7 +276,7 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
}
void StartCallInternal(void* tag) {
- init_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ init_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
init_ops_.set_output_tag(tag);
call_.PerformOps(&init_ops_);
@@ -336,6 +352,13 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
assert(size == sizeof(ClientAsyncWriter));
}
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
void StartCall(void* tag) override {
assert(!started_);
started_ = true;
@@ -418,7 +441,7 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
}
void StartCallInternal(void* tag) {
- write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
// if corked bit is set in context, we just keep the initial metadata
// buffered up to coalesce with later message send. No op is performed.
@@ -496,6 +519,13 @@ class ClientAsyncReaderWriter final
assert(size == sizeof(ClientAsyncReaderWriter));
}
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
void StartCall(void* tag) override {
assert(!started_);
started_ = true;
@@ -582,7 +612,7 @@ class ClientAsyncReaderWriter final
}
void StartCallInternal(void* tag) {
- write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+ write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
// if corked bit is set in context, we just keep the initial metadata
// buffered up to coalesce with later message send. No op is performed.
@@ -630,6 +660,9 @@ class ServerAsyncReaderInterface
/// metadata (if not sent already), response message, and status, or if
/// some failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a msg or \a status, so it
+ /// is safe to to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
/// \param[in] msg To be sent to the client as the response for this call.
@@ -650,6 +683,9 @@ class ServerAsyncReaderInterface
/// metadata (if not sent already), and status, or if some failure occurred
/// when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once FinishWithError returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
/// - Note: \a status must have a non-OK code.
@@ -674,7 +710,7 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -697,10 +733,13 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
/// initial and trailing metadata.
///
/// Note: \a msg is not sent if \a status has a non-OK code.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once Finish returns.
void Finish(const W& msg, const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
@@ -709,10 +748,10 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
}
// The response is dropped if the status is not OK.
if (status.ok()) {
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_ops_.SendMessage(msg));
} else {
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_ops_);
}
@@ -723,18 +762,21 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
/// - also sends initial metadata if not alreay sent.
/// - uses the \a ServerContext associated with this call to send possible
/// initial and trailing metadata.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once FinishWithError returns.
void FinishWithError(const Status& status, void* tag) override {
GPR_CODEGEN_ASSERT(!status.ok());
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -773,6 +815,9 @@ class ServerAsyncWriterInterface
/// metadata (if not sent already), response message, and status, or if
/// some failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
virtual void Finish(const Status& status, void* tag) = 0;
@@ -784,6 +829,9 @@ class ServerAsyncWriterInterface
/// WriteAndFinish is equivalent of performing WriteLast and Finish
/// in a single step.
///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
@@ -811,7 +859,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -847,13 +895,16 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
/// for sending trailing (and initial) metadata to the client.
///
/// Note: \a status must have an OK code.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
- write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
@@ -865,10 +916,13 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
///
/// Note: there are no restrictions are the code of
/// \a status,it may be non-OK
+ ///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -878,7 +932,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
- ops->SendInitialMetadata(ctx_->initial_metadata_,
+ ops->SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
@@ -924,6 +978,9 @@ class ServerAsyncReaderWriterInterface
/// metadata (if not sent already), response message, and status, or if some
/// failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
virtual void Finish(const Status& status, void* tag) = 0;
@@ -935,6 +992,9 @@ class ServerAsyncReaderWriterInterface
/// WriteAndFinish is equivalent of performing WriteLast and Finish in a
/// single step.
///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
@@ -965,7 +1025,7 @@ class ServerAsyncReaderWriter final
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_ops_.set_output_tag(tag);
- meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
@@ -1006,13 +1066,16 @@ class ServerAsyncReaderWriter final
/// for sending trailing (and initial) metadata to the client.
///
/// Note: \a status must have an OK code.
+ //
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
- write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
@@ -1024,11 +1087,14 @@ class ServerAsyncReaderWriter final
///
/// Note: there are no restrictions are the code of \a status,
/// it may be non-OK
+ //
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
- finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@@ -1040,7 +1106,7 @@ class ServerAsyncReaderWriter final
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
- ops->SendInitialMetadata(ctx_->initial_metadata_,
+ ops->SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h
index 60ff8e2f05..89dcb12418 100644
--- a/include/grpcpp/impl/codegen/async_unary_call.h
+++ b/include/grpcpp/impl/codegen/async_unary_call.h
@@ -174,7 +174,7 @@ class ClientAsyncResponseReader final
}
void StartCallInternal() {
- single_buf.SendInitialMetadata(context_->send_initial_metadata_,
+ single_buf.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
}
@@ -214,7 +214,7 @@ class ServerAsyncResponseWriter final
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
meta_buf_.set_output_tag(tag);
- meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+ meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
@@ -240,8 +240,9 @@ class ServerAsyncResponseWriter final
/// metadata.
void Finish(const W& msg, const Status& status, void* tag) {
finish_buf_.set_output_tag(tag);
+ finish_buf_.set_core_cq_tag(&finish_buf_);
if (!ctx_->sent_initial_metadata_) {
- finish_buf_.SendInitialMetadata(ctx_->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());
@@ -250,10 +251,10 @@ class ServerAsyncResponseWriter final
}
// The response is dropped if the status is not OK.
if (status.ok()) {
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_,
finish_buf_.SendMessage(msg));
} else {
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
}
call_.PerformOps(&finish_buf_);
}
@@ -274,14 +275,14 @@ class ServerAsyncResponseWriter final
GPR_CODEGEN_ASSERT(!status.ok());
finish_buf_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
- finish_buf_.SendInitialMetadata(ctx_->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;
}
- finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+ finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_buf_);
}
diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h
index 8cc5158115..abba5549b8 100644
--- a/include/grpcpp/impl/codegen/byte_buffer.h
+++ b/include/grpcpp/impl/codegen/byte_buffer.h
@@ -45,11 +45,18 @@ 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>
class DeserializeFuncType;
class GrpcByteBufferPeer;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+
} // namespace internal
/// A sequence of bytes.
class ByteBuffer final {
@@ -141,11 +148,16 @@ class ByteBuffer final {
template <class R>
friend class internal::CallOpRecvMessage;
friend class internal::CallOpGenericRecvMessage;
- friend class internal::MethodHandler;
+ template <class ServiceType, class RequestType, class ResponseType>
+ friend class RpcMethodHandler;
+ template <class ServiceType, class RequestType, class ResponseType>
+ friend class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
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.h b/include/grpcpp/impl/codegen/call.h
index a5e930aaa5..c040c30dd9 100644
--- a/include/grpcpp/impl/codegen/call.h
+++ b/include/grpcpp/impl/codegen/call.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015 gRPC authors.
+ * 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.
@@ -15,653 +15,31 @@
* limitations under the License.
*
*/
-
#ifndef GRPCPP_IMPL_CODEGEN_CALL_H
#define GRPCPP_IMPL_CODEGEN_CALL_H
-#include <assert.h>
-#include <cstring>
-#include <functional>
-#include <map>
-#include <memory>
-
-#include <grpcpp/impl/codegen/byte_buffer.h>
-#include <grpcpp/impl/codegen/call_hook.h>
-#include <grpcpp/impl/codegen/client_context.h>
-#include <grpcpp/impl/codegen/completion_queue_tag.h>
-#include <grpcpp/impl/codegen/config.h>
-#include <grpcpp/impl/codegen/core_codegen_interface.h>
-#include <grpcpp/impl/codegen/serialization_traits.h>
-#include <grpcpp/impl/codegen/slice.h>
-#include <grpcpp/impl/codegen/status.h>
-#include <grpcpp/impl/codegen/string_ref.h>
-
-#include <grpc/impl/codegen/atm.h>
-#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/call_hook.h>
namespace grpc {
-
-class ByteBuffer;
class CompletionQueue;
-extern CoreCodegenInterface* g_core_codegen_interface;
+namespace experimental {
+class ClientRpcInfo;
+class ServerRpcInfo;
+} // namespace experimental
namespace internal {
-class Call;
class CallHook;
-
-const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
-
-// TODO(yangg) if the map is changed before we send, the pointers will be a
-// mess. Make sure it does not happen.
-inline grpc_metadata* FillMetadataArray(
- const std::multimap<grpc::string, grpc::string>& metadata,
- size_t* metadata_count, const grpc::string& optional_error_details) {
- *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
- if (*metadata_count == 0) {
- return nullptr;
- }
- grpc_metadata* metadata_array =
- (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
- (*metadata_count) * sizeof(grpc_metadata)));
- size_t i = 0;
- for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
- metadata_array[i].key = SliceReferencingString(iter->first);
- metadata_array[i].value = SliceReferencingString(iter->second);
- }
- if (!optional_error_details.empty()) {
- metadata_array[i].key =
- g_core_codegen_interface->grpc_slice_from_static_buffer(
- kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
- metadata_array[i].value = SliceReferencingString(optional_error_details);
- }
- return metadata_array;
-}
-} // namespace internal
-
-/// Per-message write options.
-class WriteOptions {
- public:
- WriteOptions() : flags_(0), last_message_(false) {}
- WriteOptions(const WriteOptions& other)
- : flags_(other.flags_), last_message_(other.last_message_) {}
-
- /// Clear all flags.
- inline void Clear() { flags_ = 0; }
-
- /// Returns raw flags bitset.
- inline uint32_t flags() const { return flags_; }
-
- /// Sets flag for the disabling of compression for the next message write.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline WriteOptions& set_no_compression() {
- SetBit(GRPC_WRITE_NO_COMPRESS);
- return *this;
- }
-
- /// Clears flag for the disabling of compression for the next message write.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline WriteOptions& clear_no_compression() {
- ClearBit(GRPC_WRITE_NO_COMPRESS);
- return *this;
- }
-
- /// Get value for the flag indicating whether compression for the next
- /// message write is forcefully disabled.
- ///
- /// \sa GRPC_WRITE_NO_COMPRESS
- inline bool get_no_compression() const {
- return GetBit(GRPC_WRITE_NO_COMPRESS);
- }
-
- /// Sets flag indicating that the write may be buffered and need not go out on
- /// the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline WriteOptions& set_buffer_hint() {
- SetBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- /// Clears flag indicating that the write may be buffered and need not go out
- /// on the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline WriteOptions& clear_buffer_hint() {
- ClearBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- /// Get value for the flag indicating that the write may be buffered and need
- /// not go out on the wire immediately.
- ///
- /// \sa GRPC_WRITE_BUFFER_HINT
- inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
- /// corked bit: aliases set_buffer_hint currently, with the intent that
- /// set_buffer_hint will be removed in the future
- inline WriteOptions& set_corked() {
- SetBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- inline WriteOptions& clear_corked() {
- ClearBit(GRPC_WRITE_BUFFER_HINT);
- return *this;
- }
-
- inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
- /// last-message bit: indicates this is the last message in a stream
- /// client-side: makes Write the equivalent of performing Write, WritesDone
- /// in a single step
- /// server-side: hold the Write until the service handler returns (sync api)
- /// or until Finish is called (async api)
- inline WriteOptions& set_last_message() {
- last_message_ = true;
- return *this;
- }
-
- /// Clears flag indicating that this is the last message in a stream,
- /// disabling coalescing.
- inline WriteOptions& clear_last_message() {
- last_message_ = false;
- return *this;
- }
-
- /// Guarantee that all bytes have been written to the socket before completing
- /// this write (usually writes are completed when they pass flow control).
- inline WriteOptions& set_write_through() {
- SetBit(GRPC_WRITE_THROUGH);
- return *this;
- }
-
- inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
-
- /// Get value for the flag indicating that this is the last message, and
- /// should be coalesced with trailing metadata.
- ///
- /// \sa GRPC_WRITE_LAST_MESSAGE
- bool is_last_message() const { return last_message_; }
-
- WriteOptions& operator=(const WriteOptions& rhs) {
- flags_ = rhs.flags_;
- return *this;
- }
-
- private:
- void SetBit(const uint32_t mask) { flags_ |= mask; }
-
- void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
-
- bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
-
- uint32_t flags_;
- bool last_message_;
-};
-
-namespace internal {
-/// Default argument for CallOpSet. I is unused by the class, but can be
-/// used for generating multiple names for the same thing.
-template <int I>
-class CallNoOp {
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {}
- void FinishOp(bool* status) {}
-};
-
-class CallOpSendInitialMetadata {
- public:
- CallOpSendInitialMetadata() : send_(false) {
- maybe_compression_level_.is_set = false;
- }
-
- void SendInitialMetadata(
- const std::multimap<grpc::string, grpc::string>& metadata,
- uint32_t flags) {
- maybe_compression_level_.is_set = false;
- send_ = true;
- flags_ = flags;
- initial_metadata_ =
- FillMetadataArray(metadata, &initial_metadata_count_, "");
- }
-
- void set_compression_level(grpc_compression_level level) {
- maybe_compression_level_.is_set = true;
- maybe_compression_level_.level = level;
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_INITIAL_METADATA;
- op->flags = flags_;
- op->reserved = NULL;
- op->data.send_initial_metadata.count = initial_metadata_count_;
- op->data.send_initial_metadata.metadata = initial_metadata_;
- op->data.send_initial_metadata.maybe_compression_level.is_set =
- maybe_compression_level_.is_set;
- if (maybe_compression_level_.is_set) {
- op->data.send_initial_metadata.maybe_compression_level.level =
- maybe_compression_level_.level;
- }
- }
- void FinishOp(bool* status) {
- if (!send_) return;
- g_core_codegen_interface->gpr_free(initial_metadata_);
- send_ = false;
- }
-
- bool send_;
- uint32_t flags_;
- size_t initial_metadata_count_;
- grpc_metadata* initial_metadata_;
- struct {
- bool is_set;
- grpc_compression_level level;
- } maybe_compression_level_;
-};
-
-class CallOpSendMessage {
- public:
- CallOpSendMessage() : send_buf_() {}
-
- /// Send \a message using \a options for the write. The \a options are cleared
- /// after use.
- template <class M>
- Status SendMessage(const M& message,
- WriteOptions options) GRPC_MUST_USE_RESULT;
-
- template <class M>
- Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_buf_.Valid()) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_MESSAGE;
- op->flags = write_options_.flags();
- op->reserved = NULL;
- op->data.send_message.send_message = send_buf_.c_buffer();
- // Flags are per-message: clear them after use.
- write_options_.Clear();
- }
- void FinishOp(bool* status) { send_buf_.Clear(); }
-
- private:
- ByteBuffer send_buf_;
- WriteOptions write_options_;
-};
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
- write_options_ = options;
- bool own_buf;
- // TODO(vjpai): Remove the void below when possible
- // The void in the template parameter below should not be needed
- // (since it should be implicit) but is needed due to an observed
- // difference in behavior between clang and gcc for certain internal users
- Status result = SerializationTraits<M, void>::Serialize(
- message, send_buf_.bbuf_ptr(), &own_buf);
- if (!own_buf) {
- send_buf_.Duplicate();
- }
- return result;
-}
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message) {
- return SendMessage(message, WriteOptions());
-}
-
-template <class R>
-class CallOpRecvMessage {
- public:
- CallOpRecvMessage()
- : got_message(false),
- message_(nullptr),
- allow_not_getting_message_(false) {}
-
- void RecvMessage(R* message) { message_ = message; }
-
- // Do not change status if no message is received.
- void AllowNoMessage() { allow_not_getting_message_ = true; }
-
- bool got_message;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (message_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_MESSAGE;
- op->flags = 0;
- op->reserved = NULL;
- op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
- }
-
- void FinishOp(bool* status) {
- if (message_ == nullptr) return;
- if (recv_buf_.Valid()) {
- if (*status) {
- got_message = *status =
- SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
- .ok();
- recv_buf_.Release();
- } else {
- got_message = false;
- recv_buf_.Clear();
- }
- } else {
- got_message = false;
- if (!allow_not_getting_message_) {
- *status = false;
- }
- }
- message_ = nullptr;
- }
-
- private:
- R* message_;
- ByteBuffer recv_buf_;
- bool allow_not_getting_message_;
-};
-
-class DeserializeFunc {
- public:
- virtual Status Deserialize(ByteBuffer* buf) = 0;
- virtual ~DeserializeFunc() {}
-};
-
-template <class R>
-class DeserializeFuncType final : public DeserializeFunc {
- public:
- DeserializeFuncType(R* message) : message_(message) {}
- Status Deserialize(ByteBuffer* buf) override {
- return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
- }
-
- ~DeserializeFuncType() override {}
-
- private:
- R* message_; // Not a managed pointer because management is external to this
-};
-
-class CallOpGenericRecvMessage {
- public:
- CallOpGenericRecvMessage()
- : got_message(false), allow_not_getting_message_(false) {}
-
- template <class R>
- void RecvMessage(R* message) {
- // Use an explicit base class pointer to avoid resolution error in the
- // following unique_ptr::reset for some old implementations.
- DeserializeFunc* func = new DeserializeFuncType<R>(message);
- deserialize_.reset(func);
- }
-
- // Do not change status if no message is received.
- void AllowNoMessage() { allow_not_getting_message_ = true; }
-
- bool got_message;
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!deserialize_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_MESSAGE;
- op->flags = 0;
- op->reserved = NULL;
- op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
- }
-
- void FinishOp(bool* status) {
- if (!deserialize_) return;
- if (recv_buf_.Valid()) {
- if (*status) {
- got_message = true;
- *status = deserialize_->Deserialize(&recv_buf_).ok();
- recv_buf_.Release();
- } else {
- got_message = false;
- recv_buf_.Clear();
- }
- } else {
- got_message = false;
- if (!allow_not_getting_message_) {
- *status = false;
- }
- }
- deserialize_.reset();
- }
-
- private:
- std::unique_ptr<DeserializeFunc> deserialize_;
- ByteBuffer recv_buf_;
- bool allow_not_getting_message_;
-};
-
-class CallOpClientSendClose {
- public:
- CallOpClientSendClose() : send_(false) {}
-
- void ClientSendClose() { send_ = true; }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
- op->flags = 0;
- op->reserved = NULL;
- }
- void FinishOp(bool* status) { send_ = false; }
-
- private:
- bool send_;
-};
-
-class CallOpServerSendStatus {
- public:
- CallOpServerSendStatus() : send_status_available_(false) {}
-
- void ServerSendStatus(
- const std::multimap<grpc::string, grpc::string>& trailing_metadata,
- const Status& status) {
- send_error_details_ = status.error_details();
- trailing_metadata_ = FillMetadataArray(
- trailing_metadata, &trailing_metadata_count_, send_error_details_);
- send_status_available_ = true;
- send_status_code_ = static_cast<grpc_status_code>(status.error_code());
- send_error_message_ = status.error_message();
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (!send_status_available_) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
- op->data.send_status_from_server.trailing_metadata_count =
- trailing_metadata_count_;
- op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
- op->data.send_status_from_server.status = send_status_code_;
- error_message_slice_ = SliceReferencingString(send_error_message_);
- op->data.send_status_from_server.status_details =
- send_error_message_.empty() ? nullptr : &error_message_slice_;
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (!send_status_available_) return;
- g_core_codegen_interface->gpr_free(trailing_metadata_);
- send_status_available_ = false;
- }
-
- private:
- bool send_status_available_;
- grpc_status_code send_status_code_;
- grpc::string send_error_details_;
- grpc::string send_error_message_;
- size_t trailing_metadata_count_;
- grpc_metadata* trailing_metadata_;
- grpc_slice error_message_slice_;
-};
-
-class CallOpRecvInitialMetadata {
- public:
- CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
-
- void RecvInitialMetadata(ClientContext* context) {
- context->initial_metadata_received_ = true;
- metadata_map_ = &context->recv_initial_metadata_;
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (metadata_map_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_INITIAL_METADATA;
- op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (metadata_map_ == nullptr) return;
- metadata_map_->FillMap();
- metadata_map_ = nullptr;
- }
-
- private:
- MetadataMap* metadata_map_;
-};
-
-class CallOpClientRecvStatus {
- public:
- CallOpClientRecvStatus()
- : recv_status_(nullptr), debug_error_string_(nullptr) {}
-
- void ClientRecvStatus(ClientContext* context, Status* status) {
- client_context_ = context;
- metadata_map_ = &client_context_->trailing_metadata_;
- recv_status_ = status;
- error_message_ = g_core_codegen_interface->grpc_empty_slice();
- }
-
- protected:
- void AddOp(grpc_op* ops, size_t* nops) {
- if (recv_status_ == nullptr) return;
- grpc_op* op = &ops[(*nops)++];
- op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
- op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
- op->data.recv_status_on_client.status = &status_code_;
- op->data.recv_status_on_client.status_details = &error_message_;
- op->data.recv_status_on_client.error_string = &debug_error_string_;
- op->flags = 0;
- op->reserved = NULL;
- }
-
- void FinishOp(bool* status) {
- if (recv_status_ == nullptr) return;
- metadata_map_->FillMap();
- grpc::string binary_error_details;
- auto iter = metadata_map_->map()->find(kBinaryErrorDetailsKey);
- if (iter != metadata_map_->map()->end()) {
- binary_error_details =
- grpc::string(iter->second.begin(), iter->second.length());
- }
- *recv_status_ =
- Status(static_cast<StatusCode>(status_code_),
- GRPC_SLICE_IS_EMPTY(error_message_)
- ? grpc::string()
- : grpc::string(GRPC_SLICE_START_PTR(error_message_),
- GRPC_SLICE_END_PTR(error_message_)),
- binary_error_details);
- client_context_->set_debug_error_string(
- debug_error_string_ != nullptr ? debug_error_string_ : "");
- g_core_codegen_interface->grpc_slice_unref(error_message_);
- if (debug_error_string_ != nullptr) {
- g_core_codegen_interface->gpr_free((void*)debug_error_string_);
- }
- recv_status_ = nullptr;
- }
-
- private:
- ClientContext* client_context_;
- MetadataMap* metadata_map_;
- Status* recv_status_;
- const char* debug_error_string_;
- grpc_status_code status_code_;
- grpc_slice error_message_;
-};
-
-/// An abstract collection of call ops, used to generate the
-/// grpc_call_op structure to pass down to the lower layers,
-/// and as it is-a CompletionQueueTag, also massages the final
-/// completion into the correct form for consumption in the C++
-/// API.
-class CallOpSetInterface : public CompletionQueueTag {
- public:
- /// Fills in grpc_op, starting from ops[*nops] and moving
- /// upwards.
- virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0;
-};
-
-/// Primary implementation of CallOpSetInterface.
-/// Since we cannot use variadic templates, we declare slots up to
-/// the maximum count of ops we'll need in a set. We leverage the
-/// empty base class optimization to slim this class (especially
-/// when there are many unused slots used). To avoid duplicate base classes,
-/// the template parmeter for CallNoOp is varied by argument position.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
- class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
- class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class CallOpSet : public CallOpSetInterface,
- public Op1,
- public Op2,
- public Op3,
- public Op4,
- public Op5,
- public Op6 {
- public:
- CallOpSet() : return_tag_(this), call_(nullptr) {}
- void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override {
- this->Op1::AddOp(ops, nops);
- this->Op2::AddOp(ops, nops);
- this->Op3::AddOp(ops, nops);
- this->Op4::AddOp(ops, nops);
- this->Op5::AddOp(ops, nops);
- this->Op6::AddOp(ops, nops);
- g_core_codegen_interface->grpc_call_ref(call);
- call_ = call;
- }
-
- bool FinalizeResult(void** tag, bool* status) override {
- this->Op1::FinishOp(status);
- this->Op2::FinishOp(status);
- this->Op3::FinishOp(status);
- this->Op4::FinishOp(status);
- this->Op5::FinishOp(status);
- this->Op6::FinishOp(status);
- *tag = return_tag_;
-
- g_core_codegen_interface->grpc_call_unref(call_);
- return true;
- }
-
- void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
-
- private:
- void* return_tag_;
- grpc_call* call_;
-};
+class CallOpSetInterface;
/// Straightforward wrapping of the C call object
class Call final {
public:
+ Call()
+ : call_hook_(nullptr),
+ cq_(nullptr),
+ call_(nullptr),
+ max_receive_message_size_(-1) {}
/** call is owned by the caller */
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
: call_hook_(call_hook),
@@ -670,11 +48,20 @@ class Call final {
max_receive_message_size_(-1) {}
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
- int max_receive_message_size)
+ experimental::ClientRpcInfo* rpc_info)
+ : call_hook_(call_hook),
+ cq_(cq),
+ call_(call),
+ max_receive_message_size_(-1),
+ client_rpc_info_(rpc_info) {}
+
+ Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
+ int max_receive_message_size, experimental::ServerRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
call_(call),
- max_receive_message_size_(max_receive_message_size) {}
+ max_receive_message_size_(max_receive_message_size),
+ server_rpc_info_(rpc_info) {}
void PerformOps(CallOpSetInterface* ops) {
call_hook_->PerformOpsOnCall(ops, this);
@@ -685,11 +72,21 @@ class Call final {
int max_receive_message_size() const { return max_receive_message_size_; }
+ experimental::ClientRpcInfo* client_rpc_info() const {
+ return client_rpc_info_;
+ }
+
+ experimental::ServerRpcInfo* server_rpc_info() const {
+ return server_rpc_info_;
+ }
+
private:
CallHook* call_hook_;
CompletionQueue* cq_;
grpc_call* call_;
int max_receive_message_size_;
+ experimental::ClientRpcInfo* client_rpc_info_ = nullptr;
+ experimental::ServerRpcInfo* server_rpc_info_ = nullptr;
};
} // namespace internal
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h
new file mode 100644
index 0000000000..b4c34a01c9
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call_op_set.h
@@ -0,0 +1,919 @@
+/*
+ *
+ * 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_CALL_OP_SET_H
+#define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
+
+#include <assert.h>
+#include <array>
+#include <cstring>
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_hook.h>
+#include <grpcpp/impl/codegen/call_op_set_interface.h>
+#include <grpcpp/impl/codegen/client_context.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/intercepted_channel.h>
+#include <grpcpp/impl/codegen/interceptor_common.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+#include <grpc/impl/codegen/atm.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+
+class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+namespace internal {
+class Call;
+class CallHook;
+
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+inline grpc_metadata* FillMetadataArray(
+ const std::multimap<grpc::string, grpc::string>& metadata,
+ size_t* metadata_count, const grpc::string& optional_error_details) {
+ *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
+ if (*metadata_count == 0) {
+ return nullptr;
+ }
+ grpc_metadata* metadata_array =
+ (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
+ (*metadata_count) * sizeof(grpc_metadata)));
+ size_t i = 0;
+ for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
+ metadata_array[i].key = SliceReferencingString(iter->first);
+ metadata_array[i].value = SliceReferencingString(iter->second);
+ }
+ if (!optional_error_details.empty()) {
+ metadata_array[i].key =
+ g_core_codegen_interface->grpc_slice_from_static_buffer(
+ kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
+ metadata_array[i].value = SliceReferencingString(optional_error_details);
+ }
+ return metadata_array;
+}
+} // namespace internal
+
+/// Per-message write options.
+class WriteOptions {
+ public:
+ WriteOptions() : flags_(0), last_message_(false) {}
+ WriteOptions(const WriteOptions& other)
+ : flags_(other.flags_), last_message_(other.last_message_) {}
+
+ /// Clear all flags.
+ inline void Clear() { flags_ = 0; }
+
+ /// Returns raw flags bitset.
+ inline uint32_t flags() const { return flags_; }
+
+ /// Sets flag for the disabling of compression for the next message write.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline WriteOptions& set_no_compression() {
+ SetBit(GRPC_WRITE_NO_COMPRESS);
+ return *this;
+ }
+
+ /// Clears flag for the disabling of compression for the next message write.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline WriteOptions& clear_no_compression() {
+ ClearBit(GRPC_WRITE_NO_COMPRESS);
+ return *this;
+ }
+
+ /// Get value for the flag indicating whether compression for the next
+ /// message write is forcefully disabled.
+ ///
+ /// \sa GRPC_WRITE_NO_COMPRESS
+ inline bool get_no_compression() const {
+ return GetBit(GRPC_WRITE_NO_COMPRESS);
+ }
+
+ /// Sets flag indicating that the write may be buffered and need not go out on
+ /// the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline WriteOptions& set_buffer_hint() {
+ SetBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ /// Clears flag indicating that the write may be buffered and need not go out
+ /// on the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline WriteOptions& clear_buffer_hint() {
+ ClearBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ /// Get value for the flag indicating that the write may be buffered and need
+ /// not go out on the wire immediately.
+ ///
+ /// \sa GRPC_WRITE_BUFFER_HINT
+ inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+ /// corked bit: aliases set_buffer_hint currently, with the intent that
+ /// set_buffer_hint will be removed in the future
+ inline WriteOptions& set_corked() {
+ SetBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ inline WriteOptions& clear_corked() {
+ ClearBit(GRPC_WRITE_BUFFER_HINT);
+ return *this;
+ }
+
+ inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+ /// last-message bit: indicates this is the last message in a stream
+ /// client-side: makes Write the equivalent of performing Write, WritesDone
+ /// in a single step
+ /// server-side: hold the Write until the service handler returns (sync api)
+ /// or until Finish is called (async api)
+ inline WriteOptions& set_last_message() {
+ last_message_ = true;
+ return *this;
+ }
+
+ /// Clears flag indicating that this is the last message in a stream,
+ /// disabling coalescing.
+ inline WriteOptions& clear_last_message() {
+ last_message_ = false;
+ return *this;
+ }
+
+ /// Guarantee that all bytes have been written to the socket before completing
+ /// this write (usually writes are completed when they pass flow control).
+ inline WriteOptions& set_write_through() {
+ SetBit(GRPC_WRITE_THROUGH);
+ return *this;
+ }
+
+ inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
+
+ /// Get value for the flag indicating that this is the last message, and
+ /// should be coalesced with trailing metadata.
+ ///
+ /// \sa GRPC_WRITE_LAST_MESSAGE
+ bool is_last_message() const { return last_message_; }
+
+ WriteOptions& operator=(const WriteOptions& rhs) {
+ flags_ = rhs.flags_;
+ return *this;
+ }
+
+ private:
+ void SetBit(const uint32_t mask) { flags_ |= mask; }
+
+ void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
+
+ bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
+
+ uint32_t flags_;
+ bool last_message_;
+};
+
+namespace internal {
+
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
+class CallNoOp {
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {}
+ void FinishOp(bool* status) {}
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {}
+};
+
+class CallOpSendInitialMetadata {
+ public:
+ CallOpSendInitialMetadata() : send_(false) {
+ maybe_compression_level_.is_set = false;
+ }
+
+ void SendInitialMetadata(std::multimap<grpc::string, grpc::string>* metadata,
+ uint32_t flags) {
+ maybe_compression_level_.is_set = false;
+ send_ = true;
+ flags_ = flags;
+ metadata_map_ = metadata;
+ }
+
+ void set_compression_level(grpc_compression_level level) {
+ maybe_compression_level_.is_set = true;
+ maybe_compression_level_.level = level;
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->flags = flags_;
+ op->reserved = NULL;
+ initial_metadata_ =
+ FillMetadataArray(*metadata_map_, &initial_metadata_count_, "");
+ op->data.send_initial_metadata.count = initial_metadata_count_;
+ op->data.send_initial_metadata.metadata = initial_metadata_;
+ op->data.send_initial_metadata.maybe_compression_level.is_set =
+ maybe_compression_level_.is_set;
+ if (maybe_compression_level_.is_set) {
+ op->data.send_initial_metadata.maybe_compression_level.level =
+ maybe_compression_level_.level;
+ }
+ }
+ void FinishOp(bool* status) {
+ if (!send_ || hijacked_) return;
+ g_core_codegen_interface->gpr_free(initial_metadata_);
+ send_ = false;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA);
+ interceptor_methods->SetSendInitialMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ bool hijacked_ = false;
+ bool send_;
+ uint32_t flags_;
+ size_t initial_metadata_count_;
+ std::multimap<grpc::string, grpc::string>* metadata_map_;
+ grpc_metadata* initial_metadata_;
+ struct {
+ bool is_set;
+ grpc_compression_level level;
+ } maybe_compression_level_;
+};
+
+class CallOpSendMessage {
+ public:
+ CallOpSendMessage() : send_buf_() {}
+
+ /// Send \a message using \a options for the write. The \a options are cleared
+ /// after use.
+ template <class M>
+ Status SendMessage(const M& message,
+ WriteOptions options) GRPC_MUST_USE_RESULT;
+
+ template <class M>
+ Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_buf_.Valid() || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->flags = write_options_.flags();
+ op->reserved = NULL;
+ op->data.send_message.send_message = send_buf_.c_buffer();
+ // Flags are per-message: clear them after use.
+ write_options_.Clear();
+ }
+ void FinishOp(bool* status) { send_buf_.Clear(); }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_buf_.Valid()) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE);
+ interceptor_methods->SetSendMessage(&send_buf_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ ByteBuffer send_buf_;
+ WriteOptions write_options_;
+};
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
+ write_options_ = options;
+ bool own_buf;
+ // TODO(vjpai): Remove the void below when possible
+ // The void in the template parameter below should not be needed
+ // (since it should be implicit) but is needed due to an observed
+ // difference in behavior between clang and gcc for certain internal users
+ Status result = SerializationTraits<M, void>::Serialize(
+ message, send_buf_.bbuf_ptr(), &own_buf);
+ if (!own_buf) {
+ send_buf_.Duplicate();
+ }
+ return result;
+}
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message) {
+ return SendMessage(message, WriteOptions());
+}
+
+template <class R>
+class CallOpRecvMessage {
+ public:
+ CallOpRecvMessage()
+ : got_message(false),
+ message_(nullptr),
+ allow_not_getting_message_(false) {}
+
+ void RecvMessage(R* message) { message_ = message; }
+
+ // Do not change status if no message is received.
+ void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+ bool got_message;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (message_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->flags = 0;
+ op->reserved = NULL;
+ op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+ }
+
+ void FinishOp(bool* status) {
+ if (message_ == nullptr || hijacked_) return;
+ if (recv_buf_.Valid()) {
+ if (*status) {
+ got_message = *status =
+ SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
+ .ok();
+ recv_buf_.Release();
+ } else {
+ got_message = false;
+ recv_buf_.Clear();
+ }
+ } else {
+ got_message = false;
+ if (!allow_not_getting_message_) {
+ *status = false;
+ }
+ }
+ message_ = nullptr;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvMessage(message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!got_message) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ }
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (message_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
+ got_message = true;
+ }
+
+ private:
+ R* message_;
+ ByteBuffer recv_buf_;
+ bool allow_not_getting_message_;
+ bool hijacked_ = false;
+};
+
+class DeserializeFunc {
+ public:
+ virtual Status Deserialize(ByteBuffer* buf) = 0;
+ virtual ~DeserializeFunc() {}
+};
+
+template <class R>
+class DeserializeFuncType final : public DeserializeFunc {
+ public:
+ DeserializeFuncType(R* message) : message_(message) {}
+ Status Deserialize(ByteBuffer* buf) override {
+ return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
+ }
+
+ ~DeserializeFuncType() override {}
+
+ private:
+ R* message_; // Not a managed pointer because management is external to this
+};
+
+class CallOpGenericRecvMessage {
+ public:
+ CallOpGenericRecvMessage()
+ : got_message(false), allow_not_getting_message_(false) {}
+
+ template <class R>
+ void RecvMessage(R* message) {
+ // Use an explicit base class pointer to avoid resolution error in the
+ // following unique_ptr::reset for some old implementations.
+ DeserializeFunc* func = new DeserializeFuncType<R>(message);
+ deserialize_.reset(func);
+ message_ = message;
+ }
+
+ // Do not change status if no message is received.
+ void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+ bool got_message;
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!deserialize_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->flags = 0;
+ op->reserved = NULL;
+ op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+ }
+
+ void FinishOp(bool* status) {
+ if (!deserialize_ || hijacked_) return;
+ if (recv_buf_.Valid()) {
+ if (*status) {
+ got_message = true;
+ *status = deserialize_->Deserialize(&recv_buf_).ok();
+ recv_buf_.Release();
+ } else {
+ got_message = false;
+ recv_buf_.Clear();
+ }
+ } else {
+ got_message = false;
+ if (!allow_not_getting_message_) {
+ *status = false;
+ }
+ }
+ deserialize_.reset();
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvMessage(message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!got_message) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ }
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (!deserialize_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
+ }
+
+ private:
+ void* message_;
+ bool hijacked_ = false;
+ std::unique_ptr<DeserializeFunc> deserialize_;
+ ByteBuffer recv_buf_;
+ bool allow_not_getting_message_;
+};
+
+class CallOpClientSendClose {
+ public:
+ CallOpClientSendClose() : send_(false) {}
+
+ void ClientSendClose() { send_ = true; }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_ || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+ void FinishOp(bool* status) { send_ = false; }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ bool send_;
+};
+
+class CallOpServerSendStatus {
+ public:
+ CallOpServerSendStatus() : send_status_available_(false) {}
+
+ void ServerSendStatus(
+ std::multimap<grpc::string, grpc::string>* trailing_metadata,
+ const Status& status) {
+ send_error_details_ = status.error_details();
+ metadata_map_ = trailing_metadata;
+ send_status_available_ = true;
+ send_status_code_ = static_cast<grpc_status_code>(status.error_code());
+ send_error_message_ = status.error_message();
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (!send_status_available_ || hijacked_) return;
+ trailing_metadata_ = FillMetadataArray(
+ *metadata_map_, &trailing_metadata_count_, send_error_details_);
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count =
+ trailing_metadata_count_;
+ op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
+ op->data.send_status_from_server.status = send_status_code_;
+ error_message_slice_ = SliceReferencingString(send_error_message_);
+ op->data.send_status_from_server.status_details =
+ send_error_message_.empty() ? nullptr : &error_message_slice_;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (!send_status_available_ || hijacked_) return;
+ g_core_codegen_interface->gpr_free(trailing_metadata_);
+ send_status_available_ = false;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (!send_status_available_) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_STATUS);
+ interceptor_methods->SetSendTrailingMetadata(metadata_map_);
+ interceptor_methods->SetSendStatus(&send_status_code_, &send_error_details_,
+ &send_error_message_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {}
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ }
+
+ private:
+ bool hijacked_ = false;
+ bool send_status_available_;
+ grpc_status_code send_status_code_;
+ grpc::string send_error_details_;
+ grpc::string send_error_message_;
+ size_t trailing_metadata_count_;
+ std::multimap<grpc::string, grpc::string>* metadata_map_;
+ grpc_metadata* trailing_metadata_;
+ grpc_slice error_message_slice_;
+};
+
+class CallOpRecvInitialMetadata {
+ public:
+ CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
+
+ void RecvInitialMetadata(ClientContext* context) {
+ context->initial_metadata_received_ = true;
+ metadata_map_ = &context->recv_initial_metadata_;
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (metadata_map_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (metadata_map_ == nullptr || hijacked_) return;
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvInitialMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (metadata_map_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ metadata_map_ = nullptr;
+ }
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (metadata_map_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA);
+ }
+
+ private:
+ bool hijacked_ = false;
+ MetadataMap* metadata_map_;
+};
+
+class CallOpClientRecvStatus {
+ public:
+ CallOpClientRecvStatus()
+ : recv_status_(nullptr), debug_error_string_(nullptr) {}
+
+ void ClientRecvStatus(ClientContext* context, Status* status) {
+ client_context_ = context;
+ metadata_map_ = &client_context_->trailing_metadata_;
+ recv_status_ = status;
+ error_message_ = g_core_codegen_interface->grpc_empty_slice();
+ }
+
+ protected:
+ void AddOp(grpc_op* ops, size_t* nops) {
+ if (recv_status_ == nullptr || hijacked_) return;
+ grpc_op* op = &ops[(*nops)++];
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
+ op->data.recv_status_on_client.status = &status_code_;
+ op->data.recv_status_on_client.status_details = &error_message_;
+ op->data.recv_status_on_client.error_string = &debug_error_string_;
+ op->flags = 0;
+ op->reserved = NULL;
+ }
+
+ void FinishOp(bool* status) {
+ if (recv_status_ == nullptr || hijacked_) return;
+ grpc::string binary_error_details = metadata_map_->GetBinaryErrorDetails();
+ *recv_status_ =
+ Status(static_cast<StatusCode>(status_code_),
+ GRPC_SLICE_IS_EMPTY(error_message_)
+ ? grpc::string()
+ : grpc::string(GRPC_SLICE_START_PTR(error_message_),
+ GRPC_SLICE_END_PTR(error_message_)),
+ binary_error_details);
+ client_context_->set_debug_error_string(
+ debug_error_string_ != nullptr ? debug_error_string_ : "");
+ g_core_codegen_interface->grpc_slice_unref(error_message_);
+ if (debug_error_string_ != nullptr) {
+ g_core_codegen_interface->gpr_free((void*)debug_error_string_);
+ }
+ }
+
+ void SetInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ interceptor_methods->SetRecvStatus(recv_status_);
+ interceptor_methods->SetRecvTrailingMetadata(metadata_map_);
+ }
+
+ void SetFinishInterceptionHookPoint(
+ InterceptorBatchMethodsImpl* interceptor_methods) {
+ if (recv_status_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS);
+ recv_status_ = nullptr;
+ }
+
+ void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
+ hijacked_ = true;
+ if (recv_status_ == nullptr) return;
+ interceptor_methods->AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS);
+ }
+
+ private:
+ bool hijacked_ = false;
+ ClientContext* client_context_;
+ MetadataMap* metadata_map_;
+ Status* recv_status_;
+ const char* debug_error_string_;
+ grpc_status_code status_code_;
+ grpc_slice error_message_;
+};
+
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+ class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+ class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class CallOpSet;
+
+/// Primary implementation of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
+class CallOpSet : public CallOpSetInterface,
+ public Op1,
+ public Op2,
+ public Op3,
+ public Op4,
+ public Op5,
+ public Op6 {
+ public:
+ CallOpSet() : core_cq_tag_(this), return_tag_(this) {}
+ // The copy constructor and assignment operator reset the value of
+ // 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)
+ : core_cq_tag_(this),
+ return_tag_(this),
+ call_(other.call_),
+ done_intercepting_(false),
+ interceptor_methods_(InterceptorBatchMethodsImpl()) {}
+
+ CallOpSet& operator=(const CallOpSet& other) {
+ core_cq_tag_ = this;
+ return_tag_ = this;
+ call_ = other.call_;
+ done_intercepting_ = false;
+ interceptor_methods_ = InterceptorBatchMethodsImpl();
+ return *this;
+ }
+
+ void FillOps(Call* call) override {
+ done_intercepting_ = false;
+ g_core_codegen_interface->grpc_call_ref(call->call());
+ call_ =
+ *call; // It's fine to create a copy of call since it's just pointers
+
+ if (RunInterceptors()) {
+ ContinueFillOpsAfterInterception();
+ } else {
+ // After the interceptors are run, ContinueFillOpsAfterInterception will
+ // be run
+ }
+ }
+
+ bool FinalizeResult(void** tag, bool* status) override {
+ if (done_intercepting_) {
+ // We have already finished intercepting and filling in the results. This
+ // round trip from the core needed to be made because interceptors were
+ // run
+ *tag = return_tag_;
+ *status = saved_status_;
+ g_core_codegen_interface->grpc_call_unref(call_.call());
+ return true;
+ }
+
+ this->Op1::FinishOp(status);
+ this->Op2::FinishOp(status);
+ this->Op3::FinishOp(status);
+ this->Op4::FinishOp(status);
+ this->Op5::FinishOp(status);
+ this->Op6::FinishOp(status);
+ saved_status_ = *status;
+ if (RunInterceptorsPostRecv()) {
+ *tag = return_tag_;
+ g_core_codegen_interface->grpc_call_unref(call_.call());
+ return true;
+ }
+ // Interceptors are going to be run, so we can't return the tag just yet.
+ // After the interceptors are run, ContinueFinalizeResultAfterInterception
+ return false;
+ }
+
+ void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+
+ void* core_cq_tag() override { return core_cq_tag_; }
+
+ /// 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_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.
+ void SetHijackingState() override {
+ this->Op1::SetHijackingState(&interceptor_methods_);
+ this->Op2::SetHijackingState(&interceptor_methods_);
+ this->Op3::SetHijackingState(&interceptor_methods_);
+ this->Op4::SetHijackingState(&interceptor_methods_);
+ this->Op5::SetHijackingState(&interceptor_methods_);
+ this->Op6::SetHijackingState(&interceptor_methods_);
+ }
+
+ // Should be called after interceptors are done running
+ void ContinueFillOpsAfterInterception() override {
+ static const size_t MAX_OPS = 6;
+ grpc_op ops[MAX_OPS];
+ size_t nops = 0;
+ this->Op1::AddOp(ops, &nops);
+ this->Op2::AddOp(ops, &nops);
+ this->Op3::AddOp(ops, &nops);
+ this->Op4::AddOp(ops, &nops);
+ this->Op5::AddOp(ops, &nops);
+ this->Op6::AddOp(ops, &nops);
+ GPR_CODEGEN_ASSERT(GRPC_CALL_OK ==
+ g_core_codegen_interface->grpc_call_start_batch(
+ call_.call(), ops, nops, core_cq_tag(), nullptr));
+ }
+
+ // Should be called after interceptors are done running on the finalize result
+ // path
+ void ContinueFinalizeResultAfterInterception() override {
+ done_intercepting_ = true;
+ GPR_CODEGEN_ASSERT(GRPC_CALL_OK ==
+ g_core_codegen_interface->grpc_call_start_batch(
+ call_.call(), nullptr, 0, core_cq_tag(), nullptr));
+ }
+
+ private:
+ // Returns true if no interceptors need to be run
+ bool RunInterceptors() {
+ interceptor_methods_.ClearState();
+ interceptor_methods_.SetCallOpSetInterface(this);
+ interceptor_methods_.SetCall(&call_);
+ this->Op1::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op2::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op3::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op4::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op5::SetInterceptionHookPoint(&interceptor_methods_);
+ this->Op6::SetInterceptionHookPoint(&interceptor_methods_);
+ return interceptor_methods_.RunInterceptors();
+ }
+ // Returns true if no interceptors need to be run
+ bool RunInterceptorsPostRecv() {
+ // Call and OpSet had already been set on the set state.
+ // SetReverse also clears previously set hook points
+ interceptor_methods_.SetReverse();
+ this->Op1::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op2::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op3::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op4::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op5::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ this->Op6::SetFinishInterceptionHookPoint(&interceptor_methods_);
+ return interceptor_methods_.RunInterceptors();
+ }
+
+ void* core_cq_tag_;
+ void* return_tag_;
+ Call call_;
+ bool done_intercepting_ = false;
+ InterceptorBatchMethodsImpl interceptor_methods_;
+ bool saved_status_;
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
diff --git a/include/grpcpp/impl/codegen/call_op_set_interface.h b/include/grpcpp/impl/codegen/call_op_set_interface.h
new file mode 100644
index 0000000000..3b74566a6d
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call_op_set_interface.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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_CALL_OP_SET_INTERFACE_H
+#define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
+
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+
+namespace grpc {
+namespace internal {
+
+class Call;
+
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
+class CallOpSetInterface : public CompletionQueueTag {
+ public:
+ /// Fills in grpc_op, starting from ops[*nops] and moving
+ /// upwards.
+ virtual void FillOps(internal::Call* call) = 0;
+
+ /// Get the tag to be used at the core completion queue. Generally, the
+ /// 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* 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.
+ virtual void SetHijackingState() = 0;
+
+ // Should be called after interceptors are done running
+ virtual void ContinueFillOpsAfterInterception() = 0;
+
+ // Should be called after interceptors are done running on the finalize result
+ // path
+ virtual void ContinueFinalizeResultAfterInterception() = 0;
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_INTERFACE_H
diff --git a/include/grpcpp/impl/codegen/callback_common.h b/include/grpcpp/impl/codegen/callback_common.h
new file mode 100644
index 0000000000..51367cf550
--- /dev/null
+++ b/include/grpcpp/impl/codegen/callback_common.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_CALLBACK_COMMON_H
+#define GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
+
+#include <functional>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+namespace internal {
+
+/// An exception-safe way of invoking a user-specified callback function
+template <class Func, class... Args>
+void CatchingCallback(Func&& func, Args&&... args) {
+#if GRPC_ALLOW_EXCEPTIONS
+ try {
+ func(std::forward<Args>(args)...);
+ } catch (...) {
+ // nothing to return or change here, just don't crash the library
+ }
+#else // GRPC_ALLOW_EXCEPTIONS
+ func(std::forward<Args>(args)...);
+#endif // GRPC_ALLOW_EXCEPTIONS
+}
+
+// The contract on these tags is that they are single-shot. They must be
+// constructed and then fired at exactly one point. There is no expectation
+// that they can be reused without reconstruction.
+
+class CallbackWithStatusTag
+ : public grpc_experimental_completion_queue_functor {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(CallbackWithStatusTag));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
+ CompletionQueueTag* ops)
+ : call_(call), func_(std::move(f)), ops_(ops) {
+ g_core_codegen_interface->grpc_call_ref(call);
+ functor_run = &CallbackWithStatusTag::StaticRun;
+ }
+ ~CallbackWithStatusTag() {}
+ Status* status_ptr() { return &status_; }
+
+ // 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(Status s) {
+ status_ = std::move(s);
+ Run(true);
+ }
+
+ private:
+ grpc_call* call_;
+ std::function<void(Status)> func_;
+ CompletionQueueTag* ops_;
+ Status status_;
+
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
+ void* ignored = ops_;
+
+ if (!ops_->FinalizeResult(&ignored, &ok)) {
+ // The tag was swallowed
+ return;
+ }
+ GPR_CODEGEN_ASSERT(ignored == ops_);
+
+ // Last use of func_ or status_, so ok to move them out
+ 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:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(CallbackWithSuccessTag));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // 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) {
+ 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
+ // 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); }
+
+ /// check if this tag is currently set
+ operator bool() const { return call_ != nullptr; }
+
+ private:
+ grpc_call* call_;
+ std::function<void(bool)> func_;
+ CompletionQueueTag* ops_;
+
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
+ void* ignored = ops_;
+ bool new_ok = 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_);
+
+ if (do_callback) {
+ CatchingCallback(func_, ok);
+ }
+ }
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h
index ec1c6c25d8..6ec1ffb8c7 100644
--- a/include/grpcpp/impl/codegen/channel_interface.h
+++ b/include/grpcpp/impl/codegen/channel_interface.h
@@ -20,6 +20,8 @@
#define GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/client_context.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
@@ -41,6 +43,8 @@ class CallOpSetInterface;
class RpcMethod;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl;
template <class R>
class ClientAsyncReaderFactory;
template <class W>
@@ -49,6 +53,7 @@ template <class W, class R>
class ClientAsyncReaderWriterFactory;
template <class R>
class ClientAsyncResponseReaderFactory;
+class InterceptedChannel;
} // namespace internal
/// Codegen interface for \a grpc::Channel.
@@ -103,7 +108,10 @@ class ChannelInterface {
friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ template <class InputMessage, class OutputMessage>
+ friend class ::grpc::internal::CallbackUnaryCallImpl;
friend class ::grpc::internal::RpcMethod;
+ friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq) = 0;
@@ -115,6 +123,30 @@ class ChannelInterface {
CompletionQueue* cq, void* tag) = 0;
virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) = 0;
+
+ // EXPERIMENTAL
+ // This is needed to keep codegen_test_minimal happy. InterceptedChannel needs
+ // to make use of this but can't directly call Channel's implementation
+ // because of the test.
+ // Returns an empty Call object (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)
+ virtual internal::Call CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq,
+ size_t interceptor_pos) {
+ return internal::Call();
+ }
+
+ // EXPERIMENTAL
+ // A method to get the callbackable completion queue associated with this
+ // 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 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/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h
new file mode 100644
index 0000000000..4baa819091
--- /dev/null
+++ b/include/grpcpp/impl/codegen/client_callback.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * 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_CLIENT_CALLBACK_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
+
+#include <functional>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/callback_common.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class Channel;
+class ClientContext;
+class CompletionQueue;
+
+namespace internal {
+class RpcMethod;
+
+/// Perform a callback-based unary call
+/// TODO(vjpai): Combine as much as possible with the blocking unary call code
+template <class InputMessage, class OutputMessage>
+void CallbackUnaryCall(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, const InputMessage* request,
+ OutputMessage* result,
+ std::function<void(Status)> on_completion) {
+ CallbackUnaryCallImpl<InputMessage, OutputMessage> x(
+ channel, method, context, request, result, on_completion);
+}
+
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl {
+ public:
+ CallbackUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, const InputMessage* request,
+ OutputMessage* result,
+ std::function<void(Status)> on_completion) {
+ CompletionQueue* cq = channel->CallbackCQ();
+ GPR_CODEGEN_ASSERT(cq != nullptr);
+ Call call(channel->CreateCall(method, context, cq));
+
+ using FullCallOpSet =
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
+ CallOpClientSendClose, CallOpClientRecvStatus>;
+
+ auto* ops = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(FullCallOpSet))) FullCallOpSet;
+
+ auto* tag = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(CallbackWithStatusTag)))
+ CallbackWithStatusTag(call.call(), on_completion, ops);
+
+ // TODO(vjpai): Unify code with sync API as much as possible
+ Status s = ops->SendMessage(*request);
+ if (!s.ok()) {
+ tag->force_run(s);
+ return;
+ }
+ ops->SendInitialMetadata(&context->send_initial_metadata_,
+ context->initial_metadata_flags());
+ ops->RecvInitialMetadata(context);
+ ops->RecvMessage(result);
+ ops->AllowNoMessage();
+ ops->ClientSendClose();
+ ops->ClientRecvStatus(context, tag->status_ptr());
+ ops->set_core_cq_tag(tag);
+ call.PerformOps(ops);
+ }
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h
index 9dda4c7fac..75b955e760 100644
--- a/include/grpcpp/impl/codegen/client_context.h
+++ b/include/grpcpp/impl/codegen/client_context.h
@@ -41,6 +41,7 @@
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
@@ -68,6 +69,8 @@ class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl;
} // namespace internal
template <class R>
@@ -222,7 +225,7 @@ class ClientContext {
/// \warning This method should only be called before invoking the rpc.
///
/// \param deadline the deadline for the client call. Units are determined by
- /// the type used.
+ /// the type used. The deadline is an absolute (not relative) time.
template <typename T>
void set_deadline(const T& deadline) {
TimePoint<T> deadline_tp(deadline);
@@ -389,6 +392,8 @@ class ClientContext {
friend class ::grpc::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ template <class InputMessage, class OutputMessage>
+ friend class ::grpc::internal::CallbackUnaryCallImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
@@ -398,6 +403,17 @@ class ClientContext {
grpc_call* call() const { return call_; }
void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
+ experimental::ClientRpcInfo* set_client_rpc_info(
+ const char* method, grpc::ChannelInterface* channel,
+ const std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>&
+ creators,
+ size_t interceptor_pos) {
+ rpc_info_ = experimental::ClientRpcInfo(this, method, channel);
+ rpc_info_.RegisterInterceptors(creators, interceptor_pos);
+ return &rpc_info_;
+ }
+
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
(wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
@@ -410,6 +426,8 @@ class ClientContext {
grpc::string authority() { return authority_; }
+ void SendCancelToInterceptors();
+
bool initial_metadata_received_;
bool wait_for_ready_;
bool wait_for_ready_explicitly_set_;
@@ -425,8 +443,8 @@ class ClientContext {
mutable std::shared_ptr<const AuthContext> auth_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
- internal::MetadataMap recv_initial_metadata_;
- internal::MetadataMap trailing_metadata_;
+ mutable internal::MetadataMap recv_initial_metadata_;
+ mutable internal::MetadataMap trailing_metadata_;
grpc_call* propagate_from_call_;
PropagationOptions propagation_options_;
@@ -435,6 +453,8 @@ class ClientContext {
bool initial_metadata_corked_;
grpc::string debug_error_string_;
+
+ experimental::ClientRpcInfo rpc_info_;
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h
new file mode 100644
index 0000000000..f69c99ab22
--- /dev/null
+++ b/include/grpcpp/impl/codegen/client_interceptor.h
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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_CLIENT_INTERCEPTOR_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
+
+#include <memory>
+#include <vector>
+
+#include <grpcpp/impl/codegen/interceptor.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+namespace grpc {
+
+class ClientContext;
+class Channel;
+
+namespace internal {
+class InterceptorBatchMethodsImpl;
+}
+
+namespace experimental {
+class ClientRpcInfo;
+
+class ClientInterceptorFactoryInterface {
+ public:
+ 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() {}
+
+ ~ClientRpcInfo(){};
+
+ ClientRpcInfo(const ClientRpcInfo&) = delete;
+ ClientRpcInfo(ClientRpcInfo&&) = default;
+ ClientRpcInfo& operator=(ClientRpcInfo&&) = default;
+
+ // Getter methods
+ const char* method() { return method_; }
+ ChannelInterface* channel() { return channel_; }
+ grpc::ClientContext* client_context() { return ctx_; }
+
+ private:
+ ClientRpcInfo(grpc::ClientContext* ctx, const char* method,
+ grpc::ChannelInterface* channel)
+ : ctx_(ctx), method_(method), channel_(channel) {}
+ // Runs interceptor at pos \a pos.
+ void RunInterceptor(
+ experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
+ GPR_CODEGEN_ASSERT(pos < interceptors_.size());
+ interceptors_[pos]->Intercept(interceptor_methods);
+ }
+
+ void RegisterInterceptors(
+ const std::vector<std::unique_ptr<
+ experimental::ClientInterceptorFactoryInterface>>& creators,
+ 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;
+ const char* method_ = nullptr;
+ grpc::ChannelInterface* channel_ = nullptr;
+ std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
+ bool hijacked_ = false;
+ size_t hijacked_interceptor_ = 0;
+
+ friend class internal::InterceptorBatchMethodsImpl;
+ 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
+
+#endif // GRPCPP_IMPL_CODEGEN_CLIENT_INTERCEPTOR_H
diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h
index e4e8364e07..b1c80764f2 100644
--- a/include/grpcpp/impl/codegen/client_unary_call.h
+++ b/include/grpcpp/impl/codegen/client_unary_call.h
@@ -61,7 +61,7 @@ class BlockingUnaryCallImpl {
if (!status_.ok()) {
return;
}
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
ops.RecvInitialMetadata(context);
ops.RecvMessage(result);
diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h
index 3f7d4fb765..d603c7c700 100644
--- a/include/grpcpp/impl/codegen/completion_queue.h
+++ b/include/grpcpp/impl/codegen/completion_queue.h
@@ -122,8 +122,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// Read from the queue, blocking until an event is available or the queue is
/// shutting down.
///
- /// \param tag[out] Updated to point to the read event's tag.
- /// \param ok[out] true if read a successful event, false otherwise.
+ /// \param tag [out] Updated to point to the read event's tag.
+ /// \param ok [out] true if read a successful event, false otherwise.
///
/// Note that each tag sent to the completion queue (through RPC operations
/// or alarms) will be delivered out of the completion queue by a call to
@@ -178,10 +178,10 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
- /// \param tag[out] Upon sucess, updated to point to the event's tag.
- /// \param ok[out] Upon sucess, true if a successful event, false otherwise
+ /// \param tag [out] Upon sucess, updated to point to the event's tag.
+ /// \param ok [out] Upon sucess, true if a successful event, false otherwise
/// See documentation for CompletionQueue::Next for explanation of ok
- /// \param deadline[in] How long to block in wait for an event.
+ /// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T>
@@ -197,10 +197,11 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
- /// \param F[in] Function to execute before calling AsyncNext on this queue.
- /// \param tag[out] Upon sucess, updated to point to the event's tag.
- /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
- /// \param deadline[in] How long to block in wait for an event.
+ /// \param f [in] Function to execute before calling AsyncNext on this queue.
+ /// \param tag [out] Upon sucess, updated to point to the event's tag.
+ /// \param ok [out] Upon sucess, true if read a regular event, false
+ /// otherwise.
+ /// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T, typename F>
@@ -274,6 +275,9 @@ class CompletionQueue : private GrpcLibraryCodegen {
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ // Friends that need access to constructor for callback CQ
+ friend class ::grpc::Channel;
+
/// EXPERIMENTAL
/// Creates a Thread Local cache to store the first event
/// On this completion queue queued from this thread. Once
@@ -296,14 +300,17 @@ class CompletionQueue : private GrpcLibraryCodegen {
bool Pluck(internal::CompletionQueueTag* tag) {
auto deadline =
g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
- auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
- cq_, tag, deadline, nullptr);
- bool ok = ev.success != 0;
- void* ignored = tag;
- GPR_CODEGEN_ASSERT(tag->FinalizeResult(&ignored, &ok));
- GPR_CODEGEN_ASSERT(ignored == tag);
- // Ignore mutations by FinalizeResult: Pluck returns the C API status
- return ev.success != 0;
+ while (true) {
+ auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+ cq_, tag, deadline, nullptr);
+ bool ok = ev.success != 0;
+ void* ignored = tag;
+ if (tag->FinalizeResult(&ignored, &ok)) {
+ GPR_CODEGEN_ASSERT(ignored == tag);
+ // Ignore mutations by FinalizeResult: Pluck returns the C API status
+ return ev.success != 0;
+ }
+ }
}
/// Performs a single polling pluck on \a tag.
@@ -373,17 +380,23 @@ class ServerCompletionQueue : public CompletionQueue {
ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {}
private:
- /// \param is_frequently_polled Informs the GRPC library about whether the
- /// server completion queue would be actively polled (by calling Next() or
- /// AsyncNext()). By default all server completion queues are assumed to be
- /// frequently polled.
- ServerCompletionQueue(grpc_cq_polling_type polling_type)
+ /// \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.
+ /// \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_;
friend class ServerBuilder;
+ friend class Server;
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/completion_queue_tag.h b/include/grpcpp/impl/codegen/completion_queue_tag.h
index ffb642c56b..304386a9ec 100644
--- a/include/grpcpp/impl/codegen/completion_queue_tag.h
+++ b/include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -26,10 +26,25 @@ namespace internal {
class CompletionQueueTag {
public:
virtual ~CompletionQueueTag() {}
- /// Called prior to returning from Next(), return value is the status of the
- /// operation (return status is the default thing to do). If this function
- /// returns false, the tag is dropped and not returned from the completion
- /// queue
+
+ /// FinalizeResult must be called before informing user code that the
+ /// operation bound to the underlying core completion queue tag has
+ /// completed. In practice, this means:
+ ///
+ /// 1. For the sync API - before returning from Pluck
+ /// 2. For the CQ-based async API - before returning from Next
+ /// 3. For the callback-based API - before invoking the user callback
+ ///
+ /// This is the method that translates from core-side tag/status to
+ /// C++ API-observable tag/status.
+ ///
+ /// The return value is the status of the operation (returning status is the
+ /// general behavior of this function). If this function returns false, the
+ /// tag is dropped and not returned from the completion queue: this concept is
+ /// for events that are observed at core but not requested by the user
+ /// application (e.g., server shutdown, for server unimplemented method
+ /// responses, or for cases where a server-side RPC doesn't have a completion
+ /// notification registered using AsyncNotifyWhenDone)
virtual bool FinalizeResult(void** tag, bool* status) = 0;
};
} // namespace internal
diff --git a/include/grpcpp/impl/codegen/config_protobuf.h b/include/grpcpp/impl/codegen/config_protobuf.h
index 94e593d1ef..8c2e9e6792 100644
--- a/include/grpcpp/impl/codegen/config_protobuf.h
+++ b/include/grpcpp/impl/codegen/config_protobuf.h
@@ -66,6 +66,12 @@
#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
#endif
+#ifndef GRPC_CUSTOM_JSONUTIL
+#include <google/protobuf/util/json_util.h>
+#define GRPC_CUSTOM_JSONUTIL ::google::protobuf::util
+#define GRPC_CUSTOM_UTIL_STATUS ::google::protobuf::util::Status
+#endif
+
namespace grpc {
namespace protobuf {
@@ -83,6 +89,12 @@ typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase;
typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
+namespace util {
+typedef GRPC_CUSTOM_UTIL_STATUS Status;
+} // namespace util
+
+namespace json = GRPC_CUSTOM_JSONUTIL;
+
namespace io {
typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
diff --git a/include/grpcpp/impl/codegen/core_codegen.h b/include/grpcpp/impl/codegen/core_codegen.h
index e9df96bf04..6ef184d01a 100644
--- a/include/grpcpp/impl/codegen/core_codegen.h
+++ b/include/grpcpp/impl/codegen/core_codegen.h
@@ -63,6 +63,9 @@ class CoreCodegen final : public CoreCodegenInterface {
void gpr_cv_signal(gpr_cv* cv) override;
void gpr_cv_broadcast(gpr_cv* cv) override;
+ grpc_call_error grpc_call_start_batch(grpc_call* call, const grpc_op* ops,
+ size_t nops, void* tag,
+ void* reserved) override;
grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
diff --git a/include/grpcpp/impl/codegen/core_codegen_interface.h b/include/grpcpp/impl/codegen/core_codegen_interface.h
index 1167a188a2..20a5b3300c 100644
--- a/include/grpcpp/impl/codegen/core_codegen_interface.h
+++ b/include/grpcpp/impl/codegen/core_codegen_interface.h
@@ -100,6 +100,9 @@ class CoreCodegenInterface {
virtual grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*,
size_t)) = 0;
+ virtual grpc_call_error grpc_call_start_batch(grpc_call* call,
+ const grpc_op* ops, size_t nops,
+ void* tag, void* reserved) = 0;
virtual grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
grpc_status_code status,
const char* description,
@@ -142,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
new file mode 100644
index 0000000000..5255a6d147
--- /dev/null
+++ b/include/grpcpp/impl/codegen/intercepted_channel.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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_INTERCEPTED_CHANNEL_H
+#define GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
+
+#include <grpcpp/impl/codegen/channel_interface.h>
+
+namespace grpc {
+
+namespace internal {
+
+class InterceptorBatchMethodsImpl;
+
+/// An InterceptedChannel is available to client Interceptors. An
+/// InterceptedChannel is unique to an interceptor, and when an RPC is started
+/// on this channel, only those interceptors that come after this interceptor
+/// see the RPC.
+class InterceptedChannel : public ChannelInterface {
+ public:
+ virtual ~InterceptedChannel() { channel_ = nullptr; }
+
+ /// Get the current channel state. If the channel is in IDLE and
+ /// \a try_to_connect is set to true, try to connect.
+ grpc_connectivity_state GetState(bool try_to_connect) override {
+ return channel_->GetState(try_to_connect);
+ }
+
+ private:
+ InterceptedChannel(ChannelInterface* channel, size_t pos)
+ : channel_(channel), interceptor_pos_(pos) {}
+
+ Call CreateCall(const RpcMethod& method, ClientContext* context,
+ CompletionQueue* cq) override {
+ return channel_->CreateCallInternal(method, context, cq, interceptor_pos_);
+ }
+
+ void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override {
+ return channel_->PerformOpsOnCall(ops, call);
+ }
+ void* RegisterMethod(const char* method) override {
+ return channel_->RegisterMethod(method);
+ }
+
+ void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
+ gpr_timespec deadline, CompletionQueue* cq,
+ void* tag) override {
+ return channel_->NotifyOnStateChangeImpl(last_observed, deadline, cq, tag);
+ }
+ bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
+ gpr_timespec deadline) override {
+ return channel_->WaitForStateChangeImpl(last_observed, deadline);
+ }
+
+ CompletionQueue* CallbackCQ() override { return channel_->CallbackCQ(); }
+
+ ChannelInterface* channel_;
+ size_t interceptor_pos_;
+
+ friend class InterceptorBatchMethodsImpl;
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTED_CHANNEL_H
diff --git a/include/grpcpp/impl/codegen/interceptor.h b/include/grpcpp/impl/codegen/interceptor.h
new file mode 100644
index 0000000000..e449e44a23
--- /dev/null
+++ b/include/grpcpp/impl/codegen/interceptor.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * 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_INTERCEPTOR_H
+#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/metadata_map.h>
+
+namespace grpc {
+
+class ChannelInterface;
+class Status;
+
+namespace experimental {
+class InterceptedMessage {
+ public:
+ template <class M>
+ bool Extract(M* msg); // returns false if definitely invalid extraction
+ template <class M>
+ M* MutableExtract();
+ uint64_t length(); // length on wire
+};
+
+enum class InterceptionHookPoints {
+ /* The first two in this list are for clients and servers */
+ PRE_SEND_INITIAL_METADATA,
+ PRE_SEND_MESSAGE,
+ PRE_SEND_STATUS /* server only */,
+ PRE_SEND_CLOSE /* client only */,
+ /* The following three are for hijacked clients only and can only be
+ registered by the global interceptor */
+ PRE_RECV_INITIAL_METADATA,
+ PRE_RECV_MESSAGE,
+ PRE_RECV_STATUS,
+ /* The following two are for all clients and servers */
+ POST_RECV_INITIAL_METADATA,
+ POST_RECV_MESSAGE,
+ POST_RECV_STATUS /* client only */,
+ POST_RECV_CLOSE /* server only */,
+ /* This is a special hook point available to both clients and servers when
+ TryCancel() is performed.
+ - No other hook points will be present along with this.
+ - It is illegal for an interceptor to block/delay this operation.
+ - ALL interceptors see this hook point irrespective of whether the RPC was
+ hijacked or not. */
+ PRE_SEND_CANCEL,
+ NUM_INTERCEPTION_HOOKS
+};
+
+class InterceptorBatchMethods {
+ public:
+ virtual ~InterceptorBatchMethods(){};
+ // Queries to check whether the current batch has an interception hook point
+ // of type \a type
+ virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0;
+ // Calling this will signal that the interceptor is done intercepting the
+ // current batch of the RPC.
+ // Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
+ // from the Intercept method does the job of continuing the RPC in this case.
+ virtual void Proceed() = 0;
+ // Calling this indicates that the interceptor has hijacked the RPC (only
+ // valid if the batch contains send_initial_metadata on the client side)
+ virtual void Hijack() = 0;
+
+ // Returns a modifable ByteBuffer holding serialized form of the message to be
+ // sent
+ virtual ByteBuffer* GetSendMessage() = 0;
+
+ // Returns a modifiable multimap of the initial metadata to be sent
+ virtual std::multimap<grpc::string, grpc::string>*
+ GetSendInitialMetadata() = 0;
+
+ // Returns the status to be sent
+ virtual Status GetSendStatus() = 0;
+
+ // Modifies the status with \a status
+ virtual void ModifySendStatus(const Status& status) = 0;
+
+ // Returns a modifiable multimap of the trailing metadata to be sent
+ virtual std::multimap<grpc::string, grpc::string>*
+ GetSendTrailingMetadata() = 0;
+
+ // Returns a pointer to the modifiable received message. Note that the message
+ // is already deserialized
+ virtual void* GetRecvMessage() = 0;
+
+ // Returns a modifiable multimap of the received initial metadata
+ virtual std::multimap<grpc::string_ref, grpc::string_ref>*
+ GetRecvInitialMetadata() = 0;
+
+ // Returns a modifiable view of the received status
+ virtual Status* GetRecvStatus() = 0;
+
+ // Returns a modifiable multimap of the received trailing metadata
+ virtual std::multimap<grpc::string_ref, grpc::string_ref>*
+ GetRecvTrailingMetadata() = 0;
+
+ // Gets an intercepted channel. When a call is started on this interceptor,
+ // only interceptors after the current interceptor are created from the
+ // factory objects registered with the channel.
+ virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0;
+};
+
+class Interceptor {
+ public:
+ virtual ~Interceptor() {}
+
+ virtual void Intercept(InterceptorBatchMethods* methods) = 0;
+};
+
+} // namespace experimental
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_H
diff --git a/include/grpcpp/impl/codegen/interceptor_common.h b/include/grpcpp/impl/codegen/interceptor_common.h
new file mode 100644
index 0000000000..d0aa23cb0a
--- /dev/null
+++ b/include/grpcpp/impl/codegen/interceptor_common.h
@@ -0,0 +1,458 @@
+/*
+ *
+ * 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_INTERCEPTOR_COMMON_H
+#define GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
+
+#include <array>
+#include <functional>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/call_op_set_interface.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
+#include <grpcpp/impl/codegen/intercepted_channel.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+namespace internal {
+
+class InterceptorBatchMethodsImpl
+ : public experimental::InterceptorBatchMethods {
+ public:
+ InterceptorBatchMethodsImpl() {
+ for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
+ i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
+ i = static_cast<experimental::InterceptionHookPoints>(
+ static_cast<size_t>(i) + 1)) {
+ hooks_[static_cast<size_t>(i)] = false;
+ }
+ }
+
+ ~InterceptorBatchMethodsImpl() {}
+
+ bool QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints type) override {
+ return hooks_[static_cast<size_t>(type)];
+ }
+
+ void Proceed() override {
+ if (call_->client_rpc_info() != nullptr) {
+ return ProceedClient();
+ }
+ GPR_CODEGEN_ASSERT(call_->server_rpc_info() != nullptr);
+ ProceedServer();
+ }
+
+ void Hijack() override {
+ // Only the client can hijack when sending down initial metadata
+ GPR_CODEGEN_ASSERT(!reverse_ && ops_ != nullptr &&
+ call_->client_rpc_info() != nullptr);
+ // It is illegal to call Hijack twice
+ GPR_CODEGEN_ASSERT(!ran_hijacking_interceptor_);
+ auto* rpc_info = call_->client_rpc_info();
+ rpc_info->hijacked_ = true;
+ rpc_info->hijacked_interceptor_ = current_interceptor_index_;
+ ClearHookPoints();
+ ops_->SetHijackingState();
+ ran_hijacking_interceptor_ = true;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void AddInterceptionHookPoint(experimental::InterceptionHookPoints type) {
+ hooks_[static_cast<size_t>(type)] = true;
+ }
+
+ ByteBuffer* GetSendMessage() override { return send_message_; }
+
+ std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
+ return send_initial_metadata_;
+ }
+
+ Status GetSendStatus() override {
+ return Status(static_cast<StatusCode>(*code_), *error_message_,
+ *error_details_);
+ }
+
+ void ModifySendStatus(const Status& status) override {
+ *code_ = static_cast<grpc_status_code>(status.error_code());
+ *error_details_ = status.error_details();
+ *error_message_ = status.error_message();
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
+ override {
+ return send_trailing_metadata_;
+ }
+
+ void* GetRecvMessage() override { return recv_message_; }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
+ override {
+ return recv_initial_metadata_->map();
+ }
+
+ Status* GetRecvStatus() override { return recv_status_; }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
+ override {
+ return recv_trailing_metadata_->map();
+ }
+
+ void SetSendMessage(ByteBuffer* buf) { send_message_ = buf; }
+
+ void SetSendInitialMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ send_initial_metadata_ = metadata;
+ }
+
+ void SetSendStatus(grpc_status_code* code, grpc::string* error_details,
+ grpc::string* error_message) {
+ code_ = code;
+ error_details_ = error_details;
+ error_message_ = error_message;
+ }
+
+ void SetSendTrailingMetadata(
+ std::multimap<grpc::string, grpc::string>* metadata) {
+ send_trailing_metadata_ = metadata;
+ }
+
+ void SetRecvMessage(void* message) { recv_message_ = message; }
+
+ void SetRecvInitialMetadata(MetadataMap* map) {
+ recv_initial_metadata_ = map;
+ }
+
+ void SetRecvStatus(Status* status) { recv_status_ = status; }
+
+ void SetRecvTrailingMetadata(MetadataMap* map) {
+ recv_trailing_metadata_ = map;
+ }
+
+ std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
+ auto* info = call_->client_rpc_info();
+ if (info == nullptr) {
+ return std::unique_ptr<ChannelInterface>(nullptr);
+ }
+ // The intercepted channel starts from the interceptor just after the
+ // current interceptor
+ return std::unique_ptr<ChannelInterface>(new InterceptedChannel(
+ info->channel(), current_interceptor_index_ + 1));
+ }
+
+ // Clears all state
+ void ClearState() {
+ reverse_ = false;
+ ran_hijacking_interceptor_ = false;
+ ClearHookPoints();
+ }
+
+ // Prepares for Post_recv operations
+ void SetReverse() {
+ reverse_ = true;
+ ran_hijacking_interceptor_ = false;
+ ClearHookPoints();
+ }
+
+ // This needs to be set before interceptors are run
+ void SetCall(Call* call) { call_ = call; }
+
+ // This needs to be set before interceptors are run using RunInterceptors().
+ // Alternatively, RunInterceptors(std::function<void(void)> f) can be used.
+ void SetCallOpSetInterface(CallOpSetInterface* ops) { ops_ = ops; }
+
+ // Returns true if no interceptors are run. This should be used only by
+ // subclasses of CallOpSetInterface. SetCall and SetCallOpSetInterface should
+ // have been called before this. After all the interceptors are done running,
+ // either ContinueFillOpsAfterInterception or
+ // ContinueFinalizeOpsAfterInterception will be called. Note that neither of
+ // them is invoked if there were no interceptors registered.
+ bool RunInterceptors() {
+ GPR_CODEGEN_ASSERT(ops_);
+ auto* client_rpc_info = call_->client_rpc_info();
+ if (client_rpc_info != nullptr) {
+ if (client_rpc_info->interceptors_.size() == 0) {
+ return true;
+ } else {
+ RunClientInterceptors();
+ return false;
+ }
+ }
+
+ auto* server_rpc_info = call_->server_rpc_info();
+ if (server_rpc_info == nullptr ||
+ server_rpc_info->interceptors_.size() == 0) {
+ return true;
+ }
+ RunServerInterceptors();
+ return false;
+ }
+
+ // Returns true if no interceptors are run. Returns false otherwise if there
+ // are interceptors registered. After the interceptors are done running \a f
+ // will be invoked. This is to be used only by BaseAsyncRequest and
+ // SyncRequest.
+ bool RunInterceptors(std::function<void(void)> f) {
+ // This is used only by the server for initial call request
+ GPR_CODEGEN_ASSERT(reverse_ == true);
+ GPR_CODEGEN_ASSERT(call_->client_rpc_info() == nullptr);
+ auto* server_rpc_info = call_->server_rpc_info();
+ if (server_rpc_info == nullptr ||
+ server_rpc_info->interceptors_.size() == 0) {
+ return true;
+ }
+ callback_ = std::move(f);
+ RunServerInterceptors();
+ return false;
+ }
+
+ private:
+ void RunClientInterceptors() {
+ auto* rpc_info = call_->client_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_ = 0;
+ } else {
+ if (rpc_info->hijacked_) {
+ current_interceptor_index_ = rpc_info->hijacked_interceptor_;
+ } else {
+ current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
+ }
+ }
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void RunServerInterceptors() {
+ auto* rpc_info = call_->server_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_ = 0;
+ } else {
+ current_interceptor_index_ = rpc_info->interceptors_.size() - 1;
+ }
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+
+ void ProceedClient() {
+ auto* rpc_info = call_->client_rpc_info();
+ if (rpc_info->hijacked_ && !reverse_ &&
+ current_interceptor_index_ == rpc_info->hijacked_interceptor_ &&
+ !ran_hijacking_interceptor_) {
+ // We now need to provide hijacked recv ops to this interceptor
+ ClearHookPoints();
+ ops_->SetHijackingState();
+ ran_hijacking_interceptor_ = true;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ return;
+ }
+ if (!reverse_) {
+ current_interceptor_index_++;
+ // We are going down the stack of interceptors
+ if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
+ if (rpc_info->hijacked_ &&
+ current_interceptor_index_ > rpc_info->hijacked_interceptor_) {
+ // This is a hijacked RPC and we are done with hijacking
+ ops_->ContinueFillOpsAfterInterception();
+ } else {
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ }
+ } else {
+ // we are done running all the interceptors without any hijacking
+ ops_->ContinueFillOpsAfterInterception();
+ }
+ } else {
+ // We are going up the stack of interceptors
+ if (current_interceptor_index_ > 0) {
+ // Continue running interceptors
+ current_interceptor_index_--;
+ rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else {
+ // we are done running all the interceptors without any hijacking
+ ops_->ContinueFinalizeResultAfterInterception();
+ }
+ }
+ }
+
+ void ProceedServer() {
+ auto* rpc_info = call_->server_rpc_info();
+ if (!reverse_) {
+ current_interceptor_index_++;
+ if (current_interceptor_index_ < rpc_info->interceptors_.size()) {
+ return rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else if (ops_) {
+ return ops_->ContinueFillOpsAfterInterception();
+ }
+ } else {
+ // We are going up the stack of interceptors
+ if (current_interceptor_index_ > 0) {
+ // Continue running interceptors
+ current_interceptor_index_--;
+ return rpc_info->RunInterceptor(this, current_interceptor_index_);
+ } else if (ops_) {
+ return ops_->ContinueFinalizeResultAfterInterception();
+ }
+ }
+ GPR_CODEGEN_ASSERT(callback_);
+ callback_();
+ }
+
+ void ClearHookPoints() {
+ for (auto i = static_cast<experimental::InterceptionHookPoints>(0);
+ i < experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS;
+ i = static_cast<experimental::InterceptionHookPoints>(
+ static_cast<size_t>(i) + 1)) {
+ hooks_[static_cast<size_t>(i)] = false;
+ }
+ }
+
+ std::array<bool,
+ static_cast<size_t>(
+ experimental::InterceptionHookPoints::NUM_INTERCEPTION_HOOKS)>
+ hooks_;
+
+ size_t current_interceptor_index_ = 0; // Current iterator
+ bool reverse_ = false;
+ bool ran_hijacking_interceptor_ = false;
+ Call* call_ = nullptr; // The Call object is present along with CallOpSet
+ // object/callback
+ CallOpSetInterface* ops_ = nullptr;
+ std::function<void(void)> callback_;
+
+ ByteBuffer* send_message_ = nullptr;
+
+ std::multimap<grpc::string, grpc::string>* send_initial_metadata_;
+
+ grpc_status_code* code_ = nullptr;
+ grpc::string* error_details_ = nullptr;
+ grpc::string* error_message_ = nullptr;
+ Status send_status_;
+
+ std::multimap<grpc::string, grpc::string>* send_trailing_metadata_ = nullptr;
+
+ void* recv_message_ = nullptr;
+
+ MetadataMap* recv_initial_metadata_ = nullptr;
+
+ Status* recv_status_ = nullptr;
+
+ MetadataMap* recv_trailing_metadata_ = nullptr;
+};
+
+// A special implementation of InterceptorBatchMethods to send a Cancel
+// notification down the interceptor stack
+class CancelInterceptorBatchMethods
+ : public experimental::InterceptorBatchMethods {
+ public:
+ bool QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints type) override {
+ if (type == experimental::InterceptionHookPoints::PRE_SEND_CANCEL) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void Proceed() override {
+ // This is a no-op. For actual continuation of the RPC simply needs to
+ // return from the Intercept method
+ }
+
+ void Hijack() override {
+ // Only the client can hijack when sending down initial metadata
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call Hijack on a method which has a "
+ "Cancel notification");
+ }
+
+ ByteBuffer* GetSendMessage() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendMessage on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendInitialMetadata() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendInitialMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ Status GetSendStatus() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendStatus on a method which "
+ "has a Cancel notification");
+ return Status();
+ }
+
+ void ModifySendStatus(const Status& status) override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call ModifySendStatus on a method "
+ "which has a Cancel notification");
+ return;
+ }
+
+ std::multimap<grpc::string, grpc::string>* GetSendTrailingMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetSendTrailingMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ void* GetRecvMessage() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvMessage on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvInitialMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvInitialMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ Status* GetRecvStatus() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvStatus on a method which "
+ "has a Cancel notification");
+ return nullptr;
+ }
+
+ std::multimap<grpc::string_ref, grpc::string_ref>* GetRecvTrailingMetadata()
+ override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetRecvTrailingMetadata on a "
+ "method which has a Cancel notification");
+ return nullptr;
+ }
+
+ std::unique_ptr<ChannelInterface> GetInterceptedChannel() override {
+ GPR_CODEGEN_ASSERT(false &&
+ "It is illegal to call GetInterceptedChannel on a "
+ "method which has a Cancel notification");
+ return std::unique_ptr<ChannelInterface>(nullptr);
+ }
+};
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_INTERCEPTOR_COMMON_H
diff --git a/include/grpcpp/impl/codegen/metadata_map.h b/include/grpcpp/impl/codegen/metadata_map.h
index 0866539d88..9cec54d9f0 100644
--- a/include/grpcpp/impl/codegen/metadata_map.h
+++ b/include/grpcpp/impl/codegen/metadata_map.h
@@ -19,37 +19,84 @@
#ifndef GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
#define GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
+#include <map>
+
+#include <grpc/impl/codegen/log.h>
#include <grpcpp/impl/codegen/slice.h>
namespace grpc {
namespace internal {
+
+const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
+
class MetadataMap {
public:
- MetadataMap() { memset(&arr_, 0, sizeof(arr_)); }
+ MetadataMap() { Setup(); }
- ~MetadataMap() {
- g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
- }
+ ~MetadataMap() { Destroy(); }
- void FillMap() {
- for (size_t i = 0; i < arr_.count; i++) {
- // TODO(yangg) handle duplicates?
- map_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
- StringRefFromSlice(&arr_.metadata[i].key),
- StringRefFromSlice(&arr_.metadata[i].value)));
+ grpc::string GetBinaryErrorDetails() {
+ // if filled_, extract from the multimap for O(log(n))
+ if (filled_) {
+ auto iter = map_.find(kBinaryErrorDetailsKey);
+ if (iter != map_.end()) {
+ return grpc::string(iter->second.begin(), iter->second.length());
+ }
}
+ // if not yet filled, take the O(n) lookup to avoid allocating the
+ // multimap until it is requested.
+ // TODO(ncteisen): plumb this through core as a first class object, just
+ // like code and message.
+ else {
+ for (size_t i = 0; i < arr_.count; i++) {
+ if (strncmp(reinterpret_cast<const char*>(
+ GRPC_SLICE_START_PTR(arr_.metadata[i].key)),
+ kBinaryErrorDetailsKey,
+ GRPC_SLICE_LENGTH(arr_.metadata[i].key)) == 0) {
+ return grpc::string(reinterpret_cast<const char*>(
+ GRPC_SLICE_START_PTR(arr_.metadata[i].value)),
+ GRPC_SLICE_LENGTH(arr_.metadata[i].value));
+ }
+ }
+ }
+ return grpc::string();
}
- std::multimap<grpc::string_ref, grpc::string_ref>* map() { return &map_; }
- const std::multimap<grpc::string_ref, grpc::string_ref>* map() const {
+ std::multimap<grpc::string_ref, grpc::string_ref>* map() {
+ FillMap();
return &map_;
}
grpc_metadata_array* arr() { return &arr_; }
+ void Reset() {
+ filled_ = false;
+ map_.clear();
+ Destroy();
+ Setup();
+ }
+
private:
+ bool filled_ = false;
grpc_metadata_array arr_;
std::multimap<grpc::string_ref, grpc::string_ref> map_;
+
+ void Destroy() {
+ g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
+ }
+
+ void Setup() { memset(&arr_, 0, sizeof(arr_)); }
+
+ void FillMap() {
+ if (filled_) return;
+ filled_ = true;
+ for (size_t i = 0; i < arr_.count; i++) {
+ // TODO(yangg) handle duplicates?
+ map_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
+ StringRefFromSlice(&arr_.metadata[i].key),
+ StringRefFromSlice(&arr_.metadata[i].value)));
+ }
+ }
};
} // namespace internal
diff --git a/include/grpcpp/impl/codegen/method_handler_impl.h b/include/grpcpp/impl/codegen/method_handler_impl.h
index 53117f941b..dd53f975f6 100644
--- a/include/grpcpp/impl/codegen/method_handler_impl.h
+++ b/include/grpcpp/impl/codegen/method_handler_impl.h
@@ -59,21 +59,21 @@ class RpcMethodHandler : public MethodHandler {
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
- RequestType req;
- Status status = SerializationTraits<RequestType>::Deserialize(
- param.request.bbuf_ptr(), &req);
ResponseType rsp;
+ Status status = param.status;
if (status.ok()) {
- status = CatchingFunctionHandler([this, &param, &req, &rsp] {
- return func_(service_, param.server_context, &req, &rsp);
+ status = CatchingFunctionHandler([this, &param, &rsp] {
+ return func_(service_, param.server_context,
+ static_cast<RequestType*>(param.request), &rsp);
});
+ static_cast<RequestType*>(param.request)->~RequestType();
}
GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpServerSendStatus>
ops;
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -81,11 +81,26 @@ class RpcMethodHandler : public MethodHandler {
if (status.ok()) {
status = ops.SendMessage(rsp);
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
+ 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:
/// Application provided rpc handler function.
std::function<Status(ServiceType*, ServerContext*, const RequestType*,
@@ -117,7 +132,7 @@ class ClientStreamingHandler : public MethodHandler {
CallOpServerSendStatus>
ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -126,7 +141,7 @@ class ClientStreamingHandler : public MethodHandler {
if (status.ok()) {
status = ops.SendMessage(rsp);
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
}
@@ -150,26 +165,25 @@ class ServerStreamingHandler : public MethodHandler {
: func_(func), service_(service) {}
void RunHandler(const HandlerParameter& param) final {
- RequestType req;
- Status status = SerializationTraits<RequestType>::Deserialize(
- param.request.bbuf_ptr(), &req);
-
+ Status status = param.status;
if (status.ok()) {
ServerWriter<ResponseType> writer(param.call, param.server_context);
- status = CatchingFunctionHandler([this, &param, &req, &writer] {
- return func_(service_, param.server_context, &req, &writer);
+ status = CatchingFunctionHandler([this, &param, &writer] {
+ return func_(service_, param.server_context,
+ static_cast<RequestType*>(param.request), &writer);
});
+ static_cast<RequestType*>(param.request)->~RequestType();
}
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
@@ -177,6 +191,21 @@ class ServerStreamingHandler : public MethodHandler {
param.call->cq()->Pluck(&ops);
}
+ 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<Status(ServiceType*, ServerContext*, const RequestType*,
ServerWriter<ResponseType>*)>
@@ -206,7 +235,7 @@ class TemplatedBidiStreamingHandler : public MethodHandler {
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
if (!param.server_context->sent_initial_metadata_) {
- ops.SendInitialMetadata(param.server_context->initial_metadata_,
+ ops.SendInitialMetadata(&param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
@@ -218,7 +247,7 @@ class TemplatedBidiStreamingHandler : public MethodHandler {
"Service did not provide response message");
}
}
- ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+ ops.ServerSendStatus(&param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
if (param.server_context->has_pending_ops_) {
param.call->cq()->Pluck(&param.server_context->pending_ops_);
@@ -281,14 +310,14 @@ class ErrorMethodHandler : public MethodHandler {
static void FillOps(ServerContext* context, T* ops) {
Status status(code, "");
if (!context->sent_initial_metadata_) {
- ops->SendInitialMetadata(context->initial_metadata_,
+ ops->SendInitialMetadata(&context->initial_metadata_,
context->initial_metadata_flags());
if (context->compression_level_set()) {
ops->set_compression_level(context->compression_level());
}
context->sent_initial_metadata_ = true;
}
- ops->ServerSendStatus(context->trailing_metadata_, status);
+ ops->ServerSendStatus(&context->trailing_metadata_, status);
}
void RunHandler(const HandlerParameter& param) final {
@@ -296,11 +325,15 @@ class ErrorMethodHandler : public MethodHandler {
FillOps(param.server_context, &ops);
param.call->PerformOps(&ops);
param.call->cq()->Pluck(&ops);
- // We also have to destroy any request payload in the handler parameter
- ByteBuffer* payload = param.request.bbuf_ptr();
- if (payload != nullptr) {
- payload->Clear();
+ }
+
+ void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) final {
+ // We have to destroy any request payload
+ if (req != nullptr) {
+ g_core_codegen_interface->grpc_byte_buffer_destroy(req);
}
+ return nullptr;
}
};
diff --git a/include/grpcpp/impl/codegen/rpc_service_method.h b/include/grpcpp/impl/codegen/rpc_service_method.h
index 5cf88e216f..f465c5fc2f 100644
--- a/include/grpcpp/impl/codegen/rpc_service_method.h
+++ b/include/grpcpp/impl/codegen/rpc_service_method.h
@@ -40,17 +40,41 @@ class MethodHandler {
public:
virtual ~MethodHandler() {}
struct HandlerParameter {
- HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req)
- : call(c), server_context(context) {
- request.set_buffer(req);
- }
- ~HandlerParameter() { request.Release(); }
+ /// 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, 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;
- // Handler required to destroy these contents
- ByteBuffer request;
+ void* request;
+ Status status;
+ std::function<void()> call_requester;
};
virtual void RunHandler(const HandlerParameter& param) = 0;
+
+ /* Returns a pointer to the deserialized request. \a status reflects the
+ result of deserialization. This pointer and the status should be filled in
+ a HandlerParameter and passed to RunHandler. It is illegal to access the
+ pointer after calling RunHandler. Ownership of the deserialized request is
+ retained by the handler. Returns nullptr if deserialization failed. */
+ virtual void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
+ Status* status) {
+ GPR_CODEGEN_ASSERT(req == nullptr);
+ return nullptr;
+ }
};
/// Server side rpc method class
@@ -61,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.
@@ -88,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 6314364db6..82ee862f61 100644
--- a/include/grpcpp/impl/codegen/server_context.h
+++ b/include/grpcpp/impl/codegen/server_context.h
@@ -26,11 +26,14 @@
#include <grpc/impl/codegen/compression_types.h>
#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>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/time.h>
@@ -63,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>
@@ -107,7 +112,7 @@ class ServerContext {
/// Return a \a gpr_timespec representation of the server call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
- /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+ /// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client side
/// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
///
@@ -115,13 +120,13 @@ class ServerContext {
/// to the client (which can happen explicitly, or implicitly when sending a
/// a response message or status to the client).
///
- /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+ /// \param key The metadata key. If \a value is binary data, it must
/// end in "-bin".
- /// \param meta_value The metadata value. If its value is binary, the key name
+ /// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
- /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+ /// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client
/// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
///
@@ -129,13 +134,13 @@ class ServerContext {
/// metadata to the client (which happens when the call is finished and a
/// status is sent to the client).
///
- /// \param meta_key The metadata key. If \a meta_value is binary data,
+ /// \param key The metadata key. If \a value is binary data,
/// it must end in "-bin".
- /// \param meta_value The metadata value. If its value is binary, the key name
+ /// \param value The metadata value. If its value is binary, the key name
/// 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;
@@ -177,9 +182,9 @@ class ServerContext {
return compression_level_;
}
- /// Set \a algorithm to be the compression algorithm used for the server call.
+ /// Set \a level to be the compression level used for the server call.
///
- /// \param algorithm The compression algorithm used for the server call.
+ /// \param level The compression level used for the server call.
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
@@ -265,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;
@@ -275,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();
@@ -283,18 +290,37 @@ 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(
+ const char* method,
+ const std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
+ creators) {
+ if (creators.size() != 0) {
+ rpc_info_ = new experimental::ServerRpcInfo(this, method);
+ rpc_info_->RegisterInterceptors(creators);
+ }
+ return rpc_info_;
+ }
+
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_;
CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const AuthContext> auth_context_;
- internal::MetadataMap client_metadata_;
+ mutable internal::MetadataMap client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
@@ -306,6 +332,8 @@ class ServerContext {
internal::CallOpSendMessage>
pending_ops_;
bool has_pending_ops_;
+
+ experimental::ServerRpcInfo* rpc_info_;
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/server_interceptor.h b/include/grpcpp/impl/codegen/server_interceptor.h
new file mode 100644
index 0000000000..5fb5df28b7
--- /dev/null
+++ b/include/grpcpp/impl/codegen/server_interceptor.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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_INTERCEPTOR_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
+
+#include <atomic>
+#include <vector>
+
+#include <grpcpp/impl/codegen/interceptor.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+namespace grpc {
+
+class ServerContext;
+
+namespace internal {
+class InterceptorBatchMethodsImpl;
+}
+
+namespace experimental {
+class ServerRpcInfo;
+
+class ServerInterceptorFactoryInterface {
+ public:
+ virtual ~ServerInterceptorFactoryInterface() {}
+ virtual Interceptor* CreateServerInterceptor(ServerRpcInfo* info) = 0;
+};
+
+class ServerRpcInfo {
+ public:
+ ~ServerRpcInfo(){};
+
+ ServerRpcInfo(const ServerRpcInfo&) = delete;
+ ServerRpcInfo(ServerRpcInfo&&) = default;
+ ServerRpcInfo& operator=(ServerRpcInfo&&) = default;
+
+ // Getter methods
+ const char* method() { return method_; }
+ grpc::ServerContext* server_context() { return ctx_; }
+
+ private:
+ ServerRpcInfo(grpc::ServerContext* ctx, const char* method)
+ : ctx_(ctx), method_(method) {
+ ref_.store(1);
+ }
+
+ // Runs interceptor at pos \a pos.
+ void RunInterceptor(
+ experimental::InterceptorBatchMethods* interceptor_methods, size_t pos) {
+ GPR_CODEGEN_ASSERT(pos < interceptors_.size());
+ interceptors_[pos]->Intercept(interceptor_methods);
+ }
+
+ void RegisterInterceptors(
+ const std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
+ creators) {
+ for (const auto& creator : creators) {
+ interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
+ creator->CreateServerInterceptor(this)));
+ }
+ }
+
+ void Ref() { ref_++; }
+ void Unref() {
+ if (--ref_ == 0) {
+ delete this;
+ }
+ }
+
+ grpc::ServerContext* ctx_ = nullptr;
+ const char* method_ = nullptr;
+ std::atomic_int ref_;
+ std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
+
+ friend class internal::InterceptorBatchMethodsImpl;
+ friend class grpc::ServerContext;
+};
+
+} // namespace experimental
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_SERVER_INTERCEPTOR_H
diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h
index 237991cde6..55c94f4d2f 100644
--- a/include/grpcpp/impl/codegen/server_interface.h
+++ b/include/grpcpp/impl/codegen/server_interface.h
@@ -21,10 +21,12 @@
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_hook.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
+#include <grpcpp/impl/codegen/server_context.h>
namespace grpc {
@@ -148,44 +150,67 @@ class ServerInterface : public internal::CallHook {
public:
BaseAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
- CompletionQueue* call_cq, void* tag,
+ CompletionQueue* call_cq,
+ ServerCompletionQueue* notification_cq, void* tag,
bool delete_on_finalize);
virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override;
+ private:
+ void ContinueFinalizeResultAfterInterception();
+
protected:
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
+ ServerCompletionQueue* const notification_cq_;
void* const tag_;
const bool delete_on_finalize_;
grpc_call* call_;
+ internal::Call call_wrapper_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
+ bool done_intercepting_;
};
class RegisteredAsyncRequest : public BaseAsyncRequest {
public:
RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
- CompletionQueue* call_cq, void* tag);
-
- // uses BaseAsyncRequest::FinalizeResult
+ CompletionQueue* call_cq,
+ ServerCompletionQueue* notification_cq, void* tag,
+ const char* name);
+
+ virtual bool FinalizeResult(void** tag, bool* status) override {
+ /* If we are done intercepting, then there is nothing more for us to do */
+ if (done_intercepting_) {
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(),
+ context_->set_server_rpc_info(name_,
+ *server_->interceptor_creators()));
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
protected:
void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
ServerCompletionQueue* notification_cq);
+ const char* name_;
};
class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
- NoPayloadAsyncRequest(void* registered_method, ServerInterface* server,
- ServerContext* context,
+ NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
+ ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag)
- : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
- IssueRequest(registered_method, nullptr, notification_cq);
+ : RegisteredAsyncRequest(server, context, stream, call_cq,
+ notification_cq, tag,
+ registered_method->name()) {
+ IssueRequest(registered_method->server_tag(), nullptr, notification_cq);
}
// uses RegisteredAsyncRequest::FinalizeResult
@@ -194,13 +219,15 @@ class ServerInterface : public internal::CallHook {
template <class Message>
class PayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
- PayloadAsyncRequest(void* registered_method, ServerInterface* server,
- ServerContext* context,
+ PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
+ ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
Message* request)
- : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
+ : RegisteredAsyncRequest(server, context, stream, call_cq,
+ notification_cq, tag,
+ registered_method->name()),
registered_method_(registered_method),
server_(server),
context_(context),
@@ -209,7 +236,8 @@ class ServerInterface : public internal::CallHook {
notification_cq_(notification_cq),
tag_(tag),
request_(request) {
- IssueRequest(registered_method, payload_.bbuf_ptr(), notification_cq);
+ IssueRequest(registered_method->server_tag(), payload_.bbuf_ptr(),
+ notification_cq);
}
~PayloadAsyncRequest() {
@@ -217,6 +245,10 @@ class ServerInterface : public internal::CallHook {
}
bool FinalizeResult(void** tag, bool* status) override {
+ /* If we are done intercepting, then there is nothing more for us to do */
+ if (done_intercepting_) {
+ return RegisteredAsyncRequest::FinalizeResult(tag, status);
+ }
if (*status) {
if (!payload_.Valid() || !SerializationTraits<Message>::Deserialize(
payload_.bbuf_ptr(), request_)
@@ -235,15 +267,20 @@ class ServerInterface : public internal::CallHook {
return false;
}
}
+ /* Set interception point for recv message */
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ interceptor_methods_.SetRecvMessage(request_);
return RegisteredAsyncRequest::FinalizeResult(tag, status);
}
private:
- void* const registered_method_;
+ internal::RpcServiceMethod* const registered_method_;
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
+
ServerCompletionQueue* const notification_cq_;
void* const tag_;
Message* const request_;
@@ -272,9 +309,8 @@ class ServerInterface : public internal::CallHook {
ServerCompletionQueue* notification_cq, void* tag,
Message* message) {
GPR_CODEGEN_ASSERT(method);
- new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
- stream, call_cq, notification_cq, tag,
- message);
+ new PayloadAsyncRequest<Message>(method, this, context, stream, call_cq,
+ notification_cq, tag, message);
}
void RequestAsyncCall(internal::RpcServiceMethod* method,
@@ -283,8 +319,8 @@ class ServerInterface : public internal::CallHook {
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
GPR_CODEGEN_ASSERT(method);
- new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
- call_cq, notification_cq, tag);
+ new NoPayloadAsyncRequest(method, this, context, stream, call_cq,
+ notification_cq, tag);
}
void RequestAsyncGenericCall(GenericServerContext* context,
@@ -295,6 +331,28 @@ class ServerInterface : public internal::CallHook {
new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
tag, true);
}
+
+ private:
+ // EXPERIMENTAL
+ // Getter method for the vector of interceptor factory objects.
+ // 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/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h
index cbfcf25d0a..6981076f04 100644
--- a/include/grpcpp/impl/codegen/sync_stream.h
+++ b/include/grpcpp/impl/codegen/sync_stream.h
@@ -250,7 +250,7 @@ class ClientReader final : public ClientReaderInterface<R> {
::grpc::internal::CallOpSendMessage,
::grpc::internal::CallOpClientSendClose>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok());
@@ -327,7 +327,7 @@ class ClientWriter : public ClientWriterInterface<W> {
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
- ops.SendInitialMetadata(context_->send_initial_metadata_,
+ ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
@@ -386,7 +386,7 @@ class ClientWriter : public ClientWriterInterface<W> {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
@@ -498,7 +498,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
- ops.SendInitialMetadata(context_->send_initial_metadata_,
+ ops.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
@@ -557,7 +557,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
if (!context_->initial_metadata_corked_) {
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
ops;
- ops.SendInitialMetadata(context->send_initial_metadata_,
+ ops.SendInitialMetadata(&context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
@@ -583,7 +583,7 @@ class ServerReader final : public ServerReaderInterface<R> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -635,7 +635,7 @@ class ServerWriter final : public ServerWriterInterface<W> {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -660,7 +660,7 @@ class ServerWriter final : public ServerWriterInterface<W> {
return false;
}
if (!ctx_->sent_initial_metadata_) {
- ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
@@ -708,7 +708,7 @@ class ServerReaderWriterBody final {
GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
CallOpSet<CallOpSendInitialMetadata> ops;
- ops.SendInitialMetadata(ctx_->initial_metadata_,
+ ops.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
@@ -738,7 +738,7 @@ class ServerReaderWriterBody final {
return false;
}
if (!ctx_->sent_initial_metadata_) {
- ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+ ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
diff --git a/include/grpcpp/opencensus.h b/include/grpcpp/opencensus.h
index 07a1333986..29b221f767 100644
--- a/include/grpcpp/opencensus.h
+++ b/include/grpcpp/opencensus.h
@@ -19,10 +19,6 @@
#ifndef GRPCPP_OPENCENSUS_H
#define GRPCPP_OPENCENSUS_H
-#ifndef GRPC_BAZEL_BUILD
-#error OpenCensus for gRPC is only supported when building with bazel.
-#endif
-
#include "opencensus/trace/span.h"
namespace grpc {
diff --git a/include/grpcpp/security/credentials.h b/include/grpcpp/security/credentials.h
index bfadc15df5..8dfbdec3e6 100644
--- a/include/grpcpp/security/credentials.h
+++ b/include/grpcpp/security/credentials.h
@@ -24,6 +24,7 @@
#include <vector>
#include <grpc/grpc_security_constants.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/support/status.h>
@@ -38,6 +39,18 @@ class SecureChannelCredentials;
class CallCredentials;
class SecureCallCredentials;
+class ChannelCredentials;
+
+namespace experimental {
+std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
+ const grpc::string& target,
+ const std::shared_ptr<ChannelCredentials>& creds,
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+} // namespace experimental
+
/// A channel credentials object encapsulates all the state needed by a client
/// to authenticate with a server for a given channel.
/// It can make various assertions, e.g., about the client’s identity, role
@@ -62,8 +75,27 @@ class ChannelCredentials : private GrpcLibraryCodegen {
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args);
+ friend std::shared_ptr<Channel>
+ experimental::CreateCustomChannelWithInterceptors(
+ const grpc::string& target,
+ const std::shared_ptr<ChannelCredentials>& creds,
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+
virtual std::shared_ptr<Channel> CreateChannel(
const grpc::string& target, const ChannelArguments& args) = 0;
+
+ // This function should have been a pure virtual function, but it is
+ // implemented as a virtual function so that it does not break API.
+ virtual std::shared_ptr<Channel> CreateChannelWithInterceptors(
+ const grpc::string& target, const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
+ return nullptr;
+ };
};
/// A call credentials object encapsulates the state needed by a client to
diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h
index 72544c0f0b..a14a4da578 100644
--- a/include/grpcpp/server.h
+++ b/include/grpcpp/server.h
@@ -28,6 +28,7 @@
#include <grpc/compression.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/rpc_service_method.h>
@@ -99,6 +100,30 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
/// Establish a channel for in-process communication
std::shared_ptr<Channel> InProcessChannel(const ChannelArguments& args);
+ /// NOTE: class experimental_type is not part of the public API of this class.
+ /// TODO(yashykt): Integrate into public API when this is no longer
+ /// experimental.
+ class experimental_type {
+ public:
+ explicit experimental_type(Server* server) : server_(server) {}
+
+ /// Establish a channel for in-process communication with client
+ /// interceptors
+ std::shared_ptr<Channel> InProcessChannelWithInterceptors(
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
+
+ private:
+ Server* server_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
protected:
/// Register a service. This call does not take ownership of the service.
/// The service must exist for the lifetime of the Server instance.
@@ -149,7 +174,11 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
- grpc_resource_quota* server_rq = nullptr);
+ grpc_resource_quota* server_rq = nullptr,
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators = std::vector<std::unique_ptr<
+ experimental::ServerInterceptorFactoryInterface>>());
/// Start the server.
///
@@ -162,11 +191,17 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
grpc_server* server() override { return server_; };
private:
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>*
+ interceptor_creators() override {
+ return &interceptor_creators_;
+ }
+
friend class AsyncGenericService;
friend class ServerBuilder;
friend class ServerInitializer;
class SyncRequest;
+ class CallbackRequest;
class UnimplementedAsyncRequest;
class UnimplementedAsyncResponse;
@@ -189,8 +224,18 @@ class Server : public ServerInterface, private GrpcLibraryCodegen {
return max_receive_message_size_;
};
+ CompletionQueue* CallbackCQ() override;
+
ServerInitializer* initializer();
+ // A vector of interceptor factory objects.
+ // This should be destroyed after health_check_service_ and this requirement
+ // is satisfied by declaring interceptor_creators_ before
+ // health_check_service_. (C++ mandates that member objects be destroyed in
+ // the reverse order of initialization.)
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators_;
+
const int max_receive_message_size_;
/// The following completion queues are ONLY used in case of Sync API
@@ -203,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_;
@@ -226,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/server_builder.h b/include/grpcpp/server_builder.h
index a58a59c2d8..028b8cffaa 100644
--- a/include/grpcpp/server_builder.h
+++ b/include/grpcpp/server_builder.h
@@ -28,6 +28,7 @@
#include <grpc/support/cpu.h>
#include <grpc/support/workaround_list.h>
#include <grpcpp/impl/channel_argument_option.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/impl/server_builder_plugin.h>
#include <grpcpp/support/config.h>
@@ -212,6 +213,29 @@ class ServerBuilder {
/// doc/workarounds.md.
ServerBuilder& EnableWorkaround(grpc_workaround_list id);
+ /// NOTE: class experimental_type is not part of the public API of this class.
+ /// TODO(yashykt): Integrate into public API when this is no longer
+ /// experimental.
+ class experimental_type {
+ public:
+ explicit experimental_type(ServerBuilder* builder) : builder_(builder) {}
+
+ void SetInterceptorCreators(
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators) {
+ builder_->interceptor_creators_ = std::move(interceptor_creators);
+ }
+
+ private:
+ ServerBuilder* builder_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
protected:
/// Experimental, to be deprecated
struct Port {
@@ -297,6 +321,8 @@ class ServerBuilder {
grpc_compression_algorithm algorithm;
} maybe_default_compression_algorithm_;
uint32_t enabled_compression_algorithms_bitset_;
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators_;
};
} // namespace grpc
diff --git a/include/grpcpp/support/client_callback.h b/include/grpcpp/support/client_callback.h
new file mode 100644
index 0000000000..063fdc4f85
--- /dev/null
+++ b/include/grpcpp/support/client_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_CLIENT_CALLBACK_H
+#define GRPCPP_SUPPORT_CLIENT_CALLBACK_H
+
+#include <grpcpp/impl/codegen/client_callback.h>
+
+#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
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 901c22c1ea..3a76d907c8 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
<date>2018-01-19</date>
<time>16:06:07</time>
<version>
- <release>1.15.0dev</release>
- <api>1.15.0dev</api>
+ <release>1.17.0dev</release>
+ <api>1.17.0dev</api>
</version>
<stability>
<release>beta</release>
@@ -214,6 +214,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
@@ -228,11 +229,14 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
- <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts/alts_security_connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/fake/fake_security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_linux.h" role="src" />
- <file baseinstalldir="/" name="src/core/lib/security/security_connector/local_security_connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/local/local_security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/ssl/ssl_security_connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/ssl_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.h" role="src" />
@@ -246,7 +250,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" />
@@ -277,6 +281,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_channelz.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health_check_client.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
@@ -292,9 +297,8 @@
<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/tsi/alts_transport_security.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/local_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session.h" role="src" />
@@ -346,7 +350,6 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/error_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epoll1_linux.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollex_linux.h" role="src" />
- <file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollsig_linux.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.h" role="src" />
@@ -440,15 +443,19 @@
<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" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
@@ -492,7 +499,6 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/error.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epoll1_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollex_linux.cc" role="src" />
- <file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollsig_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_windows.cc" role="src" />
@@ -609,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" />
@@ -656,11 +663,14 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.cc" role="src" />
- <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts/alts_security_connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/fake/fake_security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_fallback.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/load_system_roots_linux.cc" role="src" />
- <file baseinstalldir="/" name="src/core/lib/security/security_connector/local_security_connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/local/local_security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/ssl/ssl_security_connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/security/security_connector/ssl_utils.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/client_auth_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.cc" role="src" />
@@ -679,7 +689,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" />
@@ -715,6 +725,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_plugin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health_check_client.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.cc" role="src" />
@@ -729,9 +740,8 @@
<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/tsi/alts_transport_security.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/health/health.pb.c" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/local_transport_security.cc" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc" role="src" />
@@ -750,10 +760,14 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
diff --git a/requirements.bazel.txt b/requirements.bazel.txt
index 16f31f9e94..61e529a6ec 100644
--- a/requirements.bazel.txt
+++ b/requirements.bazel.txt
@@ -8,3 +8,8 @@ wheel>=0.29
futures>=2.2.0
google-auth>=1.0.0
oauth2client==4.1.0
+requests>=2.14.2
+urllib3==1.22
+chardet==3.0.4
+certifi==2017.4.17
+idna==2.7
diff --git a/setup.py b/setup.py
index 388e629ec2..ae86e6c9fb 100644
--- a/setup.py
+++ b/setup.py
@@ -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,22 +89,26 @@ 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)
+# If this environmental variable is set, GRPC will not try to be compatible with
+# libc versions old than the one it was compiled against.
+DISABLE_LIBC_COMPATIBILITY = os.environ.get('GRPC_PYTHON_DISABLE_LIBC_COMPATIBILITY', False)
+
# Environment variable to determine whether or not to enable coverage analysis
# in Cython modules.
ENABLE_CYTHON_TRACING = os.environ.get(
@@ -198,11 +204,11 @@ if BUILD_WITH_SYSTEM_ZLIB:
if BUILD_WITH_SYSTEM_CARES:
EXTENSION_LIBRARIES += ('cares',)
-DEFINE_MACROS = (
- ('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
- ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1))
+DEFINE_MACROS = (('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600))
+if not DISABLE_LIBC_COMPATIBILITY:
+ DEFINE_MACROS += (('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),
@@ -283,8 +289,7 @@ if not PY3:
INSTALL_REQUIRES += ('futures>=2.2.0', 'enum34>=1.0.4')
SETUP_REQUIRES = INSTALL_REQUIRES + (
- 'sphinx>=1.3',
- 'sphinx_rtd_theme>=0.1.8',
+ 'Sphinx~=1.8.1',
'six>=1.10',
) if ENABLE_DOCUMENTATION_BUILD else ()
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 1e0c36451b..7986aca696 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -128,12 +128,14 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"");
}
static const char* headers_strs[] = {
+ "functional",
"grpcpp/impl/codegen/async_generic_service.h",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
"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",
@@ -547,6 +549,116 @@ void PrintHeaderClientMethod(grpc_generator::Printer* printer,
}
}
+void PrintHeaderClientMethodCallbackInterfacesStart(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ // This declares the interface for the callback-based API. The components
+ // are pure; even though this is new (post-1.0) API, it can be pure because
+ // it is an entirely new interface that happens to be scoped within
+ // StubInterface, not new additions to StubInterface itself
+ printer->Print("class experimental_async_interface {\n");
+ // All methods in this new interface are public. There is no need for private
+ // "Raw" methods since the callback-based API returns unowned raw pointers
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print("virtual ~experimental_async_interface() {}\n");
+}
+
+void PrintHeaderClientMethodCallbackInterfaces(
+ grpc_generator::Printer* printer, const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars, bool is_public) {
+ // Reserve is_public for future expansion
+ assert(is_public);
+
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "virtual void $Method$(::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)>) = 0;\n");
+ } else if (ClientOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for client-side streaming
+ } else if (ServerOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for server-side streaming
+ } else if (method->BidiStreaming()) {
+ // TODO(vjpai): Add support for bidi streaming
+ }
+}
+
+void PrintHeaderClientMethodCallbackInterfacesEnd(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ printer->Outdent();
+ printer->Print("};\n");
+
+ // Declare a function to give the async stub contents. It can't be pure
+ // since this is a new API in StubInterface, but it is meaningless by default
+ // (since any stub that wants to use it must have its own implementation of
+ // the callback functions therein), so make the default return value nullptr.
+ // Intentionally include the word "class" to avoid possible shadowing.
+ printer->Print(
+ "virtual class experimental_async_interface* experimental_async() { "
+ "return nullptr; }\n");
+}
+
+void PrintHeaderClientMethodCallbackStart(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ // This declares the stub entry for the callback-based API.
+ printer->Print("class experimental_async final :\n");
+ printer->Print(" public StubInterface::experimental_async_interface {\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+}
+
+void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer,
+ const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars,
+ bool is_public) {
+ // Reserve is_public for future expansion
+ assert(is_public);
+
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)>) override;\n");
+ } else if (ClientOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for client-side streaming
+ } else if (ServerOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for server-side streaming
+ } else if (method->BidiStreaming()) {
+ // TODO(vjpai): Add support for bidi streaming
+ }
+}
+
+void PrintHeaderClientMethodCallbackEnd(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ printer->Outdent();
+ printer->Print(" private:\n");
+ printer->Indent();
+ printer->Print("friend class Stub;\n");
+ printer->Print("explicit experimental_async(Stub* stub): stub_(stub) { }\n");
+ // include a function with a dummy use of stub_ to avoid an unused
+ // private member warning for service with no methods
+ printer->Print("Stub* stub() { return stub_; }\n");
+ printer->Print("Stub* stub_;\n");
+ printer->Outdent();
+ printer->Print("};\n");
+
+ printer->Print(
+ "class experimental_async_interface* experimental_async() override { "
+ "return &async_stub_; }\n");
+}
+
void PrintHeaderClientMethodData(grpc_generator::Printer* printer,
const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) {
@@ -589,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) {
@@ -718,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) {
@@ -951,6 +1227,14 @@ void PrintHeaderService(grpc_generator::Printer* printer,
true);
printer->Print(service->method(i)->GetTrailingComments("//").c_str());
}
+ PrintHeaderClientMethodCallbackInterfacesStart(printer, vars);
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(service->method(i)->GetLeadingComments("//").c_str());
+ PrintHeaderClientMethodCallbackInterfaces(printer, service->method(i).get(),
+ vars, true);
+ printer->Print(service->method(i)->GetTrailingComments("//").c_str());
+ }
+ PrintHeaderClientMethodCallbackInterfacesEnd(printer, vars);
printer->Outdent();
printer->Print("private:\n");
printer->Indent();
@@ -970,10 +1254,17 @@ void PrintHeaderService(grpc_generator::Printer* printer,
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
}
+ PrintHeaderClientMethodCallbackStart(printer, vars);
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodCallback(printer, service->method(i).get(), vars,
+ true);
+ }
+ PrintHeaderClientMethodCallbackEnd(printer, vars);
printer->Outdent();
printer->Print("\n private:\n");
printer->Indent();
printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
+ printer->Print("class experimental_async async_stub_{this};\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
}
@@ -1011,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");
@@ -1020,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);
@@ -1032,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);
@@ -1041,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$<");
}
@@ -1063,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$<");
@@ -1081,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$<");
@@ -1199,12 +1514,15 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
std::map<grpc::string, grpc::string> vars;
static const char* headers_strs[] = {
+ "functional",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
"grpcpp/impl/codegen/channel_interface.h",
"grpcpp/impl/codegen/client_unary_call.h",
+ "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));
@@ -1247,6 +1565,17 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
" return ::grpc::internal::BlockingUnaryCall"
"(channel_.get(), rpcmethod_$Method$_, "
"context, request, response);\n}\n\n");
+
+ printer->Print(*vars,
+ "void $ns$$Service$::Stub::experimental_async::$Method$("
+ "::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)> f) {\n");
+ printer->Print(*vars,
+ " return ::grpc::internal::CallbackUnaryCall"
+ "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
+ "context, request, response, std::move(f));\n}\n\n");
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1277,6 +1606,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, response);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1308,6 +1640,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, request);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1339,6 +1674,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1429,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/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index c7af9c38fa..e39d8be5d4 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -160,12 +160,20 @@ grpc::string GetServices(const FileDescriptor* file) {
return output;
}
+ std::string package_name;
+
+ if (file->options().has_ruby_package()) {
+ package_name = file->options().ruby_package();
+ } else {
+ package_name = file->package();
+ }
+
// Write out a file header.
std::map<grpc::string, grpc::string> header_comment_vars = ListToDict({
"file.name",
file->name(),
"file.package",
- file->package(),
+ package_name,
});
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print(header_comment_vars,
@@ -190,7 +198,7 @@ grpc::string GetServices(const FileDescriptor* file) {
// Write out services within the modules
out.Print("\n");
- std::vector<grpc::string> modules = Split(file->package(), '.');
+ std::vector<grpc::string> modules = Split(package_name, '.');
for (size_t i = 0; i < modules.size(); ++i) {
std::map<grpc::string, grpc::string> module_vars = ListToDict({
"module.name",
diff --git a/src/core/ext/filters/client_channel/OWNERS b/src/core/ext/filters/client_channel/OWNERS
index c8760d947b..d38970e0fa 100644
--- a/src/core/ext/filters/client_channel/OWNERS
+++ b/src/core/ext/filters/client_channel/OWNERS
@@ -1,4 +1,4 @@
set noparent
@markdroth
-@dgquintas
+@apolcyn
@AspirinSJL
diff --git a/src/core/ext/filters/client_channel/README.md b/src/core/ext/filters/client_channel/README.md
index 7c209db12e..9676a4535b 100644
--- a/src/core/ext/filters/client_channel/README.md
+++ b/src/core/ext/filters/client_channel/README.md
@@ -46,20 +46,4 @@ construction arguments for concrete grpc_subchannel instances.
Naming for GRPC
===============
-Names in GRPC are represented by a URI (as defined in
-[RFC 3986](https://tools.ietf.org/html/rfc3986)).
-
-The following schemes are currently supported:
-
-dns:///host:port - dns schemes are currently supported so long as authority is
- empty (authority based dns resolution is expected in a future
- release)
-
-unix:path - the unix scheme is used to create and connect to unix domain
- sockets - the authority must be empty, and the path
- represents the absolute or relative path to the desired
- socket
-
-ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination
-
-ipv6:[host]:port - a pre-resolved ipv6 address/port combination
+See [/doc/naming.md](gRPC name resolution).
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index d2bf4f388d..8e9ee889e1 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -129,6 +129,10 @@ typedef struct client_channel_channel_data {
grpc_core::UniquePtr<char> info_lb_policy_name;
/** service config in JSON form */
grpc_core::UniquePtr<char> info_service_config_json;
+ /* backpointer to grpc_channel's channelz node */
+ grpc_core::channelz::ClientChannelNode* channelz_channel;
+ /* caches if the last resolution event contained addresses */
+ bool previous_resolution_contained_addresses;
} channel_data;
typedef struct {
@@ -153,6 +157,23 @@ static void watch_lb_policy_locked(channel_data* chand,
grpc_core::LoadBalancingPolicy* lb_policy,
grpc_connectivity_state current_state);
+static const char* channel_connectivity_state_change_string(
+ grpc_connectivity_state state) {
+ switch (state) {
+ case GRPC_CHANNEL_IDLE:
+ return "Channel state change to IDLE";
+ case GRPC_CHANNEL_CONNECTING:
+ return "Channel state change to CONNECTING";
+ case GRPC_CHANNEL_READY:
+ return "Channel state change to READY";
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ return "Channel state change to TRANSIENT_FAILURE";
+ case GRPC_CHANNEL_SHUTDOWN:
+ return "Channel state change to SHUTDOWN";
+ }
+ GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
static void set_channel_connectivity_state_locked(channel_data* chand,
grpc_connectivity_state state,
grpc_error* error,
@@ -177,6 +198,12 @@ static void set_channel_connectivity_state_locked(channel_data* chand,
gpr_log(GPR_INFO, "chand=%p: setting connectivity state to %s", chand,
grpc_connectivity_state_name(state));
}
+ if (chand->channelz_channel != nullptr) {
+ chand->channelz_channel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string(
+ channel_connectivity_state_change_string(state)));
+ }
grpc_connectivity_state_set(&chand->state_tracker, state, error, reason);
}
@@ -376,6 +403,8 @@ static void request_reresolution_locked(void* arg, grpc_error* error) {
chand->lb_policy->SetReresolutionClosureLocked(&args->closure);
}
+using TraceStringVector = grpc_core::InlinedVector<char*, 3>;
+
// Creates a new LB policy, replacing any previous one.
// If the new policy is created successfully, sets *connectivity_state and
// *connectivity_error to its initial connectivity state; otherwise,
@@ -383,7 +412,7 @@ static void request_reresolution_locked(void* arg, grpc_error* error) {
static void create_new_lb_policy_locked(
channel_data* chand, char* lb_policy_name,
grpc_connectivity_state* connectivity_state,
- grpc_error** connectivity_error) {
+ grpc_error** connectivity_error, TraceStringVector* trace_strings) {
grpc_core::LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = chand->combiner;
lb_policy_args.client_channel_factory = chand->client_channel_factory;
@@ -393,11 +422,21 @@ static void create_new_lb_policy_locked(
lb_policy_name, lb_policy_args);
if (GPR_UNLIKELY(new_lb_policy == nullptr)) {
gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
+ if (chand->channelz_channel != nullptr) {
+ char* str;
+ gpr_asprintf(&str, "Could not create LB policy \'%s\'", lb_policy_name);
+ trace_strings->push_back(str);
+ }
} else {
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p: created new LB policy \"%s\" (%p)", chand,
lb_policy_name, new_lb_policy.get());
}
+ if (chand->channelz_channel != nullptr) {
+ char* str;
+ gpr_asprintf(&str, "Created new LB policy \'%s\'", lb_policy_name);
+ trace_strings->push_back(str);
+ }
// Swap out the LB policy and update the fds in
// chand->interested_parties.
if (chand->lb_policy != nullptr) {
@@ -457,7 +496,6 @@ get_service_config_from_resolver_result_locked(channel_data* chand) {
grpc_uri* uri = grpc_uri_parse(server_uri, true);
GPR_ASSERT(uri->path[0] != '\0');
service_config_parsing_state parsing_state;
- memset(&parsing_state, 0, sizeof(parsing_state));
parsing_state.server_name =
uri->path[0] == '/' ? uri->path + 1 : uri->path;
service_config->ParseGlobalParams(parse_retry_throttle_params,
@@ -473,6 +511,51 @@ get_service_config_from_resolver_result_locked(channel_data* chand) {
return grpc_core::UniquePtr<char>(gpr_strdup(service_config_json));
}
+static void maybe_add_trace_message_for_address_changes_locked(
+ channel_data* chand, TraceStringVector* trace_strings) {
+ int resolution_contains_addresses = false;
+ const grpc_arg* channel_arg =
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
+ if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
+ grpc_lb_addresses* addresses =
+ static_cast<grpc_lb_addresses*>(channel_arg->value.pointer.p);
+ if (addresses->num_addresses > 0) {
+ resolution_contains_addresses = true;
+ }
+ }
+ if (!resolution_contains_addresses &&
+ chand->previous_resolution_contained_addresses) {
+ trace_strings->push_back(gpr_strdup("Address list became empty"));
+ } else if (resolution_contains_addresses &&
+ !chand->previous_resolution_contained_addresses) {
+ trace_strings->push_back(gpr_strdup("Address list became non-empty"));
+ }
+ chand->previous_resolution_contained_addresses =
+ resolution_contains_addresses;
+}
+
+static void concatenate_and_add_channel_trace_locked(
+ channel_data* chand, TraceStringVector* trace_strings) {
+ if (!trace_strings->empty()) {
+ gpr_strvec v;
+ gpr_strvec_init(&v);
+ gpr_strvec_add(&v, gpr_strdup("Resolution event: "));
+ bool is_first = 1;
+ for (size_t i = 0; i < trace_strings->size(); ++i) {
+ if (!is_first) gpr_strvec_add(&v, gpr_strdup(", "));
+ is_first = false;
+ gpr_strvec_add(&v, (*trace_strings)[i]);
+ }
+ char* flat;
+ size_t flat_len = 0;
+ flat = gpr_strvec_flatten(&v, &flat_len);
+ chand->channelz_channel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_new(flat, flat_len, gpr_free));
+ gpr_strvec_destroy(&v);
+ }
+}
+
// Callback invoked when a resolver result is available.
static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
channel_data* chand = static_cast<channel_data*>(arg);
@@ -494,6 +577,16 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
}
// Data used to set the channel's connectivity state.
bool set_connectivity_state = true;
+ // We only want to trace the address resolution in the follow cases:
+ // (a) Address resolution resulted in service config change.
+ // (b) Address resolution that causes number of backends to go from
+ // zero to non-zero.
+ // (c) Address resolution that causes number of backends to go from
+ // non-zero to zero.
+ // (d) Address resolution that causes a new LB policy to be created.
+ //
+ // we track a list of strings to eventually be concatenated and traced.
+ TraceStringVector trace_strings;
grpc_connectivity_state connectivity_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
grpc_error* connectivity_error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
@@ -528,11 +621,29 @@ static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
} else {
// Instantiate new LB policy.
create_new_lb_policy_locked(chand, lb_policy_name.get(),
- &connectivity_state, &connectivity_error);
+ &connectivity_state, &connectivity_error,
+ &trace_strings);
}
// Find service config.
grpc_core::UniquePtr<char> service_config_json =
get_service_config_from_resolver_result_locked(chand);
+ // Note: It's safe to use chand->info_service_config_json here without
+ // taking a lock on chand->info_mu, because this function is the
+ // only thing that modifies its value, and it can only be invoked
+ // once at any given time.
+ if (chand->channelz_channel != nullptr) {
+ if (((service_config_json == nullptr) !=
+ (chand->info_service_config_json == nullptr)) ||
+ (service_config_json != nullptr &&
+ strcmp(service_config_json.get(),
+ chand->info_service_config_json.get()) != 0)) {
+ // TODO(ncteisen): might be worth somehow including a snippet of the
+ // config in the trace, at the risk of bloating the trace logs.
+ trace_strings.push_back(gpr_strdup("Service config changed"));
+ }
+ maybe_add_trace_message_for_address_changes_locked(chand, &trace_strings);
+ concatenate_and_add_channel_trace_locked(chand, &trace_strings);
+ }
// Swap out the data used by cc_get_channel_info().
gpr_mu_lock(&chand->info_mu);
chand->info_lb_policy_name = std::move(lb_policy_name);
@@ -700,6 +811,8 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
// Record enable_retries.
arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_ENABLE_RETRIES);
chand->enable_retries = grpc_channel_arg_get_bool(arg, true);
+ chand->channelz_channel = nullptr;
+ chand->previous_resolution_contained_addresses = false;
// Record client channel factory.
arg = grpc_channel_args_find(args->channel_args,
GRPC_ARG_CLIENT_CHANNEL_FACTORY);
@@ -825,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.
@@ -839,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.
@@ -862,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;
@@ -872,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;
@@ -884,14 +1023,18 @@ typedef struct {
bool completed_recv_initial_metadata : 1;
bool started_recv_trailing_metadata : 1;
bool completed_recv_trailing_metadata : 1;
+ 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;
// State for callback processing.
+ // NOTE: Do not move this next to the metadata bitfields above. That would
+ // save space but will also result in a data race because compiler will
+ // generate a 2 byte store which overwrites the meta-data fields upon
+ // setting this field.
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;
+};
// Pending batches stored in call data.
typedef struct {
@@ -906,7 +1049,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
@@ -925,24 +1105,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;
@@ -951,8 +1131,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;
@@ -963,12 +1143,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;
@@ -979,14 +1159,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,
@@ -1030,7 +1209,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) {
@@ -1067,7 +1246,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.
@@ -1537,55 +1716,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();
}
}
@@ -1778,23 +1968,22 @@ static void recv_message_ready(void* arg, grpc_error* error) {
// recv_trailing_metadata handling
//
-// Sets *status and *server_pushback_md based on batch_data and error.
-static void get_call_status(subchannel_batch_data* batch_data,
- grpc_error* error, grpc_status_code* status,
+// Sets *status and *server_pushback_md based on md_batch and error.
+// Only sets *server_pushback_md if server_pushback_md != nullptr.
+static void get_call_status(grpc_call_element* elem,
+ grpc_metadata_batch* md_batch, grpc_error* error,
+ grpc_status_code* status,
grpc_mdelem** server_pushback_md) {
- grpc_call_element* elem = batch_data->elem;
call_data* calld = static_cast<call_data*>(elem->call_data);
if (error != GRPC_ERROR_NONE) {
grpc_error_get_status(error, calld->deadline, status, nullptr, nullptr,
nullptr);
} else {
- grpc_metadata_batch* md_batch =
- batch_data->batch.payload->recv_trailing_metadata
- .recv_trailing_metadata;
GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
*status =
grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
- if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+ if (server_pushback_md != nullptr &&
+ md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
*server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
}
}
@@ -1884,7 +2073,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 &&
@@ -1967,7 +2156,9 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
// Get the call's status and check for server pushback metadata.
grpc_status_code status = GRPC_STATUS_OK;
grpc_mdelem* server_pushback_md = nullptr;
- get_call_status(batch_data, GRPC_ERROR_REF(error), &status,
+ grpc_metadata_batch* md_batch =
+ batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata;
+ get_call_status(elem, md_batch, GRPC_ERROR_REF(error), &status,
&server_pushback_md);
if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand,
@@ -2038,7 +2229,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;
@@ -2194,9 +2385,9 @@ static void add_retriable_send_initial_metadata_op(
.grpc_previous_rpc_attempts);
}
if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) {
- grpc_mdelem retry_md = grpc_mdelem_from_slices(
+ grpc_mdelem retry_md = grpc_mdelem_create(
GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
- *retry_count_strings[calld->num_attempts_completed - 1]);
+ *retry_count_strings[calld->num_attempts_completed - 1], nullptr);
grpc_error* error = grpc_metadata_batch_add_tail(
&retry_state->send_initial_metadata,
&retry_state->send_initial_metadata_storage[calld->send_initial_metadata
@@ -2230,7 +2421,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;
@@ -2362,7 +2553,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) {
@@ -2383,7 +2574,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()) {
@@ -2435,7 +2626,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;
}
@@ -2602,11 +2793,9 @@ static void create_subchannel_call(grpc_call_element* elem, grpc_error* error) {
pending_batches_fail(elem, new_error, true /* yield_call_combiner */);
} else {
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);
}
@@ -2832,6 +3021,27 @@ static void apply_service_config_to_call_locked(grpc_call_element* elem) {
}
}
+// If the channel is in TRANSIENT_FAILURE and the call is not
+// wait_for_ready=true, fails the call and returns true.
+static bool fail_call_if_in_transient_failure(grpc_call_element* elem) {
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ grpc_transport_stream_op_batch* batch = calld->pending_batches[0].batch;
+ if (grpc_connectivity_state_check(&chand->state_tracker) ==
+ GRPC_CHANNEL_TRANSIENT_FAILURE &&
+ (batch->payload->send_initial_metadata.send_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
+ pending_batches_fail(
+ elem,
+ grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "channel is in state TRANSIENT_FAILURE"),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
+ true /* yield_call_combiner */);
+ return true;
+ }
+ return false;
+}
+
// Invoked once resolver results are available.
static void process_service_config_and_start_lb_pick_locked(
grpc_call_element* elem) {
@@ -2839,6 +3049,9 @@ static void process_service_config_and_start_lb_pick_locked(
// Only get service config data on the first attempt.
if (GPR_LIKELY(calld->num_attempts_completed == 0)) {
apply_service_config_to_call_locked(elem);
+ // Check this after applying service config, since it may have
+ // affected the call's wait_for_ready value.
+ if (fail_call_if_in_transient_failure(elem)) return;
}
// Start LB pick.
grpc_core::LbPicker::StartLocked(elem);
@@ -3008,6 +3221,16 @@ static void start_pick_locked(void* arg, grpc_error* ignored) {
// We do not yet have an LB policy, so wait for a resolver result.
if (GPR_UNLIKELY(!chand->started_resolving)) {
start_resolving_locked(chand);
+ } else {
+ // Normally, we want to do this check in
+ // process_service_config_and_start_lb_pick_locked(), so that we
+ // can honor the wait_for_ready setting in the service config.
+ // However, if the channel is in TRANSIENT_FAILURE at this point, that
+ // means that the resolver has returned a failure, so we're not going
+ // to get a service config right away. In that case, we fail the
+ // call now based on the wait_for_ready value passed in from the
+ // application.
+ if (fail_call_if_in_transient_failure(elem)) return;
}
// Create a new waiter, which will delete itself when done.
grpc_core::New<grpc_core::ResolverResultWaiter>(elem);
@@ -3112,21 +3335,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;
}
@@ -3135,34 +3345,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);
}
@@ -3203,9 +3391,16 @@ static void try_to_connect_locked(void* arg, grpc_error* error_ignored) {
GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "try_to_connect");
}
+void grpc_client_channel_set_channelz_node(
+ grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) {
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ chand->channelz_channel = node;
+}
+
void grpc_client_channel_populate_child_refs(
- grpc_channel_element* elem, grpc_core::ChildRefsList* child_subchannels,
- grpc_core::ChildRefsList* child_channels) {
+ grpc_channel_element* elem,
+ grpc_core::channelz::ChildRefsList* child_subchannels,
+ grpc_core::channelz::ChildRefsList* child_channels) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
if (chand->lb_policy != nullptr) {
chand->lb_policy->FillChildRefsForChannelz(child_subchannels,
diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
index 0b44a17562..4935fd24d8 100644
--- a/src/core/ext/filters/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -40,9 +40,13 @@ extern grpc_core::TraceFlag grpc_client_channel_trace;
extern const grpc_channel_filter grpc_client_channel_filter;
+void grpc_client_channel_set_channelz_node(
+ grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node);
+
void grpc_client_channel_populate_child_refs(
- grpc_channel_element* elem, grpc_core::ChildRefsList* child_subchannels,
- grpc_core::ChildRefsList* child_channels);
+ grpc_channel_element* elem,
+ grpc_core::channelz::ChildRefsList* child_subchannels,
+ grpc_core::channelz::ChildRefsList* child_channels);
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element* elem, int try_to_connect);
diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.cc b/src/core/ext/filters/client_channel/client_channel_channelz.cc
index 86c765df52..8e5426081c 100644
--- a/src/core/ext/filters/client_channel/client_channel_channelz.cc
+++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc
@@ -20,10 +20,13 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
+#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h"
+#include <grpc/support/string_util.h>
+
namespace grpc_core {
namespace channelz {
namespace {
@@ -46,6 +49,7 @@ ClientChannelNode::ClientChannelNode(grpc_channel* channel,
: ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) {
client_channel_ =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+ grpc_client_channel_set_channelz_node(client_channel_, this);
GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter);
}
@@ -109,5 +113,74 @@ RefCountedPtr<ChannelNode> ClientChannelNode::MakeClientChannelNode(
is_top_level_channel);
}
+SubchannelNode::SubchannelNode(grpc_subchannel* subchannel,
+ size_t channel_tracer_max_nodes)
+ : BaseNode(EntityType::kSubchannel),
+ subchannel_(subchannel),
+ target_(
+ UniquePtr<char>(gpr_strdup(grpc_subchannel_get_target(subchannel_)))),
+ trace_(channel_tracer_max_nodes) {}
+
+SubchannelNode::~SubchannelNode() {}
+
+void SubchannelNode::PopulateConnectivityState(grpc_json* json) {
+ grpc_connectivity_state state;
+ if (subchannel_ == nullptr) {
+ state = GRPC_CHANNEL_SHUTDOWN;
+ } else {
+ state = grpc_subchannel_check_connectivity(
+ subchannel_, nullptr, true /* inhibit_health_checking */);
+ }
+ json = grpc_json_create_child(nullptr, json, "state", nullptr,
+ GRPC_JSON_OBJECT, false);
+ grpc_json_create_child(nullptr, json, "state",
+ grpc_connectivity_state_name(state), GRPC_JSON_STRING,
+ false);
+}
+
+grpc_json* SubchannelNode::RenderJson() {
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator = grpc_json_add_number_string_child(json, json_iterator,
+ "subchannelId", uuid());
+ // reset json iterators to top level object
+ json = top_level_json;
+ json_iterator = nullptr;
+ // create and fill the data child.
+ grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = data;
+ json_iterator = nullptr;
+ PopulateConnectivityState(json);
+ GPR_ASSERT(target_.get() != nullptr);
+ grpc_json_create_child(nullptr, json, "target", target_.get(),
+ GRPC_JSON_STRING, false);
+ // fill in the channel trace if applicable
+ grpc_json* trace_json = trace_.RenderJson();
+ if (trace_json != nullptr) {
+ trace_json->key = "trace"; // this object is named trace in channelz.proto
+ grpc_json_link_child(json, trace_json, nullptr);
+ }
+ // ask CallCountingHelper to populate trace and call count data.
+ call_counter_.PopulateCallCounts(json);
+ json = top_level_json;
+ // populate the child socket.
+ intptr_t socket_uuid = grpc_subchannel_get_child_socket_uuid(subchannel_);
+ if (socket_uuid != 0) {
+ grpc_json* array_parent = grpc_json_create_child(
+ nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
+ json_iterator = grpc_json_create_child(json_iterator, array_parent, nullptr,
+ nullptr, GRPC_JSON_OBJECT, false);
+ grpc_json_add_number_string_child(json_iterator, nullptr, "socketId",
+ socket_uuid);
+ }
+ return top_level_json;
+}
+
} // namespace channelz
} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.h b/src/core/ext/filters/client_channel/client_channel_channelz.h
index 6f27b5c8b7..8a5c3e7e5e 100644
--- a/src/core/ext/filters/client_channel/client_channel_channelz.h
+++ b/src/core/ext/filters/client_channel/client_channel_channelz.h
@@ -23,16 +23,12 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
-#include "src/core/lib/gprpp/inlined_vector.h"
-namespace grpc_core {
-
-// TODO(ncteisen), this only contains the uuids of the children for now,
-// since that is all that is strictly needed. In a future enhancement we will
-// add human readable names as in the channelz.proto
-typedef InlinedVector<intptr_t, 10> ChildRefsList;
+typedef struct grpc_subchannel grpc_subchannel;
+namespace grpc_core {
namespace channelz {
// Subtype of ChannelNode that overrides and provides client_channel specific
@@ -43,28 +39,59 @@ class ClientChannelNode : public ChannelNode {
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel);
- // Override this functionality since client_channels have a notion of
- // channel connectivity.
- void PopulateConnectivityState(grpc_json* json) override;
+ ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
+ virtual ~ClientChannelNode() {}
- // Override this functionality since client_channels have subchannels
+ // Overriding template methods from ChannelNode to render information that
+ // only ClientChannelNode knows about.
+ void PopulateConnectivityState(grpc_json* json) override;
void PopulateChildRefs(grpc_json* json) override;
// Helper to create a channel arg to ensure this type of ChannelNode is
// created.
static grpc_arg CreateChannelArg();
- protected:
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
- ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
- bool is_top_level_channel);
- virtual ~ClientChannelNode() {}
-
private:
grpc_channel_element* client_channel_;
};
+// Handles channelz bookkeeping for sockets
+class SubchannelNode : public BaseNode {
+ public:
+ SubchannelNode(grpc_subchannel* subchannel, size_t channel_tracer_max_nodes);
+ ~SubchannelNode() override;
+
+ void MarkSubchannelDestroyed() {
+ GPR_ASSERT(subchannel_ != nullptr);
+ subchannel_ = nullptr;
+ }
+
+ grpc_json* RenderJson() override;
+
+ // proxy methods to composed classes.
+ void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {
+ trace_.AddTraceEvent(severity, data);
+ }
+ void AddTraceEventWithReference(ChannelTrace::Severity severity,
+ grpc_slice data,
+ RefCountedPtr<BaseNode> referenced_channel) {
+ trace_.AddTraceEventWithReference(severity, data,
+ std::move(referenced_channel));
+ }
+ void RecordCallStarted() { call_counter_.RecordCallStarted(); }
+ void RecordCallFailed() { call_counter_.RecordCallFailed(); }
+ void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
+
+ private:
+ grpc_subchannel* subchannel_;
+ UniquePtr<char> target_;
+ CallCountingHelper call_counter_;
+ ChannelTrace trace_;
+
+ void PopulateConnectivityState(grpc_json* json);
+};
+
} // namespace channelz
} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
index 556594929c..ea34dcdab5 100644
--- a/src/core/ext/filters/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -47,6 +47,9 @@ typedef struct {
/** channel arguments (to be passed to the filters) */
grpc_channel_args* channel_args;
+
+ /** socket uuid of the connected transport. 0 if not available */
+ intptr_t socket_uuid;
} grpc_connect_out_args;
struct grpc_connector_vtable {
diff --git a/src/cpp/server/health/health.pb.c b/src/core/ext/filters/client_channel/health/health.pb.c
index 09bd98a3d9..5499c549cc 100644
--- a/src/cpp/server/health/health.pb.c
+++ b/src/core/ext/filters/client_channel/health/health.pb.c
@@ -1,8 +1,7 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.7-dev */
-#include "src/cpp/server/health/health.pb.h"
-
+#include "src/core/ext/filters/client_channel/health/health.pb.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
diff --git a/src/cpp/server/health/health.pb.h b/src/core/ext/filters/client_channel/health/health.pb.h
index 29e1f3bacb..9d54ccd618 100644
--- a/src/cpp/server/health/health.pb.h
+++ b/src/core/ext/filters/client_channel/health/health.pb.h
@@ -17,11 +17,12 @@ extern "C" {
typedef enum _grpc_health_v1_HealthCheckResponse_ServingStatus {
grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN = 0,
grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING = 1,
- grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2
+ grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2,
+ grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN = 3
} grpc_health_v1_HealthCheckResponse_ServingStatus;
#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MIN grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN
-#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING
-#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING+1))
+#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN
+#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN+1))
/* Struct definitions */
typedef struct _grpc_health_v1_HealthCheckRequest {
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
new file mode 100644
index 0000000000..587919596f
--- /dev/null
+++ b/src/core/ext/filters/client_channel/health/health_check_client.cc
@@ -0,0 +1,652 @@
+/*
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+
+#include "src/core/ext/filters/client_channel/health/health_check_client.h"
+
+#include "pb_decode.h"
+#include "pb_encode.h"
+#include "src/core/ext/filters/client_channel/health/health.pb.h"
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/mutex_lock.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/transport/status_metadata.h"
+
+#define HEALTH_CHECK_INITIAL_CONNECT_BACKOFF_SECONDS 1
+#define HEALTH_CHECK_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define HEALTH_CHECK_RECONNECT_MAX_BACKOFF_SECONDS 120
+#define HEALTH_CHECK_RECONNECT_JITTER 0.2
+
+grpc_core::TraceFlag grpc_health_check_client_trace(false,
+ "health_check_client");
+
+namespace grpc_core {
+
+//
+// HealthCheckClient
+//
+
+HealthCheckClient::HealthCheckClient(
+ const char* service_name,
+ RefCountedPtr<ConnectedSubchannel> connected_subchannel,
+ grpc_pollset_set* interested_parties,
+ grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode> channelz_node)
+ : InternallyRefCountedWithTracing<HealthCheckClient>(
+ &grpc_health_check_client_trace),
+ service_name_(service_name),
+ connected_subchannel_(std::move(connected_subchannel)),
+ interested_parties_(interested_parties),
+ channelz_node_(std::move(channelz_node)),
+ retry_backoff_(
+ BackOff::Options()
+ .set_initial_backoff(
+ HEALTH_CHECK_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
+ .set_multiplier(HEALTH_CHECK_RECONNECT_BACKOFF_MULTIPLIER)
+ .set_jitter(HEALTH_CHECK_RECONNECT_JITTER)
+ .set_max_backoff(HEALTH_CHECK_RECONNECT_MAX_BACKOFF_SECONDS *
+ 1000)) {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "created HealthCheckClient %p", this);
+ }
+ GRPC_CLOSURE_INIT(&retry_timer_callback_, OnRetryTimer, this,
+ grpc_schedule_on_exec_ctx);
+ gpr_mu_init(&mu_);
+ StartCall();
+}
+
+HealthCheckClient::~HealthCheckClient() {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "destroying HealthCheckClient %p", this);
+ }
+ GRPC_ERROR_UNREF(error_);
+ gpr_mu_destroy(&mu_);
+}
+
+void HealthCheckClient::NotifyOnHealthChange(grpc_connectivity_state* state,
+ grpc_closure* closure) {
+ MutexLock lock(&mu_);
+ GPR_ASSERT(notify_state_ == nullptr);
+ if (*state != state_) {
+ *state = state_;
+ GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_REF(error_));
+ return;
+ }
+ notify_state_ = state;
+ on_health_changed_ = closure;
+}
+
+void HealthCheckClient::SetHealthStatus(grpc_connectivity_state state,
+ grpc_error* error) {
+ MutexLock lock(&mu_);
+ SetHealthStatusLocked(state, error);
+}
+
+void HealthCheckClient::SetHealthStatusLocked(grpc_connectivity_state state,
+ grpc_error* error) {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: setting state=%d error=%s", this,
+ state, grpc_error_string(error));
+ }
+ if (notify_state_ != nullptr && *notify_state_ != state) {
+ *notify_state_ = state;
+ notify_state_ = nullptr;
+ GRPC_CLOSURE_SCHED(on_health_changed_, GRPC_ERROR_REF(error));
+ on_health_changed_ = nullptr;
+ }
+ state_ = state;
+ GRPC_ERROR_UNREF(error_);
+ error_ = error;
+}
+
+void HealthCheckClient::Orphan() {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: shutting down", this);
+ }
+ {
+ MutexLock lock(&mu_);
+ if (on_health_changed_ != nullptr) {
+ *notify_state_ = GRPC_CHANNEL_SHUTDOWN;
+ notify_state_ = nullptr;
+ GRPC_CLOSURE_SCHED(on_health_changed_, GRPC_ERROR_NONE);
+ on_health_changed_ = nullptr;
+ }
+ shutting_down_ = true;
+ call_state_.reset();
+ if (retry_timer_callback_pending_) {
+ grpc_timer_cancel(&retry_timer_);
+ }
+ }
+ Unref(DEBUG_LOCATION, "orphan");
+}
+
+void HealthCheckClient::StartCall() {
+ MutexLock lock(&mu_);
+ StartCallLocked();
+}
+
+void HealthCheckClient::StartCallLocked() {
+ if (shutting_down_) return;
+ GPR_ASSERT(call_state_ == nullptr);
+ SetHealthStatusLocked(GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE);
+ call_state_ = MakeOrphanable<CallState>(Ref(), interested_parties_);
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: created CallState %p", this,
+ call_state_.get());
+ }
+ call_state_->StartCall();
+}
+
+void HealthCheckClient::StartRetryTimer() {
+ MutexLock lock(&mu_);
+ SetHealthStatusLocked(
+ GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "health check call failed; will retry after backoff"));
+ grpc_millis next_try = retry_backoff_.NextAttemptTime();
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: health check call lost...", this);
+ grpc_millis timeout = next_try - ExecCtx::Get()->Now();
+ if (timeout > 0) {
+ gpr_log(GPR_INFO,
+ "HealthCheckClient %p: ... will retry in %" PRId64 "ms.", this,
+ timeout);
+ } else {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: ... retrying immediately.",
+ this);
+ }
+ }
+ // Ref for callback, tracked manually.
+ Ref(DEBUG_LOCATION, "health_retry_timer").release();
+ retry_timer_callback_pending_ = true;
+ grpc_timer_init(&retry_timer_, next_try, &retry_timer_callback_);
+}
+
+void HealthCheckClient::OnRetryTimer(void* arg, grpc_error* error) {
+ HealthCheckClient* self = static_cast<HealthCheckClient*>(arg);
+ {
+ MutexLock lock(&self->mu_);
+ self->retry_timer_callback_pending_ = false;
+ if (!self->shutting_down_ && error == GRPC_ERROR_NONE &&
+ self->call_state_ == nullptr) {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: restarting health check call",
+ self);
+ }
+ self->StartCallLocked();
+ }
+ }
+ self->Unref(DEBUG_LOCATION, "health_retry_timer");
+}
+
+//
+// protobuf helpers
+//
+
+namespace {
+
+void EncodeRequest(const char* service_name,
+ ManualConstructor<SliceBufferByteStream>* send_message) {
+ grpc_health_v1_HealthCheckRequest request_struct;
+ request_struct.has_service = true;
+ snprintf(request_struct.service, sizeof(request_struct.service), "%s",
+ service_name);
+ pb_ostream_t ostream;
+ memset(&ostream, 0, sizeof(ostream));
+ pb_encode(&ostream, grpc_health_v1_HealthCheckRequest_fields,
+ &request_struct);
+ grpc_slice request_slice = GRPC_SLICE_MALLOC(ostream.bytes_written);
+ ostream = pb_ostream_from_buffer(GRPC_SLICE_START_PTR(request_slice),
+ GRPC_SLICE_LENGTH(request_slice));
+ GPR_ASSERT(pb_encode(&ostream, grpc_health_v1_HealthCheckRequest_fields,
+ &request_struct) != 0);
+ grpc_slice_buffer slice_buffer;
+ grpc_slice_buffer_init(&slice_buffer);
+ grpc_slice_buffer_add(&slice_buffer, request_slice);
+ send_message->Init(&slice_buffer, 0);
+ grpc_slice_buffer_destroy_internal(&slice_buffer);
+}
+
+// Returns true if healthy.
+// If there was an error parsing the response, sets *error and returns false.
+bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error** error) {
+ // If message is empty, assume unhealthy.
+ if (slice_buffer->length == 0) {
+ *error =
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("health check response was empty");
+ return false;
+ }
+ // Concatenate the slices to form a single string.
+ UniquePtr<uint8_t> recv_message_deleter;
+ uint8_t* recv_message;
+ if (slice_buffer->count == 1) {
+ recv_message = GRPC_SLICE_START_PTR(slice_buffer->slices[0]);
+ } else {
+ recv_message = static_cast<uint8_t*>(gpr_malloc(slice_buffer->length));
+ recv_message_deleter.reset(recv_message);
+ size_t offset = 0;
+ for (size_t i = 0; i < slice_buffer->count; ++i) {
+ memcpy(recv_message + offset,
+ GRPC_SLICE_START_PTR(slice_buffer->slices[i]),
+ GRPC_SLICE_LENGTH(slice_buffer->slices[i]));
+ offset += GRPC_SLICE_LENGTH(slice_buffer->slices[i]);
+ }
+ }
+ // Deserialize message.
+ grpc_health_v1_HealthCheckResponse response_struct;
+ pb_istream_t istream =
+ pb_istream_from_buffer(recv_message, slice_buffer->length);
+ if (!pb_decode(&istream, grpc_health_v1_HealthCheckResponse_fields,
+ &response_struct)) {
+ // Can't parse message; assume unhealthy.
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "cannot parse health check response");
+ return false;
+ }
+ if (!response_struct.has_status) {
+ // Field not present; assume unhealthy.
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "status field not present in health check response");
+ return false;
+ }
+ return response_struct.status ==
+ grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING;
+}
+
+} // namespace
+
+//
+// HealthCheckClient::CallState
+//
+
+HealthCheckClient::CallState::CallState(
+ RefCountedPtr<HealthCheckClient> health_check_client,
+ grpc_pollset_set* interested_parties)
+ : InternallyRefCountedWithTracing<CallState>(
+ &grpc_health_check_client_trace),
+ 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))),
+ payload_(context_) {
+ grpc_call_combiner_init(&call_combiner_);
+ gpr_atm_rel_store(&seen_response_, static_cast<gpr_atm>(0));
+}
+
+HealthCheckClient::CallState::~CallState() {
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO, "HealthCheckClient %p: destroying CallState %p",
+ health_check_client_.get(), this);
+ }
+ if (call_ != nullptr) GRPC_SUBCHANNEL_CALL_UNREF(call_, "call_ended");
+ for (size_t i = 0; i < GRPC_CONTEXT_COUNT; i++) {
+ if (context_[i].destroy != nullptr) {
+ context_[i].destroy(context_[i].value);
+ }
+ }
+ // Unset the call combiner cancellation closure. This has the
+ // effect of scheduling the previously set cancellation closure, if
+ // any, so that it can release any internal references it may be
+ // holding to the call stack. Also flush the closures on exec_ctx so that
+ // filters that schedule cancel notification closures on exec_ctx do not
+ // need to take a ref of the call stack to guarantee closure liveness.
+ grpc_call_combiner_set_notify_on_cancel(&call_combiner_, nullptr);
+ grpc_core::ExecCtx::Get()->Flush();
+ grpc_call_combiner_destroy(&call_combiner_);
+ gpr_arena_destroy(arena_);
+}
+
+void HealthCheckClient::CallState::Orphan() {
+ grpc_call_combiner_cancel(&call_combiner_, GRPC_ERROR_CANCELLED);
+ Cancel();
+}
+
+void HealthCheckClient::CallState::StartCall() {
+ ConnectedSubchannel::CallArgs args = {
+ &pollent_,
+ GRPC_MDSTR_SLASH_GRPC_DOT_HEALTH_DOT_V1_DOT_HEALTH_SLASH_WATCH,
+ gpr_now(GPR_CLOCK_MONOTONIC), // start_time
+ GRPC_MILLIS_INF_FUTURE, // deadline
+ arena_,
+ context_,
+ &call_combiner_,
+ 0, // parent_data_size
+ };
+ grpc_error* error =
+ health_check_client_->connected_subchannel_->CreateCall(args, &call_);
+ if (error != GRPC_ERROR_NONE) {
+ gpr_log(GPR_ERROR,
+ "HealthCheckClient %p CallState %p: error creating health "
+ "checking call on subchannel (%s); will retry",
+ health_check_client_.get(), this, grpc_error_string(error));
+ GRPC_ERROR_UNREF(error);
+ // Schedule instead of running directly, since we must not be
+ // holding health_check_client_->mu_ when CallEnded() is called.
+ Ref(DEBUG_LOCATION, "call_end_closure").release();
+ GRPC_CLOSURE_SCHED(
+ GRPC_CLOSURE_INIT(&batch_.handler_private.closure, CallEndedRetry, this,
+ grpc_schedule_on_exec_ctx),
+ GRPC_ERROR_NONE);
+ return;
+ }
+ // Initialize payload and batch.
+ memset(&batch_, 0, sizeof(batch_));
+ payload_.context = context_;
+ batch_.payload = &payload_;
+ // on_complete callback takes ref, handled manually.
+ Ref(DEBUG_LOCATION, "on_complete").release();
+ batch_.on_complete = GRPC_CLOSURE_INIT(&on_complete_, OnComplete, this,
+ grpc_schedule_on_exec_ctx);
+ // Add send_initial_metadata op.
+ grpc_metadata_batch_init(&send_initial_metadata_);
+ error = grpc_metadata_batch_add_head(
+ &send_initial_metadata_, &path_metadata_storage_,
+ grpc_mdelem_from_slices(
+ GRPC_MDSTR_PATH,
+ GRPC_MDSTR_SLASH_GRPC_DOT_HEALTH_DOT_V1_DOT_HEALTH_SLASH_WATCH));
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ payload_.send_initial_metadata.send_initial_metadata =
+ &send_initial_metadata_;
+ payload_.send_initial_metadata.send_initial_metadata_flags = 0;
+ payload_.send_initial_metadata.peer_string = nullptr;
+ batch_.send_initial_metadata = true;
+ // Add send_message op.
+ EncodeRequest(health_check_client_->service_name_, &send_message_);
+ payload_.send_message.send_message.reset(send_message_.get());
+ batch_.send_message = true;
+ // Add send_trailing_metadata op.
+ grpc_metadata_batch_init(&send_trailing_metadata_);
+ payload_.send_trailing_metadata.send_trailing_metadata =
+ &send_trailing_metadata_;
+ batch_.send_trailing_metadata = true;
+ // Add recv_initial_metadata op.
+ grpc_metadata_batch_init(&recv_initial_metadata_);
+ payload_.recv_initial_metadata.recv_initial_metadata =
+ &recv_initial_metadata_;
+ payload_.recv_initial_metadata.recv_flags = nullptr;
+ payload_.recv_initial_metadata.trailing_metadata_available = nullptr;
+ payload_.recv_initial_metadata.peer_string = nullptr;
+ // recv_initial_metadata_ready callback takes ref, handled manually.
+ Ref(DEBUG_LOCATION, "recv_initial_metadata_ready").release();
+ payload_.recv_initial_metadata.recv_initial_metadata_ready =
+ GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady,
+ this, grpc_schedule_on_exec_ctx);
+ batch_.recv_initial_metadata = true;
+ // Add recv_message op.
+ payload_.recv_message.recv_message = &recv_message_;
+ // recv_message callback takes ref, handled manually.
+ Ref(DEBUG_LOCATION, "recv_message_ready").release();
+ payload_.recv_message.recv_message_ready = GRPC_CLOSURE_INIT(
+ &recv_message_ready_, RecvMessageReady, this, grpc_schedule_on_exec_ctx);
+ batch_.recv_message = true;
+ // Start batch.
+ StartBatch(&batch_);
+ // Initialize recv_trailing_metadata batch.
+ memset(&recv_trailing_metadata_batch_, 0,
+ sizeof(recv_trailing_metadata_batch_));
+ recv_trailing_metadata_batch_.payload = &payload_;
+ // Add recv_trailing_metadata op.
+ grpc_metadata_batch_init(&recv_trailing_metadata_);
+ payload_.recv_trailing_metadata.recv_trailing_metadata =
+ &recv_trailing_metadata_;
+ payload_.recv_trailing_metadata.collect_stats = &collect_stats_;
+ // This callback signals the end of the call, so it relies on the
+ // initial ref instead of taking a new ref. When it's invoked, the
+ // initial ref is released.
+ payload_.recv_trailing_metadata.recv_trailing_metadata_ready =
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
+ RecvTrailingMetadataReady, this,
+ grpc_schedule_on_exec_ctx);
+ recv_trailing_metadata_batch_.recv_trailing_metadata = true;
+ // Start recv_trailing_metadata batch.
+ StartBatch(&recv_trailing_metadata_batch_);
+}
+
+void HealthCheckClient::CallState::StartBatchInCallCombiner(void* arg,
+ grpc_error* error) {
+ grpc_transport_stream_op_batch* batch =
+ static_cast<grpc_transport_stream_op_batch*>(arg);
+ grpc_subchannel_call* call =
+ static_cast<grpc_subchannel_call*>(batch->handler_private.extra_arg);
+ grpc_subchannel_call_process_op(call, batch);
+}
+
+void HealthCheckClient::CallState::StartBatch(
+ grpc_transport_stream_op_batch* batch) {
+ batch->handler_private.extra_arg = call_;
+ GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner,
+ batch, grpc_schedule_on_exec_ctx);
+ GRPC_CALL_COMBINER_START(&call_combiner_, &batch->handler_private.closure,
+ GRPC_ERROR_NONE, "start_subchannel_batch");
+}
+
+void HealthCheckClient::CallState::OnCancelComplete(void* arg,
+ grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "health_cancel");
+ self->Unref(DEBUG_LOCATION, "cancel");
+}
+
+void HealthCheckClient::CallState::StartCancel(void* arg, grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ auto* batch = grpc_make_transport_stream_op(
+ GRPC_CLOSURE_CREATE(OnCancelComplete, self, grpc_schedule_on_exec_ctx));
+ batch->cancel_stream = true;
+ batch->payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
+ grpc_subchannel_call_process_op(self->call_, batch);
+}
+
+void HealthCheckClient::CallState::Cancel() {
+ if (call_ != nullptr) {
+ Ref(DEBUG_LOCATION, "cancel").release();
+ GRPC_CALL_COMBINER_START(
+ &call_combiner_,
+ GRPC_CLOSURE_CREATE(StartCancel, this, grpc_schedule_on_exec_ctx),
+ GRPC_ERROR_NONE, "health_cancel");
+ }
+}
+
+void HealthCheckClient::CallState::OnComplete(void* arg, grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "on_complete");
+ grpc_metadata_batch_destroy(&self->send_initial_metadata_);
+ grpc_metadata_batch_destroy(&self->send_trailing_metadata_);
+ self->Unref(DEBUG_LOCATION, "on_complete");
+}
+
+void HealthCheckClient::CallState::RecvInitialMetadataReady(void* arg,
+ grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_initial_metadata_ready");
+ grpc_metadata_batch_destroy(&self->recv_initial_metadata_);
+ self->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready");
+}
+
+void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) {
+ recv_message_.reset();
+ if (error != GRPC_ERROR_NONE) {
+ GRPC_ERROR_UNREF(error);
+ Cancel();
+ grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
+ Unref(DEBUG_LOCATION, "recv_message_ready");
+ return;
+ }
+ const bool healthy = DecodeResponse(&recv_message_buffer_, &error);
+ const grpc_connectivity_state state =
+ healthy ? GRPC_CHANNEL_READY : GRPC_CHANNEL_TRANSIENT_FAILURE;
+ if (error == GRPC_ERROR_NONE && !healthy) {
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("backend unhealthy");
+ }
+ health_check_client_->SetHealthStatus(state, error);
+ gpr_atm_rel_store(&seen_response_, static_cast<gpr_atm>(1));
+ grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
+ // Start another recv_message batch.
+ // This re-uses the ref we're holding.
+ // Note: Can't just reuse batch_ here, since we don't know that all
+ // callbacks from the original batch have completed yet.
+ memset(&recv_message_batch_, 0, sizeof(recv_message_batch_));
+ recv_message_batch_.payload = &payload_;
+ payload_.recv_message.recv_message = &recv_message_;
+ payload_.recv_message.recv_message_ready = GRPC_CLOSURE_INIT(
+ &recv_message_ready_, RecvMessageReady, this, grpc_schedule_on_exec_ctx);
+ recv_message_batch_.recv_message = true;
+ StartBatch(&recv_message_batch_);
+}
+
+grpc_error* HealthCheckClient::CallState::PullSliceFromRecvMessage() {
+ grpc_slice slice;
+ grpc_error* error = recv_message_->Pull(&slice);
+ if (error == GRPC_ERROR_NONE) {
+ grpc_slice_buffer_add(&recv_message_buffer_, slice);
+ }
+ return error;
+}
+
+void HealthCheckClient::CallState::ContinueReadingRecvMessage() {
+ while (recv_message_->Next(SIZE_MAX, &recv_message_ready_)) {
+ grpc_error* error = PullSliceFromRecvMessage();
+ if (error != GRPC_ERROR_NONE) {
+ DoneReadingRecvMessage(error);
+ return;
+ }
+ if (recv_message_buffer_.length == recv_message_->length()) {
+ DoneReadingRecvMessage(GRPC_ERROR_NONE);
+ break;
+ }
+ }
+}
+
+void HealthCheckClient::CallState::OnByteStreamNext(void* arg,
+ grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ if (error != GRPC_ERROR_NONE) {
+ self->DoneReadingRecvMessage(GRPC_ERROR_REF(error));
+ return;
+ }
+ error = self->PullSliceFromRecvMessage();
+ if (error != GRPC_ERROR_NONE) {
+ self->DoneReadingRecvMessage(error);
+ return;
+ }
+ if (self->recv_message_buffer_.length == self->recv_message_->length()) {
+ self->DoneReadingRecvMessage(GRPC_ERROR_NONE);
+ } else {
+ self->ContinueReadingRecvMessage();
+ }
+}
+
+void HealthCheckClient::CallState::RecvMessageReady(void* arg,
+ grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_message_ready");
+ if (self->recv_message_ == nullptr) {
+ self->Unref(DEBUG_LOCATION, "recv_message_ready");
+ return;
+ }
+ grpc_slice_buffer_init(&self->recv_message_buffer_);
+ GRPC_CLOSURE_INIT(&self->recv_message_ready_, OnByteStreamNext, self,
+ grpc_schedule_on_exec_ctx);
+ self->ContinueReadingRecvMessage();
+ // Ref will continue to be held until we finish draining the byte stream.
+}
+
+void HealthCheckClient::CallState::RecvTrailingMetadataReady(
+ void* arg, grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ GRPC_CALL_COMBINER_STOP(&self->call_combiner_,
+ "recv_trailing_metadata_ready");
+ // Get call status.
+ grpc_status_code status = GRPC_STATUS_UNKNOWN;
+ if (error != GRPC_ERROR_NONE) {
+ grpc_error_get_status(error, GRPC_MILLIS_INF_FUTURE, &status,
+ nullptr /* slice */, nullptr /* http_error */,
+ nullptr /* error_string */);
+ } else if (self->recv_trailing_metadata_.idx.named.grpc_status != nullptr) {
+ status = grpc_get_status_code_from_metadata(
+ self->recv_trailing_metadata_.idx.named.grpc_status->md);
+ }
+ if (grpc_health_check_client_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "HealthCheckClient %p CallState %p: health watch failed with "
+ "status %d",
+ self->health_check_client_.get(), self, status);
+ }
+ // Clean up.
+ grpc_metadata_batch_destroy(&self->recv_trailing_metadata_);
+ // For status UNIMPLEMENTED, give up and assume always healthy.
+ bool retry = true;
+ if (status == GRPC_STATUS_UNIMPLEMENTED) {
+ static const char kErrorMessage[] =
+ "health checking Watch method returned UNIMPLEMENTED; "
+ "disabling health checks but assuming server is healthy";
+ gpr_log(GPR_ERROR, kErrorMessage);
+ if (self->health_check_client_->channelz_node_ != nullptr) {
+ self->health_check_client_->channelz_node_->AddTraceEvent(
+ channelz::ChannelTrace::Error,
+ grpc_slice_from_static_string(kErrorMessage));
+ }
+ self->health_check_client_->SetHealthStatus(GRPC_CHANNEL_READY,
+ GRPC_ERROR_NONE);
+ retry = false;
+ }
+ self->CallEnded(retry);
+}
+
+void HealthCheckClient::CallState::CallEndedRetry(void* arg,
+ grpc_error* error) {
+ HealthCheckClient::CallState* self =
+ static_cast<HealthCheckClient::CallState*>(arg);
+ self->CallEnded(true /* retry */);
+ self->Unref(DEBUG_LOCATION, "call_end_closure");
+}
+
+void HealthCheckClient::CallState::CallEnded(bool retry) {
+ // If this CallState is still in use, this call ended because of a failure,
+ // so we need to stop using it and optionally create a new one.
+ // Otherwise, we have deliberately ended this call, and no further action
+ // is required.
+ if (this == health_check_client_->call_state_.get()) {
+ health_check_client_->call_state_.reset();
+ if (retry) {
+ GPR_ASSERT(!health_check_client_->shutting_down_);
+ if (static_cast<bool>(gpr_atm_acq_load(&seen_response_))) {
+ // If the call fails after we've gotten a successful response, reset
+ // the backoff and restart the call immediately.
+ health_check_client_->retry_backoff_.Reset();
+ health_check_client_->StartCall();
+ } else {
+ // If the call failed without receiving any messages, retry later.
+ health_check_client_->StartRetryTimer();
+ }
+ }
+ }
+ Unref(DEBUG_LOCATION, "call_ended");
+}
+
+} // namespace grpc_core
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
new file mode 100644
index 0000000000..f6babef7d6
--- /dev/null
+++ b/src/core/ext/filters/client_channel/health/health_check_client.h
@@ -0,0 +1,173 @@
+/*
+ *
+ * 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_EXT_FILTERS_CLIENT_CHANNEL_HEALTH_HEALTH_CHECK_CLIENT_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HEALTH_HEALTH_CHECK_CLIENT_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/backoff/backoff.h"
+#include "src/core/lib/gpr/arena.h"
+#include "src/core/lib/gprpp/orphanable.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/call_combiner.h"
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/transport.h"
+
+namespace grpc_core {
+
+class HealthCheckClient
+ : public InternallyRefCountedWithTracing<HealthCheckClient> {
+ public:
+ HealthCheckClient(const char* service_name,
+ RefCountedPtr<ConnectedSubchannel> connected_subchannel,
+ grpc_pollset_set* interested_parties,
+ RefCountedPtr<channelz::SubchannelNode> channelz_node);
+
+ ~HealthCheckClient();
+
+ // When the health state changes from *state, sets *state to the new
+ // value and schedules closure.
+ // Only one closure can be outstanding at a time.
+ void NotifyOnHealthChange(grpc_connectivity_state* state,
+ grpc_closure* closure);
+
+ void Orphan() override;
+
+ private:
+ // Contains a call to the backend and all the data related to the call.
+ class CallState : public InternallyRefCountedWithTracing<CallState> {
+ public:
+ CallState(RefCountedPtr<HealthCheckClient> health_check_client,
+ grpc_pollset_set* interested_parties_);
+ ~CallState();
+
+ void Orphan() override;
+
+ void StartCall();
+
+ private:
+ void Cancel();
+
+ void StartBatch(grpc_transport_stream_op_batch* batch);
+ static void StartBatchInCallCombiner(void* arg, grpc_error* error);
+
+ static void CallEndedRetry(void* arg, grpc_error* error);
+ void CallEnded(bool retry);
+
+ static void OnComplete(void* arg, grpc_error* error);
+ static void RecvInitialMetadataReady(void* arg, grpc_error* error);
+ static void RecvMessageReady(void* arg, grpc_error* error);
+ static void RecvTrailingMetadataReady(void* arg, grpc_error* error);
+ static void StartCancel(void* arg, grpc_error* error);
+ static void OnCancelComplete(void* arg, grpc_error* error);
+
+ static void OnByteStreamNext(void* arg, grpc_error* error);
+ void ContinueReadingRecvMessage();
+ grpc_error* PullSliceFromRecvMessage();
+ void DoneReadingRecvMessage(grpc_error* error);
+
+ RefCountedPtr<HealthCheckClient> health_check_client_;
+ grpc_polling_entity pollent_;
+
+ gpr_arena* arena_;
+ grpc_call_combiner call_combiner_;
+ grpc_call_context_element context_[GRPC_CONTEXT_COUNT] = {};
+
+ // The streaming call to the backend. Always non-NULL.
+ grpc_subchannel_call* call_;
+
+ grpc_transport_stream_op_batch_payload payload_;
+ grpc_transport_stream_op_batch batch_;
+ grpc_transport_stream_op_batch recv_message_batch_;
+ grpc_transport_stream_op_batch recv_trailing_metadata_batch_;
+
+ grpc_closure on_complete_;
+
+ // send_initial_metadata
+ grpc_metadata_batch send_initial_metadata_;
+ grpc_linked_mdelem path_metadata_storage_;
+
+ // send_message
+ ManualConstructor<SliceBufferByteStream> send_message_;
+
+ // send_trailing_metadata
+ grpc_metadata_batch send_trailing_metadata_;
+
+ // recv_initial_metadata
+ grpc_metadata_batch recv_initial_metadata_;
+ grpc_closure recv_initial_metadata_ready_;
+
+ // recv_message
+ OrphanablePtr<ByteStream> recv_message_;
+ grpc_closure recv_message_ready_;
+ grpc_slice_buffer recv_message_buffer_;
+ gpr_atm seen_response_;
+
+ // recv_trailing_metadata
+ grpc_metadata_batch recv_trailing_metadata_;
+ grpc_transport_stream_stats collect_stats_;
+ grpc_closure recv_trailing_metadata_ready_;
+ };
+
+ void StartCall();
+ void StartCallLocked(); // Requires holding mu_.
+
+ void StartRetryTimer();
+ static void OnRetryTimer(void* arg, grpc_error* error);
+
+ void SetHealthStatus(grpc_connectivity_state state, grpc_error* error);
+ void SetHealthStatusLocked(grpc_connectivity_state state,
+ grpc_error* error); // Requires holding mu_.
+
+ const char* service_name_; // Do not own.
+ RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
+ grpc_pollset_set* interested_parties_; // Do not own.
+ RefCountedPtr<channelz::SubchannelNode> channelz_node_;
+
+ gpr_mu mu_;
+ grpc_connectivity_state state_ = GRPC_CHANNEL_CONNECTING;
+ grpc_error* error_ = GRPC_ERROR_NONE;
+ grpc_connectivity_state* notify_state_ = nullptr;
+ grpc_closure* on_health_changed_ = nullptr;
+ bool shutting_down_ = false;
+
+ // The data associated with the current health check call. It holds a ref
+ // to this HealthCheckClient object.
+ OrphanablePtr<CallState> call_state_;
+
+ // Call retry state.
+ BackOff retry_backoff_;
+ grpc_timer retry_timer_;
+ grpc_closure retry_timer_callback_;
+ bool retry_timer_callback_pending_ = false;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HEALTH_HEALTH_CHECK_CLIENT_H */
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 7ce8da8c00..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.
@@ -351,6 +351,7 @@ static grpc_handshaker* grpc_http_connect_handshaker_create() {
static void handshaker_factory_add_handshakers(
grpc_handshaker_factory* factory, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_handshake_manager_add(handshake_mgr,
grpc_http_connect_handshaker_create());
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 3c0a9c1118..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.
@@ -151,9 +151,9 @@ class LoadBalancingPolicy
/// LB policy's referenced children. This is not invoked from the
/// client_channel's combiner. The implementation is responsible for
/// providing its own synchronization.
- virtual void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
- ChildRefsList* child_channels)
- GRPC_ABSTRACT;
+ virtual void FillChildRefsForChannelz(
+ channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* child_channels) GRPC_ABSTRACT;
void Orphan() override {
// Invoke ShutdownAndUnrefLocked() inside of the combiner.
@@ -212,8 +212,8 @@ class LoadBalancingPolicy
// Dummy classes needed for alignment issues.
// See https://github.com/grpc/grpc/issues/16032 for context.
// TODO(ncteisen): remove this as soon as the issue is resolved.
- ChildRefsList dummy_list_foo;
- ChildRefsList dummy_list_bar;
+ channelz::ChildRefsList dummy_list_foo;
+ channelz::ChildRefsList dummy_list_bar;
};
} // namespace grpc_core
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/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 25b0149393..dbb90b438c 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -136,8 +136,9 @@ class GrpcLb : public LoadBalancingPolicy {
void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
void ExitIdleLocked() override;
void ResetBackoffLocked() override;
- void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
- ChildRefsList* child_channels) override;
+ void FillChildRefsForChannelz(
+ channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* child_channels) override;
private:
/// Linked list of pending pick requests. It stores all information needed to
@@ -852,10 +853,12 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
}
} else {
// No valid initial response or serverlist found.
+ char* response_slice_str =
+ grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX);
gpr_log(GPR_ERROR,
"[grpclb %p] Invalid LB response received: '%s'. Ignoring.",
- grpclb_policy,
- grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
+ grpclb_policy, response_slice_str);
+ gpr_free(response_slice_str);
}
grpc_slice_unref_internal(response_slice);
if (!grpclb_policy->shutting_down_) {
@@ -1256,8 +1259,9 @@ bool GrpcLb::PickLocked(PickState* pick, grpc_error** error) {
return pick_done;
}
-void GrpcLb::FillChildRefsForChannelz(ChildRefsList* child_subchannels,
- ChildRefsList* child_channels) {
+void GrpcLb::FillChildRefsForChannelz(
+ channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* child_channels) {
// delegate to the RoundRobin to fill the children subchannels.
rr_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
MutexLock lock(&lb_channel_mu_);
@@ -1265,7 +1269,7 @@ void GrpcLb::FillChildRefsForChannelz(ChildRefsList* child_subchannels,
grpc_core::channelz::ChannelNode* channel_node =
grpc_channel_get_channelz_node(lb_channel_);
if (channel_node != nullptr) {
- child_channels->push_back(channel_node->channel_uuid());
+ child_channels->push_back(channel_node->uuid());
}
}
}
@@ -1329,11 +1333,8 @@ void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
void GrpcLb::UpdateLocked(const grpc_channel_args& args) {
ProcessChannelArgsLocked(args);
- // If fallback is configured and the RR policy already exists, update
- // it with the new fallback addresses.
- if (lb_fallback_timeout_ms_ > 0 && rr_policy_ != nullptr) {
- CreateOrUpdateRoundRobinPolicyLocked();
- }
+ // Update the existing RR policy.
+ if (rr_policy_ != nullptr) CreateOrUpdateRoundRobinPolicyLocked();
// Start watching the LB channel connectivity for connection, if not
// already doing so.
if (!watching_lb_channel_) {
@@ -1487,7 +1488,7 @@ void GrpcLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
grpclb_policy->lb_call_backoff_.Reset();
grpclb_policy->StartBalancerCallLocked();
}
- // Fall through.
+ // fallthrough
case GRPC_CHANNEL_SHUTDOWN:
done:
grpclb_policy->watching_lb_channel_ = false;
@@ -1695,7 +1696,7 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() {
// Replace the LB addresses in the channel args that we pass down to
// the subchannel.
static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES};
- const grpc_arg args_to_add[] = {
+ grpc_arg args_to_add[3] = {
grpc_lb_addresses_create_channel_arg(addresses),
// A channel arg indicating if the target is a backend inferred from a
// grpclb load balancer.
@@ -1704,9 +1705,15 @@ grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() {
GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER),
is_backend_from_grpclb_load_balancer),
};
+ size_t num_args_to_add = 2;
+ if (is_backend_from_grpclb_load_balancer) {
+ args_to_add[2] = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
+ ++num_args_to_add;
+ }
grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove(
args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add,
- GPR_ARRAY_SIZE(args_to_add));
+ num_args_to_add);
grpc_lb_addresses_destroy(addresses);
return args;
}
diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
index 9120abfa3c..eb494486b9 100644
--- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -59,8 +59,8 @@ class PickFirst : public LoadBalancingPolicy {
void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
void ExitIdleLocked() override;
void ResetBackoffLocked() override;
- void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
- ChildRefsList* ignored) override;
+ void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* ignored) override;
private:
~PickFirst();
@@ -71,11 +71,12 @@ class PickFirst : public LoadBalancingPolicy {
: public SubchannelData<PickFirstSubchannelList,
PickFirstSubchannelData> {
public:
- PickFirstSubchannelData(PickFirstSubchannelList* subchannel_list,
- const grpc_lb_user_data_vtable* user_data_vtable,
- const grpc_lb_address& address,
- grpc_subchannel* subchannel,
- grpc_combiner* combiner)
+ PickFirstSubchannelData(
+ SubchannelList<PickFirstSubchannelList, PickFirstSubchannelData>*
+ subchannel_list,
+ const grpc_lb_user_data_vtable* user_data_vtable,
+ const grpc_lb_address& address, grpc_subchannel* subchannel,
+ grpc_combiner* combiner)
: SubchannelData(subchannel_list, user_data_vtable, address, subchannel,
combiner) {}
@@ -126,7 +127,6 @@ class PickFirst : public LoadBalancingPolicy {
void ShutdownLocked() override;
void StartPickingLocked();
- void DestroyUnselectedSubchannelsLocked();
void UpdateChildRefsLocked();
// All our subchannels.
@@ -147,8 +147,8 @@ class PickFirst : public LoadBalancingPolicy {
/// Lock and data used to capture snapshots of this channels child
/// channels and subchannels. This data is consumed by channelz.
gpr_mu child_refs_mu_;
- ChildRefsList child_subchannels_;
- ChildRefsList child_channels_;
+ channelz::ChildRefsList child_subchannels_;
+ channelz::ChildRefsList child_channels_;
};
PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) {
@@ -250,14 +250,9 @@ void PickFirst::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
void PickFirst::StartPickingLocked() {
started_picking_ = true;
- if (subchannel_list_ != nullptr) {
- for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
- if (subchannel_list_->subchannel(i)->subchannel() != nullptr) {
- subchannel_list_->subchannel(i)
- ->CheckConnectivityStateAndStartWatchingLocked();
- break;
- }
- }
+ if (subchannel_list_ != nullptr && subchannel_list_->num_subchannels() > 0) {
+ subchannel_list_->subchannel(0)
+ ->CheckConnectivityStateAndStartWatchingLocked();
}
}
@@ -294,15 +289,6 @@ bool PickFirst::PickLocked(PickState* pick, grpc_error** error) {
return false;
}
-void PickFirst::DestroyUnselectedSubchannelsLocked() {
- for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
- PickFirstSubchannelData* sd = subchannel_list_->subchannel(i);
- if (selected_ != sd) {
- sd->UnrefSubchannelLocked("selected_different_subchannel");
- }
- }
-}
-
grpc_connectivity_state PickFirst::CheckConnectivityLocked(grpc_error** error) {
return grpc_connectivity_state_get(&state_tracker_, error);
}
@@ -314,7 +300,8 @@ void PickFirst::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
}
void PickFirst::FillChildRefsForChannelz(
- ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) {
+ channelz::ChildRefsList* child_subchannels_to_fill,
+ channelz::ChildRefsList* ignored) {
MutexLock lock(&child_refs_mu_);
for (size_t i = 0; i < child_subchannels_.size(); ++i) {
// TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
@@ -334,7 +321,7 @@ void PickFirst::FillChildRefsForChannelz(
}
void PickFirst::UpdateChildRefsLocked() {
- ChildRefsList cs;
+ channelz::ChildRefsList cs;
if (subchannel_list_ != nullptr) {
subchannel_list_->PopulateChildRefsList(&cs);
}
@@ -372,9 +359,14 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
"Pick First %p received update with %" PRIuPTR " addresses", this,
addresses->num_addresses);
}
+ grpc_arg new_arg = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
+ grpc_channel_args* new_args =
+ grpc_channel_args_copy_and_add(&args, &new_arg, 1);
auto subchannel_list = MakeOrphanable<PickFirstSubchannelList>(
this, &grpc_lb_pick_first_trace, addresses, combiner(),
- client_channel_factory(), args);
+ client_channel_factory(), *new_args);
+ grpc_channel_args_destroy(new_args);
if (subchannel_list->num_subchannels() == 0) {
// Empty update or no valid subchannels. Unsubscribe from all current
// subchannels and put the channel in TRANSIENT_FAILURE.
@@ -419,7 +411,6 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
if (sd->CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) {
selected_ = sd;
subchannel_list_ = std::move(subchannel_list);
- DestroyUnselectedSubchannelsLocked();
sd->StartConnectivityWatchLocked();
// If there was a previously pending update (which may or may
// not have contained the currently selected subchannel), drop
@@ -504,7 +495,6 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
p->TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_NONE);
// In transient failure. Rely on re-resolution to recover.
p->selected_ = nullptr;
- UnrefSubchannelLocked("pf_selected_shutdown");
StopConnectivityWatchLocked();
} else {
grpc_connectivity_state_set(&p->state_tracker_, connectivity_state,
@@ -535,11 +525,9 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
case GRPC_CHANNEL_TRANSIENT_FAILURE: {
StopConnectivityWatchLocked();
PickFirstSubchannelData* sd = this;
- do {
- size_t next_index =
- (sd->Index() + 1) % subchannel_list()->num_subchannels();
- sd = subchannel_list()->subchannel(next_index);
- } while (sd->subchannel() == nullptr);
+ size_t next_index =
+ (sd->Index() + 1) % subchannel_list()->num_subchannels();
+ sd = subchannel_list()->subchannel(next_index);
// Case 1: Only set state to TRANSIENT_FAILURE if we've tried
// all subchannels.
if (sd->Index() == 0 && subchannel_list() == p->subchannel_list_.get()) {
@@ -600,8 +588,6 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
if (grpc_lb_pick_first_trace.enabled()) {
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel());
}
- // Drop all other subchannels, since we are now connected.
- p->DestroyUnselectedSubchannelsLocked();
// Update any calls that were waiting for a pick.
PickState* pick;
while ((pick = p->pending_picks_)) {
diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
index 4195c1e9d1..e9ed85cf66 100644
--- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
@@ -70,8 +70,8 @@ class RoundRobin : public LoadBalancingPolicy {
void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
void ExitIdleLocked() override;
void ResetBackoffLocked() override;
- void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
- ChildRefsList* ignored) override;
+ void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* ignored) override;
private:
~RoundRobin();
@@ -89,11 +89,12 @@ class RoundRobin : public LoadBalancingPolicy {
: public SubchannelData<RoundRobinSubchannelList,
RoundRobinSubchannelData> {
public:
- RoundRobinSubchannelData(RoundRobinSubchannelList* subchannel_list,
- const grpc_lb_user_data_vtable* user_data_vtable,
- const grpc_lb_address& address,
- grpc_subchannel* subchannel,
- grpc_combiner* combiner)
+ RoundRobinSubchannelData(
+ SubchannelList<RoundRobinSubchannelList, RoundRobinSubchannelData>*
+ subchannel_list,
+ const grpc_lb_user_data_vtable* user_data_vtable,
+ const grpc_lb_address& address, grpc_subchannel* subchannel,
+ grpc_combiner* combiner)
: SubchannelData(subchannel_list, user_data_vtable, address, subchannel,
combiner),
user_data_vtable_(user_data_vtable),
@@ -222,8 +223,8 @@ class RoundRobin : public LoadBalancingPolicy {
/// Lock and data used to capture snapshots of this channel's child
/// channels and subchannels. This data is consumed by channelz.
gpr_mu child_refs_mu_;
- ChildRefsList child_subchannels_;
- ChildRefsList child_channels_;
+ channelz::ChildRefsList child_subchannels_;
+ channelz::ChildRefsList child_channels_;
};
RoundRobin::RoundRobin(const Args& args) : LoadBalancingPolicy(args) {
@@ -401,7 +402,8 @@ bool RoundRobin::PickLocked(PickState* pick, grpc_error** error) {
}
void RoundRobin::FillChildRefsForChannelz(
- ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) {
+ channelz::ChildRefsList* child_subchannels_to_fill,
+ channelz::ChildRefsList* ignored) {
MutexLock lock(&child_refs_mu_);
for (size_t i = 0; i < child_subchannels_.size(); ++i) {
// TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
@@ -421,7 +423,7 @@ void RoundRobin::FillChildRefsForChannelz(
}
void RoundRobin::UpdateChildRefsLocked() {
- ChildRefsList cs;
+ channelz::ChildRefsList cs;
if (subchannel_list_ != nullptr) {
subchannel_list_->PopulateChildRefsList(&cs);
}
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
index 0fa2f04e73..4ec9e935ed 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -65,6 +65,10 @@ class MySubchannelList
namespace grpc_core {
+// Forward declaration.
+template <typename SubchannelListType, typename SubchannelDataType>
+class SubchannelList;
+
// Stores data for a particular subchannel in a subchannel list.
// Callers must create a subclass that implements the
// ProcessConnectivityChangeLocked() method.
@@ -72,7 +76,9 @@ template <typename SubchannelListType, typename SubchannelDataType>
class SubchannelData {
public:
// Returns a pointer to the subchannel list containing this object.
- SubchannelListType* subchannel_list() const { return subchannel_list_; }
+ SubchannelListType* subchannel_list() const {
+ return static_cast<SubchannelListType*>(subchannel_list_);
+ }
// Returns the index into the subchannel list of this object.
size_t Index() const {
@@ -96,17 +102,12 @@ class SubchannelData {
// ProcessConnectivityChangeLocked()).
grpc_connectivity_state CheckConnectivityStateLocked(grpc_error** error) {
GPR_ASSERT(!connectivity_notification_pending_);
- pending_connectivity_state_unsafe_ =
- grpc_subchannel_check_connectivity(subchannel(), error);
+ pending_connectivity_state_unsafe_ = grpc_subchannel_check_connectivity(
+ subchannel(), error, subchannel_list_->inhibit_health_checking());
UpdateConnectedSubchannelLocked();
return pending_connectivity_state_unsafe_;
}
- // Unrefs the subchannel. May be used if an individual subchannel is
- // no longer needed even though the subchannel list as a whole is not
- // being unreffed.
- virtual void UnrefSubchannelLocked(const char* reason);
-
// Resets the connection backoff.
// TODO(roth): This method should go away when we move the backoff
// code out of the subchannel and into the LB policies.
@@ -138,10 +139,11 @@ class SubchannelData {
GRPC_ABSTRACT_BASE_CLASS
protected:
- SubchannelData(SubchannelListType* subchannel_list,
- const grpc_lb_user_data_vtable* user_data_vtable,
- const grpc_lb_address& address, grpc_subchannel* subchannel,
- grpc_combiner* combiner);
+ SubchannelData(
+ SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
+ const grpc_lb_user_data_vtable* user_data_vtable,
+ const grpc_lb_address& address, grpc_subchannel* subchannel,
+ grpc_combiner* combiner);
virtual ~SubchannelData();
@@ -154,6 +156,10 @@ class SubchannelData {
grpc_connectivity_state connectivity_state,
grpc_error* error) GRPC_ABSTRACT;
+ // Unrefs the subchannel. May be overridden by subclasses that need
+ // to perform extra cleanup when unreffing the subchannel.
+ virtual void UnrefSubchannelLocked(const char* reason);
+
private:
// Updates connected_subchannel_ based on pending_connectivity_state_unsafe_.
// Returns true if the connectivity state should be reported.
@@ -162,7 +168,7 @@ class SubchannelData {
static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
// Backpointer to owning subchannel list. Not owned.
- SubchannelListType* subchannel_list_;
+ SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list_;
// The subchannel and connected subchannel.
grpc_subchannel* subchannel_;
@@ -195,13 +201,13 @@ class SubchannelList
bool shutting_down() const { return shutting_down_; }
// Populates refs_list with the uuids of this SubchannelLists's subchannels.
- void PopulateChildRefsList(ChildRefsList* refs_list) {
+ void PopulateChildRefsList(channelz::ChildRefsList* refs_list) {
for (size_t i = 0; i < subchannels_.size(); ++i) {
if (subchannels_[i].subchannel() != nullptr) {
grpc_core::channelz::SubchannelNode* subchannel_node =
grpc_subchannel_get_channelz_node(subchannels_[i].subchannel());
if (subchannel_node != nullptr) {
- refs_list->push_back(subchannel_node->subchannel_uuid());
+ refs_list->push_back(subchannel_node->uuid());
}
}
}
@@ -210,6 +216,7 @@ class SubchannelList
// Accessors.
LoadBalancingPolicy* policy() const { return policy_; }
TraceFlag* tracer() const { return tracer_; }
+ bool inhibit_health_checking() const { return inhibit_health_checking_; }
// Resets connection backoff of all subchannels.
// TODO(roth): We will probably need to rethink this as part of moving
@@ -248,6 +255,8 @@ class SubchannelList
TraceFlag* tracer_;
+ bool inhibit_health_checking_;
+
grpc_combiner* combiner_;
// The list of subchannels.
@@ -269,7 +278,7 @@ class SubchannelList
template <typename SubchannelListType, typename SubchannelDataType>
SubchannelData<SubchannelListType, SubchannelDataType>::SubchannelData(
- SubchannelListType* subchannel_list,
+ SubchannelList<SubchannelListType, SubchannelDataType>* subchannel_list,
const grpc_lb_user_data_vtable* user_data_vtable,
const grpc_lb_address& address, grpc_subchannel* subchannel,
grpc_combiner* combiner)
@@ -334,7 +343,8 @@ void SubchannelData<SubchannelListType,
subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release();
grpc_subchannel_notify_on_state_change(
subchannel_, subchannel_list_->policy()->interested_parties(),
- &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
+ &pending_connectivity_state_unsafe_, &connectivity_changed_closure_,
+ subchannel_list_->inhibit_health_checking());
}
template <typename SubchannelListType, typename SubchannelDataType>
@@ -353,7 +363,8 @@ void SubchannelData<SubchannelListType,
GPR_ASSERT(connectivity_notification_pending_);
grpc_subchannel_notify_on_state_change(
subchannel_, subchannel_list_->policy()->interested_parties(),
- &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
+ &pending_connectivity_state_unsafe_, &connectivity_changed_closure_,
+ subchannel_list_->inhibit_health_checking());
}
template <typename SubchannelListType, typename SubchannelDataType>
@@ -384,8 +395,9 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
subchannel_, reason);
}
GPR_ASSERT(connectivity_notification_pending_);
- grpc_subchannel_notify_on_state_change(subchannel_, nullptr, nullptr,
- &connectivity_changed_closure_);
+ grpc_subchannel_notify_on_state_change(
+ subchannel_, nullptr, nullptr, &connectivity_changed_closure_,
+ subchannel_list_->inhibit_health_checking());
}
template <typename SubchannelListType, typename SubchannelDataType>
@@ -493,8 +505,13 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
subchannels_.reserve(addresses->num_addresses);
// We need to remove the LB addresses in order to be able to compare the
// subchannel keys of subchannels from a different batch of addresses.
+ // We also remove the inhibit-health-checking arg, since we are
+ // handling that here.
+ inhibit_health_checking_ = grpc_channel_arg_get_bool(
+ grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
- GRPC_ARG_LB_ADDRESSES};
+ GRPC_ARG_LB_ADDRESSES,
+ GRPC_ARG_INHIBIT_HEALTH_CHECKING};
// Create a subchannel for each address.
grpc_subchannel_args sc_args;
for (size_t i = 0; i < addresses->num_addresses; i++) {
@@ -533,8 +550,7 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
address_uri);
gpr_free(address_uri);
}
- subchannels_.emplace_back(static_cast<SubchannelListType*>(this),
- addresses->user_data_vtable,
+ subchannels_.emplace_back(this, addresses->user_data_vtable,
addresses->addresses[i], subchannel, combiner);
}
}
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
new file mode 100644
index 0000000000..59d57295d4
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
@@ -0,0 +1,1828 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/// Implementation of the gRPC LB policy.
+///
+/// This policy takes as input a list of resolved addresses, which must
+/// include at least one balancer address.
+///
+/// An internal channel (\a lb_channel_) is created for the addresses
+/// from that are balancers. This channel behaves just like a regular
+/// channel that uses pick_first to select from the list of balancer
+/// addresses.
+///
+/// The first time the xDS policy gets a request for a pick or to exit the idle
+/// state, \a StartPickingLocked() is called. This method is responsible for
+/// instantiating the internal *streaming* call to the LB server (whichever
+/// address pick_first chose). The call will be complete when either the
+/// balancer sends status or when we cancel the call (e.g., because we are
+/// shutting down). In needed, we retry the call. If we received at least one
+/// valid message from the server, a new call attempt will be made immediately;
+/// otherwise, we apply back-off delays between attempts.
+///
+/// We maintain an internal child policy (round_robin) instance for distributing
+/// requests across backends. Whenever we receive a new serverlist from
+/// the balancer, we update the child policy with the new list of
+/// addresses.
+///
+/// Once a child policy instance is in place (and getting updated as
+/// described), calls for a pick, or a cancellation will be serviced right away
+/// by forwarding them to the child policy instance. Any time there's no child
+/// policy available (i.e., right after the creation of the xDS policy), pick
+/// requests are added to a list of pending picks to be flushed and serviced
+/// when the child policy instance becomes available.
+///
+/// \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
+/// high level design and details.
+
+// With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+// using that endpoint. Because of various transitive includes in uv.h,
+// including windows.h on Windows, uv.h must be included before other system
+// headers. Therefore, sockaddr.h must always be included first.
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
+
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
+#include "src/core/ext/filters/client_channel/subchannel_index.h"
+#include "src/core/lib/backoff/backoff.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/mutex_lock.h"
+#include "src/core/lib/gprpp/orphanable.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#define GRPC_XDS_INITIAL_CONNECT_BACKOFF_SECONDS 1
+#define GRPC_XDS_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define GRPC_XDS_RECONNECT_MAX_BACKOFF_SECONDS 120
+#define GRPC_XDS_RECONNECT_JITTER 0.2
+#define GRPC_XDS_DEFAULT_FALLBACK_TIMEOUT_MS 10000
+
+namespace grpc_core {
+
+TraceFlag grpc_lb_xds_trace(false, "xds");
+
+namespace {
+
+class XdsLb : public LoadBalancingPolicy {
+ public:
+ XdsLb(const grpc_lb_addresses* addresses, const Args& args);
+
+ void UpdateLocked(const grpc_channel_args& args) override;
+ bool PickLocked(PickState* pick, grpc_error** error) override;
+ void CancelPickLocked(PickState* pick, grpc_error* error) override;
+ void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+ uint32_t initial_metadata_flags_eq,
+ grpc_error* error) override;
+ void NotifyOnStateChangeLocked(grpc_connectivity_state* state,
+ grpc_closure* closure) override;
+ grpc_connectivity_state CheckConnectivityLocked(
+ grpc_error** connectivity_error) override;
+ void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
+ void ExitIdleLocked() override;
+ void ResetBackoffLocked() override;
+ void FillChildRefsForChannelz(
+ channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* child_channels) override;
+
+ private:
+ /// Linked list of pending pick requests. It stores all information needed to
+ /// eventually call pick() on them. They mainly stay pending waiting for the
+ /// child policy to be created.
+ ///
+ /// Note that when a pick is sent to the child policy, we inject our own
+ /// on_complete callback, so that we can intercept the result before
+ /// invoking the original on_complete callback. This allows us to set the
+ /// LB token metadata and add client_stats to the call context.
+ /// See \a pending_pick_complete() for details.
+ struct PendingPick {
+ // The xds lb instance that created the wrapping. This instance is not
+ // owned; reference counts are untouched. It's used only for logging
+ // purposes.
+ XdsLb* xdslb_policy;
+ // The original pick.
+ PickState* pick;
+ // Our on_complete closure and the original one.
+ grpc_closure on_complete;
+ grpc_closure* original_on_complete;
+ // The LB token associated with the pick. This is set via user_data in
+ // the pick.
+ grpc_mdelem lb_token;
+ // Stats for client-side load reporting.
+ RefCountedPtr<XdsLbClientStats> client_stats;
+ // Next pending pick.
+ PendingPick* next = nullptr;
+ };
+
+ /// Contains a call to the LB server and all the data related to the call.
+ class BalancerCallState
+ : public InternallyRefCountedWithTracing<BalancerCallState> {
+ public:
+ explicit BalancerCallState(
+ RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy);
+
+ // It's the caller's responsibility to ensure that Orphan() is called from
+ // inside the combiner.
+ void Orphan() override;
+
+ void StartQuery();
+
+ XdsLbClientStats* client_stats() const { return client_stats_.get(); }
+
+ bool seen_initial_response() const { return seen_initial_response_; }
+
+ private:
+ // So Delete() can access our private dtor.
+ template <typename T>
+ friend void grpc_core::Delete(T*);
+
+ ~BalancerCallState();
+
+ XdsLb* xdslb_policy() const {
+ return static_cast<XdsLb*>(xdslb_policy_.get());
+ }
+
+ void ScheduleNextClientLoadReportLocked();
+ void SendClientLoadReportLocked();
+
+ static bool LoadReportCountersAreZero(xds_grpclb_request* request);
+
+ static void MaybeSendClientLoadReportLocked(void* arg, grpc_error* error);
+ static void ClientLoadReportDoneLocked(void* arg, grpc_error* error);
+ static void OnInitialRequestSentLocked(void* arg, grpc_error* error);
+ static void OnBalancerMessageReceivedLocked(void* arg, grpc_error* error);
+ static void OnBalancerStatusReceivedLocked(void* arg, grpc_error* error);
+
+ // The owning LB policy.
+ RefCountedPtr<LoadBalancingPolicy> xdslb_policy_;
+
+ // The streaming call to the LB server. Always non-NULL.
+ grpc_call* lb_call_ = nullptr;
+
+ // recv_initial_metadata
+ grpc_metadata_array lb_initial_metadata_recv_;
+
+ // send_message
+ grpc_byte_buffer* send_message_payload_ = nullptr;
+ grpc_closure lb_on_initial_request_sent_;
+
+ // recv_message
+ grpc_byte_buffer* recv_message_payload_ = nullptr;
+ grpc_closure lb_on_balancer_message_received_;
+ bool seen_initial_response_ = false;
+
+ // recv_trailing_metadata
+ grpc_closure lb_on_balancer_status_received_;
+ grpc_metadata_array lb_trailing_metadata_recv_;
+ grpc_status_code lb_call_status_;
+ grpc_slice lb_call_status_details_;
+
+ // The stats for client-side load reporting associated with this LB call.
+ // Created after the first serverlist is received.
+ RefCountedPtr<XdsLbClientStats> client_stats_;
+ grpc_millis client_stats_report_interval_ = 0;
+ grpc_timer client_load_report_timer_;
+ bool client_load_report_timer_callback_pending_ = false;
+ bool last_client_load_report_counters_were_zero_ = false;
+ bool client_load_report_is_due_ = false;
+ // The closure used for either the load report timer or the callback for
+ // completion of sending the load report.
+ grpc_closure client_load_report_closure_;
+ };
+
+ ~XdsLb();
+
+ void ShutdownLocked() override;
+
+ // Helper function used in ctor and UpdateLocked().
+ void ProcessChannelArgsLocked(const grpc_channel_args& args);
+
+ // Methods for dealing with the balancer channel and call.
+ void StartPickingLocked();
+ void StartBalancerCallLocked();
+ static void OnFallbackTimerLocked(void* arg, grpc_error* error);
+ void StartBalancerCallRetryTimerLocked();
+ static void OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error);
+ static void OnBalancerChannelConnectivityChangedLocked(void* arg,
+ grpc_error* error);
+
+ // Pending pick methods.
+ static void PendingPickSetMetadataAndContext(PendingPick* pp);
+ PendingPick* PendingPickCreate(PickState* pick);
+ void AddPendingPick(PendingPick* pp);
+ static void OnPendingPickComplete(void* arg, grpc_error* error);
+
+ // Methods for dealing with the child policy.
+ void CreateOrUpdateChildPolicyLocked();
+ grpc_channel_args* CreateChildPolicyArgsLocked();
+ void CreateChildPolicyLocked(const Args& args);
+ bool PickFromChildPolicyLocked(bool force_async, PendingPick* pp,
+ grpc_error** error);
+ void UpdateConnectivityStateFromChildPolicyLocked(
+ grpc_error* child_state_error);
+ static void OnChildPolicyConnectivityChangedLocked(void* arg,
+ grpc_error* error);
+ static void OnChildPolicyRequestReresolutionLocked(void* arg,
+ grpc_error* error);
+
+ // Who the client is trying to communicate with.
+ const char* server_name_ = nullptr;
+
+ // Current channel args from the resolver.
+ grpc_channel_args* args_ = nullptr;
+
+ // Internal state.
+ bool started_picking_ = false;
+ bool shutting_down_ = false;
+ grpc_connectivity_state_tracker state_tracker_;
+
+ // The channel for communicating with the LB server.
+ grpc_channel* lb_channel_ = nullptr;
+ // Mutex to protect the channel to the LB server. This is used when
+ // processing a channelz request.
+ gpr_mu lb_channel_mu_;
+ grpc_connectivity_state lb_channel_connectivity_;
+ grpc_closure lb_channel_on_connectivity_changed_;
+ // Are we already watching the LB channel's connectivity?
+ bool watching_lb_channel_ = false;
+ // Response generator to inject address updates into lb_channel_.
+ RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
+
+ // The data associated with the current LB call. It holds a ref to this LB
+ // policy. It's initialized every time we query for backends. It's reset to
+ // NULL whenever the current LB call is no longer needed (e.g., the LB policy
+ // is shutting down, or the LB call has ended). A non-NULL lb_calld_ always
+ // contains a non-NULL lb_call_.
+ OrphanablePtr<BalancerCallState> lb_calld_;
+ // Timeout in milliseconds for the LB call. 0 means no deadline.
+ int lb_call_timeout_ms_ = 0;
+ // Balancer call retry state.
+ BackOff lb_call_backoff_;
+ bool retry_timer_callback_pending_ = false;
+ grpc_timer lb_call_retry_timer_;
+ grpc_closure lb_on_call_retry_;
+
+ // The deserialized response from the balancer. May be nullptr until one
+ // such response has arrived.
+ xds_grpclb_serverlist* serverlist_ = nullptr;
+
+ // Timeout in milliseconds for before using fallback backend addresses.
+ // 0 means not using fallback.
+ int lb_fallback_timeout_ms_ = 0;
+ // The backend addresses from the resolver.
+ grpc_lb_addresses* fallback_backend_addresses_ = nullptr;
+ // Fallback timer.
+ bool fallback_timer_callback_pending_ = false;
+ grpc_timer lb_fallback_timer_;
+ grpc_closure lb_on_fallback_;
+
+ // Pending picks that are waiting on the xDS policy's connectivity.
+ PendingPick* pending_picks_ = nullptr;
+
+ // The policy to use for the backends.
+ OrphanablePtr<LoadBalancingPolicy> child_policy_;
+ grpc_connectivity_state child_connectivity_state_;
+ grpc_closure on_child_connectivity_changed_;
+ grpc_closure on_child_request_reresolution_;
+};
+
+//
+// serverlist parsing code
+//
+
+// vtable for LB tokens in grpc_lb_addresses
+void* lb_token_copy(void* token) {
+ return token == nullptr
+ ? nullptr
+ : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload;
+}
+void lb_token_destroy(void* token) {
+ if (token != nullptr) {
+ GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token});
+ }
+}
+int lb_token_cmp(void* token1, void* token2) {
+ if (token1 > token2) return 1;
+ if (token1 < token2) return -1;
+ return 0;
+}
+const grpc_lb_user_data_vtable lb_token_vtable = {
+ lb_token_copy, lb_token_destroy, lb_token_cmp};
+
+// Returns the backend addresses extracted from the given addresses.
+grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) {
+ // First pass: count the number of backend addresses.
+ size_t num_backends = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (!addresses->addresses[i].is_balancer) {
+ ++num_backends;
+ }
+ }
+ // Second pass: actually populate the addresses and (empty) LB tokens.
+ grpc_lb_addresses* backend_addresses =
+ grpc_lb_addresses_create(num_backends, &lb_token_vtable);
+ size_t num_copied = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (addresses->addresses[i].is_balancer) continue;
+ const grpc_resolved_address* addr = &addresses->addresses[i].address;
+ grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr,
+ addr->len, false /* is_balancer */,
+ nullptr /* balancer_name */,
+ (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload);
+ ++num_copied;
+ }
+ return backend_addresses;
+}
+
+bool IsServerValid(const xds_grpclb_server* server, size_t idx, bool log) {
+ if (server->drop) return false;
+ const xds_grpclb_ip_address* ip = &server->ip_address;
+ if (GPR_UNLIKELY(server->port >> 16 != 0)) {
+ if (log) {
+ gpr_log(GPR_ERROR,
+ "Invalid port '%d' at index %lu of serverlist. Ignoring.",
+ server->port, (unsigned long)idx);
+ }
+ return false;
+ }
+ if (GPR_UNLIKELY(ip->size != 4 && ip->size != 16)) {
+ if (log) {
+ gpr_log(GPR_ERROR,
+ "Expected IP to be 4 or 16 bytes, got %d at index %lu of "
+ "serverlist. Ignoring",
+ ip->size, (unsigned long)idx);
+ }
+ return false;
+ }
+ return true;
+}
+
+void ParseServer(const xds_grpclb_server* server, grpc_resolved_address* addr) {
+ memset(addr, 0, sizeof(*addr));
+ if (server->drop) return;
+ const uint16_t netorder_port = grpc_htons((uint16_t)server->port);
+ /* the addresses are given in binary format (a in(6)_addr struct) in
+ * server->ip_address.bytes. */
+ const xds_grpclb_ip_address* ip = &server->ip_address;
+ if (ip->size == 4) {
+ addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
+ grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(&addr->addr);
+ addr4->sin_family = GRPC_AF_INET;
+ memcpy(&addr4->sin_addr, ip->bytes, ip->size);
+ addr4->sin_port = netorder_port;
+ } else if (ip->size == 16) {
+ addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
+ grpc_sockaddr_in6* addr6 = (grpc_sockaddr_in6*)&addr->addr;
+ addr6->sin6_family = GRPC_AF_INET6;
+ memcpy(&addr6->sin6_addr, ip->bytes, ip->size);
+ addr6->sin6_port = netorder_port;
+ }
+}
+
+// Returns addresses extracted from \a serverlist.
+grpc_lb_addresses* ProcessServerlist(const xds_grpclb_serverlist* serverlist) {
+ size_t num_valid = 0;
+ /* first pass: count how many are valid in order to allocate the necessary
+ * memory in a single block */
+ for (size_t i = 0; i < serverlist->num_servers; ++i) {
+ if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid;
+ }
+ grpc_lb_addresses* lb_addresses =
+ grpc_lb_addresses_create(num_valid, &lb_token_vtable);
+ /* second pass: actually populate the addresses and LB tokens (aka user data
+ * to the outside world) to be read by the child policy during its creation.
+ * Given that the validity tests are very cheap, they are performed again
+ * instead of marking the valid ones during the first pass, as this would
+ * incurr in an allocation due to the arbitrary number of server */
+ size_t addr_idx = 0;
+ for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) {
+ const xds_grpclb_server* server = serverlist->servers[sl_idx];
+ if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue;
+ GPR_ASSERT(addr_idx < num_valid);
+ /* address processing */
+ grpc_resolved_address addr;
+ ParseServer(server, &addr);
+ /* lb token processing */
+ void* user_data;
+ if (server->has_load_balance_token) {
+ const size_t lb_token_max_length =
+ GPR_ARRAY_SIZE(server->load_balance_token);
+ const size_t lb_token_length =
+ strnlen(server->load_balance_token, lb_token_max_length);
+ grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer(
+ server->load_balance_token, lb_token_length);
+ user_data =
+ (void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr)
+ .payload;
+ } else {
+ char* uri = grpc_sockaddr_to_uri(&addr);
+ gpr_log(GPR_INFO,
+ "Missing LB token for backend address '%s'. The empty token will "
+ "be used instead",
+ uri);
+ gpr_free(uri);
+ user_data = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload;
+ }
+ grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len,
+ false /* is_balancer */,
+ nullptr /* balancer_name */, user_data);
+ ++addr_idx;
+ }
+ GPR_ASSERT(addr_idx == num_valid);
+ return lb_addresses;
+}
+
+//
+// XdsLb::BalancerCallState
+//
+
+XdsLb::BalancerCallState::BalancerCallState(
+ RefCountedPtr<LoadBalancingPolicy> parent_xdslb_policy)
+ : InternallyRefCountedWithTracing<BalancerCallState>(&grpc_lb_xds_trace),
+ xdslb_policy_(std::move(parent_xdslb_policy)) {
+ GPR_ASSERT(xdslb_policy_ != nullptr);
+ GPR_ASSERT(!xdslb_policy()->shutting_down_);
+ // Init the LB call. Note that the LB call will progress every time there's
+ // activity in xdslb_policy_->interested_parties(), which is comprised of
+ // the polling entities from client_channel.
+ GPR_ASSERT(xdslb_policy()->server_name_ != nullptr);
+ GPR_ASSERT(xdslb_policy()->server_name_[0] != '\0');
+ const grpc_millis deadline =
+ xdslb_policy()->lb_call_timeout_ms_ == 0
+ ? GRPC_MILLIS_INF_FUTURE
+ : ExecCtx::Get()->Now() + xdslb_policy()->lb_call_timeout_ms_;
+ lb_call_ = grpc_channel_create_pollset_set_call(
+ xdslb_policy()->lb_channel_, nullptr, GRPC_PROPAGATE_DEFAULTS,
+ xdslb_policy_->interested_parties(),
+ GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD,
+ nullptr, deadline, nullptr);
+ // Init the LB call request payload.
+ xds_grpclb_request* request =
+ xds_grpclb_request_create(xdslb_policy()->server_name_);
+ grpc_slice request_payload_slice = xds_grpclb_request_encode(request);
+ send_message_payload_ =
+ grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+ grpc_slice_unref_internal(request_payload_slice);
+ xds_grpclb_request_destroy(request);
+ // Init other data associated with the LB call.
+ grpc_metadata_array_init(&lb_initial_metadata_recv_);
+ grpc_metadata_array_init(&lb_trailing_metadata_recv_);
+ GRPC_CLOSURE_INIT(&lb_on_initial_request_sent_, OnInitialRequestSentLocked,
+ this, grpc_combiner_scheduler(xdslb_policy()->combiner()));
+ GRPC_CLOSURE_INIT(&lb_on_balancer_message_received_,
+ OnBalancerMessageReceivedLocked, this,
+ grpc_combiner_scheduler(xdslb_policy()->combiner()));
+ GRPC_CLOSURE_INIT(&lb_on_balancer_status_received_,
+ OnBalancerStatusReceivedLocked, this,
+ grpc_combiner_scheduler(xdslb_policy()->combiner()));
+}
+
+XdsLb::BalancerCallState::~BalancerCallState() {
+ GPR_ASSERT(lb_call_ != nullptr);
+ grpc_call_unref(lb_call_);
+ grpc_metadata_array_destroy(&lb_initial_metadata_recv_);
+ grpc_metadata_array_destroy(&lb_trailing_metadata_recv_);
+ grpc_byte_buffer_destroy(send_message_payload_);
+ grpc_byte_buffer_destroy(recv_message_payload_);
+ grpc_slice_unref_internal(lb_call_status_details_);
+}
+
+void XdsLb::BalancerCallState::Orphan() {
+ GPR_ASSERT(lb_call_ != nullptr);
+ // If we are here because xdslb_policy wants to cancel the call,
+ // lb_on_balancer_status_received_ will complete the cancellation and clean
+ // up. Otherwise, we are here because xdslb_policy has to orphan a failed
+ // call, then the following cancellation will be a no-op.
+ grpc_call_cancel(lb_call_, nullptr);
+ if (client_load_report_timer_callback_pending_) {
+ grpc_timer_cancel(&client_load_report_timer_);
+ }
+ // Note that the initial ref is hold by lb_on_balancer_status_received_
+ // instead of the caller of this function. So the corresponding unref happens
+ // in lb_on_balancer_status_received_ instead of here.
+}
+
+void XdsLb::BalancerCallState::StartQuery() {
+ GPR_ASSERT(lb_call_ != nullptr);
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Starting LB call (lb_calld: %p, lb_call: %p)",
+ xdslb_policy_.get(), this, lb_call_);
+ }
+ // Create the ops.
+ grpc_call_error call_error;
+ grpc_op ops[3];
+ memset(ops, 0, sizeof(ops));
+ // Op: send initial metadata.
+ grpc_op* op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ // Op: send request message.
+ GPR_ASSERT(send_message_payload_ != nullptr);
+ op->op = GRPC_OP_SEND_MESSAGE;
+ op->data.send_message.send_message = send_message_payload_;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = Ref(DEBUG_LOCATION, "on_initial_request_sent");
+ self.release();
+ call_error = grpc_call_start_batch_and_execute(
+ lb_call_, ops, (size_t)(op - ops), &lb_on_initial_request_sent_);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ // Op: recv initial metadata.
+ op = ops;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata =
+ &lb_initial_metadata_recv_;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ // Op: recv response.
+ op->op = GRPC_OP_RECV_MESSAGE;
+ op->data.recv_message.recv_message = &recv_message_payload_;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ self = Ref(DEBUG_LOCATION, "on_message_received");
+ self.release();
+ call_error = grpc_call_start_batch_and_execute(
+ lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_message_received_);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ // Op: recv server status.
+ op = ops;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata =
+ &lb_trailing_metadata_recv_;
+ op->data.recv_status_on_client.status = &lb_call_status_;
+ op->data.recv_status_on_client.status_details = &lb_call_status_details_;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ // This callback signals the end of the LB call, so it relies on the initial
+ // ref instead of a new ref. When it's invoked, it's the initial ref that is
+ // unreffed.
+ call_error = grpc_call_start_batch_and_execute(
+ lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_status_received_);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+void XdsLb::BalancerCallState::ScheduleNextClientLoadReportLocked() {
+ const grpc_millis next_client_load_report_time =
+ ExecCtx::Get()->Now() + client_stats_report_interval_;
+ GRPC_CLOSURE_INIT(&client_load_report_closure_,
+ MaybeSendClientLoadReportLocked, this,
+ grpc_combiner_scheduler(xdslb_policy()->combiner()));
+ grpc_timer_init(&client_load_report_timer_, next_client_load_report_time,
+ &client_load_report_closure_);
+ client_load_report_timer_callback_pending_ = true;
+}
+
+void XdsLb::BalancerCallState::MaybeSendClientLoadReportLocked(
+ void* arg, grpc_error* error) {
+ BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+ XdsLb* xdslb_policy = lb_calld->xdslb_policy();
+ lb_calld->client_load_report_timer_callback_pending_ = false;
+ if (error != GRPC_ERROR_NONE || lb_calld != xdslb_policy->lb_calld_.get()) {
+ lb_calld->Unref(DEBUG_LOCATION, "client_load_report");
+ return;
+ }
+ // If we've already sent the initial request, then we can go ahead and send
+ // the load report. Otherwise, we need to wait until the initial request has
+ // been sent to send this (see OnInitialRequestSentLocked()).
+ if (lb_calld->send_message_payload_ == nullptr) {
+ lb_calld->SendClientLoadReportLocked();
+ } else {
+ lb_calld->client_load_report_is_due_ = true;
+ }
+}
+
+bool XdsLb::BalancerCallState::LoadReportCountersAreZero(
+ xds_grpclb_request* request) {
+ XdsLbClientStats::DroppedCallCounts* drop_entries =
+ static_cast<XdsLbClientStats::DroppedCallCounts*>(
+ request->client_stats.calls_finished_with_drop.arg);
+ return request->client_stats.num_calls_started == 0 &&
+ request->client_stats.num_calls_finished == 0 &&
+ request->client_stats.num_calls_finished_with_client_failed_to_send ==
+ 0 &&
+ request->client_stats.num_calls_finished_known_received == 0 &&
+ (drop_entries == nullptr || drop_entries->empty());
+}
+
+void XdsLb::BalancerCallState::SendClientLoadReportLocked() {
+ // Construct message payload.
+ GPR_ASSERT(send_message_payload_ == nullptr);
+ xds_grpclb_request* request =
+ xds_grpclb_load_report_request_create_locked(client_stats_.get());
+ // Skip client load report if the counters were all zero in the last
+ // report and they are still zero in this one.
+ if (LoadReportCountersAreZero(request)) {
+ if (last_client_load_report_counters_were_zero_) {
+ xds_grpclb_request_destroy(request);
+ ScheduleNextClientLoadReportLocked();
+ return;
+ }
+ last_client_load_report_counters_were_zero_ = true;
+ } else {
+ last_client_load_report_counters_were_zero_ = false;
+ }
+ grpc_slice request_payload_slice = xds_grpclb_request_encode(request);
+ send_message_payload_ =
+ grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+ grpc_slice_unref_internal(request_payload_slice);
+ xds_grpclb_request_destroy(request);
+ // Send the report.
+ grpc_op op;
+ memset(&op, 0, sizeof(op));
+ op.op = GRPC_OP_SEND_MESSAGE;
+ op.data.send_message.send_message = send_message_payload_;
+ GRPC_CLOSURE_INIT(&client_load_report_closure_, ClientLoadReportDoneLocked,
+ this, grpc_combiner_scheduler(xdslb_policy()->combiner()));
+ grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ lb_call_, &op, 1, &client_load_report_closure_);
+ if (GPR_UNLIKELY(call_error != GRPC_CALL_OK)) {
+ gpr_log(GPR_ERROR, "[xdslb %p] call_error=%d", xdslb_policy_.get(),
+ call_error);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ }
+}
+
+void XdsLb::BalancerCallState::ClientLoadReportDoneLocked(void* arg,
+ grpc_error* error) {
+ BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+ XdsLb* xdslb_policy = lb_calld->xdslb_policy();
+ grpc_byte_buffer_destroy(lb_calld->send_message_payload_);
+ lb_calld->send_message_payload_ = nullptr;
+ if (error != GRPC_ERROR_NONE || lb_calld != xdslb_policy->lb_calld_.get()) {
+ lb_calld->Unref(DEBUG_LOCATION, "client_load_report");
+ return;
+ }
+ lb_calld->ScheduleNextClientLoadReportLocked();
+}
+
+void XdsLb::BalancerCallState::OnInitialRequestSentLocked(void* arg,
+ grpc_error* error) {
+ BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+ grpc_byte_buffer_destroy(lb_calld->send_message_payload_);
+ lb_calld->send_message_payload_ = nullptr;
+ // If we attempted to send a client load report before the initial request was
+ // sent (and this lb_calld is still in use), send the load report now.
+ if (lb_calld->client_load_report_is_due_ &&
+ lb_calld == lb_calld->xdslb_policy()->lb_calld_.get()) {
+ lb_calld->SendClientLoadReportLocked();
+ lb_calld->client_load_report_is_due_ = false;
+ }
+ lb_calld->Unref(DEBUG_LOCATION, "on_initial_request_sent");
+}
+
+void XdsLb::BalancerCallState::OnBalancerMessageReceivedLocked(
+ void* arg, grpc_error* error) {
+ BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+ XdsLb* xdslb_policy = lb_calld->xdslb_policy();
+ // Empty payload means the LB call was cancelled.
+ if (lb_calld != xdslb_policy->lb_calld_.get() ||
+ lb_calld->recv_message_payload_ == nullptr) {
+ lb_calld->Unref(DEBUG_LOCATION, "on_message_received");
+ return;
+ }
+ grpc_byte_buffer_reader bbr;
+ grpc_byte_buffer_reader_init(&bbr, lb_calld->recv_message_payload_);
+ grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
+ grpc_byte_buffer_reader_destroy(&bbr);
+ grpc_byte_buffer_destroy(lb_calld->recv_message_payload_);
+ lb_calld->recv_message_payload_ = nullptr;
+ xds_grpclb_initial_response* initial_response;
+ xds_grpclb_serverlist* serverlist;
+ if (!lb_calld->seen_initial_response_ &&
+ (initial_response = xds_grpclb_initial_response_parse(response_slice)) !=
+ nullptr) {
+ // Have NOT seen initial response, look for initial response.
+ if (initial_response->has_client_stats_report_interval) {
+ lb_calld->client_stats_report_interval_ = GPR_MAX(
+ GPR_MS_PER_SEC, xds_grpclb_duration_to_millis(
+ &initial_response->client_stats_report_interval));
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Received initial LB response message; "
+ "client load reporting interval = %" PRId64 " milliseconds",
+ xdslb_policy, lb_calld->client_stats_report_interval_);
+ }
+ } else if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Received initial LB response message; client load "
+ "reporting NOT enabled",
+ xdslb_policy);
+ }
+ xds_grpclb_initial_response_destroy(initial_response);
+ lb_calld->seen_initial_response_ = true;
+ } else if ((serverlist = xds_grpclb_response_parse_serverlist(
+ response_slice)) != nullptr) {
+ // Have seen initial response, look for serverlist.
+ GPR_ASSERT(lb_calld->lb_call_ != nullptr);
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Serverlist with %" PRIuPTR " servers received",
+ xdslb_policy, serverlist->num_servers);
+ for (size_t i = 0; i < serverlist->num_servers; ++i) {
+ grpc_resolved_address addr;
+ ParseServer(serverlist->servers[i], &addr);
+ char* ipport;
+ grpc_sockaddr_to_string(&ipport, &addr, false);
+ gpr_log(GPR_INFO, "[xdslb %p] Serverlist[%" PRIuPTR "]: %s",
+ xdslb_policy, i, ipport);
+ gpr_free(ipport);
+ }
+ }
+ /* update serverlist */
+ if (serverlist->num_servers > 0) {
+ // Start sending client load report only after we start using the
+ // serverlist returned from the current LB call.
+ if (lb_calld->client_stats_report_interval_ > 0 &&
+ lb_calld->client_stats_ == nullptr) {
+ lb_calld->client_stats_.reset(New<XdsLbClientStats>());
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report");
+ self.release();
+ lb_calld->ScheduleNextClientLoadReportLocked();
+ }
+ if (xds_grpclb_serverlist_equals(xdslb_policy->serverlist_, serverlist)) {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Incoming server list identical to current, "
+ "ignoring.",
+ xdslb_policy);
+ }
+ xds_grpclb_destroy_serverlist(serverlist);
+ } else { /* new serverlist */
+ if (xdslb_policy->serverlist_ != nullptr) {
+ /* dispose of the old serverlist */
+ xds_grpclb_destroy_serverlist(xdslb_policy->serverlist_);
+ } else {
+ /* or dispose of the fallback */
+ grpc_lb_addresses_destroy(xdslb_policy->fallback_backend_addresses_);
+ xdslb_policy->fallback_backend_addresses_ = nullptr;
+ if (xdslb_policy->fallback_timer_callback_pending_) {
+ grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_);
+ }
+ }
+ // and update the copy in the XdsLb instance. This
+ // serverlist instance will be destroyed either upon the next
+ // update or when the XdsLb instance is destroyed.
+ xdslb_policy->serverlist_ = serverlist;
+ xdslb_policy->CreateOrUpdateChildPolicyLocked();
+ }
+ } else {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Received empty server list, ignoring.",
+ xdslb_policy);
+ }
+ xds_grpclb_destroy_serverlist(serverlist);
+ }
+ } else {
+ // No valid initial response or serverlist found.
+ char* response_slice_str =
+ grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX);
+ gpr_log(GPR_ERROR,
+ "[xdslb %p] Invalid LB response received: '%s'. Ignoring.",
+ xdslb_policy, response_slice_str);
+ gpr_free(response_slice_str);
+ }
+ grpc_slice_unref_internal(response_slice);
+ if (!xdslb_policy->shutting_down_) {
+ // Keep listening for serverlist updates.
+ grpc_op op;
+ memset(&op, 0, sizeof(op));
+ op.op = GRPC_OP_RECV_MESSAGE;
+ op.data.recv_message.recv_message = &lb_calld->recv_message_payload_;
+ op.flags = 0;
+ op.reserved = nullptr;
+ // Reuse the "OnBalancerMessageReceivedLocked" ref taken in StartQuery().
+ const grpc_call_error call_error = grpc_call_start_batch_and_execute(
+ lb_calld->lb_call_, &op, 1,
+ &lb_calld->lb_on_balancer_message_received_);
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
+ } else {
+ lb_calld->Unref(DEBUG_LOCATION, "on_message_received+xds_shutdown");
+ }
+}
+
+void XdsLb::BalancerCallState::OnBalancerStatusReceivedLocked(
+ void* arg, grpc_error* error) {
+ BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+ XdsLb* xdslb_policy = lb_calld->xdslb_policy();
+ GPR_ASSERT(lb_calld->lb_call_ != nullptr);
+ if (grpc_lb_xds_trace.enabled()) {
+ char* status_details =
+ grpc_slice_to_c_string(lb_calld->lb_call_status_details_);
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Status from LB server received. Status = %d, details "
+ "= '%s', (lb_calld: %p, lb_call: %p), error '%s'",
+ xdslb_policy, lb_calld->lb_call_status_, status_details, lb_calld,
+ lb_calld->lb_call_, grpc_error_string(error));
+ gpr_free(status_details);
+ }
+ xdslb_policy->TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_NONE);
+ // If this lb_calld is still in use, this call ended because of a failure so
+ // we want to retry connecting. Otherwise, we have deliberately ended this
+ // call and no further action is required.
+ if (lb_calld == xdslb_policy->lb_calld_.get()) {
+ xdslb_policy->lb_calld_.reset();
+ GPR_ASSERT(!xdslb_policy->shutting_down_);
+ if (lb_calld->seen_initial_response_) {
+ // If we lose connection to the LB server, reset the backoff and restart
+ // the LB call immediately.
+ xdslb_policy->lb_call_backoff_.Reset();
+ xdslb_policy->StartBalancerCallLocked();
+ } else {
+ // If this LB call fails establishing any connection to the LB server,
+ // retry later.
+ xdslb_policy->StartBalancerCallRetryTimerLocked();
+ }
+ }
+ lb_calld->Unref(DEBUG_LOCATION, "lb_call_ended");
+}
+
+//
+// helper code for creating balancer channel
+//
+
+grpc_lb_addresses* ExtractBalancerAddresses(
+ const grpc_lb_addresses* addresses) {
+ size_t num_grpclb_addrs = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
+ }
+ // There must be at least one balancer address, or else the
+ // client_channel would not have chosen this LB policy.
+ GPR_ASSERT(num_grpclb_addrs > 0);
+ grpc_lb_addresses* lb_addresses =
+ grpc_lb_addresses_create(num_grpclb_addrs, nullptr);
+ size_t lb_addresses_idx = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (!addresses->addresses[i].is_balancer) continue;
+ if (GPR_UNLIKELY(addresses->addresses[i].user_data != nullptr)) {
+ gpr_log(GPR_ERROR,
+ "This LB policy doesn't support user data. It will be ignored");
+ }
+ grpc_lb_addresses_set_address(
+ lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr,
+ addresses->addresses[i].address.len, false /* is balancer */,
+ addresses->addresses[i].balancer_name, nullptr /* user data */);
+ }
+ GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx);
+ return lb_addresses;
+}
+
+/* Returns the channel args for the LB channel, used to create a bidirectional
+ * stream for the reception of load balancing updates.
+ *
+ * Inputs:
+ * - \a addresses: corresponding to the balancers.
+ * - \a response_generator: in order to propagate updates from the resolver
+ * above the grpclb policy.
+ * - \a args: other args inherited from the xds policy. */
+grpc_channel_args* BuildBalancerChannelArgs(
+ const grpc_lb_addresses* addresses,
+ FakeResolverResponseGenerator* response_generator,
+ const grpc_channel_args* args) {
+ grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses);
+ // Channel args to remove.
+ static const char* args_to_remove[] = {
+ // LB policy name, since we want to use the default (pick_first) in
+ // the LB channel.
+ GRPC_ARG_LB_POLICY_NAME,
+ // The channel arg for the server URI, since that will be different for
+ // the LB channel than for the parent channel. The client channel
+ // factory will re-add this arg with the right value.
+ GRPC_ARG_SERVER_URI,
+ // The resolved addresses, which will be generated by the name resolver
+ // used in the LB channel. Note that the LB channel will use the fake
+ // resolver, so this won't actually generate a query to DNS (or some
+ // other name service). However, the addresses returned by the fake
+ // resolver will have is_balancer=false, whereas our own addresses have
+ // is_balancer=true. We need the LB channel to return addresses with
+ // is_balancer=false so that it does not wind up recursively using the
+ // xds LB policy, as per the special case logic in client_channel.c.
+ GRPC_ARG_LB_ADDRESSES,
+ // The fake resolver response generator, because we are replacing it
+ // with the one from the xds policy, used to propagate updates to
+ // the LB channel.
+ GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
+ // The LB channel should use the authority indicated by the target
+ // authority table (see \a grpc_lb_policy_xds_modify_lb_channel_args),
+ // as opposed to the authority from the parent channel.
+ GRPC_ARG_DEFAULT_AUTHORITY,
+ // Just as for \a GRPC_ARG_DEFAULT_AUTHORITY, the LB channel should be
+ // treated as a stand-alone channel and not inherit this argument from the
+ // args of the parent channel.
+ GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+ };
+ // Channel args to add.
+ const grpc_arg args_to_add[] = {
+ // New LB addresses.
+ // Note that we pass these in both when creating the LB channel
+ // and via the fake resolver. The latter is what actually gets used.
+ grpc_lb_addresses_create_channel_arg(lb_addresses),
+ // The fake resolver response generator, which we use to inject
+ // address updates into the LB channel.
+ grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+ response_generator),
+ // A channel arg indicating the target is a xds load balancer.
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1),
+ // A channel arg indicating this is an internal channels, aka it is
+ // owned by components in Core, not by the user application.
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
+ };
+ // Construct channel args.
+ grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
+ args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
+ GPR_ARRAY_SIZE(args_to_add));
+ // Make any necessary modifications for security.
+ new_args = grpc_lb_policy_xds_modify_lb_channel_args(new_args);
+ // Clean up.
+ grpc_lb_addresses_destroy(lb_addresses);
+ return new_args;
+}
+
+//
+// ctor and dtor
+//
+
+XdsLb::XdsLb(const grpc_lb_addresses* addresses,
+ const LoadBalancingPolicy::Args& args)
+ : LoadBalancingPolicy(args),
+ response_generator_(MakeRefCounted<FakeResolverResponseGenerator>()),
+ lb_call_backoff_(
+ BackOff::Options()
+ .set_initial_backoff(GRPC_XDS_INITIAL_CONNECT_BACKOFF_SECONDS *
+ 1000)
+ .set_multiplier(GRPC_XDS_RECONNECT_BACKOFF_MULTIPLIER)
+ .set_jitter(GRPC_XDS_RECONNECT_JITTER)
+ .set_max_backoff(GRPC_XDS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
+ // Initialization.
+ gpr_mu_init(&lb_channel_mu_);
+ grpc_subchannel_index_ref();
+ GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_,
+ &XdsLb::OnBalancerChannelConnectivityChangedLocked, this,
+ grpc_combiner_scheduler(args.combiner));
+ GRPC_CLOSURE_INIT(&on_child_connectivity_changed_,
+ &XdsLb::OnChildPolicyConnectivityChangedLocked, this,
+ grpc_combiner_scheduler(args.combiner));
+ GRPC_CLOSURE_INIT(&on_child_request_reresolution_,
+ &XdsLb::OnChildPolicyRequestReresolutionLocked, this,
+ grpc_combiner_scheduler(args.combiner));
+ grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, "xds");
+ // Record server name.
+ const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI);
+ const char* server_uri = grpc_channel_arg_get_string(arg);
+ GPR_ASSERT(server_uri != nullptr);
+ grpc_uri* uri = grpc_uri_parse(server_uri, true);
+ GPR_ASSERT(uri->path[0] != '\0');
+ server_name_ = gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path);
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Will use '%s' as the server name for LB request.", this,
+ server_name_);
+ }
+ grpc_uri_destroy(uri);
+ // Record LB call timeout.
+ arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS);
+ lb_call_timeout_ms_ = grpc_channel_arg_get_integer(arg, {0, 0, INT_MAX});
+ // Record fallback timeout.
+ arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS);
+ lb_fallback_timeout_ms_ = grpc_channel_arg_get_integer(
+ arg, {GRPC_XDS_DEFAULT_FALLBACK_TIMEOUT_MS, 0, INT_MAX});
+ // Process channel args.
+ ProcessChannelArgsLocked(*args.args);
+}
+
+XdsLb::~XdsLb() {
+ GPR_ASSERT(pending_picks_ == nullptr);
+ gpr_mu_destroy(&lb_channel_mu_);
+ gpr_free((void*)server_name_);
+ grpc_channel_args_destroy(args_);
+ grpc_connectivity_state_destroy(&state_tracker_);
+ if (serverlist_ != nullptr) {
+ xds_grpclb_destroy_serverlist(serverlist_);
+ }
+ if (fallback_backend_addresses_ != nullptr) {
+ grpc_lb_addresses_destroy(fallback_backend_addresses_);
+ }
+ grpc_subchannel_index_unref();
+}
+
+void XdsLb::ShutdownLocked() {
+ grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
+ shutting_down_ = true;
+ lb_calld_.reset();
+ if (retry_timer_callback_pending_) {
+ grpc_timer_cancel(&lb_call_retry_timer_);
+ }
+ if (fallback_timer_callback_pending_) {
+ grpc_timer_cancel(&lb_fallback_timer_);
+ }
+ child_policy_.reset();
+ TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_CANCELLED);
+ // We destroy the LB channel here instead of in our destructor because
+ // destroying the channel triggers a last callback to
+ // OnBalancerChannelConnectivityChangedLocked(), and we need to be
+ // alive when that callback is invoked.
+ if (lb_channel_ != nullptr) {
+ gpr_mu_lock(&lb_channel_mu_);
+ grpc_channel_destroy(lb_channel_);
+ lb_channel_ = nullptr;
+ gpr_mu_unlock(&lb_channel_mu_);
+ }
+ grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_REF(error), "xds_shutdown");
+ // Clear pending picks.
+ PendingPick* pp;
+ while ((pp = pending_picks_) != nullptr) {
+ pending_picks_ = pp->next;
+ pp->pick->connected_subchannel.reset();
+ // Note: pp is deleted in this callback.
+ GRPC_CLOSURE_SCHED(&pp->on_complete, GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+//
+// public methods
+//
+
+void XdsLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
+ PendingPick* pp;
+ while ((pp = pending_picks_) != nullptr) {
+ pending_picks_ = pp->next;
+ pp->pick->on_complete = pp->original_on_complete;
+ pp->pick->user_data = nullptr;
+ grpc_error* error = GRPC_ERROR_NONE;
+ if (new_policy->PickLocked(pp->pick, &error)) {
+ // Synchronous return; schedule closure.
+ GRPC_CLOSURE_SCHED(pp->pick->on_complete, error);
+ }
+ Delete(pp);
+ }
+}
+
+// Cancel a specific pending pick.
+//
+// A pick progresses as follows:
+// - If there's a child policy available, it'll be handed over to child policy
+// (in CreateChildPolicyLocked()). From that point onwards, it'll be the
+// child policy's responsibility. For cancellations, that implies the pick
+// needs to be also cancelled by the child policy instance.
+// - Otherwise, without a child policy instance, picks stay pending at this
+// policy's level (xds), inside the pending_picks_ list. To cancel these,
+// we invoke the completion closure and set the pick's connected
+// subchannel to nullptr right here.
+void XdsLb::CancelPickLocked(PickState* pick, grpc_error* error) {
+ PendingPick* pp = pending_picks_;
+ pending_picks_ = nullptr;
+ while (pp != nullptr) {
+ PendingPick* next = pp->next;
+ if (pp->pick == pick) {
+ pick->connected_subchannel.reset();
+ // Note: pp is deleted in this callback.
+ GRPC_CLOSURE_SCHED(&pp->on_complete,
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+ "Pick Cancelled", &error, 1));
+ } else {
+ pp->next = pending_picks_;
+ pending_picks_ = pp;
+ }
+ pp = next;
+ }
+ if (child_policy_ != nullptr) {
+ child_policy_->CancelPickLocked(pick, GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+// Cancel all pending picks.
+//
+// A pick progresses as follows:
+// - If there's a child policy available, it'll be handed over to child policy
+// (in CreateChildPolicyLocked()). From that point onwards, it'll be the
+// child policy's responsibility. For cancellations, that implies the pick
+// needs to be also cancelled by the child policy instance.
+// - Otherwise, without a child policy instance, picks stay pending at this
+// policy's level (xds), inside the pending_picks_ list. To cancel these,
+// we invoke the completion closure and set the pick's connected
+// subchannel to nullptr right here.
+void XdsLb::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+ uint32_t initial_metadata_flags_eq,
+ grpc_error* error) {
+ PendingPick* pp = pending_picks_;
+ pending_picks_ = nullptr;
+ while (pp != nullptr) {
+ PendingPick* next = pp->next;
+ if ((pp->pick->initial_metadata_flags & initial_metadata_flags_mask) ==
+ initial_metadata_flags_eq) {
+ // Note: pp is deleted in this callback.
+ GRPC_CLOSURE_SCHED(&pp->on_complete,
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+ "Pick Cancelled", &error, 1));
+ } else {
+ pp->next = pending_picks_;
+ pending_picks_ = pp;
+ }
+ pp = next;
+ }
+ if (child_policy_ != nullptr) {
+ child_policy_->CancelMatchingPicksLocked(initial_metadata_flags_mask,
+ initial_metadata_flags_eq,
+ GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+void XdsLb::ExitIdleLocked() {
+ if (!started_picking_) {
+ StartPickingLocked();
+ }
+}
+
+void XdsLb::ResetBackoffLocked() {
+ if (lb_channel_ != nullptr) {
+ grpc_channel_reset_connect_backoff(lb_channel_);
+ }
+ if (child_policy_ != nullptr) {
+ child_policy_->ResetBackoffLocked();
+ }
+}
+
+bool XdsLb::PickLocked(PickState* pick, grpc_error** error) {
+ PendingPick* pp = PendingPickCreate(pick);
+ bool pick_done = false;
+ if (child_policy_ != nullptr) {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] about to PICK from policy %p", this,
+ child_policy_.get());
+ }
+ pick_done = PickFromChildPolicyLocked(false /* force_async */, pp, error);
+ } else { // child_policy_ == NULL
+ if (pick->on_complete == nullptr) {
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "No pick result available but synchronous result required.");
+ pick_done = true;
+ } else {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] No child policy. Adding to xds's pending picks",
+ this);
+ }
+ AddPendingPick(pp);
+ if (!started_picking_) {
+ StartPickingLocked();
+ }
+ pick_done = false;
+ }
+ }
+ return pick_done;
+}
+
+void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
+ channelz::ChildRefsList* child_channels) {
+ // delegate to the child_policy_ to fill the children subchannels.
+ child_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
+ MutexLock lock(&lb_channel_mu_);
+ if (lb_channel_ != nullptr) {
+ grpc_core::channelz::ChannelNode* channel_node =
+ grpc_channel_get_channelz_node(lb_channel_);
+ if (channel_node != nullptr) {
+ child_channels->push_back(channel_node->uuid());
+ }
+ }
+}
+
+grpc_connectivity_state XdsLb::CheckConnectivityLocked(
+ grpc_error** connectivity_error) {
+ return grpc_connectivity_state_get(&state_tracker_, connectivity_error);
+}
+
+void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
+ grpc_closure* closure) {
+ grpc_connectivity_state_notify_on_state_change(&state_tracker_, current,
+ closure);
+}
+
+void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
+ const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
+ if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) {
+ // Ignore this update.
+ gpr_log(GPR_ERROR,
+ "[xdslb %p] No valid LB addresses channel arg in update, ignoring.",
+ this);
+ return;
+ }
+ const grpc_lb_addresses* addresses =
+ static_cast<const grpc_lb_addresses*>(arg->value.pointer.p);
+ // Update fallback address list.
+ if (fallback_backend_addresses_ != nullptr) {
+ grpc_lb_addresses_destroy(fallback_backend_addresses_);
+ }
+ fallback_backend_addresses_ = ExtractBackendAddresses(addresses);
+ // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args,
+ // since we use this to trigger the client_load_reporting filter.
+ static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME};
+ grpc_arg new_arg = grpc_channel_arg_string_create(
+ (char*)GRPC_ARG_LB_POLICY_NAME, (char*)"xds");
+ grpc_channel_args_destroy(args_);
+ args_ = grpc_channel_args_copy_and_add_and_remove(
+ &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
+ // Construct args for balancer channel.
+ grpc_channel_args* lb_channel_args =
+ BuildBalancerChannelArgs(addresses, response_generator_.get(), &args);
+ // Create balancer channel if needed.
+ if (lb_channel_ == nullptr) {
+ char* uri_str;
+ gpr_asprintf(&uri_str, "fake:///%s", server_name_);
+ gpr_mu_lock(&lb_channel_mu_);
+ lb_channel_ = grpc_client_channel_factory_create_channel(
+ client_channel_factory(), uri_str,
+ GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, lb_channel_args);
+ gpr_mu_unlock(&lb_channel_mu_);
+ GPR_ASSERT(lb_channel_ != nullptr);
+ gpr_free(uri_str);
+ }
+ // Propagate updates to the LB channel (pick_first) through the fake
+ // resolver.
+ response_generator_->SetResponse(lb_channel_args);
+ grpc_channel_args_destroy(lb_channel_args);
+}
+
+void XdsLb::UpdateLocked(const grpc_channel_args& args) {
+ ProcessChannelArgsLocked(args);
+ // Update the existing child policy.
+ // Note: We have disabled fallback mode in the code, so this child policy must
+ // have been created from a serverlist.
+ // TODO(vpowar): Handle the fallback_address changes when we add support for
+ // fallback in xDS.
+ if (child_policy_ != nullptr) CreateOrUpdateChildPolicyLocked();
+ // Start watching the LB channel connectivity for connection, if not
+ // already doing so.
+ if (!watching_lb_channel_) {
+ lb_channel_connectivity_ = grpc_channel_check_connectivity_state(
+ lb_channel_, true /* try to connect */);
+ grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
+ grpc_channel_get_channel_stack(lb_channel_));
+ GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+ watching_lb_channel_ = true;
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = Ref(DEBUG_LOCATION, "watch_lb_channel_connectivity");
+ self.release();
+ grpc_client_channel_watch_connectivity_state(
+ client_channel_elem,
+ grpc_polling_entity_create_from_pollset_set(interested_parties()),
+ &lb_channel_connectivity_, &lb_channel_on_connectivity_changed_,
+ nullptr);
+ }
+}
+
+//
+// code for balancer channel and call
+//
+
+void XdsLb::StartPickingLocked() {
+ // Start a timer to fall back.
+ if (lb_fallback_timeout_ms_ > 0 && serverlist_ == nullptr &&
+ !fallback_timer_callback_pending_) {
+ grpc_millis deadline = ExecCtx::Get()->Now() + lb_fallback_timeout_ms_;
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = Ref(DEBUG_LOCATION, "on_fallback_timer");
+ self.release();
+ GRPC_CLOSURE_INIT(&lb_on_fallback_, &XdsLb::OnFallbackTimerLocked, this,
+ grpc_combiner_scheduler(combiner()));
+ fallback_timer_callback_pending_ = true;
+ grpc_timer_init(&lb_fallback_timer_, deadline, &lb_on_fallback_);
+ }
+ started_picking_ = true;
+ StartBalancerCallLocked();
+}
+
+void XdsLb::StartBalancerCallLocked() {
+ GPR_ASSERT(lb_channel_ != nullptr);
+ if (shutting_down_) return;
+ // Init the LB call data.
+ GPR_ASSERT(lb_calld_ == nullptr);
+ lb_calld_ = MakeOrphanable<BalancerCallState>(Ref());
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Query for backends (lb_channel: %p, lb_calld: %p)",
+ this, lb_channel_, lb_calld_.get());
+ }
+ lb_calld_->StartQuery();
+}
+
+void XdsLb::OnFallbackTimerLocked(void* arg, grpc_error* error) {
+ XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
+ xdslb_policy->fallback_timer_callback_pending_ = false;
+ // If we receive a serverlist after the timer fires but before this callback
+ // actually runs, don't fall back.
+ if (xdslb_policy->serverlist_ == nullptr && !xdslb_policy->shutting_down_ &&
+ error == GRPC_ERROR_NONE) {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Fallback timer fired. Not using fallback backends",
+ xdslb_policy);
+ }
+ }
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_fallback_timer");
+}
+
+void XdsLb::StartBalancerCallRetryTimerLocked() {
+ grpc_millis next_try = lb_call_backoff_.NextAttemptTime();
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Connection to LB server lost...", this);
+ grpc_millis timeout = next_try - ExecCtx::Get()->Now();
+ if (timeout > 0) {
+ gpr_log(GPR_INFO, "[xdslb %p] ... retry_timer_active in %" PRId64 "ms.",
+ this, timeout);
+ } else {
+ gpr_log(GPR_INFO, "[xdslb %p] ... retry_timer_active immediately.", this);
+ }
+ }
+ // TODO(roth): We currently track this ref manually. Once the
+ // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+ // with the callback.
+ auto self = Ref(DEBUG_LOCATION, "on_balancer_call_retry_timer");
+ self.release();
+ GRPC_CLOSURE_INIT(&lb_on_call_retry_, &XdsLb::OnBalancerCallRetryTimerLocked,
+ this, grpc_combiner_scheduler(combiner()));
+ retry_timer_callback_pending_ = true;
+ grpc_timer_init(&lb_call_retry_timer_, next_try, &lb_on_call_retry_);
+}
+
+void XdsLb::OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error) {
+ XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
+ xdslb_policy->retry_timer_callback_pending_ = false;
+ if (!xdslb_policy->shutting_down_ && error == GRPC_ERROR_NONE &&
+ xdslb_policy->lb_calld_ == nullptr) {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Restarting call to LB server",
+ xdslb_policy);
+ }
+ xdslb_policy->StartBalancerCallLocked();
+ }
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_balancer_call_retry_timer");
+}
+
+// Invoked as part of the update process. It continues watching the LB channel
+// until it shuts down or becomes READY. It's invoked even if the LB channel
+// stayed READY throughout the update (for example if the update is identical).
+void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
+ grpc_error* error) {
+ XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
+ if (xdslb_policy->shutting_down_) goto done;
+ // Re-initialize the lb_call. This should also take care of updating the
+ // child policy. Note that the current child policy, if any, will
+ // stay in effect until an update from the new lb_call is received.
+ switch (xdslb_policy->lb_channel_connectivity_) {
+ case GRPC_CHANNEL_CONNECTING:
+ case GRPC_CHANNEL_TRANSIENT_FAILURE: {
+ // Keep watching the LB channel.
+ grpc_channel_element* client_channel_elem =
+ grpc_channel_stack_last_element(
+ grpc_channel_get_channel_stack(xdslb_policy->lb_channel_));
+ GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+ grpc_client_channel_watch_connectivity_state(
+ client_channel_elem,
+ grpc_polling_entity_create_from_pollset_set(
+ xdslb_policy->interested_parties()),
+ &xdslb_policy->lb_channel_connectivity_,
+ &xdslb_policy->lb_channel_on_connectivity_changed_, nullptr);
+ break;
+ }
+ // The LB channel may be IDLE because it's shut down before the update.
+ // Restart the LB call to kick the LB channel into gear.
+ case GRPC_CHANNEL_IDLE:
+ case GRPC_CHANNEL_READY:
+ xdslb_policy->lb_calld_.reset();
+ if (xdslb_policy->started_picking_) {
+ if (xdslb_policy->retry_timer_callback_pending_) {
+ grpc_timer_cancel(&xdslb_policy->lb_call_retry_timer_);
+ }
+ xdslb_policy->lb_call_backoff_.Reset();
+ xdslb_policy->StartBalancerCallLocked();
+ }
+ // Fall through.
+ case GRPC_CHANNEL_SHUTDOWN:
+ done:
+ xdslb_policy->watching_lb_channel_ = false;
+ xdslb_policy->Unref(DEBUG_LOCATION,
+ "watch_lb_channel_connectivity_cb_shutdown");
+ }
+}
+
+//
+// PendingPick
+//
+
+// Adds lb_token of selected subchannel (address) to the call's initial
+// metadata.
+grpc_error* AddLbTokenToInitialMetadata(
+ grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage,
+ grpc_metadata_batch* initial_metadata) {
+ GPR_ASSERT(lb_token_mdelem_storage != nullptr);
+ GPR_ASSERT(!GRPC_MDISNULL(lb_token));
+ return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
+ lb_token);
+}
+
+// Destroy function used when embedding client stats in call context.
+void DestroyClientStats(void* arg) {
+ static_cast<XdsLbClientStats*>(arg)->Unref();
+}
+
+void XdsLb::PendingPickSetMetadataAndContext(PendingPick* pp) {
+ /* if connected_subchannel is nullptr, no pick has been made by the
+ * child policy (e.g., all addresses failed to connect). There won't be any
+ * user_data/token available */
+ if (pp->pick->connected_subchannel != nullptr) {
+ if (GPR_LIKELY(!GRPC_MDISNULL(pp->lb_token))) {
+ AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token),
+ &pp->pick->lb_token_mdelem_storage,
+ pp->pick->initial_metadata);
+ } else {
+ gpr_log(GPR_ERROR,
+ "[xdslb %p] No LB token for connected subchannel pick %p",
+ pp->xdslb_policy, pp->pick);
+ abort();
+ }
+ // Pass on client stats via context. Passes ownership of the reference.
+ if (pp->client_stats != nullptr) {
+ pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value =
+ pp->client_stats.release();
+ pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].destroy =
+ DestroyClientStats;
+ }
+ } else {
+ pp->client_stats.reset();
+ }
+}
+
+/* The \a on_complete closure passed as part of the pick requires keeping a
+ * reference to its associated child policy instance. We wrap this closure in
+ * order to unref the child policy instance upon its invocation */
+void XdsLb::OnPendingPickComplete(void* arg, grpc_error* error) {
+ PendingPick* pp = static_cast<PendingPick*>(arg);
+ PendingPickSetMetadataAndContext(pp);
+ GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error));
+ Delete(pp);
+}
+
+XdsLb::PendingPick* XdsLb::PendingPickCreate(PickState* pick) {
+ PendingPick* pp = New<PendingPick>();
+ pp->xdslb_policy = this;
+ pp->pick = pick;
+ GRPC_CLOSURE_INIT(&pp->on_complete, &XdsLb::OnPendingPickComplete, pp,
+ grpc_schedule_on_exec_ctx);
+ pp->original_on_complete = pick->on_complete;
+ pick->on_complete = &pp->on_complete;
+ return pp;
+}
+
+void XdsLb::AddPendingPick(PendingPick* pp) {
+ pp->next = pending_picks_;
+ pending_picks_ = pp;
+}
+
+//
+// code for interacting with the child policy
+//
+
+// Performs a pick over \a child_policy_. Given that a pick can return
+// immediately (ignoring its completion callback), we need to perform the
+// cleanups this callback would otherwise be responsible for.
+// If \a force_async is true, then we will manually schedule the
+// completion callback even if the pick is available immediately.
+bool XdsLb::PickFromChildPolicyLocked(bool force_async, PendingPick* pp,
+ grpc_error** error) {
+ // Set client_stats and user_data.
+ if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) {
+ pp->client_stats = lb_calld_->client_stats()->Ref();
+ }
+ GPR_ASSERT(pp->pick->user_data == nullptr);
+ pp->pick->user_data = (void**)&pp->lb_token;
+ // Pick via the child policy.
+ bool pick_done = child_policy_->PickLocked(pp->pick, error);
+ if (pick_done) {
+ PendingPickSetMetadataAndContext(pp);
+ if (force_async) {
+ GRPC_CLOSURE_SCHED(pp->original_on_complete, *error);
+ *error = GRPC_ERROR_NONE;
+ pick_done = false;
+ }
+ Delete(pp);
+ }
+ // else, the pending pick will be registered and taken care of by the
+ // pending pick list inside the child policy. Eventually,
+ // OnPendingPickComplete() will be called, which will (among other
+ // things) add the LB token to the call's initial metadata.
+ return pick_done;
+}
+
+void XdsLb::CreateChildPolicyLocked(const Args& args) {
+ GPR_ASSERT(child_policy_ == nullptr);
+ child_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+ "round_robin", args);
+ if (GPR_UNLIKELY(child_policy_ == nullptr)) {
+ gpr_log(GPR_ERROR, "[xdslb %p] Failure creating a child policy", this);
+ return;
+ }
+ // TODO(roth): We currently track this ref manually. Once the new
+ // ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
+ auto self = Ref(DEBUG_LOCATION, "on_child_reresolution_requested");
+ self.release();
+ child_policy_->SetReresolutionClosureLocked(&on_child_request_reresolution_);
+ grpc_error* child_state_error = nullptr;
+ child_connectivity_state_ =
+ child_policy_->CheckConnectivityLocked(&child_state_error);
+ // Connectivity state is a function of the child policy updated/created.
+ UpdateConnectivityStateFromChildPolicyLocked(child_state_error);
+ // Add the xDS's interested_parties pollset_set to that of the newly created
+ // child policy. This will make the child policy progress upon activity on
+ // xDS LB, which in turn is tied to the application's call.
+ grpc_pollset_set_add_pollset_set(child_policy_->interested_parties(),
+ interested_parties());
+ // Subscribe to changes to the connectivity of the new child policy.
+ // TODO(roth): We currently track this ref manually. Once the new
+ // ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
+ self = Ref(DEBUG_LOCATION, "on_child_connectivity_changed");
+ self.release();
+ child_policy_->NotifyOnStateChangeLocked(&child_connectivity_state_,
+ &on_child_connectivity_changed_);
+ child_policy_->ExitIdleLocked();
+ // Send pending picks to child policy.
+ PendingPick* pp;
+ while ((pp = pending_picks_)) {
+ pending_picks_ = pp->next;
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(
+ GPR_INFO,
+ "[xdslb %p] Pending pick about to (async) PICK from child policy %p",
+ this, child_policy_.get());
+ }
+ grpc_error* error = GRPC_ERROR_NONE;
+ PickFromChildPolicyLocked(true /* force_async */, pp, &error);
+ }
+}
+
+grpc_channel_args* XdsLb::CreateChildPolicyArgsLocked() {
+ grpc_lb_addresses* addresses;
+ bool is_backend_from_grpclb_load_balancer = false;
+ // This should never be invoked if we do not have serverlist_, as fallback
+ // mode is disabled for xDS plugin.
+ GPR_ASSERT(serverlist_ != nullptr);
+ GPR_ASSERT(serverlist_->num_servers > 0);
+ addresses = ProcessServerlist(serverlist_);
+ is_backend_from_grpclb_load_balancer = true;
+ GPR_ASSERT(addresses != nullptr);
+ // Replace the LB addresses in the channel args that we pass down to
+ // the subchannel.
+ static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES};
+ const grpc_arg args_to_add[] = {
+ grpc_lb_addresses_create_channel_arg(addresses),
+ // A channel arg indicating if the target is a backend inferred from a
+ // grpclb load balancer.
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ADDRESS_IS_BACKEND_FROM_XDS_LOAD_BALANCER),
+ is_backend_from_grpclb_load_balancer),
+ };
+ grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove(
+ args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add,
+ GPR_ARRAY_SIZE(args_to_add));
+ grpc_lb_addresses_destroy(addresses);
+ return args;
+}
+
+void XdsLb::CreateOrUpdateChildPolicyLocked() {
+ if (shutting_down_) return;
+ grpc_channel_args* args = CreateChildPolicyArgsLocked();
+ GPR_ASSERT(args != nullptr);
+ if (child_policy_ != nullptr) {
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Updating the child policy %p", this,
+ child_policy_.get());
+ }
+ child_policy_->UpdateLocked(*args);
+ } else {
+ LoadBalancingPolicy::Args lb_policy_args;
+ lb_policy_args.combiner = combiner();
+ lb_policy_args.client_channel_factory = client_channel_factory();
+ lb_policy_args.args = args;
+ CreateChildPolicyLocked(lb_policy_args);
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO, "[xdslb %p] Created a new child policy %p", this,
+ child_policy_.get());
+ }
+ }
+ grpc_channel_args_destroy(args);
+}
+
+void XdsLb::OnChildPolicyRequestReresolutionLocked(void* arg,
+ grpc_error* error) {
+ XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
+ if (xdslb_policy->shutting_down_ || error != GRPC_ERROR_NONE) {
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_child_reresolution_requested");
+ return;
+ }
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Re-resolution requested from child policy "
+ "(%p).",
+ xdslb_policy, xdslb_policy->child_policy_.get());
+ }
+ // If we are talking to a balancer, we expect to get updated addresses form
+ // the balancer, so we can ignore the re-resolution request from the child
+ // policy.
+ // Otherwise, handle the re-resolution request using the xds policy's
+ // original re-resolution closure.
+ if (xdslb_policy->lb_calld_ == nullptr ||
+ !xdslb_policy->lb_calld_->seen_initial_response()) {
+ xdslb_policy->TryReresolutionLocked(&grpc_lb_xds_trace, GRPC_ERROR_NONE);
+ }
+ // Give back the wrapper closure to the child policy.
+ xdslb_policy->child_policy_->SetReresolutionClosureLocked(
+ &xdslb_policy->on_child_request_reresolution_);
+}
+
+void XdsLb::UpdateConnectivityStateFromChildPolicyLocked(
+ grpc_error* child_state_error) {
+ const grpc_connectivity_state curr_glb_state =
+ grpc_connectivity_state_check(&state_tracker_);
+ /* The new connectivity status is a function of the previous one and the new
+ * input coming from the status of the child policy.
+ *
+ * current state (xds's)
+ * |
+ * v || I | C | R | TF | SD | <- new state (child policy's)
+ * ===++====+=====+=====+======+======+
+ * I || I | C | R | [I] | [I] |
+ * ---++----+-----+-----+------+------+
+ * C || I | C | R | [C] | [C] |
+ * ---++----+-----+-----+------+------+
+ * R || I | C | R | [R] | [R] |
+ * ---++----+-----+-----+------+------+
+ * TF || I | C | R | [TF] | [TF] |
+ * ---++----+-----+-----+------+------+
+ * SD || NA | NA | NA | NA | NA | (*)
+ * ---++----+-----+-----+------+------+
+ *
+ * A [STATE] indicates that the old child policy is kept. In those cases,
+ * STATE is the current state of xds, which is left untouched.
+ *
+ * In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to
+ * the previous child policy instance.
+ *
+ * Note that the status is never updated to SHUTDOWN as a result of calling
+ * this function. Only glb_shutdown() has the power to set that state.
+ *
+ * (*) This function mustn't be called during shutting down. */
+ GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN);
+ switch (child_connectivity_state_) {
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ case GRPC_CHANNEL_SHUTDOWN:
+ GPR_ASSERT(child_state_error != GRPC_ERROR_NONE);
+ break;
+ case GRPC_CHANNEL_IDLE:
+ case GRPC_CHANNEL_CONNECTING:
+ case GRPC_CHANNEL_READY:
+ GPR_ASSERT(child_state_error == GRPC_ERROR_NONE);
+ }
+ if (grpc_lb_xds_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "[xdslb %p] Setting xds's state to %s from child policy %p state.",
+ this, grpc_connectivity_state_name(child_connectivity_state_),
+ child_policy_.get());
+ }
+ grpc_connectivity_state_set(&state_tracker_, child_connectivity_state_,
+ child_state_error,
+ "update_lb_connectivity_status_locked");
+}
+
+void XdsLb::OnChildPolicyConnectivityChangedLocked(void* arg,
+ grpc_error* error) {
+ XdsLb* xdslb_policy = static_cast<XdsLb*>(arg);
+ if (xdslb_policy->shutting_down_) {
+ xdslb_policy->Unref(DEBUG_LOCATION, "on_child_connectivity_changed");
+ return;
+ }
+ xdslb_policy->UpdateConnectivityStateFromChildPolicyLocked(
+ GRPC_ERROR_REF(error));
+ // Resubscribe. Reuse the "on_child_connectivity_changed" ref.
+ xdslb_policy->child_policy_->NotifyOnStateChangeLocked(
+ &xdslb_policy->child_connectivity_state_,
+ &xdslb_policy->on_child_connectivity_changed_);
+}
+
+//
+// factory
+//
+
+class XdsFactory : public LoadBalancingPolicyFactory {
+ public:
+ OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+ const LoadBalancingPolicy::Args& args) const override {
+ /* Count the number of gRPC-LB addresses. There must be at least one. */
+ const grpc_arg* arg =
+ grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES);
+ if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
+ return nullptr;
+ }
+ grpc_lb_addresses* addresses =
+ static_cast<grpc_lb_addresses*>(arg->value.pointer.p);
+ size_t num_grpclb_addrs = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
+ }
+ if (num_grpclb_addrs == 0) return nullptr;
+ return OrphanablePtr<LoadBalancingPolicy>(New<XdsLb>(addresses, args));
+ }
+
+ const char* name() const override { return "xds"; }
+};
+
+} // namespace
+
+} // namespace grpc_core
+
+//
+// Plugin registration
+//
+
+void grpc_lb_policy_xds_init() {
+ grpc_core::LoadBalancingPolicyRegistry::Builder::
+ RegisterLoadBalancingPolicyFactory(
+ grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
+ grpc_core::New<grpc_core::XdsFactory>()));
+}
+
+void grpc_lb_policy_xds_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds.h
new file mode 100644
index 0000000000..8b20680f2d
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H
+
+#include <grpc/support/port_platform.h>
+
+/** Channel arg indicating if a target corresponding to the address is grpclb
+ * loadbalancer. The type of this arg is an integer and the value is treated as
+ * a bool. */
+#define GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER \
+ "grpc.address_is_xds_load_balancer"
+/** Channel arg indicating if a target corresponding to the address is a backend
+ * received from a balancer. The type of this arg is an integer and the value is
+ * treated as a bool. */
+#define GRPC_ARG_ADDRESS_IS_BACKEND_FROM_XDS_LOAD_BALANCER \
+ "grpc.address_is_backend_from_xds_load_balancer"
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_H \
+ */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
index 2ba2f0a63b..0aa145a24e 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.h
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015 gRPC authors.
+ * 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.
@@ -16,20 +16,11 @@
*
*/
-#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
-#define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
-
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/port.h"
-
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request);
-
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-void* grpc_fd_get_polling_island(grpc_fd* fd);
-void* grpc_pollset_get_polling_island(grpc_pollset* ps);
-bool grpc_are_polling_islands_equal(void* p, void* q);
-#endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
-#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */
+grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
+ grpc_channel_args* args) {
+ return args;
+}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
new file mode 100644
index 0000000000..32c4acc8a3
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+
+/// Makes any necessary modifications to \a args for use in the xds
+/// balancer channel.
+///
+/// Takes ownership of \a args.
+///
+/// Caller takes ownership of the returned args.
+grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
+ grpc_channel_args* args);
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CHANNEL_H \
+ */
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
new file mode 100644
index 0000000000..5ab72efce4
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
@@ -0,0 +1,107 @@
+/*
+ *
+ * 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/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <string.h>
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+namespace grpc_core {
+namespace {
+
+int BalancerNameCmp(const grpc_core::UniquePtr<char>& a,
+ const grpc_core::UniquePtr<char>& b) {
+ return strcmp(a.get(), b.get());
+}
+
+RefCountedPtr<TargetAuthorityTable> CreateTargetAuthorityTable(
+ grpc_lb_addresses* addresses) {
+ TargetAuthorityTable::Entry* target_authority_entries =
+ static_cast<TargetAuthorityTable::Entry*>(gpr_zalloc(
+ sizeof(*target_authority_entries) * addresses->num_addresses));
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ char* addr_str;
+ GPR_ASSERT(grpc_sockaddr_to_string(
+ &addr_str, &addresses->addresses[i].address, true) > 0);
+ target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str);
+ target_authority_entries[i].value.reset(
+ gpr_strdup(addresses->addresses[i].balancer_name));
+ gpr_free(addr_str);
+ }
+ RefCountedPtr<TargetAuthorityTable> target_authority_table =
+ TargetAuthorityTable::Create(addresses->num_addresses,
+ target_authority_entries, BalancerNameCmp);
+ gpr_free(target_authority_entries);
+ return target_authority_table;
+}
+
+} // namespace
+} // namespace grpc_core
+
+grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
+ grpc_channel_args* args) {
+ const char* args_to_remove[1];
+ size_t num_args_to_remove = 0;
+ grpc_arg args_to_add[2];
+ size_t num_args_to_add = 0;
+ // Add arg for targets info table.
+ const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES);
+ GPR_ASSERT(arg != nullptr);
+ GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
+ grpc_lb_addresses* addresses =
+ static_cast<grpc_lb_addresses*>(arg->value.pointer.p);
+ grpc_core::RefCountedPtr<grpc_core::TargetAuthorityTable>
+ target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses);
+ args_to_add[num_args_to_add++] =
+ grpc_core::CreateTargetAuthorityTableChannelArg(
+ target_authority_table.get());
+ // Substitute the channel credentials with a version without call
+ // credentials: the load balancer is not necessarily trusted to handle
+ // bearer token credentials.
+ grpc_channel_credentials* channel_credentials =
+ grpc_channel_credentials_find_in_args(args);
+ grpc_channel_credentials* creds_sans_call_creds = nullptr;
+ if (channel_credentials != nullptr) {
+ creds_sans_call_creds =
+ grpc_channel_credentials_duplicate_without_call_credentials(
+ channel_credentials);
+ GPR_ASSERT(creds_sans_call_creds != nullptr);
+ args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
+ args_to_add[num_args_to_add++] =
+ grpc_channel_credentials_to_arg(creds_sans_call_creds);
+ }
+ grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
+ args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
+ // Clean up.
+ grpc_channel_args_destroy(args);
+ if (creds_sans_call_creds != nullptr) {
+ grpc_channel_credentials_unref(creds_sans_call_creds);
+ }
+ return result;
+}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
new file mode 100644
index 0000000000..cdf5408be3
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+
+#include <grpc/support/atm.h>
+#include <grpc/support/string_util.h>
+#include <string.h>
+
+namespace grpc_core {
+
+void XdsLbClientStats::AddCallStarted() {
+ gpr_atm_full_fetch_add(&num_calls_started_, (gpr_atm)1);
+}
+
+void XdsLbClientStats::AddCallFinished(bool finished_with_client_failed_to_send,
+ bool finished_known_received) {
+ gpr_atm_full_fetch_add(&num_calls_finished_, (gpr_atm)1);
+ if (finished_with_client_failed_to_send) {
+ gpr_atm_full_fetch_add(&num_calls_finished_with_client_failed_to_send_,
+ (gpr_atm)1);
+ }
+ if (finished_known_received) {
+ gpr_atm_full_fetch_add(&num_calls_finished_known_received_, (gpr_atm)1);
+ }
+}
+
+void XdsLbClientStats::AddCallDroppedLocked(char* token) {
+ // Increment num_calls_started and num_calls_finished.
+ gpr_atm_full_fetch_add(&num_calls_started_, (gpr_atm)1);
+ gpr_atm_full_fetch_add(&num_calls_finished_, (gpr_atm)1);
+ // Record the drop.
+ if (drop_token_counts_ == nullptr) {
+ drop_token_counts_.reset(New<DroppedCallCounts>());
+ }
+ for (size_t i = 0; i < drop_token_counts_->size(); ++i) {
+ if (strcmp((*drop_token_counts_)[i].token.get(), token) == 0) {
+ ++(*drop_token_counts_)[i].count;
+ return;
+ }
+ }
+ // Not found, so add a new entry.
+ drop_token_counts_->emplace_back(UniquePtr<char>(gpr_strdup(token)), 1);
+}
+
+namespace {
+
+void AtomicGetAndResetCounter(int64_t* value, gpr_atm* counter) {
+ *value = static_cast<int64_t>(gpr_atm_full_xchg(counter, (gpr_atm)0));
+}
+
+} // namespace
+
+void XdsLbClientStats::GetLocked(
+ int64_t* num_calls_started, int64_t* num_calls_finished,
+ int64_t* num_calls_finished_with_client_failed_to_send,
+ int64_t* num_calls_finished_known_received,
+ UniquePtr<DroppedCallCounts>* drop_token_counts) {
+ AtomicGetAndResetCounter(num_calls_started, &num_calls_started_);
+ AtomicGetAndResetCounter(num_calls_finished, &num_calls_finished_);
+ AtomicGetAndResetCounter(num_calls_finished_with_client_failed_to_send,
+ &num_calls_finished_with_client_failed_to_send_);
+ AtomicGetAndResetCounter(num_calls_finished_known_received,
+ &num_calls_finished_known_received_);
+ *drop_token_counts = std::move(drop_token_counts_);
+}
+
+} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
new file mode 100644
index 0000000000..fa0b9f4b63
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/atm.h>
+
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+
+namespace grpc_core {
+
+class XdsLbClientStats : public RefCounted<XdsLbClientStats> {
+ public:
+ struct DropTokenCount {
+ UniquePtr<char> token;
+ int64_t count;
+
+ DropTokenCount(UniquePtr<char> token, int64_t count)
+ : token(std::move(token)), count(count) {}
+ };
+
+ typedef InlinedVector<DropTokenCount, 10> DroppedCallCounts;
+
+ XdsLbClientStats() {}
+
+ void AddCallStarted();
+ void AddCallFinished(bool finished_with_client_failed_to_send,
+ bool finished_known_received);
+
+ // This method is not thread-safe; caller must synchronize.
+ void AddCallDroppedLocked(char* token);
+
+ // This method is not thread-safe; caller must synchronize.
+ void GetLocked(int64_t* num_calls_started, int64_t* num_calls_finished,
+ int64_t* num_calls_finished_with_client_failed_to_send,
+ int64_t* num_calls_finished_known_received,
+ UniquePtr<DroppedCallCounts>* drop_token_counts);
+
+ private:
+ // This field must only be accessed via *_locked() methods.
+ UniquePtr<DroppedCallCounts> drop_token_counts_;
+ // These fields may be accessed from multiple threads at a time.
+ gpr_atm num_calls_started_ = 0;
+ gpr_atm num_calls_finished_ = 0;
+ gpr_atm num_calls_finished_with_client_failed_to_send_ = 0;
+ gpr_atm num_calls_finished_known_received_ = 0;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_CLIENT_STATS_H \
+ */
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
new file mode 100644
index 0000000000..79b7bdbe33
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
@@ -0,0 +1,307 @@
+/*
+ *
+ * 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 "pb_decode.h"
+#include "pb_encode.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+
+#include <grpc/support/alloc.h>
+
+/* invoked once for every Server in ServerList */
+static bool count_serverlist(pb_istream_t* stream, const pb_field_t* field,
+ void** arg) {
+ xds_grpclb_serverlist* sl = static_cast<xds_grpclb_serverlist*>(*arg);
+ xds_grpclb_server server;
+ if (GPR_UNLIKELY(!pb_decode(stream, grpc_lb_v1_Server_fields, &server))) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
+ return false;
+ }
+ ++sl->num_servers;
+ return true;
+}
+
+typedef struct decode_serverlist_arg {
+ /* The decoding callback is invoked once per server in serverlist. Remember
+ * which index of the serverlist are we currently decoding */
+ size_t decoding_idx;
+ /* The decoded serverlist */
+ xds_grpclb_serverlist* serverlist;
+} decode_serverlist_arg;
+
+/* invoked once for every Server in ServerList */
+static bool decode_serverlist(pb_istream_t* stream, const pb_field_t* field,
+ void** arg) {
+ decode_serverlist_arg* dec_arg = static_cast<decode_serverlist_arg*>(*arg);
+ GPR_ASSERT(dec_arg->serverlist->num_servers >= dec_arg->decoding_idx);
+ xds_grpclb_server* server =
+ static_cast<xds_grpclb_server*>(gpr_zalloc(sizeof(xds_grpclb_server)));
+ if (GPR_UNLIKELY(!pb_decode(stream, grpc_lb_v1_Server_fields, server))) {
+ gpr_free(server);
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
+ return false;
+ }
+ dec_arg->serverlist->servers[dec_arg->decoding_idx++] = server;
+ return true;
+}
+
+xds_grpclb_request* xds_grpclb_request_create(const char* lb_service_name) {
+ xds_grpclb_request* req =
+ static_cast<xds_grpclb_request*>(gpr_malloc(sizeof(xds_grpclb_request)));
+ req->has_client_stats = false;
+ req->has_initial_request = true;
+ req->initial_request.has_name = true;
+ strncpy(req->initial_request.name, lb_service_name,
+ XDS_SERVICE_NAME_MAX_LENGTH);
+ return req;
+}
+
+static void populate_timestamp(gpr_timespec timestamp,
+ xds_grpclb_timestamp* timestamp_pb) {
+ timestamp_pb->has_seconds = true;
+ timestamp_pb->seconds = timestamp.tv_sec;
+ timestamp_pb->has_nanos = true;
+ timestamp_pb->nanos = timestamp.tv_nsec;
+}
+
+static bool encode_string(pb_ostream_t* stream, const pb_field_t* field,
+ void* const* arg) {
+ char* str = static_cast<char*>(*arg);
+ if (!pb_encode_tag_for_field(stream, field)) return false;
+ return pb_encode_string(stream, reinterpret_cast<uint8_t*>(str), strlen(str));
+}
+
+static bool encode_drops(pb_ostream_t* stream, const pb_field_t* field,
+ void* const* arg) {
+ grpc_core::XdsLbClientStats::DroppedCallCounts* drop_entries =
+ static_cast<grpc_core::XdsLbClientStats::DroppedCallCounts*>(*arg);
+ if (drop_entries == nullptr) return true;
+ for (size_t i = 0; i < drop_entries->size(); ++i) {
+ if (!pb_encode_tag_for_field(stream, field)) return false;
+ grpc_lb_v1_ClientStatsPerToken drop_message;
+ drop_message.load_balance_token.funcs.encode = encode_string;
+ drop_message.load_balance_token.arg = (*drop_entries)[i].token.get();
+ drop_message.has_num_calls = true;
+ drop_message.num_calls = (*drop_entries)[i].count;
+ if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields,
+ &drop_message)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+xds_grpclb_request* xds_grpclb_load_report_request_create_locked(
+ grpc_core::XdsLbClientStats* client_stats) {
+ xds_grpclb_request* req =
+ static_cast<xds_grpclb_request*>(gpr_zalloc(sizeof(xds_grpclb_request)));
+ req->has_client_stats = true;
+ req->client_stats.has_timestamp = true;
+ populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp);
+ req->client_stats.has_num_calls_started = true;
+ req->client_stats.has_num_calls_finished = true;
+ req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
+ req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
+ req->client_stats.has_num_calls_finished_known_received = true;
+ req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops;
+ grpc_core::UniquePtr<grpc_core::XdsLbClientStats::DroppedCallCounts>
+ drop_counts;
+ client_stats->GetLocked(
+ &req->client_stats.num_calls_started,
+ &req->client_stats.num_calls_finished,
+ &req->client_stats.num_calls_finished_with_client_failed_to_send,
+ &req->client_stats.num_calls_finished_known_received, &drop_counts);
+ // Will be deleted in xds_grpclb_request_destroy().
+ req->client_stats.calls_finished_with_drop.arg = drop_counts.release();
+ return req;
+}
+
+grpc_slice xds_grpclb_request_encode(const xds_grpclb_request* request) {
+ size_t encoded_length;
+ pb_ostream_t sizestream;
+ pb_ostream_t outputstream;
+ grpc_slice slice;
+ memset(&sizestream, 0, sizeof(pb_ostream_t));
+ pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request);
+ encoded_length = sizestream.bytes_written;
+
+ slice = GRPC_SLICE_MALLOC(encoded_length);
+ outputstream =
+ pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length);
+ GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields,
+ request) != 0);
+ return slice;
+}
+
+void xds_grpclb_request_destroy(xds_grpclb_request* request) {
+ if (request->has_client_stats) {
+ grpc_core::XdsLbClientStats::DroppedCallCounts* drop_entries =
+ static_cast<grpc_core::XdsLbClientStats::DroppedCallCounts*>(
+ request->client_stats.calls_finished_with_drop.arg);
+ grpc_core::Delete(drop_entries);
+ }
+ gpr_free(request);
+}
+
+typedef grpc_lb_v1_LoadBalanceResponse xds_grpclb_response;
+xds_grpclb_initial_response* xds_grpclb_initial_response_parse(
+ grpc_slice encoded_xds_grpclb_response) {
+ pb_istream_t stream =
+ pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_xds_grpclb_response),
+ GRPC_SLICE_LENGTH(encoded_xds_grpclb_response));
+ xds_grpclb_response res;
+ memset(&res, 0, sizeof(xds_grpclb_response));
+ if (GPR_UNLIKELY(
+ !pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res))) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+ return nullptr;
+ }
+
+ if (!res.has_initial_response) return nullptr;
+
+ xds_grpclb_initial_response* initial_res =
+ static_cast<xds_grpclb_initial_response*>(
+ gpr_malloc(sizeof(xds_grpclb_initial_response)));
+ memcpy(initial_res, &res.initial_response,
+ sizeof(xds_grpclb_initial_response));
+
+ return initial_res;
+}
+
+xds_grpclb_serverlist* xds_grpclb_response_parse_serverlist(
+ grpc_slice encoded_xds_grpclb_response) {
+ pb_istream_t stream =
+ pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_xds_grpclb_response),
+ GRPC_SLICE_LENGTH(encoded_xds_grpclb_response));
+ pb_istream_t stream_at_start = stream;
+ xds_grpclb_serverlist* sl = static_cast<xds_grpclb_serverlist*>(
+ gpr_zalloc(sizeof(xds_grpclb_serverlist)));
+ xds_grpclb_response res;
+ memset(&res, 0, sizeof(xds_grpclb_response));
+ // First pass: count number of servers.
+ res.server_list.servers.funcs.decode = count_serverlist;
+ res.server_list.servers.arg = sl;
+ bool status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res);
+ if (GPR_UNLIKELY(!status)) {
+ gpr_free(sl);
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+ return nullptr;
+ }
+ // Second pass: populate servers.
+ if (sl->num_servers > 0) {
+ sl->servers = static_cast<xds_grpclb_server**>(
+ gpr_zalloc(sizeof(xds_grpclb_server*) * sl->num_servers));
+ decode_serverlist_arg decode_arg;
+ memset(&decode_arg, 0, sizeof(decode_arg));
+ decode_arg.serverlist = sl;
+ res.server_list.servers.funcs.decode = decode_serverlist;
+ res.server_list.servers.arg = &decode_arg;
+ status = pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields,
+ &res);
+ if (GPR_UNLIKELY(!status)) {
+ xds_grpclb_destroy_serverlist(sl);
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+ return nullptr;
+ }
+ }
+ return sl;
+}
+
+void xds_grpclb_destroy_serverlist(xds_grpclb_serverlist* serverlist) {
+ if (serverlist == nullptr) {
+ return;
+ }
+ for (size_t i = 0; i < serverlist->num_servers; i++) {
+ gpr_free(serverlist->servers[i]);
+ }
+ gpr_free(serverlist->servers);
+ gpr_free(serverlist);
+}
+
+xds_grpclb_serverlist* xds_grpclb_serverlist_copy(
+ const xds_grpclb_serverlist* sl) {
+ xds_grpclb_serverlist* copy = static_cast<xds_grpclb_serverlist*>(
+ gpr_zalloc(sizeof(xds_grpclb_serverlist)));
+ copy->num_servers = sl->num_servers;
+ copy->servers = static_cast<xds_grpclb_server**>(
+ gpr_malloc(sizeof(xds_grpclb_server*) * sl->num_servers));
+ for (size_t i = 0; i < sl->num_servers; i++) {
+ copy->servers[i] =
+ static_cast<xds_grpclb_server*>(gpr_malloc(sizeof(xds_grpclb_server)));
+ memcpy(copy->servers[i], sl->servers[i], sizeof(xds_grpclb_server));
+ }
+ return copy;
+}
+
+bool xds_grpclb_serverlist_equals(const xds_grpclb_serverlist* lhs,
+ const xds_grpclb_serverlist* rhs) {
+ if (lhs == nullptr || rhs == nullptr) {
+ return false;
+ }
+ if (lhs->num_servers != rhs->num_servers) {
+ return false;
+ }
+ for (size_t i = 0; i < lhs->num_servers; i++) {
+ if (!xds_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool xds_grpclb_server_equals(const xds_grpclb_server* lhs,
+ const xds_grpclb_server* rhs) {
+ return memcmp(lhs, rhs, sizeof(xds_grpclb_server)) == 0;
+}
+
+int xds_grpclb_duration_compare(const xds_grpclb_duration* lhs,
+ const xds_grpclb_duration* rhs) {
+ GPR_ASSERT(lhs && rhs);
+ if (lhs->has_seconds && rhs->has_seconds) {
+ if (lhs->seconds < rhs->seconds) return -1;
+ if (lhs->seconds > rhs->seconds) return 1;
+ } else if (lhs->has_seconds) {
+ return 1;
+ } else if (rhs->has_seconds) {
+ return -1;
+ }
+
+ GPR_ASSERT(lhs->seconds == rhs->seconds);
+ if (lhs->has_nanos && rhs->has_nanos) {
+ if (lhs->nanos < rhs->nanos) return -1;
+ if (lhs->nanos > rhs->nanos) return 1;
+ } else if (lhs->has_nanos) {
+ return 1;
+ } else if (rhs->has_nanos) {
+ return -1;
+ }
+
+ return 0;
+}
+
+grpc_millis xds_grpclb_duration_to_millis(xds_grpclb_duration* duration_pb) {
+ return static_cast<grpc_millis>(
+ (duration_pb->has_seconds ? duration_pb->seconds : 0) * GPR_MS_PER_SEC +
+ (duration_pb->has_nanos ? duration_pb->nanos : 0) / GPR_NS_PER_MS);
+}
+
+void xds_grpclb_initial_response_destroy(
+ xds_grpclb_initial_response* response) {
+ gpr_free(response);
+}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
new file mode 100644
index 0000000000..9d08defa7e
--- /dev/null
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/slice_buffer.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+
+#define XDS_SERVICE_NAME_MAX_LENGTH 128
+
+typedef grpc_lb_v1_Server_ip_address_t xds_grpclb_ip_address;
+typedef grpc_lb_v1_LoadBalanceRequest xds_grpclb_request;
+typedef grpc_lb_v1_InitialLoadBalanceResponse xds_grpclb_initial_response;
+typedef grpc_lb_v1_Server xds_grpclb_server;
+typedef google_protobuf_Duration xds_grpclb_duration;
+typedef google_protobuf_Timestamp xds_grpclb_timestamp;
+
+typedef struct {
+ xds_grpclb_server** servers;
+ size_t num_servers;
+} xds_grpclb_serverlist;
+
+/** Create a request for a gRPC LB service under \a lb_service_name */
+xds_grpclb_request* xds_grpclb_request_create(const char* lb_service_name);
+xds_grpclb_request* xds_grpclb_load_report_request_create_locked(
+ grpc_core::XdsLbClientStats* client_stats);
+
+/** Protocol Buffers v3-encode \a request */
+grpc_slice xds_grpclb_request_encode(const xds_grpclb_request* request);
+
+/** Destroy \a request */
+void xds_grpclb_request_destroy(xds_grpclb_request* request);
+
+/** Parse (ie, decode) the bytes in \a encoded_xds_grpclb_response as a \a
+ * xds_grpclb_initial_response */
+xds_grpclb_initial_response* xds_grpclb_initial_response_parse(
+ grpc_slice encoded_xds_grpclb_response);
+
+/** Parse the list of servers from an encoded \a xds_grpclb_response */
+xds_grpclb_serverlist* xds_grpclb_response_parse_serverlist(
+ grpc_slice encoded_xds_grpclb_response);
+
+/** Return a copy of \a sl. The caller is responsible for calling \a
+ * xds_grpclb_destroy_serverlist on the returned copy. */
+xds_grpclb_serverlist* xds_grpclb_serverlist_copy(
+ const xds_grpclb_serverlist* sl);
+
+bool xds_grpclb_serverlist_equals(const xds_grpclb_serverlist* lhs,
+ const xds_grpclb_serverlist* rhs);
+
+bool xds_grpclb_server_equals(const xds_grpclb_server* lhs,
+ const xds_grpclb_server* rhs);
+
+/** Destroy \a serverlist */
+void xds_grpclb_destroy_serverlist(xds_grpclb_serverlist* serverlist);
+
+/** Compare \a lhs against \a rhs and return 0 if \a lhs and \a rhs are equal,
+ * < 0 if \a lhs represents a duration shorter than \a rhs and > 0 otherwise */
+int xds_grpclb_duration_compare(const xds_grpclb_duration* lhs,
+ const xds_grpclb_duration* rhs);
+
+grpc_millis xds_grpclb_duration_to_millis(xds_grpclb_duration* duration_pb);
+
+/** Destroy \a initial_response */
+void xds_grpclb_initial_response_destroy(xds_grpclb_initial_response* response);
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H \
+ */
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 c07792d8a7..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
@@ -70,16 +70,14 @@ grpc_lb_addresses* grpc_lb_addresses_create(
grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses);
/** Sets the value of the address at index \a index of \a addresses.
- * \a address is a socket address of length \a address_len.
- * Takes ownership of \a balancer_name. */
+ * \a address is a socket address of length \a address_len. */
void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index,
const void* address, size_t address_len,
bool is_balancer, const char* balancer_name,
void* user_data);
/** Sets the value of the address at index \a index of \a addresses from \a uri.
- * Returns true upon success, false otherwise. Takes ownership of \a
- * balancer_name. */
+ * Returns true upon success, false otherwise. */
bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses,
size_t index, const grpc_uri* uri,
bool is_balancer,
diff --git a/src/core/ext/filters/client_channel/parse_address.cc b/src/core/ext/filters/client_channel/parse_address.cc
index b3900114ad..707beb8876 100644
--- a/src/core/ext/filters/client_channel/parse_address.cc
+++ b/src/core/ext/filters/client_channel/parse_address.cc
@@ -125,27 +125,41 @@ bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
char* host_end = static_cast<char*>(gpr_memrchr(host, '%', strlen(host)));
if (host_end != nullptr) {
GPR_ASSERT(host_end >= host);
- char host_without_scope[GRPC_INET6_ADDRSTRLEN];
+ char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
size_t host_without_scope_len = static_cast<size_t>(host_end - host);
uint32_t sin6_scope_id = 0;
+ if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
+ if (log_errors) {
+ gpr_log(
+ GPR_ERROR,
+ "invalid ipv6 address length %zu. Length cannot be greater than "
+ "GRPC_INET6_ADDRSTRLEN i.e %d)",
+ host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
+ }
+ goto done;
+ }
strncpy(host_without_scope, host, host_without_scope_len);
host_without_scope[host_without_scope_len] = '\0';
if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
0) {
- gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
+ if (log_errors) {
+ gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
+ }
goto done;
}
if (gpr_parse_bytes_to_uint32(host_end + 1,
strlen(host) - host_without_scope_len - 1,
&sin6_scope_id) == 0) {
- gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
+ if (log_errors) {
+ gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
+ }
goto done;
}
// Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
in6->sin6_scope_id = sin6_scope_id;
} else {
if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) {
- gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
+ if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
goto done;
}
}
@@ -190,3 +204,12 @@ bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
return false;
}
+
+uint16_t grpc_strhtons(const char* port) {
+ if (strcmp(port, "http") == 0) {
+ return htons(80);
+ } else if (strcmp(port, "https") == 0) {
+ return htons(443);
+ }
+ return htons(static_cast<unsigned short>(atoi(port)));
+}
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index 9a88b66edc..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. */
@@ -47,4 +47,7 @@ bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
bool log_errors);
+/* Converts named or numeric port to a uint16 suitable for use in a sockaddr. */
+uint16_t grpc_strhtons(const char* port);
+
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */
diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
index 48f2e89095..e9acbb7c41 100644
--- a/src/core/ext/filters/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -81,18 +81,7 @@ class Resolver : public InternallyRefCountedWithTracing<Resolver> {
///
/// If this causes new data to become available, then the currently
/// pending call to \a NextLocked() will return the new result.
- ///
- /// Note: Currently, all resolvers are required to return a new result
- /// shortly after this method is called. For pull-based mechanisms, if
- /// the implementation decides to delay querying the name service, it
- /// should immediately return a new copy of the previously returned
- /// result (and it can then return the updated data later, when it
- /// actually does query the name service). For push-based mechanisms,
- /// the implementation should immediately return a new copy of the
- /// last-seen result.
- /// TODO(roth): Remove this requirement once we fix pick_first to not
- /// throw away unselected subchannels.
- virtual void RequestReresolutionLocked() GRPC_ABSTRACT;
+ virtual void RequestReresolutionLocked() {}
/// Resets the re-resolution backoff, if any.
/// This needs to be implemented only by pull-based implementations;
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index f2bb5f3c71..9562a3f893 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -120,6 +120,8 @@ class AresDnsResolver : public Resolver {
grpc_lb_addresses* lb_addresses_ = nullptr;
/// currently resolving service config
char* service_config_json_ = nullptr;
+ // has shutdown been initiated
+ bool shutdown_initiated_ = false;
};
AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
@@ -197,11 +199,12 @@ void AresDnsResolver::ResetBackoffLocked() {
}
void AresDnsResolver::ShutdownLocked() {
+ shutdown_initiated_ = true;
if (have_next_resolution_timer_) {
grpc_timer_cancel(&next_resolution_timer_);
}
if (pending_request_ != nullptr) {
- grpc_cancel_ares_request(pending_request_);
+ grpc_cancel_ares_request_locked(pending_request_);
}
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
@@ -213,9 +216,13 @@ void AresDnsResolver::ShutdownLocked() {
void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
+ GRPC_CARES_TRACE_LOG(
+ "%p re-resolution timer fired. error: %s. shutdown_initiated_: %d", r,
+ grpc_error_string(error), r->shutdown_initiated_);
r->have_next_resolution_timer_ = false;
- if (error == GRPC_ERROR_NONE) {
+ if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) {
if (!r->resolving_) {
+ GRPC_CARES_TRACE_LOG("%p start resolving due to re-resolution timer", r);
r->StartResolvingLocked();
}
}
@@ -298,6 +305,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
grpc_channel_args* result = nullptr;
GPR_ASSERT(r->resolving_);
r->resolving_ = false;
+ gpr_free(r->pending_request_);
r->pending_request_ = nullptr;
if (r->lb_addresses_ != nullptr) {
static const char* args_to_remove[2];
@@ -339,7 +347,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
// Reset backoff state so that we start from the beginning when the
// next request gets triggered.
r->backoff_.Reset();
- } else {
+ } else if (!r->shutdown_initiated_) {
const char* msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
grpc_millis next_try = r->backoff_.NextAttemptTime();
@@ -373,13 +381,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
void AresDnsResolver::MaybeStartResolvingLocked() {
// If there is an existing timer, the time it fires is the earliest time we
// can start the next resolution.
- if (have_next_resolution_timer_) {
- // TODO(dgq): remove the following two lines once Pick First stops
- // discarding subchannels after selecting.
- ++resolved_version_;
- MaybeFinishNextLocked();
- return;
- }
+ if (have_next_resolution_timer_) return;
if (last_resolution_timestamp_ >= 0) {
const grpc_millis earliest_next_resolution =
last_resolution_timestamp_ + min_time_between_resolutions_;
@@ -401,10 +403,6 @@ void AresDnsResolver::MaybeStartResolvingLocked() {
self.release();
grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
&on_next_resolution_);
- // TODO(dgq): remove the following two lines once Pick First stops
- // discarding subchannels after selecting.
- ++resolved_version_;
- MaybeFinishNextLocked();
return;
}
}
@@ -483,7 +481,9 @@ void grpc_resolver_dns_ares_init() {
GRPC_LOG_IF_ERROR("ares_library_init() failed", error);
return;
}
- default_resolver = grpc_resolve_address_impl;
+ if (default_resolver == nullptr) {
+ default_resolver = grpc_resolve_address_impl;
+ }
grpc_set_resolver_impl(&ares_resolver);
grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
grpc_core::UniquePtr<grpc_core::ResolverFactory>(
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index 485998f5e4..582e2203fc 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -87,15 +87,6 @@ typedef struct grpc_ares_hostbyname_request {
static void do_basic_init(void) { gpr_mu_init(&g_init_mu); }
-static uint16_t strhtons(const char* port) {
- if (strcmp(port, "http") == 0) {
- return htons(80);
- } else if (strcmp(port, "https") == 0) {
- return htons(443);
- }
- return htons(static_cast<unsigned short>(atoi(port)));
-}
-
static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
const char* input_output_str) {
for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
@@ -139,12 +130,6 @@ void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) {
}
}
-/* Allow tests to access grpc_ares_wrapper_address_sorting_sort */
-void grpc_cares_wrapper_test_only_address_sorting_sort(
- grpc_lb_addresses* lb_addrs) {
- grpc_cares_wrapper_address_sorting_sort(lb_addrs);
-}
-
static void grpc_ares_request_ref_locked(grpc_ares_request* r) {
r->pending_queries++;
}
@@ -159,12 +144,12 @@ static void grpc_ares_request_unref_locked(grpc_ares_request* r) {
void grpc_ares_complete_request_locked(grpc_ares_request* r) {
/* Invoke on_done callback and destroy the
request */
+ r->ev_driver = nullptr;
grpc_lb_addresses* lb_addrs = *(r->lb_addrs_out);
if (lb_addrs != nullptr) {
grpc_cares_wrapper_address_sorting_sort(lb_addrs);
}
GRPC_CLOSURE_SCHED(r->on_done, r->error);
- gpr_free(r);
}
static grpc_ares_hostbyname_request* create_hostbyname_request_locked(
@@ -371,14 +356,12 @@ done:
grpc_ares_request_unref_locked(r);
}
-static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
- const char* dns_server, const char* name, const char* default_port,
- grpc_pollset_set* interested_parties, grpc_closure* on_done,
- grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
- grpc_combiner* combiner) {
+void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
+ grpc_ares_request* r, const char* dns_server, const char* name,
+ const char* default_port, grpc_pollset_set* interested_parties,
+ bool check_grpclb, grpc_combiner* combiner) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_ares_hostbyname_request* hr = nullptr;
- grpc_ares_request* r = nullptr;
ares_channel* channel = nullptr;
/* TODO(zyc): Enable tracing after #9603 is checked in */
/* if (grpc_dns_trace) {
@@ -404,14 +387,6 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
}
port = gpr_strdup(default_port);
}
- r = static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
- r->ev_driver = nullptr;
- r->on_done = on_done;
- r->lb_addrs_out = addrs;
- r->service_config_json_out = service_config_json;
- r->success = false;
- r->error = GRPC_ERROR_NONE;
- r->pending_queries = 0;
error = grpc_ares_ev_driver_create_locked(&r->ev_driver, interested_parties,
combiner, r);
if (error != GRPC_ERROR_NONE) goto error_cleanup;
@@ -454,12 +429,12 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
}
r->pending_queries = 1;
if (grpc_ares_query_ipv6()) {
- hr = create_hostbyname_request_locked(r, host, strhtons(port),
+ hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port),
false /* is_balancer */);
ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_locked,
hr);
}
- hr = create_hostbyname_request_locked(r, host, strhtons(port),
+ hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port),
false /* is_balancer */);
ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_locked,
hr);
@@ -472,7 +447,7 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
on_srv_query_done_locked, r);
gpr_free(service_name);
}
- if (service_config_json != nullptr) {
+ if (r->service_config_json_out != nullptr) {
grpc_ares_request_ref_locked(r);
char* config_name;
gpr_asprintf(&config_name, "_grpc_config.%s", host);
@@ -484,14 +459,95 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
grpc_ares_request_unref_locked(r);
gpr_free(host);
gpr_free(port);
- return r;
+ return;
error_cleanup:
- GRPC_CLOSURE_SCHED(on_done, error);
- gpr_free(r);
+ GRPC_CLOSURE_SCHED(r->on_done, error);
+ gpr_free(host);
+ gpr_free(port);
+}
+
+static bool inner_resolve_as_ip_literal_locked(const char* name,
+ const char* default_port,
+ grpc_lb_addresses** addrs,
+ char** host, char** port,
+ char** hostport) {
+ gpr_split_host_port(name, host, port);
+ if (*host == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Failed to parse %s to host:port while attempting to resolve as ip "
+ "literal.",
+ name);
+ return false;
+ }
+ if (*port == nullptr) {
+ if (default_port == nullptr) {
+ gpr_log(GPR_ERROR,
+ "No port or default port for %s while attempting to resolve as "
+ "ip literal.",
+ name);
+ return false;
+ }
+ *port = gpr_strdup(default_port);
+ }
+ grpc_resolved_address addr;
+ GPR_ASSERT(gpr_join_host_port(hostport, *host, atoi(*port)));
+ if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) ||
+ grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) {
+ GPR_ASSERT(*addrs == nullptr);
+ *addrs = grpc_lb_addresses_create(1, nullptr);
+ grpc_lb_addresses_set_address(
+ *addrs, 0, addr.addr, addr.len, false /* is_balancer */,
+ nullptr /* balancer_name */, nullptr /* user_data */);
+ return true;
+ }
+ return false;
+}
+
+static bool resolve_as_ip_literal_locked(const char* name,
+ const char* default_port,
+ grpc_lb_addresses** addrs) {
+ char* host = nullptr;
+ char* port = nullptr;
+ char* hostport = nullptr;
+ bool out = inner_resolve_as_ip_literal_locked(name, default_port, addrs,
+ &host, &port, &hostport);
gpr_free(host);
gpr_free(port);
- return nullptr;
+ gpr_free(hostport);
+ return out;
+}
+
+static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
+ const char* dns_server, const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties, grpc_closure* on_done,
+ grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+ grpc_combiner* combiner) {
+ grpc_ares_request* r =
+ static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
+ r->ev_driver = nullptr;
+ r->on_done = on_done;
+ r->lb_addrs_out = addrs;
+ r->service_config_json_out = service_config_json;
+ r->success = false;
+ r->error = GRPC_ERROR_NONE;
+ r->pending_queries = 0;
+ // Early out if the target is an ipv4 or ipv6 literal.
+ if (resolve_as_ip_literal_locked(name, default_port, addrs)) {
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return r;
+ }
+ // Early out if the target is localhost and we're on Windows.
+ if (grpc_ares_maybe_resolve_localhost_manually_locked(name, default_port,
+ addrs)) {
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return r;
+ }
+ // Look up name using c-ares lib.
+ grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
+ r, dns_server, name, default_port, interested_parties, check_grpclb,
+ combiner);
+ return r;
}
grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
@@ -500,12 +556,16 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
-void grpc_cancel_ares_request(grpc_ares_request* r) {
- if (grpc_dns_lookup_ares_locked == grpc_dns_lookup_ares_locked_impl) {
+static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {
+ GPR_ASSERT(r != nullptr);
+ if (r->ev_driver != nullptr) {
grpc_ares_ev_driver_shutdown_locked(r->ev_driver);
}
}
+void (*grpc_cancel_ares_request_locked)(grpc_ares_request* r) =
+ grpc_cancel_ares_request_locked_impl;
+
grpc_error* grpc_ares_init(void) {
gpr_once_init(&g_basic_init, do_basic_init);
gpr_mu_lock(&g_init_mu);
@@ -542,20 +602,23 @@ typedef struct grpc_resolve_address_ares_request {
grpc_lb_addresses* lb_addrs;
/** closure to call when the resolve_address_ares request completes */
grpc_closure* on_resolve_address_done;
- /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the
- grpc_dns_lookup_ares_locked operation is done. */
- grpc_closure on_dns_lookup_done;
+ /** a closure wrapping on_resolve_address_done, which should be invoked when
+ the grpc_dns_lookup_ares_locked operation is done. */
+ grpc_closure on_dns_lookup_done_locked;
/* target name */
const char* name;
/* default port to use if none is specified */
const char* default_port;
/* pollset_set to be driven by */
grpc_pollset_set* interested_parties;
+ /* underlying ares_request that the query is performed on */
+ grpc_ares_request* ares_request;
} grpc_resolve_address_ares_request;
-static void on_dns_lookup_done_cb(void* arg, grpc_error* error) {
+static void on_dns_lookup_done_locked(void* arg, grpc_error* error) {
grpc_resolve_address_ares_request* r =
static_cast<grpc_resolve_address_ares_request*>(arg);
+ gpr_free(r->ares_request);
grpc_resolved_addresses** resolved_addresses = r->addrs_out;
if (r->lb_addrs == nullptr || r->lb_addrs->num_addresses == 0) {
*resolved_addresses = nullptr;
@@ -582,9 +645,9 @@ static void grpc_resolve_address_invoke_dns_lookup_ares_locked(
void* arg, grpc_error* unused_error) {
grpc_resolve_address_ares_request* r =
static_cast<grpc_resolve_address_ares_request*>(arg);
- grpc_dns_lookup_ares_locked(
+ r->ares_request = grpc_dns_lookup_ares_locked(
nullptr /* dns_server */, r->name, r->default_port, r->interested_parties,
- &r->on_dns_lookup_done, &r->lb_addrs, false /* check_grpclb */,
+ &r->on_dns_lookup_done_locked, &r->lb_addrs, false /* check_grpclb */,
nullptr /* service_config_json */, r->combiner);
}
@@ -599,8 +662,8 @@ static void grpc_resolve_address_ares_impl(const char* name,
r->combiner = grpc_combiner_create();
r->addrs_out = addrs;
r->on_resolve_address_done = on_done;
- GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
- grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&r->on_dns_lookup_done_locked, on_dns_lookup_done_locked, r,
+ grpc_combiner_scheduler(r->combiner));
r->name = name;
r->default_port = default_port;
r->interested_parties = interested_parties;
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index ca5779e1d7..a1231cc4e0 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -54,7 +54,8 @@ extern void (*grpc_resolve_address_ares)(const char* name,
port in \a name. grpc_ares_init() must be called at least once before this
function. \a on_done may be called directly in this function without being
scheduled with \a exec_ctx, so it must not try to acquire locks that are
- being held by the caller. */
+ being held by the caller. The returned grpc_ares_request object is owned
+ by the caller and it is safe to free after on_done is called back. */
extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
@@ -62,7 +63,7 @@ extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
char** service_config_json, grpc_combiner* combiner);
/* Cancel the pending grpc_ares_request \a request */
-void grpc_cancel_ares_request(grpc_ares_request* request);
+extern void (*grpc_cancel_ares_request_locked)(grpc_ares_request* request);
/* Initialize gRPC ares wrapper. Must be called at least once before
grpc_resolve_address_ares(). */
@@ -81,9 +82,15 @@ void grpc_ares_complete_request_locked(grpc_ares_request* request);
/* E.g., return false if ipv6 is known to not be available. */
bool grpc_ares_query_ipv6();
-/* Exposed only for testing */
-void grpc_cares_wrapper_test_only_address_sorting_sort(
- grpc_lb_addresses* lb_addrs);
+/* Maybe (depending on the current platform) checks if "name" matches
+ * "localhost" and if so fills in addrs with the correct sockaddr structures.
+ * Returns a bool indicating whether or not such an action was performed.
+ * See https://github.com/grpc/grpc/issues/15158. */
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs);
+
+/* Sorts destinations in lb_addrs according to RFC 6724. */
+void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
*/
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
index d6a76fc8b6..9f293c1ac0 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
@@ -40,7 +40,10 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
-void grpc_cancel_ares_request(grpc_ares_request* r) {}
+static void grpc_cancel_ares_request_locked_impl(grpc_ares_request* r) {}
+
+void (*grpc_cancel_ares_request_locked)(grpc_ares_request* r) =
+ grpc_cancel_ares_request_locked_impl;
grpc_error* grpc_ares_init(void) { return GRPC_ERROR_NONE; }
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
index 23c0fec74f..639eec2323 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
@@ -26,4 +26,9 @@
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs) {
+ return false;
+}
+
#endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
index ee827e284e..7e34784691 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
@@ -21,9 +21,79 @@
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GPR_WINDOWS)
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/socket_windows.h"
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
+static bool inner_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs,
+ char** host, char** port) {
+ gpr_split_host_port(name, host, port);
+ if (*host == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Failed to parse %s into host:port during Windows localhost "
+ "resolution check.",
+ name);
+ return false;
+ }
+ if (*port == nullptr) {
+ if (default_port == nullptr) {
+ gpr_log(GPR_ERROR,
+ "No port or default port for %s during Windows localhost "
+ "resolution check.",
+ name);
+ return false;
+ }
+ *port = gpr_strdup(default_port);
+ }
+ if (gpr_stricmp(*host, "localhost") == 0) {
+ GPR_ASSERT(*addrs == nullptr);
+ *addrs = grpc_lb_addresses_create(2, nullptr);
+ uint16_t numeric_port = grpc_strhtons(*port);
+ // Append the ipv6 loopback address.
+ struct sockaddr_in6 ipv6_loopback_addr;
+ memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
+ ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
+ ipv6_loopback_addr.sin6_family = AF_INET6;
+ ipv6_loopback_addr.sin6_port = numeric_port;
+ grpc_lb_addresses_set_address(
+ *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
+ false /* is_balancer */, nullptr /* balancer_name */,
+ nullptr /* user_data */);
+ // Append the ipv4 loopback address.
+ struct sockaddr_in ipv4_loopback_addr;
+ memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
+ ((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
+ ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
+ ipv4_loopback_addr.sin_family = AF_INET;
+ ipv4_loopback_addr.sin_port = numeric_port;
+ grpc_lb_addresses_set_address(
+ *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
+ false /* is_balancer */, nullptr /* balancer_name */,
+ nullptr /* user_data */);
+ // Let the address sorter figure out which one should be tried first.
+ grpc_cares_wrapper_address_sorting_sort(*addrs);
+ return true;
+ }
+ return false;
+}
+
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs) {
+ char* host = nullptr;
+ char* port = nullptr;
+ bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port,
+ addrs, &host, &port);
+ gpr_free(host);
+ gpr_free(port);
+ return out;
+}
+
#endif /* GRPC_ARES == 1 && defined(GPR_WINDOWS) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 282caf215c..65ff1ec1a5 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -247,13 +247,7 @@ void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
void NativeDnsResolver::MaybeStartResolvingLocked() {
// If there is an existing timer, the time it fires is the earliest time we
// can start the next resolution.
- if (have_next_resolution_timer_) {
- // TODO(dgq): remove the following two lines once Pick First stops
- // discarding subchannels after selecting.
- ++resolved_version_;
- MaybeFinishNextLocked();
- return;
- }
+ if (have_next_resolution_timer_) return;
if (last_resolution_timestamp_ >= 0) {
const grpc_millis earliest_next_resolution =
last_resolution_timestamp_ + min_time_between_resolutions_;
@@ -275,10 +269,6 @@ void NativeDnsResolver::MaybeStartResolvingLocked() {
self.release();
grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
&on_next_resolution_);
- // TODO(dgq): remove the following two lines once Pick First stops
- // discarding subchannels after selecting.
- ++resolved_version_;
- MaybeFinishNextLocked();
return;
}
}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index 99a33f2277..144ac24a56 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -73,11 +73,6 @@ class FakeResolver : public Resolver {
// Results to use for the pretended re-resolution in
// RequestReresolutionLocked().
grpc_channel_args* reresolution_results_ = nullptr;
- // TODO(juanlishen): This can go away once pick_first is changed to not throw
- // away its subchannels, since that will eliminate its dependence on
- // channel_saw_error_locked() causing an immediate resolver return.
- // A copy of the most-recently used resolution results.
- grpc_channel_args* last_used_results_ = nullptr;
// pending next completion, or NULL
grpc_closure* next_completion_ = nullptr;
// target result address for next completion
@@ -96,7 +91,6 @@ FakeResolver::FakeResolver(const ResolverArgs& args) : Resolver(args.combiner) {
FakeResolver::~FakeResolver() {
grpc_channel_args_destroy(next_results_);
grpc_channel_args_destroy(reresolution_results_);
- grpc_channel_args_destroy(last_used_results_);
grpc_channel_args_destroy(channel_args_);
}
@@ -109,17 +103,11 @@ void FakeResolver::NextLocked(grpc_channel_args** target_result,
}
void FakeResolver::RequestReresolutionLocked() {
- // A resolution must have been returned before an error is seen.
- GPR_ASSERT(last_used_results_ != nullptr);
- grpc_channel_args_destroy(next_results_);
if (reresolution_results_ != nullptr) {
+ grpc_channel_args_destroy(next_results_);
next_results_ = grpc_channel_args_copy(reresolution_results_);
- } else {
- // If reresolution_results is unavailable, re-resolve with the most-recently
- // used results to avoid a no-op re-resolution.
- next_results_ = grpc_channel_args_copy(last_used_results_);
+ MaybeFinishNextLocked();
}
- MaybeFinishNextLocked();
}
void FakeResolver::MaybeFinishNextLocked() {
@@ -161,8 +149,6 @@ void FakeResolverResponseGenerator::SetResponseLocked(void* arg,
FakeResolver* resolver = closure_arg->generator->resolver_;
grpc_channel_args_destroy(resolver->next_results_);
resolver->next_results_ = closure_arg->response;
- grpc_channel_args_destroy(resolver->last_used_results_);
- resolver->last_used_results_ = grpc_channel_args_copy(closure_arg->response);
resolver->MaybeFinishNextLocked();
Delete(closure_arg);
}
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 e5175f9b7b..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"
@@ -53,7 +53,8 @@ class FakeResolverResponseGenerator
// The new re-resolution response replaces any previous re-resolution
// response that may have been set by a previous call.
// If the re-resolution response is set to NULL, then the fake
- // resolver will return the last value set via \a SetResponse().
+ // resolver will not return anything when \a RequestReresolutionLocked()
+ // is called.
void SetReresolutionResponse(grpc_channel_args* response);
// Tells the resolver to return a transient failure (signalled by
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index f74ac5aebe..801734764b 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -50,8 +50,6 @@ class SockaddrResolver : public Resolver {
void NextLocked(grpc_channel_args** result,
grpc_closure* on_complete) override;
- void RequestReresolutionLocked() override;
-
void ShutdownLocked() override;
private:
@@ -90,11 +88,6 @@ void SockaddrResolver::NextLocked(grpc_channel_args** target_result,
MaybeFinishNextLocked();
}
-void SockaddrResolver::RequestReresolutionLocked() {
- published_ = false;
- MaybeFinishNextLocked();
-}
-
void SockaddrResolver::ShutdownLocked() {
if (next_completion_ != nullptr) {
*target_result_ = nullptr;
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 0e40f42e18..a56db0201b 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -30,10 +30,10 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/health/health_check_client.h"
#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"
@@ -41,6 +41,7 @@
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/mutex_lock.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/timer.h"
@@ -49,6 +50,10 @@
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/transport/connectivity_state.h"
+#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))
@@ -64,6 +69,10 @@ struct state_watcher {
grpc_closure closure;
grpc_subchannel* subchannel;
grpc_connectivity_state connectivity_state;
+ grpc_connectivity_state last_connectivity_state;
+ grpc_core::OrphanablePtr<grpc_core::HealthCheckClient> health_check_client;
+ grpc_closure health_check_closure;
+ grpc_connectivity_state health_state;
};
} // namespace
@@ -76,6 +85,12 @@ typedef struct external_state_watcher {
struct external_state_watcher* prev;
} external_state_watcher;
+namespace grpc_core {
+
+class ConnectedSubchannelStateWatcher;
+
+} // namespace grpc_core
+
struct grpc_subchannel {
grpc_connector* connector;
@@ -107,19 +122,24 @@ struct grpc_subchannel {
being setup */
grpc_pollset_set* pollset_set;
+ grpc_core::UniquePtr<char> health_check_service_name;
+
/** mutex protecting remaining elements */
gpr_mu mu;
- /** active connection, or null; of type grpc_core::ConnectedSubchannel
- */
+ /** active connection, or null */
grpc_core::RefCountedPtr<grpc_core::ConnectedSubchannel> connected_subchannel;
+ grpc_core::OrphanablePtr<grpc_core::ConnectedSubchannelStateWatcher>
+ connected_subchannel_watcher;
/** have we seen a disconnection? */
bool disconnected;
/** are we connecting */
bool connecting;
+
/** connectivity state tracking */
grpc_connectivity_state_tracker state_tracker;
+ grpc_connectivity_state_tracker state_and_health_tracker;
external_state_watcher root_external_state_watcher;
@@ -142,10 +162,184 @@ 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 = nullptr;
+ grpc_millis deadline;
};
+static void maybe_start_connecting_locked(grpc_subchannel* c);
+
+static const char* subchannel_connectivity_state_change_string(
+ grpc_connectivity_state state) {
+ switch (state) {
+ case GRPC_CHANNEL_IDLE:
+ return "Subchannel state change to IDLE";
+ case GRPC_CHANNEL_CONNECTING:
+ return "Subchannel state change to CONNECTING";
+ case GRPC_CHANNEL_READY:
+ return "Subchannel state change to READY";
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ return "Subchannel state change to TRANSIENT_FAILURE";
+ case GRPC_CHANNEL_SHUTDOWN:
+ return "Subchannel state change to SHUTDOWN";
+ }
+ GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
+static void set_subchannel_connectivity_state_locked(
+ grpc_subchannel* c, grpc_connectivity_state state, grpc_error* error,
+ const char* reason) {
+ if (c->channelz_subchannel != nullptr) {
+ c->channelz_subchannel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string(
+ subchannel_connectivity_state_change_string(state)));
+ }
+ grpc_connectivity_state_set(&c->state_tracker, state, error, reason);
+}
+
+namespace grpc_core {
+
+class ConnectedSubchannelStateWatcher
+ : public InternallyRefCounted<ConnectedSubchannelStateWatcher> {
+ public:
+ // Must be instantiated while holding c->mu.
+ explicit ConnectedSubchannelStateWatcher(grpc_subchannel* c)
+ : subchannel_(c) {
+ // Steal subchannel ref for connecting.
+ GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "state_watcher");
+ GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "connecting");
+ // Start watching for connectivity state changes.
+ // Callback uses initial ref to this.
+ GRPC_CLOSURE_INIT(&on_connectivity_changed_, OnConnectivityChanged, this,
+ grpc_schedule_on_exec_ctx);
+ c->connected_subchannel->NotifyOnStateChange(c->pollset_set,
+ &pending_connectivity_state_,
+ &on_connectivity_changed_);
+ // Start health check if needed.
+ grpc_connectivity_state health_state = GRPC_CHANNEL_READY;
+ if (c->health_check_service_name != nullptr) {
+ health_check_client_ = grpc_core::MakeOrphanable<HealthCheckClient>(
+ c->health_check_service_name.get(), c->connected_subchannel,
+ c->pollset_set, c->channelz_subchannel);
+ GRPC_CLOSURE_INIT(&on_health_changed_, OnHealthChanged, this,
+ grpc_schedule_on_exec_ctx);
+ Ref().release(); // Ref for health callback tracked manually.
+ health_check_client_->NotifyOnHealthChange(&health_state_,
+ &on_health_changed_);
+ health_state = GRPC_CHANNEL_CONNECTING;
+ }
+ // Report initial state.
+ set_subchannel_connectivity_state_locked(
+ c, GRPC_CHANNEL_READY, GRPC_ERROR_NONE, "subchannel_connected");
+ grpc_connectivity_state_set(&c->state_and_health_tracker, health_state,
+ GRPC_ERROR_NONE, "subchannel_connected");
+ }
+
+ ~ConnectedSubchannelStateWatcher() {
+ GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "state_watcher");
+ }
+
+ void Orphan() override { health_check_client_.reset(); }
+
+ private:
+ static void OnConnectivityChanged(void* arg, grpc_error* error) {
+ auto* self = static_cast<ConnectedSubchannelStateWatcher*>(arg);
+ grpc_subchannel* c = self->subchannel_;
+ {
+ MutexLock lock(&c->mu);
+ switch (self->pending_connectivity_state_) {
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ case GRPC_CHANNEL_SHUTDOWN: {
+ if (!c->disconnected && c->connected_subchannel != nullptr) {
+ if (grpc_trace_stream_refcount.enabled()) {
+ gpr_log(GPR_INFO,
+ "Connected subchannel %p of subchannel %p has gone into "
+ "%s. Attempting to reconnect.",
+ c->connected_subchannel.get(), c,
+ grpc_connectivity_state_name(
+ self->pending_connectivity_state_));
+ }
+ c->connected_subchannel.reset();
+ c->connected_subchannel_watcher.reset();
+ self->last_connectivity_state_ = GRPC_CHANNEL_TRANSIENT_FAILURE;
+ set_subchannel_connectivity_state_locked(
+ c, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
+ "reflect_child");
+ grpc_connectivity_state_set(&c->state_and_health_tracker,
+ GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_REF(error), "reflect_child");
+ c->backoff_begun = false;
+ c->backoff->Reset();
+ maybe_start_connecting_locked(c);
+ } else {
+ self->last_connectivity_state_ = GRPC_CHANNEL_SHUTDOWN;
+ }
+ self->health_check_client_.reset();
+ break;
+ }
+ default: {
+ // In principle, this should never happen. We should not get
+ // a callback for READY, because that was the state we started
+ // this watch from. And a connected subchannel should never go
+ // from READY to CONNECTING or IDLE.
+ self->last_connectivity_state_ = self->pending_connectivity_state_;
+ set_subchannel_connectivity_state_locked(
+ c, self->pending_connectivity_state_, GRPC_ERROR_REF(error),
+ "reflect_child");
+ if (self->pending_connectivity_state_ != GRPC_CHANNEL_READY) {
+ grpc_connectivity_state_set(&c->state_and_health_tracker,
+ self->pending_connectivity_state_,
+ GRPC_ERROR_REF(error), "reflect_child");
+ }
+ c->connected_subchannel->NotifyOnStateChange(
+ nullptr, &self->pending_connectivity_state_,
+ &self->on_connectivity_changed_);
+ self = nullptr; // So we don't unref below.
+ }
+ }
+ }
+ // Don't unref until we've released the lock, because this might
+ // cause the subchannel (which contains the lock) to be destroyed.
+ if (self != nullptr) self->Unref();
+ }
+
+ static void OnHealthChanged(void* arg, grpc_error* error) {
+ auto* self = static_cast<ConnectedSubchannelStateWatcher*>(arg);
+ if (self->health_state_ == GRPC_CHANNEL_SHUTDOWN) {
+ self->Unref();
+ return;
+ }
+ grpc_subchannel* c = self->subchannel_;
+ MutexLock lock(&c->mu);
+ if (self->last_connectivity_state_ == GRPC_CHANNEL_READY) {
+ grpc_connectivity_state_set(&c->state_and_health_tracker,
+ self->health_state_, GRPC_ERROR_REF(error),
+ "health_changed");
+ }
+ self->health_check_client_->NotifyOnHealthChange(&self->health_state_,
+ &self->on_health_changed_);
+ }
+
+ grpc_subchannel* subchannel_;
+ grpc_closure on_connectivity_changed_;
+ grpc_connectivity_state pending_connectivity_state_ = GRPC_CHANNEL_READY;
+ grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_READY;
+ grpc_core::OrphanablePtr<grpc_core::HealthCheckClient> health_check_client_;
+ grpc_closure on_health_changed_;
+ grpc_connectivity_state health_state_ = GRPC_CHANNEL_CONNECTING;
+};
+
+} // namespace grpc_core
+
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) \
(grpc_call_stack*)((char*)(call) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE( \
sizeof(grpc_subchannel_call)))
@@ -183,10 +377,18 @@ static void connection_destroy(void* arg, grpc_error* error) {
static void subchannel_destroy(void* arg, grpc_error* error) {
grpc_subchannel* c = static_cast<grpc_subchannel*>(arg);
- c->channelz_subchannel.reset();
+ if (c->channelz_subchannel != nullptr) {
+ c->channelz_subchannel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("Subchannel destroyed"));
+ c->channelz_subchannel->MarkSubchannelDestroyed();
+ c->channelz_subchannel.reset();
+ }
gpr_free((void*)c->filters);
+ c->health_check_service_name.reset();
grpc_channel_args_destroy(c->args);
grpc_connectivity_state_destroy(&c->state_tracker);
+ grpc_connectivity_state_destroy(&c->state_and_health_tracker);
grpc_connector_unref(c->connector);
grpc_pollset_set_destroy(c->pollset_set);
grpc_subchannel_key_destroy(c->key);
@@ -249,6 +451,7 @@ static void disconnect(grpc_subchannel* c) {
grpc_connector_shutdown(c->connector, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Subchannel disconnected"));
c->connected_subchannel.reset();
+ c->connected_subchannel_watcher.reset();
gpr_mu_unlock(&c->mu);
}
@@ -324,6 +527,31 @@ static void parse_args_for_backoff_values(
.set_max_backoff(max_backoff_ms);
}
+namespace grpc_core {
+namespace {
+
+struct HealthCheckParams {
+ UniquePtr<char> service_name;
+
+ static void Parse(const grpc_json* field, HealthCheckParams* params) {
+ if (strcmp(field->key, "healthCheckConfig") == 0) {
+ if (field->type != GRPC_JSON_OBJECT) return;
+ for (grpc_json* sub_field = field->child; sub_field != nullptr;
+ sub_field = sub_field->next) {
+ if (sub_field->key == nullptr) return;
+ if (strcmp(sub_field->key, "serviceName") == 0) {
+ if (params->service_name != nullptr) return; // Duplicate.
+ if (sub_field->type != GRPC_JSON_STRING) return;
+ params->service_name.reset(gpr_strdup(sub_field->value));
+ }
+ }
+ }
+ }
+};
+
+} // namespace
+} // namespace grpc_core
+
grpc_subchannel* grpc_subchannel_create(grpc_connector* connector,
const grpc_subchannel_args* args) {
grpc_subchannel_key* key = grpc_subchannel_key_create(args);
@@ -374,18 +602,45 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector,
grpc_schedule_on_exec_ctx);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
+ grpc_connectivity_state_init(&c->state_and_health_tracker, GRPC_CHANNEL_IDLE,
+ "subchannel");
grpc_core::BackOff::Options backoff_options;
parse_args_for_backoff_values(args->args, &backoff_options,
&c->min_connect_timeout_ms);
c->backoff.Init(backoff_options);
gpr_mu_init(&c->mu);
+ // Check whether we should enable health checking.
+ const char* service_config_json = grpc_channel_arg_get_string(
+ grpc_channel_args_find(c->args, GRPC_ARG_SERVICE_CONFIG));
+ if (service_config_json != nullptr) {
+ grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config =
+ grpc_core::ServiceConfig::Create(service_config_json);
+ if (service_config != nullptr) {
+ grpc_core::HealthCheckParams params;
+ service_config->ParseGlobalParams(grpc_core::HealthCheckParams::Parse,
+ &params);
+ c->health_check_service_name = std::move(params.service_name);
+ }
+ }
+
const grpc_arg* arg =
grpc_channel_args_find(c->args, GRPC_ARG_ENABLE_CHANNELZ);
- bool channelz_enabled = grpc_channel_arg_get_bool(arg, false);
+ bool channelz_enabled =
+ grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT);
+ arg = grpc_channel_args_find(
+ c->args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE);
+ const grpc_integer_options options = {
+ GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX};
+ size_t channel_tracer_max_memory =
+ (size_t)grpc_channel_arg_get_integer(arg, options);
if (channelz_enabled) {
c->channelz_subchannel =
- grpc_core::MakeRefCounted<grpc_core::channelz::SubchannelNode>();
+ grpc_core::MakeRefCounted<grpc_core::channelz::SubchannelNode>(
+ c, channel_tracer_max_memory);
+ c->channelz_subchannel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("Subchannel created"));
}
return grpc_subchannel_index_register(key, c);
@@ -396,6 +651,14 @@ grpc_core::channelz::SubchannelNode* grpc_subchannel_get_channelz_node(
return subchannel->channelz_subchannel.get();
}
+intptr_t grpc_subchannel_get_child_socket_uuid(grpc_subchannel* subchannel) {
+ if (subchannel->connected_subchannel != nullptr) {
+ return subchannel->connected_subchannel->socket_uuid();
+ } else {
+ return 0;
+ }
+}
+
static void continue_connect_locked(grpc_subchannel* c) {
grpc_connect_in_args args;
args.interested_parties = c->pollset_set;
@@ -404,17 +667,21 @@ static void continue_connect_locked(grpc_subchannel* c) {
c->next_attempt_deadline = c->backoff->NextAttemptTime();
args.deadline = std::max(c->next_attempt_deadline, min_deadline);
args.channel_args = c->args;
- grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_CONNECTING,
- GRPC_ERROR_NONE, "connecting");
+ set_subchannel_connectivity_state_locked(c, GRPC_CHANNEL_CONNECTING,
+ GRPC_ERROR_NONE, "connecting");
+ grpc_connectivity_state_set(&c->state_and_health_tracker,
+ GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
+ "connecting");
grpc_connector_connect(c->connector, &args, &c->connecting_result,
&c->on_connected);
}
-grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel* c,
- grpc_error** error) {
- grpc_connectivity_state state;
+grpc_connectivity_state grpc_subchannel_check_connectivity(
+ grpc_subchannel* c, grpc_error** error, bool inhibit_health_checks) {
gpr_mu_lock(&c->mu);
- state = grpc_connectivity_state_get(&c->state_tracker, error);
+ grpc_connectivity_state_tracker* tracker =
+ inhibit_health_checks ? &c->state_tracker : &c->state_and_health_tracker;
+ grpc_connectivity_state state = grpc_connectivity_state_get(tracker, error);
gpr_mu_unlock(&c->mu);
return state;
}
@@ -472,7 +739,8 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) {
/* Already connected: don't restart */
return;
}
- if (!grpc_connectivity_state_has_watchers(&c->state_tracker)) {
+ if (!grpc_connectivity_state_has_watchers(&c->state_tracker) &&
+ !grpc_connectivity_state_has_watchers(&c->state_and_health_tracker)) {
/* Nobody is interested in connecting: so don't just yet */
return;
}
@@ -499,16 +767,18 @@ static void maybe_start_connecting_locked(grpc_subchannel* c) {
void grpc_subchannel_notify_on_state_change(
grpc_subchannel* c, grpc_pollset_set* interested_parties,
- grpc_connectivity_state* state, grpc_closure* notify) {
+ grpc_connectivity_state* state, grpc_closure* notify,
+ bool inhibit_health_checks) {
+ grpc_connectivity_state_tracker* tracker =
+ inhibit_health_checks ? &c->state_tracker : &c->state_and_health_tracker;
external_state_watcher* w;
-
if (state == nullptr) {
gpr_mu_lock(&c->mu);
for (w = c->root_external_state_watcher.next;
w != &c->root_external_state_watcher; w = w->next) {
if (w->notify == notify) {
- grpc_connectivity_state_notify_on_state_change(&c->state_tracker,
- nullptr, &w->closure);
+ grpc_connectivity_state_notify_on_state_change(tracker, nullptr,
+ &w->closure);
}
}
gpr_mu_unlock(&c->mu);
@@ -527,62 +797,12 @@ void grpc_subchannel_notify_on_state_change(
w->next = &c->root_external_state_watcher;
w->prev = w->next->prev;
w->next->prev = w->prev->next = w;
- grpc_connectivity_state_notify_on_state_change(&c->state_tracker, state,
- &w->closure);
+ grpc_connectivity_state_notify_on_state_change(tracker, state, &w->closure);
maybe_start_connecting_locked(c);
gpr_mu_unlock(&c->mu);
}
}
-static void on_connected_subchannel_connectivity_changed(void* p,
- grpc_error* error) {
- state_watcher* connected_subchannel_watcher = static_cast<state_watcher*>(p);
- grpc_subchannel* c = connected_subchannel_watcher->subchannel;
- gpr_mu* mu = &c->mu;
-
- gpr_mu_lock(mu);
-
- switch (connected_subchannel_watcher->connectivity_state) {
- case GRPC_CHANNEL_TRANSIENT_FAILURE:
- case GRPC_CHANNEL_SHUTDOWN: {
- if (!c->disconnected && c->connected_subchannel != nullptr) {
- if (grpc_trace_stream_refcount.enabled()) {
- gpr_log(GPR_INFO,
- "Connected subchannel %p of subchannel %p has gone into %s. "
- "Attempting to reconnect.",
- c->connected_subchannel.get(), c,
- grpc_connectivity_state_name(
- connected_subchannel_watcher->connectivity_state));
- }
- c->connected_subchannel.reset();
- grpc_connectivity_state_set(&c->state_tracker,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- GRPC_ERROR_REF(error), "reflect_child");
- c->backoff_begun = false;
- c->backoff->Reset();
- maybe_start_connecting_locked(c);
- } else {
- connected_subchannel_watcher->connectivity_state =
- GRPC_CHANNEL_SHUTDOWN;
- }
- break;
- }
- default: {
- grpc_connectivity_state_set(
- &c->state_tracker, connected_subchannel_watcher->connectivity_state,
- GRPC_ERROR_REF(error), "reflect_child");
- GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
- c->connected_subchannel->NotifyOnStateChange(
- nullptr, &connected_subchannel_watcher->connectivity_state,
- &connected_subchannel_watcher->closure);
- connected_subchannel_watcher = nullptr;
- }
- }
- gpr_mu_unlock(mu);
- GRPC_SUBCHANNEL_WEAK_UNREF(c, "state_watcher");
- gpr_free(connected_subchannel_watcher);
-}
-
static bool publish_transport_locked(grpc_subchannel* c) {
/* construct channel stack */
grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
@@ -606,41 +826,25 @@ static bool publish_transport_locked(grpc_subchannel* c) {
GRPC_ERROR_UNREF(error);
return false;
}
+ intptr_t socket_uuid = c->connecting_result.socket_uuid;
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
- /* initialize state watcher */
- state_watcher* connected_subchannel_watcher = static_cast<state_watcher*>(
- gpr_zalloc(sizeof(*connected_subchannel_watcher)));
- connected_subchannel_watcher->subchannel = c;
- connected_subchannel_watcher->connectivity_state = GRPC_CHANNEL_READY;
- GRPC_CLOSURE_INIT(&connected_subchannel_watcher->closure,
- on_connected_subchannel_connectivity_changed,
- connected_subchannel_watcher, grpc_schedule_on_exec_ctx);
-
if (c->disconnected) {
- gpr_free(connected_subchannel_watcher);
grpc_channel_stack_destroy(stk);
gpr_free(stk);
return false;
}
/* publish */
- c->connected_subchannel.reset(
- grpc_core::New<grpc_core::ConnectedSubchannel>(stk));
+ c->connected_subchannel.reset(grpc_core::New<grpc_core::ConnectedSubchannel>(
+ stk, c->channelz_subchannel, socket_uuid));
gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p",
c->connected_subchannel.get(), c);
- /* setup subchannel watching connected subchannel for changes; subchannel
- ref for connecting is donated to the state watcher */
- GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
- GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
- c->connected_subchannel->NotifyOnStateChange(
- c->pollset_set, &connected_subchannel_watcher->connectivity_state,
- &connected_subchannel_watcher->closure);
-
- /* signal completion */
- grpc_connectivity_state_set(&c->state_tracker, GRPC_CHANNEL_READY,
- GRPC_ERROR_NONE, "connected");
+ // Instantiate state watcher. Will clean itself up.
+ c->connected_subchannel_watcher =
+ grpc_core::MakeOrphanable<grpc_core::ConnectedSubchannelStateWatcher>(c);
+
return true;
}
@@ -657,8 +861,14 @@ static void on_subchannel_connected(void* arg, grpc_error* error) {
} else if (c->disconnected) {
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
} else {
+ set_subchannel_connectivity_state_locked(
+ c, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+ "Connect Failed", &error, 1),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
+ "connect_failed");
grpc_connectivity_state_set(
- &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ &c->state_and_health_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Connect Failed", &error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
@@ -699,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,
@@ -719,9 +930,71 @@ void grpc_subchannel_call_unref(
GRPC_CALL_STACK_UNREF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
}
+// Sets *status based on md_batch and error.
+static void get_call_status(grpc_subchannel_call* call,
+ grpc_metadata_batch* md_batch, grpc_error* error,
+ grpc_status_code* status) {
+ if (error != GRPC_ERROR_NONE) {
+ grpc_error_get_status(error, call->deadline, status, nullptr, nullptr,
+ nullptr);
+ } else {
+ if (md_batch->idx.named.grpc_status != nullptr) {
+ *status = grpc_get_status_code_from_metadata(
+ md_batch->idx.named.grpc_status->md);
+ } else {
+ *status = GRPC_STATUS_UNKNOWN;
+ }
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
+ grpc_subchannel_call* call = static_cast<grpc_subchannel_call*>(arg);
+ GPR_ASSERT(call->recv_trailing_metadata != nullptr);
+ grpc_status_code status = GRPC_STATUS_OK;
+ grpc_metadata_batch* md_batch = call->recv_trailing_metadata;
+ get_call_status(call, md_batch, GRPC_ERROR_REF(error), &status);
+ grpc_core::channelz::SubchannelNode* channelz_subchannel =
+ call->connection->channelz_subchannel();
+ GPR_ASSERT(channelz_subchannel != nullptr);
+ if (status == GRPC_STATUS_OK) {
+ channelz_subchannel->RecordCallSucceeded();
+ } else {
+ channelz_subchannel->RecordCallFailed();
+ }
+ GRPC_CLOSURE_RUN(call->original_recv_trailing_metadata,
+ GRPC_ERROR_REF(error));
+}
+
+// If channelz is enabled, intercept recv_trailing so that we may check the
+// status and associate it to a subchannel.
+static void maybe_intercept_recv_trailing_metadata(
+ grpc_subchannel_call* call, grpc_transport_stream_op_batch* batch) {
+ // only intercept payloads with recv trailing.
+ if (!batch->recv_trailing_metadata) {
+ return;
+ }
+ // only add interceptor is channelz is enabled.
+ if (call->connection->channelz_subchannel() == nullptr) {
+ return;
+ }
+ GRPC_CLOSURE_INIT(&call->recv_trailing_metadata_ready,
+ recv_trailing_metadata_ready, call,
+ grpc_schedule_on_exec_ctx);
+ // save some state needed for the interception callback.
+ GPR_ASSERT(call->recv_trailing_metadata == nullptr);
+ call->recv_trailing_metadata =
+ batch->payload->recv_trailing_metadata.recv_trailing_metadata;
+ call->original_recv_trailing_metadata =
+ batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+ batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+ &call->recv_trailing_metadata_ready;
+}
+
void grpc_subchannel_call_process_op(grpc_subchannel_call* call,
grpc_transport_stream_op_batch* batch) {
GPR_TIMER_SCOPE("grpc_subchannel_call_process_op", 0);
+ maybe_intercept_recv_trailing_metadata(call, batch);
grpc_call_stack* call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
grpc_call_element* top_elem = grpc_call_stack_element(call_stack, 0);
GRPC_CALL_LOG_OP(GPR_INFO, top_elem, batch);
@@ -770,6 +1043,14 @@ void grpc_get_subchannel_address_arg(const grpc_channel_args* args,
}
}
+const char* grpc_subchannel_get_target(grpc_subchannel* subchannel) {
+ const grpc_arg* addr_arg =
+ grpc_channel_args_find(subchannel->args, GRPC_ARG_SUBCHANNEL_ADDRESS);
+ const char* addr_str = grpc_channel_arg_get_string(addr_arg);
+ GPR_ASSERT(addr_str != nullptr); // Should have been set by LB policy.
+ return addr_str;
+}
+
const char* grpc_get_subchannel_address_uri_arg(const grpc_channel_args* args) {
const grpc_arg* addr_arg =
grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS);
@@ -786,9 +1067,15 @@ grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) {
namespace grpc_core {
-ConnectedSubchannel::ConnectedSubchannel(grpc_channel_stack* channel_stack)
+ConnectedSubchannel::ConnectedSubchannel(
+ grpc_channel_stack* channel_stack,
+ grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode>
+ channelz_subchannel,
+ intptr_t socket_uuid)
: RefCountedWithTracing<ConnectedSubchannel>(&grpc_trace_stream_refcount),
- channel_stack_(channel_stack) {}
+ channel_stack_(channel_stack),
+ channelz_subchannel_(std::move(channelz_subchannel)),
+ socket_uuid_(socket_uuid) {}
ConnectedSubchannel::~ConnectedSubchannel() {
GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor");
@@ -818,22 +1105,14 @@ void ConnectedSubchannel::Ping(grpc_closure* on_initiate,
grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
grpc_subchannel_call** call) {
- size_t allocation_size =
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_subchannel_call));
- if (args.parent_data_size > 0) {
- allocation_size +=
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
- args.parent_data_size;
- } else {
- allocation_size += channel_stack_->call_stack_size;
- }
- *call = static_cast<grpc_subchannel_call*>(
- gpr_arena_alloc(args.arena, allocation_size));
+ const size_t allocation_size =
+ GetInitialCallSizeEstimate(args.parent_data_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;
const grpc_call_element_args call_args = {
callstk, /* call_stack */
nullptr, /* server_transport_data */
@@ -852,7 +1131,24 @@ 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;
}
+size_t ConnectedSubchannel::GetInitialCallSizeEstimate(
+ size_t parent_data_size) const {
+ size_t allocation_size =
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_subchannel_call));
+ if (parent_data_size > 0) {
+ allocation_size +=
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
+ parent_data_size;
+ } else {
+ allocation_size += channel_stack_->call_stack_size;
+ }
+ return allocation_size;
+}
+
} // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
index a135035d62..ec3b4d86e4 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -85,7 +85,11 @@ class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> {
size_t parent_data_size;
};
- explicit ConnectedSubchannel(grpc_channel_stack* channel_stack);
+ explicit ConnectedSubchannel(
+ grpc_channel_stack* channel_stack,
+ grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode>
+ channelz_subchannel,
+ intptr_t socket_uuid);
~ConnectedSubchannel();
grpc_channel_stack* channel_stack() { return channel_stack_; }
@@ -94,9 +98,21 @@ class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> {
grpc_closure* closure);
void Ping(grpc_closure* on_initiate, grpc_closure* on_ack);
grpc_error* CreateCall(const CallArgs& args, grpc_subchannel_call** call);
+ channelz::SubchannelNode* channelz_subchannel() {
+ return channelz_subchannel_.get();
+ }
+ intptr_t socket_uuid() { return socket_uuid_; }
+
+ size_t GetInitialCallSizeEstimate(size_t parent_data_size) const;
private:
grpc_channel_stack* channel_stack_;
+ // ref counted pointer to the channelz node in this connected subchannel's
+ // owning subchannel.
+ grpc_core::RefCountedPtr<grpc_core::channelz::SubchannelNode>
+ channelz_subchannel_;
+ // uuid of this subchannel's socket. 0 if this subchannel is not connected.
+ const intptr_t socket_uuid_;
};
} // namespace grpc_core
@@ -119,6 +135,8 @@ void grpc_subchannel_call_unref(
grpc_core::channelz::SubchannelNode* grpc_subchannel_get_channelz_node(
grpc_subchannel* subchannel);
+intptr_t grpc_subchannel_get_child_socket_uuid(grpc_subchannel* subchannel);
+
/** Returns a pointer to the parent data associated with \a subchannel_call.
The data will be of the size specified in \a parent_data_size
field of the args passed to \a grpc_connected_subchannel_create_call(). */
@@ -127,13 +145,14 @@ void* grpc_connected_subchannel_call_get_parent_data(
/** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity(
- grpc_subchannel* channel, grpc_error** error);
+ grpc_subchannel* channel, grpc_error** error, bool inhibit_health_checking);
/** Calls notify when the connectivity state of a channel becomes different
from *state. Updates *state with the new state of the channel. */
void grpc_subchannel_notify_on_state_change(
grpc_subchannel* channel, grpc_pollset_set* interested_parties,
- grpc_connectivity_state* state, grpc_closure* notify);
+ grpc_connectivity_state* state, grpc_closure* notify,
+ bool inhibit_health_checks);
/** retrieve the grpc_core::ConnectedSubchannel - or nullptr if not connected
* (which may happen before it initially connects or during transient failures)
@@ -184,6 +203,8 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector,
void grpc_get_subchannel_address_arg(const grpc_channel_args* args,
grpc_resolved_address* addr);
+const char* grpc_subchannel_get_target(grpc_subchannel* subchannel);
+
/// Returns the URI string for the address to connect to.
const char* grpc_get_subchannel_address_uri_arg(const grpc_channel_args* args);
diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc
index cb02b1a748..1c23a6c4be 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.cc
+++ b/src/core/ext/filters/client_channel/subchannel_index.cc
@@ -73,7 +73,8 @@ static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) {
int grpc_subchannel_key_compare(const grpc_subchannel_key* a,
const grpc_subchannel_key* b) {
- if (g_force_creation) return false;
+ // To pretend the keys are different, return a non-zero value.
+ if (GPR_UNLIKELY(g_force_creation)) return 1;
int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
if (c != 0) return c;
if (a->args.filter_count > 0) {
diff --git a/src/core/ext/filters/client_channel/subchannel_index.h b/src/core/ext/filters/client_channel/subchannel_index.h
index a7dae9d47d..c135613d26 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.h
+++ b/src/core/ext/filters/client_channel/subchannel_index.h
@@ -65,13 +65,10 @@ void grpc_subchannel_index_ref(void);
void grpc_subchannel_index_unref(void);
/** \em TEST ONLY.
- * If \a force_creation is true, all key comparisons will be false, resulting in
+ * If \a force_creation is true, all keys are regarded different, resulting in
* new subchannels always being created. Otherwise, the keys will be compared as
* usual.
*
- * This function is *not* threadsafe on purpose: it should *only* be used in
- * test code.
- *
* Tests using this function \em MUST run tests with and without \a
* force_creation set. */
void grpc_subchannel_index_test_only_set_force_creation(bool force_creation);
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 1678051beb..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,15 +72,18 @@ struct call_data {
grpc_linked_mdelem user_agent;
// State for handling recv_initial_metadata ops.
grpc_metadata_batch* recv_initial_metadata;
- 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 = 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;
@@ -78,7 +102,12 @@ struct channel_data {
static grpc_error* client_filter_incoming_metadata(grpc_call_element* elem,
grpc_metadata_batch* b) {
if (b->idx.named.status != nullptr) {
- if (grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) {
+ /* If both gRPC status and HTTP status are provided in the response, we
+ * should prefer the gRPC status code, as mentioned in
+ * https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md.
+ */
+ if (b->idx.named.grpc_status != nullptr ||
+ grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) {
grpc_metadata_batch_remove(b, b->idx.named.status);
} else {
char* val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md),
@@ -147,21 +176,39 @@ static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
call_data* calld = static_cast<call_data*>(elem->call_data);
if (error == GRPC_ERROR_NONE) {
error = client_filter_incoming_metadata(elem, calld->recv_initial_metadata);
+ calld->recv_initial_metadata_error = GRPC_ERROR_REF(error);
} else {
GRPC_ERROR_REF(error);
}
- GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, error);
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(
+ calld->call_combiner, &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error, "continue recv_trailing_metadata");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
}
static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->original_recv_initial_metadata_ready != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_initial_metadata_ready");
+ return;
+ }
if (error == GRPC_ERROR_NONE) {
error =
client_filter_incoming_metadata(elem, calld->recv_trailing_metadata);
} else {
GRPC_ERROR_REF(error);
}
+ error = grpc_error_add_child(
+ error, GRPC_ERROR_REF(calld->recv_initial_metadata_error));
GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error);
}
@@ -416,25 +463,17 @@ 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;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
- grpc_closure* ignored) {}
+ grpc_closure* ignored) {
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ calld->~call_data();
+}
static grpc_mdelem scheme_from_args(const grpc_channel_args* args) {
unsigned i;
diff --git a/src/core/ext/filters/http/client_authority_filter.cc b/src/core/ext/filters/http/client_authority_filter.cc
index 1ca20ebb26..6383f12594 100644
--- a/src/core/ext/filters/http/client_authority_filter.cc
+++ b/src/core/ext/filters/http/client_authority_filter.cc
@@ -59,9 +59,8 @@ void authority_start_transport_stream_op_batch(
initial_metadata->idx.named.authority == nullptr) {
grpc_error* error = grpc_metadata_batch_add_head(
initial_metadata, &calld->authority_storage,
- grpc_mdelem_from_slices(
- GRPC_MDSTR_AUTHORITY,
- grpc_slice_ref_internal(chand->default_authority)));
+ grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, chand->default_authority,
+ nullptr));
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(batch, error,
calld->call_combiner);
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 3919447f26..ce1be8370c 100644
--- a/src/core/ext/filters/http/server/http_server_filter.cc
+++ b/src/core/ext/filters/http/server/http_server_filter.cc
@@ -23,6 +23,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <string.h>
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/b64.h"
@@ -34,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.
@@ -46,20 +70,31 @@ 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_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 = false;
+};
+
+struct channel_data {
+ bool surface_user_agent;
};
} // namespace
@@ -258,6 +293,11 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority")));
}
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+ if (!chand->surface_user_agent && b->idx.named.user_agent != nullptr) {
+ grpc_metadata_batch_remove(b, b->idx.named.user_agent);
+ }
+
return error;
}
@@ -267,6 +307,7 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
calld->seen_recv_initial_metadata_ready = true;
if (err == GRPC_ERROR_NONE) {
err = hs_filter_incoming_metadata(elem, calld->recv_initial_metadata);
+ calld->recv_initial_metadata_ready_error = GRPC_ERROR_REF(err);
if (calld->seen_recv_message_ready) {
// We've already seen the recv_message callback, but we previously
// deferred it, so we need to return it here.
@@ -286,6 +327,13 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
} else {
GRPC_ERROR_REF(err);
}
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_ready_error,
+ "resuming hs_recv_trailing_metadata_ready from "
+ "hs_recv_initial_metadata_ready");
+ }
GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, err);
}
@@ -313,6 +361,23 @@ static void hs_recv_message_ready(void* user_data, grpc_error* err) {
}
}
+static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+ grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (!calld->seen_recv_initial_metadata_ready) {
+ calld->recv_trailing_metadata_ready_error = GRPC_ERROR_REF(err);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring hs_recv_trailing_metadata_ready until "
+ "ater hs_recv_initial_metadata_ready");
+ return;
+ }
+ err = grpc_error_add_child(
+ GRPC_ERROR_REF(err),
+ GRPC_ERROR_REF(calld->recv_initial_metadata_ready_error));
+ GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err);
+}
+
static grpc_error* hs_mutate_op(grpc_call_element* elem,
grpc_transport_stream_op_batch* op) {
/* grab pointers to our data from the call element */
@@ -357,6 +422,13 @@ static grpc_error* hs_mutate_op(grpc_call_element* elem,
op->payload->recv_message.recv_message_ready = &calld->recv_message_ready;
}
+ if (op->recv_trailing_metadata) {
+ calld->original_recv_trailing_metadata_ready =
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+ &calld->recv_trailing_metadata_ready;
+ }
+
if (op->send_trailing_metadata) {
grpc_error* error = hs_filter_outgoing_metadata(
elem, op->payload->send_trailing_metadata.send_trailing_metadata);
@@ -382,13 +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);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
@@ -397,15 +463,18 @@ 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);
- if (calld->have_read_stream) {
- calld->read_stream->Orphan();
- }
+ calld->~call_data();
}
/* Constructor for channel_data */
static grpc_error* hs_init_channel_elem(grpc_channel_element* elem,
grpc_channel_element_args* args) {
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
GPR_ASSERT(!args->is_last);
+ chand->surface_user_agent = grpc_channel_arg_get_bool(
+ grpc_channel_args_find(args->channel_args,
+ const_cast<char*>(GRPC_ARG_SURFACE_USER_AGENT)),
+ true);
return GRPC_ERROR_NONE;
}
@@ -419,7 +488,7 @@ const grpc_channel_filter grpc_http_server_filter = {
hs_init_call_elem,
grpc_call_stack_ignore_set_pollset_or_pollset_set,
hs_destroy_call_elem,
- 0,
+ sizeof(channel_data),
hs_init_channel_elem,
hs_destroy_channel_elem,
grpc_channel_next_get_info,
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/max_age/max_age_filter.cc b/src/core/ext/filters/max_age/max_age_filter.cc
index 1fe8288bd0..431472609e 100644
--- a/src/core/ext/filters/max_age/max_age_filter.cc
+++ b/src/core/ext/filters/max_age/max_age_filter.cc
@@ -429,8 +429,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
? GRPC_MILLIS_INF_FUTURE
: DEFAULT_MAX_CONNECTION_IDLE_MS;
chand->idle_state = MAX_IDLE_STATE_INIT;
- gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis,
- GRPC_MILLIS_INF_PAST);
+ gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis, GPR_ATM_MIN);
for (size_t i = 0; i < args->channel_args->num_args; ++i) {
if (0 == strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
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 c7fc3f2e62..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,27 +90,70 @@ 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
// recv_message_ready up-call on transport_stream_op, and remember to
// call our next_recv_message_ready member after handling it.
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_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;
-};
-
-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;
+ 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 = false;
+ grpc_error* recv_trailing_metadata_error;
};
} // namespace
@@ -130,18 +173,52 @@ static void recv_message_ready(void* user_data, grpc_error* error) {
grpc_error* new_error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_ERROR_UNREF(calld->error);
if (error == GRPC_ERROR_NONE) {
error = new_error;
} else {
error = grpc_error_add_child(error, new_error);
- GRPC_ERROR_UNREF(new_error);
}
+ calld->error = GRPC_ERROR_REF(error);
gpr_free(message_string);
} else {
GRPC_ERROR_REF(error);
}
// Invoke the next callback.
- GRPC_CLOSURE_RUN(calld->next_recv_message_ready, error);
+ grpc_closure* closure = calld->next_recv_message_ready;
+ calld->next_recv_message_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata) {
+ /* We might potentially see another RECV_MESSAGE op. In that case, we do not
+ * want to run the recv_trailing_metadata_ready closure again. The newer
+ * RECV_MESSAGE op cannot cause any errors since the transport has already
+ * invoked the recv_trailing_metadata_ready closure and all further
+ * RECV_MESSAGE ops will get null payloads. */
+ calld->seen_recv_trailing_metadata = false;
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
+}
+
+// Callback invoked on completion of recv_trailing_metadata
+// Notifies the recv_trailing_metadata batch of any message size failures
+static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
+ grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->next_recv_message_ready != nullptr) {
+ calld->seen_recv_trailing_metadata = true;
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_message_ready");
+ return;
+ }
+ error =
+ grpc_error_add_child(GRPC_ERROR_REF(error), GRPC_ERROR_REF(calld->error));
+ // Invoke the next callback.
+ GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error);
}
// Start transport stream op.
@@ -172,6 +249,13 @@ static void start_transport_stream_op_batch(
calld->recv_message = op->payload->recv_message.recv_message;
op->payload->recv_message.recv_message_ready = &calld->recv_message_ready;
}
+ // Inject callback for receiving trailing metadata.
+ if (op->recv_trailing_metadata) {
+ calld->original_recv_trailing_metadata_ready =
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+ &calld->recv_trailing_metadata_ready;
+ }
// Chain to the next filter.
grpc_call_next_op(elem, op);
}
@@ -180,40 +264,17 @@ 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;
- GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_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;
}
// Destructor for call_data.
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
- grpc_closure* ignored) {}
+ grpc_closure* ignored) {
+ call_data* calld = (call_data*)elem->call_data;
+ calld->~call_data();
+}
static int default_size(const grpc_channel_args* args,
int without_minimal_stack) {
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
index e7522ffba8..60a32022f5 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
@@ -117,6 +117,8 @@ static void on_handshake_done(void* arg, grpc_error* error) {
c->args.interested_parties);
c->result->transport =
grpc_create_chttp2_transport(args->args, args->endpoint, true);
+ c->result->socket_uuid =
+ grpc_chttp2_transport_get_socket_uuid(c->result->transport);
GPR_ASSERT(c->result->transport);
// TODO(roth): We ideally want to wait until we receive HTTP/2
// settings from the server before we consider the connection
@@ -158,12 +160,11 @@ static void on_handshake_done(void* arg, grpc_error* error) {
static void start_handshake_locked(chttp2_connector* c) {
c->handshake_mgr = grpc_handshake_manager_create();
grpc_handshakers_add(HANDSHAKER_CLIENT, c->args.channel_args,
- c->handshake_mgr);
+ c->args.interested_parties, c->handshake_mgr);
grpc_endpoint_add_to_pollset_set(c->endpoint, c->args.interested_parties);
grpc_handshake_manager_do_handshake(
- c->handshake_mgr, c->args.interested_parties, c->endpoint,
- c->args.channel_args, c->args.deadline, nullptr /* acceptor */,
- on_handshake_done, c);
+ c->handshake_mgr, c->endpoint, c->args.channel_args, c->args.deadline,
+ nullptr /* acceptor */, on_handshake_done, c);
c->endpoint = nullptr; // Endpoint handed off to handshake manager.
}
@@ -211,9 +212,17 @@ static void chttp2_connector_connect(grpc_connector* con,
GRPC_CLOSURE_INIT(&c->connected, connected, c, grpc_schedule_on_exec_ctx);
GPR_ASSERT(!c->connecting);
c->connecting = true;
- grpc_tcp_client_connect(&c->connected, &c->endpoint, args->interested_parties,
- args->channel_args, &addr, args->deadline);
+ grpc_closure* closure = &c->connected;
+ grpc_endpoint** ep = &c->endpoint;
gpr_mu_unlock(&c->mu);
+ // In some implementations, the closure can be flushed before
+ // grpc_tcp_client_connect and since the closure requires access to c->mu,
+ // this can result in a deadlock. Refer
+ // https://github.com/grpc/grpc/issues/16427
+ // grpc_tcp_client_connect would fill c->endpoint with proper contents and we
+ // make sure that we would still exist at that point by taking a ref.
+ grpc_tcp_client_connect(closure, ep, args->interested_parties,
+ args->channel_args, &addr, args->deadline);
}
static const grpc_connector_vtable chttp2_connector_vtable = {
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 3f8a26ae32..33d2b22aa5 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.cc
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc
@@ -37,8 +37,10 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/handshaker_registry.h"
+#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
@@ -53,6 +55,8 @@ typedef struct {
grpc_closure tcp_server_shutdown_complete;
grpc_closure* server_destroy_listener_done;
grpc_handshake_manager* pending_handshake_mgrs;
+ grpc_core::RefCountedPtr<grpc_core::channelz::ListenSocketNode>
+ channelz_listen_socket;
} server_state;
typedef struct {
@@ -67,6 +71,7 @@ typedef struct {
grpc_timer timer;
grpc_closure on_timeout;
grpc_closure on_receive_settings;
+ grpc_pollset_set* interested_parties;
} server_connection_state;
static void server_connection_state_unref(
@@ -76,6 +81,9 @@ static void server_connection_state_unref(
GRPC_CHTTP2_UNREF_TRANSPORT(connection_state->transport,
"receive settings timeout");
}
+ grpc_pollset_set_del_pollset(connection_state->interested_parties,
+ connection_state->accepting_pollset);
+ grpc_pollset_set_destroy(connection_state->interested_parties);
gpr_free(connection_state);
}
}
@@ -108,9 +116,16 @@ static void on_handshake_done(void* arg, grpc_error* error) {
server_connection_state* connection_state =
static_cast<server_connection_state*>(args->user_data);
gpr_mu_lock(&connection_state->svr_state->mu);
+ grpc_resource_user* resource_user = grpc_server_get_default_resource_user(
+ connection_state->svr_state->server);
if (error != GRPC_ERROR_NONE || connection_state->svr_state->shutdown) {
const char* error_str = grpc_error_string(error);
gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
+ grpc_resource_user* resource_user = grpc_server_get_default_resource_user(
+ connection_state->svr_state->server);
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
if (error == GRPC_ERROR_NONE && args->endpoint != nullptr) {
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
@@ -129,11 +144,12 @@ static void on_handshake_done(void* arg, grpc_error* error) {
// handshaker may have handed off the connection to some external
// code, so we can just clean up here without creating a transport.
if (args->endpoint != nullptr) {
- grpc_transport* transport =
- grpc_create_chttp2_transport(args->args, args->endpoint, false);
+ grpc_transport* transport = grpc_create_chttp2_transport(
+ args->args, args->endpoint, false, resource_user);
grpc_server_setup_transport(
connection_state->svr_state->server, transport,
- connection_state->accepting_pollset, args->args);
+ connection_state->accepting_pollset, args->args,
+ grpc_chttp2_transport_get_socket_uuid(transport), resource_user);
// Use notify_on_receive_settings callback to enforce the
// handshake deadline.
connection_state->transport =
@@ -152,6 +168,11 @@ static void on_handshake_done(void* arg, grpc_error* error) {
connection_state, grpc_schedule_on_exec_ctx);
grpc_timer_init(&connection_state->timer, connection_state->deadline,
&connection_state->on_timeout);
+ } else {
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
}
}
grpc_handshake_manager_pending_list_remove(
@@ -176,6 +197,20 @@ static void on_accept(void* arg, grpc_endpoint* tcp,
gpr_free(acceptor);
return;
}
+ grpc_resource_user* resource_user =
+ grpc_server_get_default_resource_user(state->server);
+ if (resource_user != nullptr &&
+ !grpc_resource_user_safe_alloc(resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE)) {
+ gpr_log(
+ GPR_ERROR,
+ "Memory quota exhausted, rejecting the connection, no handshaking.");
+ gpr_mu_unlock(&state->mu);
+ grpc_endpoint_shutdown(tcp, GRPC_ERROR_NONE);
+ grpc_endpoint_destroy(tcp);
+ gpr_free(acceptor);
+ return;
+ }
grpc_handshake_manager* handshake_mgr = grpc_handshake_manager_create();
grpc_handshake_manager_pending_list_add(&state->pending_handshake_mgrs,
handshake_mgr);
@@ -189,7 +224,11 @@ static void on_accept(void* arg, grpc_endpoint* tcp,
connection_state->accepting_pollset = accepting_pollset;
connection_state->acceptor = acceptor;
connection_state->handshake_mgr = handshake_mgr;
+ connection_state->interested_parties = grpc_pollset_set_create();
+ grpc_pollset_set_add_pollset(connection_state->interested_parties,
+ connection_state->accepting_pollset);
grpc_handshakers_add(HANDSHAKER_SERVER, state->args,
+ connection_state->interested_parties,
connection_state->handshake_mgr);
const grpc_arg* timeout_arg =
grpc_channel_args_find(state->args, GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS);
@@ -197,10 +236,10 @@ static void on_accept(void* arg, grpc_endpoint* tcp,
grpc_core::ExecCtx::Get()->Now() +
grpc_channel_arg_get_integer(timeout_arg,
{120 * GPR_MS_PER_SEC, 1, INT_MAX});
- grpc_handshake_manager_do_handshake(
- connection_state->handshake_mgr, nullptr /* interested_parties */, tcp,
- state->args, connection_state->deadline, acceptor, on_handshake_done,
- connection_state);
+ grpc_handshake_manager_do_handshake(connection_state->handshake_mgr, tcp,
+ state->args, connection_state->deadline,
+ acceptor, on_handshake_done,
+ connection_state);
}
/* Server callback: start listening on our ports */
@@ -223,6 +262,7 @@ static void tcp_server_shutdown_complete(void* arg, grpc_error* error) {
GPR_ASSERT(state->shutdown);
grpc_handshake_manager_pending_list_shutdown_all(
state->pending_handshake_mgrs, GRPC_ERROR_REF(error));
+ state->channelz_listen_socket.reset();
gpr_mu_unlock(&state->mu);
// Flush queued work before destroying handshaker factory, since that
// may do a synchronous unref.
@@ -262,6 +302,8 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr,
server_state* state = nullptr;
grpc_error** errors = nullptr;
size_t naddrs = 0;
+ const grpc_arg* arg = nullptr;
+ intptr_t socket_uuid = 0;
*port_num = -1;
@@ -323,9 +365,17 @@ 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, GRPC_ENABLE_CHANNELZ_DEFAULT)) {
+ state->channelz_listen_socket =
+ grpc_core::MakeRefCounted<grpc_core::channelz::ListenSocketNode>(
+ grpc_core::UniquePtr<char>(gpr_strdup(addr)));
+ socket_uuid = state->channelz_listen_socket->uuid();
+ }
+
/* Register with the server only upon success */
grpc_server_add_listener(server, state, server_start_listener,
- server_destroy_listener);
+ server_destroy_listener, socket_uuid);
goto done;
/* Error path: cleanup and return */
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
index e4bd91d07b..b9024a87e2 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -61,7 +61,7 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
grpc_endpoint_add_to_pollset(server_endpoint, pollsets[i]);
}
- grpc_server_setup_transport(server, transport, nullptr, server_args);
+ grpc_server_setup_transport(server, transport, nullptr, server_args, 0);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 8e07e3e4f9..da29ff1b37 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -54,6 +54,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
@@ -155,51 +156,55 @@ bool g_flow_control_enabled = true;
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
-static void destruct_transport(grpc_chttp2_transport* t) {
+grpc_chttp2_transport::~grpc_chttp2_transport() {
gpr_log(GPR_INFO, "destruct transport %p", t);
size_t i;
- grpc_endpoint_destroy(t->ep);
+ if (channelz_socket != nullptr) {
+ channelz_socket.reset();
+ }
+
+ 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_core::ContextList::Execute(t->cl, nullptr, GRPC_ERROR_NONE);
+ grpc_core::ContextList::Execute(cl, nullptr, GRPC_ERROR_NONE);
+ grpc_slice_buffer_destroy_internal(&read_buffer);
+ grpc_chttp2_hpack_parser_destroy(&hpack_parser);
+ grpc_chttp2_goaway_parser_destroy(&goaway_parser);
- grpc_slice_buffer_destroy_internal(&t->read_buffer);
- grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
- grpc_chttp2_goaway_parser_destroy(&t->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 +216,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 +232,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); }
@@ -234,35 +241,178 @@ void grpc_chttp2_ref_transport(grpc_chttp2_transport* t) { gpr_ref(&t->refs); }
static const grpc_transport_vtable* get_vtable(void);
-static void init_transport(grpc_chttp2_transport* t,
- const grpc_channel_args* channel_args,
- grpc_endpoint* ep, bool is_client) {
+/* Returns whether bdp is enabled */
+static bool read_channel_args(grpc_chttp2_transport* t,
+ const grpc_channel_args* channel_args,
+ bool is_client) {
+ bool enable_bdp = true;
+ bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT;
size_t i;
int j;
- GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
- GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
-
- t->base.vtable = get_vtable();
- t->ep = ep;
- /* 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->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);
+ for (i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
+ const grpc_integer_options options = {-1, 0, INT_MAX};
+ const int value =
+ grpc_channel_arg_get_integer(&channel_args->args[i], options);
+ if (value >= 0) {
+ if ((t->next_stream_id & 1) != (value & 1)) {
+ gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
+ GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->next_stream_id & 1,
+ is_client ? "client" : "server");
+ } else {
+ t->next_stream_id = static_cast<uint32_t>(value);
+ }
+ }
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
+ const grpc_integer_options options = {-1, 0, INT_MAX};
+ const int value =
+ grpc_channel_arg_get_integer(&channel_args->args[i], options);
+ if (value >= 0) {
+ grpc_chttp2_hpack_compressor_set_max_usable_size(
+ &t->hpack_compressor, static_cast<uint32_t>(value));
+ }
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) {
+ t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ {g_default_max_pings_without_data, 0, INT_MAX});
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MAX_PING_STRIKES)) {
+ t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer(
+ &channel_args->args[i], {g_default_max_ping_strikes, 0, INT_MAX});
+ } else if (0 ==
+ strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS)) {
+ t->ping_policy.min_sent_ping_interval_without_data =
+ grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ grpc_integer_options{
+ g_default_min_sent_ping_interval_without_data_ms, 0,
+ INT_MAX});
+ } else if (0 ==
+ strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)) {
+ t->ping_policy.min_recv_ping_interval_without_data =
+ grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ grpc_integer_options{
+ g_default_min_recv_ping_interval_without_data_ms, 0,
+ INT_MAX});
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
+ t->write_buffer_size = static_cast<uint32_t>(grpc_channel_arg_get_integer(
+ &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}));
+ } else if (0 ==
+ strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
+ enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
+ } else if (0 ==
+ strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ grpc_integer_options{t->is_client
+ ? g_default_client_keepalive_time_ms
+ : g_default_server_keepalive_time_ms,
+ 1, INT_MAX});
+ t->keepalive_time = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i],
+ grpc_integer_options{t->is_client
+ ? g_default_client_keepalive_timeout_ms
+ : g_default_server_keepalive_timeout_ms,
+ 0, INT_MAX});
+ t->keepalive_timeout = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
+ t->keepalive_permit_without_calls = static_cast<uint32_t>(
+ grpc_channel_arg_get_integer(&channel_args->args[i], {0, 0, 1}));
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_OPTIMIZATION_TARGET)) {
+ if (channel_args->args[i].type != GRPC_ARG_STRING) {
+ gpr_log(GPR_ERROR, "%s should be a string",
+ GRPC_ARG_OPTIMIZATION_TARGET);
+ } else if (0 == strcmp(channel_args->args[i].value.string, "blend")) {
+ t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
+ } else if (0 == strcmp(channel_args->args[i].value.string, "latency")) {
+ t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
+ } else if (0 ==
+ strcmp(channel_args->args[i].value.string, "throughput")) {
+ t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT;
+ } else {
+ gpr_log(GPR_ERROR, "%s value '%s' unknown, assuming 'blend'",
+ GRPC_ARG_OPTIMIZATION_TARGET,
+ channel_args->args[i].value.string);
+ }
+ } else if (0 ==
+ strcmp(channel_args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
+ channelz_enabled = grpc_channel_arg_get_bool(
+ &channel_args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT);
+ } else {
+ static const struct {
+ const char* channel_arg_name;
+ grpc_chttp2_setting_id setting_id;
+ grpc_integer_options integer_options;
+ bool availability[2] /* server, client */;
+ } settings_map[] = {{GRPC_ARG_MAX_CONCURRENT_STREAMS,
+ GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
+ {-1, 0, INT32_MAX},
+ {true, false}},
+ {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
+ GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
+ {-1, 0, INT32_MAX},
+ {true, true}},
+ {GRPC_ARG_MAX_METADATA_SIZE,
+ GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
+ {-1, 0, INT32_MAX},
+ {true, true}},
+ {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
+ GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
+ {-1, 16384, 16777215},
+ {true, true}},
+ {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY,
+ GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA,
+ {1, 0, 1},
+ {true, true}},
+ {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
+ GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
+ {-1, 5, INT32_MAX},
+ {true, true}}};
+ for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(settings_map); j++) {
+ if (0 == strcmp(channel_args->args[i].key,
+ settings_map[j].channel_arg_name)) {
+ if (!settings_map[j].availability[is_client]) {
+ gpr_log(GPR_DEBUG, "%s is not available on %s",
+ settings_map[j].channel_arg_name,
+ is_client ? "clients" : "servers");
+ } else {
+ int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i], settings_map[j].integer_options);
+ if (value >= 0) {
+ queue_setting_update(t, settings_map[j].setting_id,
+ static_cast<uint32_t>(value));
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ 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::UniquePtr<char>(),
+ grpc_core::UniquePtr<char>(gpr_strdup(t->peer_string)));
+ }
+ return enable_bdp;
+}
+static void init_transport_closures(grpc_chttp2_transport* t) {
GRPC_CLOSURE_INIT(&t->read_action_locked, read_action_locked, t,
grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->benign_reclaimer_locked, benign_reclaimer_locked, t,
@@ -290,56 +440,9 @@ static void init_transport(grpc_chttp2_transport* t,
GRPC_CLOSURE_INIT(&t->keepalive_watchdog_fired_locked,
keepalive_watchdog_fired_locked, t,
grpc_combiner_scheduler(t->combiner));
+}
- 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);
-
- /* 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);
-
- /* copy in initial settings to all setting sets */
- 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;
- }
- }
- 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;
-
- if (is_client) {
- grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
- GRPC_CHTTP2_CLIENT_CONNECT_STRING));
- }
-
- /* 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(t, 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);
-
- t->ping_policy.max_pings_without_data = g_default_max_pings_without_data;
- t->ping_policy.min_sent_ping_interval_without_data =
- g_default_min_sent_ping_interval_without_data_ms;
- t->ping_policy.max_ping_strikes = g_default_max_ping_strikes;
- t->ping_policy.min_recv_ping_interval_without_data =
- g_default_min_recv_ping_interval_without_data_ms;
-
- /* Keepalive setting */
+static void init_transport_keepalive_settings(grpc_chttp2_transport* t) {
if (t->is_client) {
t->keepalive_time = g_default_client_keepalive_time_ms == INT_MAX
? GRPC_MILLIS_INF_FUTURE
@@ -359,205 +462,122 @@ static void init_transport(grpc_chttp2_transport* t,
t->keepalive_permit_without_calls =
g_default_server_keepalive_permit_without_calls;
}
+}
- t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
+static void configure_transport_ping_policy(grpc_chttp2_transport* t) {
+ t->ping_policy.max_pings_without_data = g_default_max_pings_without_data;
+ t->ping_policy.min_sent_ping_interval_without_data =
+ g_default_min_sent_ping_interval_without_data_ms;
+ t->ping_policy.max_ping_strikes = g_default_max_ping_strikes;
+ t->ping_policy.min_recv_ping_interval_without_data =
+ g_default_min_recv_ping_interval_without_data_ms;
+}
- bool enable_bdp = true;
+static void init_keepalive_pings_if_enabled(grpc_chttp2_transport* t) {
+ if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) {
+ t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
+ GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
+ grpc_timer_init(&t->keepalive_ping_timer,
+ grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
+ &t->init_keepalive_ping_locked);
+ } else {
+ /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no
+ inflight keeaplive timers */
+ t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
+ }
+}
- if (channel_args) {
- for (i = 0; i < channel_args->num_args; i++) {
- if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
- const grpc_integer_options options = {-1, 0, INT_MAX};
- const int value =
- grpc_channel_arg_get_integer(&channel_args->args[i], options);
- if (value >= 0) {
- if ((t->next_stream_id & 1) != (value & 1)) {
- gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
- GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
- t->next_stream_id & 1, is_client ? "client" : "server");
- } else {
- t->next_stream_id = static_cast<uint32_t>(value);
- }
- }
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
- const grpc_integer_options options = {-1, 0, INT_MAX};
- const int value =
- grpc_channel_arg_get_integer(&channel_args->args[i], options);
- if (value >= 0) {
- grpc_chttp2_hpack_compressor_set_max_usable_size(
- &t->hpack_compressor, static_cast<uint32_t>(value));
- }
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) {
- t->ping_policy.max_pings_without_data = grpc_channel_arg_get_integer(
- &channel_args->args[i],
- {g_default_max_pings_without_data, 0, INT_MAX});
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_MAX_PING_STRIKES)) {
- t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer(
- &channel_args->args[i], {g_default_max_ping_strikes, 0, INT_MAX});
- } else if (0 ==
- strcmp(
- channel_args->args[i].key,
- GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS)) {
- t->ping_policy.min_sent_ping_interval_without_data =
- grpc_channel_arg_get_integer(
- &channel_args->args[i],
- grpc_integer_options{
- g_default_min_sent_ping_interval_without_data_ms, 0,
- INT_MAX});
- } else if (0 ==
- strcmp(
- channel_args->args[i].key,
- GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS)) {
- t->ping_policy.min_recv_ping_interval_without_data =
- grpc_channel_arg_get_integer(
- &channel_args->args[i],
- grpc_integer_options{
- g_default_min_recv_ping_interval_without_data_ms, 0,
- INT_MAX});
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
- t->write_buffer_size =
- static_cast<uint32_t>(grpc_channel_arg_get_integer(
- &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}));
- } else if (0 ==
- strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
- enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_KEEPALIVE_TIME_MS)) {
- const int value = grpc_channel_arg_get_integer(
- &channel_args->args[i],
- grpc_integer_options{t->is_client
- ? g_default_client_keepalive_time_ms
- : g_default_server_keepalive_time_ms,
- 1, INT_MAX});
- t->keepalive_time = value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
- const int value = grpc_channel_arg_get_integer(
- &channel_args->args[i],
- grpc_integer_options{t->is_client
- ? g_default_client_keepalive_timeout_ms
- : g_default_server_keepalive_timeout_ms,
- 0, INT_MAX});
- t->keepalive_timeout =
- value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
- t->keepalive_permit_without_calls = static_cast<uint32_t>(
- grpc_channel_arg_get_integer(&channel_args->args[i], {0, 0, 1}));
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_OPTIMIZATION_TARGET)) {
- if (channel_args->args[i].type != GRPC_ARG_STRING) {
- gpr_log(GPR_ERROR, "%s should be a string",
- GRPC_ARG_OPTIMIZATION_TARGET);
- } else if (0 == strcmp(channel_args->args[i].value.string, "blend")) {
- t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
- } else if (0 == strcmp(channel_args->args[i].value.string, "latency")) {
- t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
- } else if (0 ==
- strcmp(channel_args->args[i].value.string, "throughput")) {
- t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_THROUGHPUT;
- } else {
- gpr_log(GPR_ERROR, "%s value '%s' unknown, assuming 'blend'",
- GRPC_ARG_OPTIMIZATION_TARGET,
- channel_args->args[i].value.string);
- }
- } else {
- static const struct {
- const char* channel_arg_name;
- grpc_chttp2_setting_id setting_id;
- grpc_integer_options integer_options;
- bool availability[2] /* server, client */;
- } settings_map[] = {
- {GRPC_ARG_MAX_CONCURRENT_STREAMS,
- GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
- {-1, 0, INT32_MAX},
- {true, false}},
- {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER,
- GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
- {-1, 0, INT32_MAX},
- {true, true}},
- {GRPC_ARG_MAX_METADATA_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
- {-1, 0, INT32_MAX},
- {true, true}},
- {GRPC_ARG_HTTP2_MAX_FRAME_SIZE,
- GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
- {-1, 16384, 16777215},
- {true, true}},
- {GRPC_ARG_HTTP2_ENABLE_TRUE_BINARY,
- GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA,
- {1, 0, 1},
- {true, true}},
- {GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES,
- GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
- {-1, 5, INT32_MAX},
- {true, true}}};
- for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(settings_map); j++) {
- if (0 == strcmp(channel_args->args[i].key,
- settings_map[j].channel_arg_name)) {
- if (!settings_map[j].availability[is_client]) {
- gpr_log(GPR_DEBUG, "%s is not available on %s",
- settings_map[j].channel_arg_name,
- is_client ? "clients" : "servers");
- } else {
- int value = grpc_channel_arg_get_integer(
- &channel_args->args[i], settings_map[j].integer_options);
- if (value >= 0) {
- queue_setting_update(t, settings_map[j].setting_id,
- static_cast<uint32_t>(value));
- }
- }
- break;
- }
- }
- }
+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);
+ base.vtable = get_vtable();
+ /* one ref is for destroy */
+ 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(&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++) {
+ settings[j][i] = grpc_chttp2_settings_parameters[i].default_value;
}
}
+ grpc_chttp2_hpack_parser_init(&hpack_parser);
+ grpc_chttp2_goaway_parser_init(&goaway_parser);
+
+ init_transport_closures(this);
+
+ /* configure http2 the way we like it */
+ if (is_client) {
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
+ }
+ queue_setting_update(this, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
+ DEFAULT_MAX_HEADER_LIST_SIZE);
+ queue_setting_update(this,
+ GRPC_CHTTP2_SETTINGS_GRPC_ALLOW_TRUE_BINARY_METADATA, 1);
+
+ configure_transport_ping_policy(this);
+ init_transport_keepalive_settings(this);
+
+ bool enable_bdp = true;
+ if (channel_args) {
+ 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;
- /* Start keepalive pings */
- if (t->keepalive_time != GRPC_MILLIS_INF_FUTURE) {
- t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
- GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
- grpc_timer_init(&t->keepalive_ping_timer,
- grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
- &t->init_keepalive_ping_locked);
- } else {
- /* Use GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED to indicate there are no
- inflight keeaplive timers */
- t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
- }
+ 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) {
@@ -567,6 +587,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");
}
@@ -651,103 +672,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);
+
+ 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));
}
-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_chttp2_stream::~grpc_chttp2_stream() {
+ if (t->channelz_socket != nullptr) {
+ 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);
+
+ flow_control.Destroy();
- s->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);
+}
- GRPC_CLOSURE_SCHED(s->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;
+}
+
+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,
@@ -783,7 +809,21 @@ grpc_chttp2_stream* grpc_chttp2_parsing_accept_stream(grpc_chttp2_transport* t,
if (t->channel_callback.accept_stream == nullptr) {
return nullptr;
}
- grpc_chttp2_stream* accepting;
+ // Don't accept the stream if memory quota doesn't allow. Note that we should
+ // simply refuse the stream here instead of canceling the stream after it's
+ // accepted since the latter will create the call which costs much memory.
+ if (t->resource_user != nullptr &&
+ !grpc_resource_user_safe_alloc(t->resource_user,
+ GRPC_RESOURCE_QUOTA_CALL_SIZE)) {
+ gpr_log(GPR_ERROR, "Memory exhausted, rejecting the stream.");
+ grpc_slice_buffer_add(
+ &t->qbuf,
+ grpc_chttp2_rst_stream_create(
+ id, static_cast<uint32_t>(GRPC_HTTP2_REFUSED_STREAM), nullptr));
+ grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RST_STREAM);
+ return nullptr;
+ }
+ grpc_chttp2_stream* accepting = nullptr;
GPR_ASSERT(t->accepting_stream == nullptr);
t->accepting_stream = &accepting;
t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
@@ -1401,6 +1441,9 @@ static void perform_stream_op_locked(void* stream_op,
}
if (op->send_initial_metadata) {
+ if (t->is_client && t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordStreamStartedFromLocal();
+ }
GRPC_STATS_INC_HTTP2_OP_SEND_INITIAL_METADATA();
GPR_ASSERT(s->send_initial_metadata_finished == nullptr);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
@@ -1486,6 +1529,7 @@ static void perform_stream_op_locked(void* stream_op,
if (op->send_message) {
GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE();
+ t->num_messages_in_next_write++;
GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE(
op->payload->send_message.send_message->length());
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
@@ -1670,8 +1714,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)),
@@ -2097,8 +2141,7 @@ void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
"add_status_message",
grpc_chttp2_incoming_metadata_buffer_replace_or_add(
&s->metadata_buffer[1],
- grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_MESSAGE,
- grpc_slice_ref_internal(slice))));
+ grpc_mdelem_create(GRPC_MDSTR_GRPC_MESSAGE, slice, nullptr)));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s);
@@ -2678,6 +2721,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 {
@@ -2701,6 +2745,9 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
return;
}
+ if (t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordKeepaliveSent();
+ }
GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog");
grpc_timer_init(&t->keepalive_watchdog_timer,
grpc_core::ExecCtx::Get()->Now() + t->keepalive_timeout,
@@ -2728,10 +2775,10 @@ static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
if (error == GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
close_transport_locked(
- t,
- grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "keepalive watchdog timeout"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL));
+ t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "keepalive watchdog timeout"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNAVAILABLE));
}
} else {
/* The watchdog timer should have been cancelled by
@@ -2897,17 +2944,20 @@ bool Chttp2IncomingByteStream::Next(size_t max_size_hint,
}
}
+void Chttp2IncomingByteStream::MaybeCreateStreamDecompressionCtx() {
+ if (!stream_->stream_decompression_ctx) {
+ stream_->stream_decompression_ctx = grpc_stream_compression_context_create(
+ stream_->stream_decompression_method);
+ }
+}
+
grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
grpc_error* error;
if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
if (!stream_->unprocessed_incoming_frames_decompressed) {
bool end_of_context;
- if (!stream_->stream_decompression_ctx) {
- stream_->stream_decompression_ctx =
- grpc_stream_compression_context_create(
- stream_->stream_decompression_method);
- }
+ MaybeCreateStreamDecompressionCtx();
if (!grpc_stream_decompress(stream_->stream_decompression_ctx,
&stream_->unprocessed_incoming_frames_buffer,
&stream_->decompressed_data_buffer, nullptr,
@@ -3138,11 +3188,21 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
static const grpc_transport_vtable* get_vtable(void) { return &vtable; }
+intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport) {
+ grpc_chttp2_transport* t =
+ reinterpret_cast<grpc_chttp2_transport*>(transport);
+ if (t->channelz_socket != nullptr) {
+ return t->channelz_socket->uuid();
+ } else {
+ return 0;
+ }
+}
+
grpc_transport* grpc_create_chttp2_transport(
- const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client) {
- grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(
- gpr_zalloc(sizeof(grpc_chttp2_transport)));
- init_transport(t, channel_args, ep, is_client);
+ const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* 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/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index 9d55b3f4b0..b3fe1c082e 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -32,7 +32,10 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount;
extern bool g_flow_control_enabled;
grpc_transport* grpc_create_chttp2_transport(
- const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client);
+ const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client,
+ grpc_resource_user* resource_user = nullptr);
+
+intptr_t grpc_chttp2_transport_get_socket_uuid(grpc_transport* transport);
/// Takes ownership of \a read_buffer, which (if non-NULL) contains
/// leftover bytes previously read from the endpoint (e.g., by handshakers).
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc
index f8f06f6789..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,
@@ -62,6 +56,7 @@ grpc_error* grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser* parser,
if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
s->received_last_frame = true;
+ s->eos_received = true;
} else {
s->received_last_frame = false;
}
@@ -191,6 +186,9 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
GPR_ASSERT(stream_out != nullptr);
GPR_ASSERT(p->parsing_frame == nullptr);
p->frame_size |= (static_cast<uint32_t>(*cur));
+ if (t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordMessageReceived();
+ }
p->state = GRPC_CHTTP2_DATA_FRAME;
++cur;
message_flags = 0;
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/frame_rst_stream.cc b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
index 4bdd4309a4..a0a7534594 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
@@ -32,7 +32,7 @@ grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
grpc_transport_one_way_stats* stats) {
static const size_t frame_size = 13;
grpc_slice slice = GRPC_SLICE_MALLOC(frame_size);
- stats->framing_bytes += frame_size;
+ if (stats != nullptr) stats->framing_bytes += frame_size;
uint8_t* p = GRPC_SLICE_START_PTR(slice);
// Frame size.
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 0eaf63f133..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 =
- grpc_mdelem_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 size_t decoder_space_usage =
+ grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
+ 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)
@@ -688,11 +691,22 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
emit_advertise_table_size_change(c, &st);
}
for (size_t i = 0; i < extra_headers_size; ++i) {
- hpack_enc(c, *extra_headers[i], &st);
+ grpc_mdelem md = *extra_headers[i];
+ uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
+ if (static_index) {
+ emit_indexed(c, static_index, &st);
+ } else {
+ hpack_enc(c, md, &st);
+ }
}
grpc_metadata_batch_assert_ok(metadata);
for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) {
- hpack_enc(c, l->md, &st);
+ uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
+ if (static_index) {
+ emit_indexed(c, static_index, &st);
+ } else {
+ hpack_enc(c, l->md, &st);
+ }
}
grpc_millis deadline = metadata->deadline;
if (deadline != GRPC_MILLIS_INF_FUTURE) {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc
index 7929258356..fcfb01872b 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc
@@ -29,6 +29,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/transport/static_metadata.h"
extern grpc_core::TraceFlag grpc_http_trace;
@@ -366,3 +367,31 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
return r;
}
+
+static size_t get_base64_encoded_size(size_t raw_length) {
+ static const uint8_t tail_xtra[3] = {0, 2, 3};
+ return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
+}
+
+size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
+ bool use_true_binary_metadata) {
+ size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+ size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
+ if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+ return overhead_and_key + (use_true_binary_metadata
+ ? value_len + 1
+ : get_base64_encoded_size(value_len));
+ } else {
+ return overhead_and_key + value_len;
+ }
+}
+
+uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ uint8_t index = GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table;
+ if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
+ return index + 1; // Hpack static metadata element indices start at 1
+ }
+ }
+ return 0;
+}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 98026a4ba4..a0ffc6fab7 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -83,6 +83,15 @@ grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl,
/* add a table entry to the index */
grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
grpc_mdelem md) GRPC_MUST_USE_RESULT;
+
+size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
+ bool use_true_binary_metadata);
+
+/* Returns the static hpack table index that corresponds to /a elem. Returns 0
+ if /a elem is not statically stored or if it is not in the static hpack
+ table */
+uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md);
+
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
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 32a13df48c..8a83f4894c 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -36,6 +36,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/compression/stream_compression.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/iomgr/combiner.h"
@@ -106,8 +107,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 {
@@ -250,6 +251,8 @@ class Chttp2IncomingByteStream : public ByteStream {
static void NextLocked(void* arg, grpc_error* error_ignored);
static void OrphanLocked(void* arg, grpc_error* error_ignored);
+ void MaybeCreateStreamDecompressionCtx();
+
grpc_chttp2_transport* transport_; // Immutable.
grpc_chttp2_stream* stream_; // Immutable.
@@ -281,34 +284,41 @@ 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;
char* peer_string;
+ grpc_resource_user* resource_user;
+
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;
@@ -325,7 +335,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 */
@@ -349,41 +359,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 */
@@ -409,22 +421,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;
@@ -433,23 +445,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 */
@@ -470,10 +482,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::ContextList* cl;
+ grpc_core::RefCountedPtr<grpc_core::channelz::SocketNode> channelz_socket;
+ uint32_t num_messages_in_next_write = 0;
};
typedef enum {
@@ -484,6 +498,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();
+
void* context;
grpc_chttp2_transport* t;
grpc_stream_refcount* refcount;
@@ -492,59 +510,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 = 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];
@@ -554,33 +576,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,
@@ -590,32 +612,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/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 1e491d2ef8..1ff96d3cd3 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -368,6 +368,7 @@ static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t) {
&s->data_parser, t->incoming_frame_flags, s->id, s);
}
error_handler:
+ intptr_t unused;
if (err == GRPC_ERROR_NONE) {
t->incoming_stream = s;
/* t->parser = grpc_chttp2_data_parser_parse;*/
@@ -375,7 +376,7 @@ error_handler:
t->parser_data = &s->data_parser;
t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
return GRPC_ERROR_NONE;
- } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
/* handle stream errors by closing the stream */
if (s != nullptr) {
grpc_chttp2_mark_stream_closed(t, s, true, false, err);
@@ -409,67 +410,81 @@ static void on_initial_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
- !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
- /* TODO(ctiller): check for a status like " 0" */
- s->seen_error = true;
- }
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ // We don't use grpc_mdelem_eq here to avoid executing additional
+ // instructions. The reasoning is if the payload is not equal, we already
+ // know that the metadata elements are not equal because the md is
+ // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
+ // payloads are not equal, grpc_mdelem_eq executes more instructions to
+ // determine if they're equal or not.
+ if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
+ md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
+ s->seen_error = true;
+ }
+ } else {
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ /* TODO(ctiller): check for a status like " 0" */
+ s->seen_error = true;
+ }
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
- grpc_millis* cached_timeout =
- static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
- grpc_millis timeout;
- if (cached_timeout != nullptr) {
- timeout = *cached_timeout;
- } else {
- if (GPR_UNLIKELY(
- !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
- char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
- gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
- gpr_free(val);
- timeout = GRPC_MILLIS_INF_FUTURE;
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
+ grpc_millis* cached_timeout = static_cast<grpc_millis*>(
+ grpc_mdelem_get_user_data(md, free_timeout));
+ grpc_millis timeout;
+ if (cached_timeout != nullptr) {
+ timeout = *cached_timeout;
+ } else {
+ if (GPR_UNLIKELY(
+ !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
+ char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+ gpr_free(val);
+ timeout = GRPC_MILLIS_INF_FUTURE;
+ }
+ if (GRPC_MDELEM_IS_INTERNED(md)) {
+ /* store the result */
+ cached_timeout =
+ static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
+ *cached_timeout = timeout;
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ }
}
- if (GRPC_MDELEM_IS_INTERNED(md)) {
- /* store the result */
- cached_timeout =
- static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
- *cached_timeout = timeout;
- grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ if (timeout != GRPC_MILLIS_INF_FUTURE) {
+ grpc_chttp2_incoming_metadata_buffer_set_deadline(
+ &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
}
+ GRPC_MDELEM_UNREF(md);
+ return;
}
- if (timeout != GRPC_MILLIS_INF_FUTURE) {
- grpc_chttp2_incoming_metadata_buffer_set_deadline(
- &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
- }
+ }
+
+ const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
+ const size_t metadata_size_limit =
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+ if (new_size > metadata_size_limit) {
+ gpr_log(GPR_DEBUG,
+ "received initial metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
+ new_size, metadata_size_limit);
+ grpc_chttp2_cancel_stream(
+ t, s,
+ grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "received initial metadata size exceeds limit"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_RESOURCE_EXHAUSTED));
+ grpc_chttp2_parsing_become_skip_parser(t);
+ s->seen_error = true;
GRPC_MDELEM_UNREF(md);
} else {
- const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
- const size_t metadata_size_limit =
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
- if (new_size > metadata_size_limit) {
- gpr_log(GPR_DEBUG,
- "received initial metadata size exceeds limit (%" PRIuPTR
- " vs. %" PRIuPTR ")",
- new_size, metadata_size_limit);
- grpc_chttp2_cancel_stream(
- t, s,
- grpc_error_set_int(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "received initial metadata size exceeds limit"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
+ grpc_error* error =
+ grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
- } else {
- grpc_error* error =
- grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
- if (error != GRPC_ERROR_NONE) {
- grpc_chttp2_cancel_stream(t, s, error);
- grpc_chttp2_parsing_become_skip_parser(t);
- s->seen_error = true;
- GRPC_MDELEM_UNREF(md);
- }
}
}
}
@@ -491,8 +506,19 @@ static void on_trailing_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
- !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ // We don't use grpc_mdelem_eq here to avoid executing additional
+ // instructions. The reasoning is if the payload is not equal, we already
+ // know that the metadata elements are not equal because the md is
+ // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
+ // payloads are not equal, grpc_mdelem_eq executes more instructions to
+ // determine if they're equal or not.
+ if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
+ md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
+ s->seen_error = true;
+ }
+ } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
@@ -598,6 +624,9 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"));
return init_skip_frame_parser(t, 1);
}
+ if (t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordStreamStartedFromRemote();
+ }
} else {
t->incoming_stream = s;
}
@@ -611,6 +640,9 @@ static grpc_error* init_header_frame_parser(grpc_chttp2_transport* t,
}
t->parser = grpc_chttp2_header_parser_parse;
t->parser_data = &t->hpack_parser;
+ if (t->header_eof) {
+ s->eos_received = true;
+ }
switch (s->header_frames_received) {
case 0:
if (t->is_client && t->header_eof) {
@@ -725,9 +757,10 @@ static grpc_error* parse_frame_slice(grpc_chttp2_transport* t, grpc_slice slice,
int is_last) {
grpc_chttp2_stream* s = t->incoming_stream;
grpc_error* err = t->parser(t->parser_data, t, s, slice, is_last);
+ intptr_t unused;
if (GPR_LIKELY(err == GRPC_ERROR_NONE)) {
return err;
- } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
if (grpc_http_trace.enabled()) {
const char* msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index c9273f7e39..3b3367d0f3 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -574,6 +574,7 @@ class StreamWriteContext {
void SentLastFrame() {
s_->send_trailing_metadata = nullptr;
s_->sent_trailing_metadata = true;
+ s_->eos_sent = true;
if (!t_->is_client && !s_->read_closed) {
grpc_slice_buffer_add(
@@ -637,6 +638,11 @@ void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error* error) {
GPR_TIMER_SCOPE("grpc_chttp2_end_write", 0);
grpc_chttp2_stream* s;
+ if (t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordMessagesSent(t->num_messages_in_next_write);
+ }
+ t->num_messages_in_next_write = 0;
+
while (grpc_chttp2_list_pop_writing_stream(t, &s)) {
if (s->sending_bytes != 0) {
update_list(t, s, static_cast<int64_t>(s->sending_bytes),
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc
index 4a252d972d..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;
@@ -1287,7 +1293,7 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
grpc_error* error = GRPC_ERROR_NONE;
if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
error = GRPC_ERROR_REF(stream_state->cancel_error);
- } else if (stream_state->state_op_done[OP_FAILED]) {
+ } else if (stream_state->state_callback_received[OP_FAILED]) {
error = make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable.");
} else if (oas->s->state.rs.trailing_metadata_valid) {
grpc_chttp2_incoming_metadata_buffer_publish(
@@ -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 b0ca7f8207..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) {
@@ -1256,7 +1234,9 @@ grpc_channel* grpc_inproc_channel_create(grpc_server* server,
inproc_transports_create(&server_transport, server_args, &client_transport,
client_args);
- grpc_server_setup_transport(server, server_transport, nullptr, server_args);
+ // TODO(ncteisen): design and support channelz GetSocket for inproc.
+ grpc_server_setup_transport(server, server_transport, nullptr, server_args,
+ 0);
grpc_channel* channel = grpc_channel_create(
"inproc", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport);
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/channel_stack_builder.cc b/src/core/lib/channel/channel_stack_builder.cc
index df5a783631..8b3008f221 100644
--- a/src/core/lib/channel/channel_stack_builder.cc
+++ b/src/core/lib/channel/channel_stack_builder.cc
@@ -40,6 +40,7 @@ struct grpc_channel_stack_builder {
// various set/get-able parameters
grpc_channel_args* args;
grpc_transport* transport;
+ grpc_resource_user* resource_user;
char* target;
const char* name;
};
@@ -157,6 +158,11 @@ void grpc_channel_stack_builder_set_channel_arguments(
builder->args = grpc_channel_args_copy(args);
}
+const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
+ grpc_channel_stack_builder* builder) {
+ return builder->args;
+}
+
void grpc_channel_stack_builder_set_transport(
grpc_channel_stack_builder* builder, grpc_transport* transport) {
GPR_ASSERT(builder->transport == nullptr);
@@ -168,9 +174,15 @@ grpc_transport* grpc_channel_stack_builder_get_transport(
return builder->transport;
}
-const grpc_channel_args* grpc_channel_stack_builder_get_channel_arguments(
+void grpc_channel_stack_builder_set_resource_user(
+ grpc_channel_stack_builder* builder, grpc_resource_user* resource_user) {
+ GPR_ASSERT(builder->resource_user == nullptr);
+ builder->resource_user = resource_user;
+}
+
+grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
grpc_channel_stack_builder* builder) {
- return builder->args;
+ return builder->resource_user;
}
bool grpc_channel_stack_builder_append_filter(
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 9196de9378..89c30e0c5e 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -54,6 +54,14 @@ void grpc_channel_stack_builder_set_transport(
grpc_transport* grpc_channel_stack_builder_get_transport(
grpc_channel_stack_builder* builder);
+/// Attach \a resource_user to the builder (does not take ownership)
+void grpc_channel_stack_builder_set_resource_user(
+ grpc_channel_stack_builder* builder, grpc_resource_user* resource_user);
+
+/// Fetch attached resource user
+grpc_resource_user* grpc_channel_stack_builder_get_resource_user(
+ grpc_channel_stack_builder* builder);
+
/// Set channel arguments: copies args
void grpc_channel_stack_builder_set_channel_arguments(
grpc_channel_stack_builder* builder, const grpc_channel_args* args);
diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc
index b3443310ac..f0d21db32a 100644
--- a/src/core/lib/channel/channel_trace.cc
+++ b/src/core/lib/channel/channel_trace.cc
@@ -41,40 +41,42 @@
namespace grpc_core {
namespace channelz {
-ChannelTrace::TraceEvent::TraceEvent(
- Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_channel, ReferencedType type)
+ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data,
+ RefCountedPtr<BaseNode> referenced_entity)
: severity_(severity),
data_(data),
timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME)),
next_(nullptr),
- referenced_channel_(std::move(referenced_channel)),
- referenced_type_(type) {}
+ referenced_entity_(std::move(referenced_entity)),
+ memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
: severity_(severity),
data_(data),
timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME)),
- next_(nullptr) {}
+ next_(nullptr),
+ memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
-ChannelTrace::ChannelTrace(size_t max_events)
+ChannelTrace::ChannelTrace(size_t max_event_memory)
: num_events_logged_(0),
- list_size_(0),
- max_list_size_(max_events),
+ event_list_memory_usage_(0),
+ max_event_memory_(max_event_memory),
head_trace_(nullptr),
tail_trace_(nullptr) {
- if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ if (max_event_memory_ == 0)
+ return; // tracing is disabled if max_event_memory_ == 0
gpr_mu_init(&tracer_mu_);
time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME);
}
ChannelTrace::~ChannelTrace() {
- if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ if (max_event_memory_ == 0)
+ return; // tracing is disabled if max_event_memory_ == 0
TraceEvent* it = head_trace_;
while (it != nullptr) {
TraceEvent* to_free = it;
@@ -95,38 +97,34 @@ void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
tail_trace_->set_next(new_trace_event);
tail_trace_ = tail_trace_->next();
}
- ++list_size_;
- // maybe garbage collect the end
- if (list_size_ > max_list_size_) {
+ event_list_memory_usage_ += new_trace_event->memory_usage();
+ // maybe garbage collect the tail until we are under the memory limit.
+ while (event_list_memory_usage_ > max_event_memory_) {
TraceEvent* to_free = head_trace_;
+ event_list_memory_usage_ -= to_free->memory_usage();
head_trace_ = head_trace_->next();
Delete<TraceEvent>(to_free);
- --list_size_;
}
}
void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
- if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ if (max_event_memory_ == 0) {
+ grpc_slice_unref_internal(data);
+ return; // tracing is disabled if max_event_memory_ == 0
+ }
AddTraceEventHelper(New<TraceEvent>(severity, data));
}
-void ChannelTrace::AddTraceEventReferencingChannel(
- Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_channel) {
- if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
- // create and fill up the new event
- AddTraceEventHelper(New<TraceEvent>(
- severity, data, std::move(referenced_channel), ReferencedType::Channel));
-}
-
-void ChannelTrace::AddTraceEventReferencingSubchannel(
+void ChannelTrace::AddTraceEventWithReference(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_subchannel) {
- if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ RefCountedPtr<BaseNode> referenced_entity) {
+ if (max_event_memory_ == 0) {
+ grpc_slice_unref_internal(data);
+ return; // tracing is disabled if max_event_memory_ == 0
+ }
// create and fill up the new event
- AddTraceEventHelper(New<TraceEvent>(severity, data,
- std::move(referenced_subchannel),
- ReferencedType::Subchannel));
+ AddTraceEventHelper(
+ New<TraceEvent>(severity, data, std::move(referenced_entity)));
}
namespace {
@@ -157,45 +155,46 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
json_iterator = grpc_json_create_child(json_iterator, json, "timestamp",
gpr_format_timespec(timestamp_),
GRPC_JSON_STRING, true);
- if (referenced_channel_ != nullptr) {
+ if (referenced_entity_ != nullptr) {
+ const bool is_channel =
+ (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
+ referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
char* uuid_str;
- gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_channel_->channel_uuid());
+ gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_entity_->uuid());
grpc_json* child_ref = grpc_json_create_child(
- json_iterator, json,
- (referenced_type_ == ReferencedType::Channel) ? "channelRef"
- : "subchannelRef",
+ json_iterator, json, is_channel ? "channelRef" : "subchannelRef",
nullptr, GRPC_JSON_OBJECT, false);
json_iterator = grpc_json_create_child(
- nullptr, child_ref,
- (referenced_type_ == ReferencedType::Channel) ? "channelId"
- : "subchannelId",
- uuid_str, GRPC_JSON_STRING, true);
+ nullptr, child_ref, is_channel ? "channelId" : "subchannelId", uuid_str,
+ GRPC_JSON_STRING, true);
json_iterator = child_ref;
}
}
grpc_json* ChannelTrace::RenderJson() const {
- if (!max_list_size_)
- return nullptr; // tracing is disabled if max_events == 0
+ if (max_event_memory_ == 0)
+ return nullptr; // tracing is disabled if max_event_memory_ == 0
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
- char* num_events_logged_str;
- gpr_asprintf(&num_events_logged_str, "%" PRId64, num_events_logged_);
grpc_json* json_iterator = nullptr;
- json_iterator =
- grpc_json_create_child(json_iterator, json, "numEventsLogged",
- num_events_logged_str, GRPC_JSON_STRING, true);
+ if (num_events_logged_ > 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "numEventsLogged", num_events_logged_);
+ }
json_iterator = grpc_json_create_child(
json_iterator, json, "creationTimestamp",
gpr_format_timespec(time_created_), GRPC_JSON_STRING, true);
- grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
- nullptr, GRPC_JSON_ARRAY, false);
- json_iterator = nullptr;
- TraceEvent* it = head_trace_;
- while (it != nullptr) {
- json_iterator = grpc_json_create_child(json_iterator, events, nullptr,
- nullptr, GRPC_JSON_OBJECT, false);
- it->RenderTraceEvent(json_iterator);
- it = it->next();
+ // only add in the event list if it is non-empty.
+ if (head_trace_ != nullptr) {
+ grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
+ nullptr, GRPC_JSON_ARRAY, false);
+ json_iterator = nullptr;
+ TraceEvent* it = head_trace_;
+ while (it != nullptr) {
+ json_iterator = grpc_json_create_child(json_iterator, events, nullptr,
+ nullptr, GRPC_JSON_OBJECT, false);
+ it->RenderTraceEvent(json_iterator);
+ it = it->next();
+ }
}
return json;
}
diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h
index 596af7402f..8ff91ee8c8 100644
--- a/src/core/lib/channel/channel_trace.h
+++ b/src/core/lib/channel/channel_trace.h
@@ -30,14 +30,18 @@
namespace grpc_core {
namespace channelz {
-class ChannelNode;
+namespace testing {
+size_t GetSizeofTraceEvent(void);
+}
+
+class BaseNode;
// Object used to hold live data for a channel. This data is exposed via the
// channelz service:
// https://github.com/grpc/proposal/blob/master/A14-channelz.md
class ChannelTrace {
public:
- ChannelTrace(size_t max_events);
+ ChannelTrace(size_t max_event_memory);
~ChannelTrace();
enum Severity {
@@ -49,41 +53,42 @@ class ChannelTrace {
// Adds a new trace event to the tracing object
//
+ // NOTE: each ChannelTrace tracks the memory used by its list of trace
+ // events, so adding an event with a large amount of data could cause other
+ // trace event to be evicted. If a single trace is larger than the limit, it
+ // will cause all events to be evicted. The limit is set with the arg:
+ // GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE.
+ //
// TODO(ncteisen): as this call is used more and more throughout the gRPC
// stack, determine if it makes more sense to accept a char* instead of a
// slice.
void AddTraceEvent(Severity severity, grpc_slice data);
// Adds a new trace event to the tracing object. This trace event refers to a
- // an event on a child of the channel. For example, if this channel has
- // created a new subchannel, then it would record that with a TraceEvent
- // referencing the new subchannel.
+ // an event that concerns a different channelz entity. For example, if this
+ // channel has created a new subchannel, then it would record that with
+ // a TraceEvent referencing the new subchannel.
//
- // TODO(ncteisen): as this call is used more and more throughout the gRPC
- // stack, determine if it makes more sense to accept a char* instead of a
- // slice.
- void AddTraceEventReferencingChannel(
- Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_channel);
- void AddTraceEventReferencingSubchannel(
- Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_subchannel);
+ // NOTE: see the note in the method above.
+ //
+ // TODO(ncteisen): see the todo in the method above.
+ void AddTraceEventWithReference(Severity severity, grpc_slice data,
+ RefCountedPtr<BaseNode> referenced_entity);
// Creates and returns the raw grpc_json object, so a parent channelz
// object may incorporate the json before rendering.
grpc_json* RenderJson() const;
private:
- // Types of objects that can be references by trace events.
- enum class ReferencedType { Channel, Subchannel };
+ friend size_t testing::GetSizeofTraceEvent(void);
+
// Private class to encapsulate all the data and bookkeeping needed for a
// a trace event.
class TraceEvent {
public:
- // Constructor for a TraceEvent that references a different channel.
+ // Constructor for a TraceEvent that references a channel.
TraceEvent(Severity severity, grpc_slice data,
- RefCountedPtr<ChannelNode> referenced_channel,
- ReferencedType type);
+ RefCountedPtr<BaseNode> referenced_entity_);
// Constructor for a TraceEvent that does not reverence a different
// channel.
@@ -99,16 +104,16 @@ class ChannelTrace {
TraceEvent* next() const { return next_; }
void set_next(TraceEvent* next) { next_ = next; }
+ size_t memory_usage() const { return memory_usage_; }
+
private:
Severity severity_;
grpc_slice data_;
gpr_timespec timestamp_;
TraceEvent* next_;
// the tracer object for the (sub)channel that this trace event refers to.
- RefCountedPtr<ChannelNode> referenced_channel_;
- // the type that the referenced tracer points to. Unused if this trace
- // does not point to any channel or subchannel
- ReferencedType referenced_type_;
+ RefCountedPtr<BaseNode> referenced_entity_;
+ size_t memory_usage_;
}; // TraceEvent
// Internal helper to add and link in a trace event
@@ -116,8 +121,8 @@ class ChannelTrace {
gpr_mu tracer_mu_;
uint64_t num_events_logged_;
- size_t list_size_;
- size_t max_list_size_;
+ size_t event_list_memory_usage_;
+ size_t max_event_memory_;
TraceEvent* head_trace_;
TraceEvent* tail_trace_;
gpr_timespec time_created_;
diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc
index 9d6002ed8a..8d589f5983 100644
--- a/src/core/lib/channel/channelz.cc
+++ b/src/core/lib/channel/channelz.cc
@@ -30,44 +30,122 @@
#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 {
-ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
- bool is_top_level_channel)
- : channel_(channel),
- target_(nullptr),
- channel_uuid_(-1),
- is_top_level_channel_(is_top_level_channel) {
- trace_.Init(channel_tracer_max_nodes);
- target_ = UniquePtr<char>(grpc_channel_get_target(channel_));
- channel_uuid_ = ChannelzRegistry::RegisterChannelNode(this);
- gpr_atm_no_barrier_store(&last_call_started_millis_,
- (gpr_atm)ExecCtx::Get()->Now());
+BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) {
+ // The registry will set uuid_ under its lock.
+ ChannelzRegistry::Register(this);
}
-ChannelNode::~ChannelNode() {
- trace_.Destroy();
- ChannelzRegistry::UnregisterChannelNode(channel_uuid_);
+BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
+
+char* BaseNode::RenderJsonString() {
+ grpc_json* json = RenderJson();
+ GPR_ASSERT(json != nullptr);
+ char* json_str = grpc_json_dump_to_string(json, 0);
+ grpc_json_destroy(json);
+ return json_str;
}
-void ChannelNode::RecordCallStarted() {
- gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1);
- gpr_atm_no_barrier_store(&last_call_started_millis_,
- (gpr_atm)ExecCtx::Get()->Now());
+CallCountingHelper::CallCountingHelper() {
+ num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
+ per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>(
+ gpr_zalloc(sizeof(AtomicCounterData) * num_cores_));
}
-void ChannelNode::PopulateConnectivityState(grpc_json* json) {}
+CallCountingHelper::~CallCountingHelper() {
+ gpr_free(per_cpu_counter_data_storage_);
+}
-void ChannelNode::PopulateChildRefs(grpc_json* json) {}
+void CallCountingHelper::RecordCallStarted() {
+ gpr_atm_no_barrier_fetch_add(
+ &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
+ .calls_started,
+ static_cast<gpr_atm>(1));
+ gpr_atm_no_barrier_store(
+ &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
+ .last_call_started_millis,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+void CallCountingHelper::RecordCallFailed() {
+ gpr_atm_no_barrier_fetch_add(
+ &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
+ .calls_failed,
+ static_cast<gpr_atm>(1));
+}
+
+void CallCountingHelper::RecordCallSucceeded() {
+ gpr_atm_no_barrier_fetch_add(
+ &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
+ .calls_succeeded,
+ static_cast<gpr_atm>(1));
+}
+
+void CallCountingHelper::CollectData(CounterData* out) {
+ for (size_t core = 0; core < num_cores_; ++core) {
+ out->calls_started += gpr_atm_no_barrier_load(
+ &per_cpu_counter_data_storage_[core].calls_started);
+ out->calls_succeeded += gpr_atm_no_barrier_load(
+ &per_cpu_counter_data_storage_[core].calls_succeeded);
+ out->calls_failed += gpr_atm_no_barrier_load(
+ &per_cpu_counter_data_storage_[core].calls_failed);
+ gpr_atm last_call = gpr_atm_no_barrier_load(
+ &per_cpu_counter_data_storage_[core].last_call_started_millis);
+ if (last_call > out->last_call_started_millis) {
+ out->last_call_started_millis = last_call;
+ }
+ }
+}
+
+void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
+ grpc_json* json_iterator = nullptr;
+ CounterData data;
+ CollectData(&data);
+ if (data.calls_started != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsStarted", data.calls_started);
+ }
+ if (data.calls_succeeded != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsSucceeded", data.calls_succeeded);
+ }
+ if (data.calls_failed) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsFailed", data.calls_failed);
+ }
+ if (data.calls_started != 0) {
+ gpr_timespec ts = grpc_millis_to_timespec(data.last_call_started_millis,
+ GPR_CLOCK_REALTIME);
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
+ gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ }
+}
+
+ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel)
+ : BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel
+ : EntityType::kInternalChannel),
+ channel_(channel),
+ target_(UniquePtr<char>(grpc_channel_get_target(channel_))),
+ trace_(channel_tracer_max_nodes) {}
+
+ChannelNode::~ChannelNode() {}
grpc_json* ChannelNode::RenderJson() {
// We need to track these three json objects to build our object
@@ -80,7 +158,7 @@ grpc_json* ChannelNode::RenderJson() {
json = json_iterator;
json_iterator = nullptr;
json_iterator = grpc_json_add_number_string_child(json, json_iterator,
- "channelId", channel_uuid_);
+ "channelId", uuid());
// reset json iterators to top level object
json = top_level_json;
json_iterator = nullptr;
@@ -89,51 +167,28 @@ grpc_json* ChannelNode::RenderJson() {
GRPC_JSON_OBJECT, false);
json = data;
json_iterator = nullptr;
+ // template method. Child classes may override this to add their specific
+ // functionality.
PopulateConnectivityState(json);
+ // populate the target.
GPR_ASSERT(target_.get() != nullptr);
- json_iterator = grpc_json_create_child(
- json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false);
+ grpc_json_create_child(nullptr, json, "target", target_.get(),
+ GRPC_JSON_STRING, false);
// fill in the channel trace if applicable
- grpc_json* trace = trace_->RenderJson();
- if (trace != nullptr) {
- // we manually link up and fill the child since it was created for us in
- // ChannelTrace::RenderJson
- trace->key = "trace"; // this object is named trace in channelz.proto
- json_iterator = grpc_json_link_child(json, trace, json_iterator);
- }
- // reset the parent to be the data object.
- json = data;
- json_iterator = nullptr;
- if (calls_started_ != 0) {
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsStarted", calls_started_);
- }
- if (calls_succeeded_ != 0) {
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsSucceeded", calls_succeeded_);
+ grpc_json* trace_json = trace_.RenderJson();
+ if (trace_json != nullptr) {
+ trace_json->key = "trace"; // this object is named trace in channelz.proto
+ grpc_json_link_child(json, trace_json, nullptr);
}
- if (calls_failed_) {
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsFailed", calls_failed_);
- }
- gpr_timespec ts =
- grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME);
- json_iterator =
- grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
- gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ // ask CallCountingHelper to populate trace and call count data.
+ call_counter_.PopulateCallCounts(json);
json = top_level_json;
- json_iterator = nullptr;
+ // template method. Child classes may override this to add their specific
+ // functionality.
PopulateChildRefs(json);
return top_level_json;
}
-char* ChannelNode::RenderJsonString() {
- grpc_json* json = RenderJson();
- char* json_str = grpc_json_dump_to_string(json, 0);
- grpc_json_destroy(json);
- return json_str;
-}
-
RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel) {
@@ -141,12 +196,263 @@ RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
channel, channel_tracer_max_nodes, is_top_level_channel);
}
-SubchannelNode::SubchannelNode() {
- subchannel_uuid_ = ChannelzRegistry::RegisterSubchannelNode(this);
+ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
+ : BaseNode(EntityType::kServer),
+ server_(server),
+ trace_(channel_tracer_max_nodes) {}
+
+ServerNode::~ServerNode() {}
+
+char* ServerNode::RenderServerSockets(intptr_t start_socket_id) {
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ ChildRefsList socket_refs;
+ // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
+ // reserved). However, we want to support requests coming in with
+ // start_server_id=0, which signifies "give me everything."
+ size_t start_idx = start_socket_id == 0 ? 0 : start_socket_id - 1;
+ grpc_server_populate_server_sockets(server_, &socket_refs, start_idx);
+ if (!socket_refs.empty()) {
+ // create list of socket refs
+ grpc_json* array_parent = grpc_json_create_child(
+ nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
+ for (size_t i = 0; i < socket_refs.size(); ++i) {
+ json_iterator =
+ grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
+ GRPC_JSON_OBJECT, false);
+ grpc_json_add_number_string_child(json_iterator, nullptr, "socketId",
+ socket_refs[i]);
+ }
+ }
+ // For now we do not have any pagination rules. In the future we could
+ // pick a constant for max_channels_sent for a GetServers request.
+ // Tracking: https://github.com/grpc/grpc/issues/16019.
+ json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
+ GRPC_JSON_TRUE, false);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
}
-SubchannelNode::~SubchannelNode() {
- ChannelzRegistry::UnregisterSubchannelNode(subchannel_uuid_);
+grpc_json* ServerNode::RenderJson() {
+ // We need to track these three json objects to build our object
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ // create and fill the ref child
+ json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator = grpc_json_add_number_string_child(json, json_iterator,
+ "serverId", uuid());
+ // reset json iterators to top level object
+ json = top_level_json;
+ json_iterator = nullptr;
+ // create and fill the data child.
+ grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = data;
+ json_iterator = nullptr;
+ // fill in the channel trace if applicable
+ grpc_json* trace_json = trace_.RenderJson();
+ if (trace_json != nullptr) {
+ trace_json->key = "trace"; // this object is named trace in channelz.proto
+ grpc_json_link_child(json, trace_json, nullptr);
+ }
+ // ask CallCountingHelper to populate trace and call count data.
+ call_counter_.PopulateCallCounts(json);
+ json = top_level_json;
+ ChildRefsList listen_sockets;
+ grpc_server_populate_listen_sockets(server_, &listen_sockets);
+ if (!listen_sockets.empty()) {
+ grpc_json* array_parent = grpc_json_create_child(
+ nullptr, json, "listenSocket", nullptr, GRPC_JSON_ARRAY, false);
+ for (size_t i = 0; i < listen_sockets.size(); ++i) {
+ json_iterator =
+ grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
+ GRPC_JSON_OBJECT, false);
+ grpc_json_add_number_string_child(json_iterator, nullptr, "socketId",
+ listen_sockets[i]);
+ }
+ }
+ return top_level_json;
+}
+
+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));
+ gpr_atm_no_barrier_store(&last_local_stream_created_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+void SocketNode::RecordStreamStartedFromRemote() {
+ gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
+ gpr_atm_no_barrier_store(&last_remote_stream_created_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+void SocketNode::RecordMessagesSent(uint32_t num_sent) {
+ gpr_atm_no_barrier_fetch_add(&messages_sent_, static_cast<gpr_atm>(num_sent));
+ gpr_atm_no_barrier_store(&last_message_sent_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+void SocketNode::RecordMessageReceived() {
+ gpr_atm_no_barrier_fetch_add(&messages_received_, static_cast<gpr_atm>(1));
+ gpr_atm_no_barrier_store(&last_message_received_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+grpc_json* SocketNode::RenderJson() {
+ // We need to track these three json objects to build our object
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ // create and fill the ref child
+ json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ 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;
+ // create and fill the data child.
+ grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = data;
+ json_iterator = nullptr;
+ gpr_timespec ts;
+ if (streams_started_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "streamsStarted", streams_started_);
+ if (last_local_stream_created_millis_ != 0) {
+ ts = grpc_millis_to_timespec(last_local_stream_created_millis_,
+ GPR_CLOCK_REALTIME);
+ json_iterator = grpc_json_create_child(
+ json_iterator, json, "lastLocalStreamCreatedTimestamp",
+ gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ }
+ if (last_remote_stream_created_millis_ != 0) {
+ ts = grpc_millis_to_timespec(last_remote_stream_created_millis_,
+ GPR_CLOCK_REALTIME);
+ json_iterator = grpc_json_create_child(
+ json_iterator, json, "lastRemoteStreamCreatedTimestamp",
+ gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ }
+ }
+ if (streams_succeeded_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "streamsSucceeded", streams_succeeded_);
+ }
+ if (streams_failed_) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "streamsFailed", streams_failed_);
+ }
+ if (messages_sent_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "messagesSent", messages_sent_);
+ ts = grpc_millis_to_timespec(last_message_sent_millis_, GPR_CLOCK_REALTIME);
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp",
+ gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ }
+ if (messages_received_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "messagesReceived", messages_received_);
+ ts = grpc_millis_to_timespec(last_message_received_millis_,
+ GPR_CLOCK_REALTIME);
+ json_iterator = grpc_json_create_child(
+ json_iterator, json, "lastMessageReceivedTimestamp",
+ gpr_format_timespec(ts), GRPC_JSON_STRING, true);
+ }
+ if (keepalives_sent_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "keepAlivesSent", keepalives_sent_);
+ }
+ return top_level_json;
+}
+
+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
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ // create and fill the ref child
+ json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ json_iterator = nullptr;
+ json_iterator = grpc_json_add_number_string_child(json, json_iterator,
+ "socketId", uuid());
+ json = top_level_json;
+ PopulateSocketAddressJson(json, "local", local_addr_.get());
+
+ return top_level_json;
}
} // namespace channelz
diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h
index 07eb73d626..64ab5cb3a6 100644
--- a/src/core/lib/channel/channelz.h
+++ b/src/core/lib/channel/channelz.h
@@ -24,6 +24,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
@@ -39,38 +40,134 @@
#define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \
"grpc.channelz_channel_is_internal_channel"
+/** This is the default value for whether or not to enable channelz. If
+ * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */
+#define GRPC_ENABLE_CHANNELZ_DEFAULT true
+
+/** This is the default value for the maximum amount of memory used by trace
+ * events per channel trace node. If
+ * GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override
+ * this default value. */
+#define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT 1024 * 4
+
namespace grpc_core {
+
namespace channelz {
+// TODO(ncteisen), this only contains the uuids of the children for now,
+// since that is all that is strictly needed. In a future enhancement we will
+// add human readable names as in the channelz.proto
+typedef InlinedVector<intptr_t, 10> ChildRefsList;
+
namespace testing {
+class CallCountingHelperPeer;
class ChannelNodePeer;
-}
+} // namespace testing
-class ChannelNode : public RefCounted<ChannelNode> {
+// base class for all channelz entities
+class BaseNode : public RefCounted<BaseNode> {
public:
- static RefCountedPtr<ChannelNode> MakeChannelNode(
- grpc_channel* channel, size_t channel_tracer_max_nodes,
- bool is_top_level_channel);
+ // There are only four high level channelz entities. However, to support
+ // GetTopChannelsRequest, we split the Channel entity into two different
+ // types. All children of BaseNode must be one of these types.
+ enum class EntityType {
+ kTopLevelChannel,
+ kInternalChannel,
+ kSubchannel,
+ kServer,
+ kSocket,
+ };
- void RecordCallStarted();
- void RecordCallFailed() {
- gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1)));
- }
- void RecordCallSucceeded() {
- gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
- }
+ explicit BaseNode(EntityType type);
+ virtual ~BaseNode();
- grpc_json* RenderJson();
+ // All children must implement this function.
+ virtual grpc_json* RenderJson() GRPC_ABSTRACT;
+
+ // Renders the json and returns allocated string that must be freed by the
+ // caller.
char* RenderJsonString();
- // helper for getting and populating connectivity state. It is virtual
- // because it allows the client_channel specific code to live in ext/
- // instead of lib/
- virtual void PopulateConnectivityState(grpc_json* json);
+ EntityType type() const { return type_; }
+ intptr_t uuid() const { return uuid_; }
+
+ private:
+ // to allow the ChannelzRegistry to set uuid_ under its lock.
+ friend class ChannelzRegistry;
+ const EntityType type_;
+ intptr_t uuid_;
+};
- virtual void PopulateChildRefs(grpc_json* json);
+// This class is a helper class for channelz entities that deal with Channels,
+// Subchannels, and Servers, since those have similar proto definitions.
+// This class has the ability to:
+// - track calls_{started,succeeded,failed}
+// - track last_call_started_timestamp
+// - perform rendering of the above items
+class CallCountingHelper {
+ public:
+ CallCountingHelper();
+ ~CallCountingHelper();
- ChannelTrace* trace() { return trace_.get(); }
+ void RecordCallStarted();
+ void RecordCallFailed();
+ void RecordCallSucceeded();
+
+ // Common rendering of the call count data and last_call_started_timestamp.
+ void PopulateCallCounts(grpc_json* json);
+
+ private:
+ // testing peer friend.
+ friend class testing::CallCountingHelperPeer;
+
+ struct AtomicCounterData {
+ gpr_atm calls_started = 0;
+ gpr_atm calls_succeeded = 0;
+ gpr_atm calls_failed = 0;
+ gpr_atm last_call_started_millis = 0;
+ };
+
+ struct CounterData {
+ intptr_t calls_started = 0;
+ intptr_t calls_succeeded = 0;
+ intptr_t calls_failed = 0;
+ intptr_t last_call_started_millis = 0;
+ };
+
+ // collects the sharded data into one CounterData struct.
+ void CollectData(CounterData* out);
+
+ AtomicCounterData* per_cpu_counter_data_storage_ = nullptr;
+ size_t num_cores_ = 0;
+};
+
+// Handles channelz bookkeeping for channels
+class ChannelNode : public BaseNode {
+ public:
+ static RefCountedPtr<ChannelNode> MakeChannelNode(
+ grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
+
+ ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
+ ~ChannelNode() override;
+
+ grpc_json* RenderJson() override;
+
+ // template methods. RenderJSON uses these methods to render its JSON
+ // representation. These are virtual so that children classes may provide
+ // their specific mechanism for populating these parts of the channelz
+ // object.
+ //
+ // ChannelNode does not have a notion of connectivity state or child refs,
+ // so it leaves these implementations blank.
+ //
+ // This is utilizing the template method design pattern.
+ //
+ // TODO(ncteisen): remove these template methods in favor of manual traversal
+ // and mutation of the grpc_json object.
+ virtual void PopulateConnectivityState(grpc_json* json) {}
+ virtual void PopulateChildRefs(grpc_json* json) {}
void MarkChannelDestroyed() {
GPR_ASSERT(channel_ != nullptr);
@@ -79,47 +176,107 @@ class ChannelNode : public RefCounted<ChannelNode> {
bool ChannelIsDestroyed() { return channel_ == nullptr; }
- intptr_t channel_uuid() { return channel_uuid_; }
- bool is_top_level_channel() { return is_top_level_channel_; }
-
- protected:
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
- ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
- bool is_top_level_channel);
- virtual ~ChannelNode();
+ // proxy methods to composed classes.
+ void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {
+ trace_.AddTraceEvent(severity, data);
+ }
+ void AddTraceEventWithReference(ChannelTrace::Severity severity,
+ grpc_slice data,
+ RefCountedPtr<BaseNode> referenced_channel) {
+ trace_.AddTraceEventWithReference(severity, data,
+ std::move(referenced_channel));
+ }
+ void RecordCallStarted() { call_counter_.RecordCallStarted(); }
+ void RecordCallFailed() { call_counter_.RecordCallFailed(); }
+ void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
private:
- // testing peer friend.
+ // to allow the channel trace test to access trace_.
friend class testing::ChannelNodePeer;
-
grpc_channel* channel_ = nullptr;
UniquePtr<char> target_;
- gpr_atm calls_started_ = 0;
- gpr_atm calls_succeeded_ = 0;
- gpr_atm calls_failed_ = 0;
- gpr_atm last_call_started_millis_ = 0;
- intptr_t channel_uuid_;
- bool is_top_level_channel_ = true;
- ManualConstructor<ChannelTrace> trace_;
+ CallCountingHelper call_counter_;
+ ChannelTrace trace_;
+};
+
+// Handles channelz bookkeeping for servers
+class ServerNode : public BaseNode {
+ public:
+ ServerNode(grpc_server* server, size_t channel_tracer_max_nodes);
+ ~ServerNode() override;
+
+ grpc_json* RenderJson() override;
+
+ char* RenderServerSockets(intptr_t start_socket_id);
+
+ // proxy methods to composed classes.
+ void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {
+ trace_.AddTraceEvent(severity, data);
+ }
+ void AddTraceEventWithReference(ChannelTrace::Severity severity,
+ grpc_slice data,
+ RefCountedPtr<BaseNode> referenced_channel) {
+ trace_.AddTraceEventWithReference(severity, data,
+ std::move(referenced_channel));
+ }
+ void RecordCallStarted() { call_counter_.RecordCallStarted(); }
+ void RecordCallFailed() { call_counter_.RecordCallFailed(); }
+ void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
+
+ private:
+ grpc_server* server_;
+ CallCountingHelper call_counter_;
+ ChannelTrace trace_;
};
-// Placeholds channelz class for subchannels. All this can do now is track its
-// uuid (this information is needed by the parent channelz class).
-// TODO(ncteisen): build this out to support the GetSubchannel channelz request.
-class SubchannelNode : public RefCounted<SubchannelNode> {
+// Handles channelz bookkeeping for sockets
+class SocketNode : public BaseNode {
public:
- SubchannelNode();
- virtual ~SubchannelNode();
+ SocketNode(UniquePtr<char> local, UniquePtr<char> remote);
+ ~SocketNode() override {}
- intptr_t subchannel_uuid() { return subchannel_uuid_; }
+ grpc_json* RenderJson() override;
+
+ void RecordStreamStartedFromLocal();
+ void RecordStreamStartedFromRemote();
+ void RecordStreamSucceeded() {
+ gpr_atm_no_barrier_fetch_add(&streams_succeeded_, static_cast<gpr_atm>(1));
+ }
+ void RecordStreamFailed() {
+ gpr_atm_no_barrier_fetch_add(&streams_failed_, static_cast<gpr_atm>(1));
+ }
+ void RecordMessagesSent(uint32_t num_sent);
+ void RecordMessageReceived();
+ void RecordKeepaliveSent() {
+ gpr_atm_no_barrier_fetch_add(&keepalives_sent_, static_cast<gpr_atm>(1));
+ }
+
+ private:
+ gpr_atm streams_started_ = 0;
+ gpr_atm streams_succeeded_ = 0;
+ gpr_atm streams_failed_ = 0;
+ gpr_atm messages_sent_ = 0;
+ gpr_atm messages_received_ = 0;
+ gpr_atm keepalives_sent_ = 0;
+ gpr_atm last_local_stream_created_millis_ = 0;
+ gpr_atm last_remote_stream_created_millis_ = 0;
+ gpr_atm last_message_sent_millis_ = 0;
+ gpr_atm last_message_received_millis_ = 0;
+ UniquePtr<char> local_;
+ UniquePtr<char> remote_;
+};
+
+// Handles channelz bookkeeping for listen sockets
+class ListenSocketNode : public BaseNode {
+ public:
+ // ListenSocketNode takes ownership of host.
+ explicit ListenSocketNode(UniquePtr<char> local_addr);
+ ~ListenSocketNode() override {}
- protected:
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
- GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
+ grpc_json* RenderJson() override;
private:
- intptr_t subchannel_uuid_;
+ 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 f79d2f0c17..bc23b90a66 100644
--- a/src/core/lib/channel/channelz_registry.cc
+++ b/src/core/lib/channel/channelz_registry.cc
@@ -38,6 +38,8 @@ namespace {
// singleton instance of the registry.
ChannelzRegistry* g_channelz_registry = nullptr;
+const int kPaginationLimit = 100;
+
} // anonymous namespace
void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); }
@@ -53,54 +55,101 @@ ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }
ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
-intptr_t ChannelzRegistry::InternalRegisterEntry(const RegistryEntry& entry) {
+void ChannelzRegistry::InternalRegister(BaseNode* node) {
MutexLock lock(&mu_);
- entities_.push_back(entry);
- intptr_t uuid = entities_.size();
- return uuid;
+ entities_.push_back(node);
+ node->uuid_ = ++uuid_generator_;
+}
+
+void ChannelzRegistry::MaybePerformCompactionLocked() {
+ constexpr double kEmptinessTheshold = 1 / 3;
+ double emptiness_ratio =
+ double(num_empty_slots_) / double(entities_.capacity());
+ if (emptiness_ratio > kEmptinessTheshold) {
+ int front = 0;
+ for (size_t i = 0; i < entities_.size(); ++i) {
+ if (entities_[i] != nullptr) {
+ entities_[front++] = entities_[i];
+ }
+ }
+ for (int i = 0; i < num_empty_slots_; ++i) {
+ entities_.pop_back();
+ }
+ num_empty_slots_ = 0;
+ }
}
-void ChannelzRegistry::InternalUnregisterEntry(intptr_t uuid, EntityType type) {
+int ChannelzRegistry::FindByUuidLocked(intptr_t target_uuid,
+ bool direct_hit_needed) {
+ int left = 0;
+ int right = int(entities_.size() - 1);
+ while (left <= right) {
+ int true_middle = left + (right - left) / 2;
+ int first_non_null = true_middle;
+ while (first_non_null < right && entities_[first_non_null] == nullptr) {
+ first_non_null++;
+ }
+ if (entities_[first_non_null] == nullptr) {
+ right = true_middle - 1;
+ continue;
+ }
+ intptr_t uuid = entities_[first_non_null]->uuid();
+ if (uuid == target_uuid) {
+ return int(first_non_null);
+ }
+ if (uuid < target_uuid) {
+ left = first_non_null + 1;
+ } else {
+ right = true_middle - 1;
+ }
+ }
+ return direct_hit_needed ? -1 : left;
+}
+
+void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
GPR_ASSERT(uuid >= 1);
MutexLock lock(&mu_);
- GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
- GPR_ASSERT(entities_[uuid - 1].type == type);
- entities_[uuid - 1].object = nullptr;
- entities_[uuid - 1].type = EntityType::kUnset;
+ GPR_ASSERT(uuid <= uuid_generator_);
+ int idx = FindByUuidLocked(uuid, true);
+ GPR_ASSERT(idx >= 0);
+ entities_[idx] = nullptr;
+ num_empty_slots_++;
+ MaybePerformCompactionLocked();
}
-void* ChannelzRegistry::InternalGetEntry(intptr_t uuid, EntityType type) {
+BaseNode* ChannelzRegistry::InternalGet(intptr_t uuid) {
MutexLock lock(&mu_);
- if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) {
- return nullptr;
- }
- if (entities_[uuid - 1].type == type) {
- return entities_[uuid - 1].object;
- } else {
+ if (uuid < 1 || uuid > uuid_generator_) {
return nullptr;
}
+ int idx = FindByUuidLocked(uuid, true);
+ return idx < 0 ? nullptr : entities_[idx];
}
char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
+ MutexLock lock(&mu_);
grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json* json = top_level_json;
grpc_json* json_iterator = nullptr;
- InlinedVector<ChannelNode*, 10> top_level_channels;
- // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
- // reserved). However, we want to support requests coming in with
- // start_channel_id=0, which signifies "give me everything." Hence this
- // funky looking line below.
- size_t start_idx = start_channel_id == 0 ? 0 : start_channel_id - 1;
+ InlinedVector<BaseNode*, 10> top_level_channels;
+ bool reached_pagination_limit = false;
+ int start_idx = GPR_MAX(FindByUuidLocked(start_channel_id, false), 0);
for (size_t i = start_idx; i < entities_.size(); ++i) {
- if (entities_[i].type == EntityType::kChannelNode) {
- ChannelNode* channel_node =
- static_cast<ChannelNode*>(entities_[i].object);
- if (channel_node->is_top_level_channel()) {
- top_level_channels.push_back(channel_node);
+ if (entities_[i] != nullptr &&
+ entities_[i]->type() ==
+ grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
+ entities_[i]->uuid() >= start_channel_id) {
+ // check if we are over pagination limit to determine if we need to set
+ // the "end" element. If we don't go through this block, we know that
+ // when the loop terminates, we have <= to kPaginationLimit.
+ if (top_level_channels.size() == kPaginationLimit) {
+ reached_pagination_limit = true;
+ break;
}
+ top_level_channels.push_back(entities_[i]);
}
}
- if (top_level_channels.size() > 0) {
+ if (!top_level_channels.empty()) {
// create list of channels
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false);
@@ -110,16 +159,68 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
grpc_json_link_child(array_parent, channel_json, json_iterator);
}
}
- // For now we do not have any pagination rules. In the future we could
- // pick a constant for max_channels_sent for a GetTopChannels request.
- // Tracking: https://github.com/grpc/grpc/issues/16019.
- json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
- GRPC_JSON_TRUE, false);
+ if (!reached_pagination_limit) {
+ grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE,
+ false);
+ }
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
+
+char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
+ MutexLock lock(&mu_);
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ InlinedVector<BaseNode*, 10> servers;
+ bool reached_pagination_limit = false;
+ int start_idx = GPR_MAX(FindByUuidLocked(start_server_id, false), 0);
+ for (size_t i = start_idx; i < entities_.size(); ++i) {
+ if (entities_[i] != nullptr &&
+ entities_[i]->type() ==
+ grpc_core::channelz::BaseNode::EntityType::kServer &&
+ entities_[i]->uuid() >= start_server_id) {
+ // check if we are over pagination limit to determine if we need to set
+ // the "end" element. If we don't go through this block, we know that
+ // when the loop terminates, we have <= to kPaginationLimit.
+ if (servers.size() == kPaginationLimit) {
+ reached_pagination_limit = true;
+ break;
+ }
+ servers.push_back(entities_[i]);
+ }
+ }
+ if (!servers.empty()) {
+ // create list of servers
+ grpc_json* array_parent = grpc_json_create_child(
+ nullptr, json, "server", nullptr, GRPC_JSON_ARRAY, false);
+ for (size_t i = 0; i < servers.size(); ++i) {
+ grpc_json* server_json = servers[i]->RenderJson();
+ json_iterator =
+ grpc_json_link_child(array_parent, server_json, json_iterator);
+ }
+ }
+ if (!reached_pagination_limit) {
+ grpc_json_create_child(nullptr, json, "end", nullptr, GRPC_JSON_TRUE,
+ false);
+ }
char* json_str = grpc_json_dump_to_string(top_level_json, 0);
grpc_json_destroy(top_level_json);
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
@@ -128,10 +229,51 @@ char* grpc_channelz_get_top_channels(intptr_t start_channel_id) {
start_channel_id);
}
+char* grpc_channelz_get_servers(intptr_t start_server_id) {
+ return grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id);
+}
+
+char* grpc_channelz_get_server(intptr_t server_id) {
+ grpc_core::channelz::BaseNode* server_node =
+ grpc_core::channelz::ChannelzRegistry::Get(server_id);
+ if (server_node == nullptr ||
+ server_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kServer) {
+ return nullptr;
+ }
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* channel_json = server_node->RenderJson();
+ channel_json->key = "server";
+ grpc_json_link_child(json, channel_json, nullptr);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
+
+char* grpc_channelz_get_server_sockets(intptr_t server_id,
+ intptr_t start_socket_id) {
+ grpc_core::channelz::BaseNode* base_node =
+ grpc_core::channelz::ChannelzRegistry::Get(server_id);
+ if (base_node == nullptr ||
+ base_node->type() != grpc_core::channelz::BaseNode::EntityType::kServer) {
+ return nullptr;
+ }
+ // This cast is ok since we have just checked to make sure base_node is
+ // actually a server node
+ grpc_core::channelz::ServerNode* server_node =
+ static_cast<grpc_core::channelz::ServerNode*>(base_node);
+ return server_node->RenderServerSockets(start_socket_id);
+}
+
char* grpc_channelz_get_channel(intptr_t channel_id) {
- grpc_core::channelz::ChannelNode* channel_node =
- grpc_core::channelz::ChannelzRegistry::GetChannelNode(channel_id);
- if (channel_node == nullptr) {
+ grpc_core::channelz::BaseNode* channel_node =
+ grpc_core::channelz::ChannelzRegistry::Get(channel_id);
+ if (channel_node == nullptr ||
+ (channel_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
+ channel_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kInternalChannel)) {
return nullptr;
}
grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
@@ -143,3 +285,39 @@ char* grpc_channelz_get_channel(intptr_t channel_id) {
grpc_json_destroy(top_level_json);
return json_str;
}
+
+char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
+ grpc_core::channelz::BaseNode* subchannel_node =
+ grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
+ if (subchannel_node == nullptr ||
+ subchannel_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kSubchannel) {
+ return nullptr;
+ }
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* subchannel_json = subchannel_node->RenderJson();
+ subchannel_json->key = "subchannel";
+ grpc_json_link_child(json, subchannel_json, nullptr);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
+
+char* grpc_channelz_get_socket(intptr_t socket_id) {
+ grpc_core::channelz::BaseNode* socket_node =
+ grpc_core::channelz::ChannelzRegistry::Get(socket_id);
+ if (socket_node == nullptr ||
+ socket_node->type() !=
+ grpc_core::channelz::BaseNode::EntityType::kSocket) {
+ return nullptr;
+ }
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* socket_json = socket_node->RenderJson();
+ socket_json->key = "socket";
+ grpc_json_link_child(json, socket_json, nullptr);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h
index 5d7c936726..73b330785d 100644
--- a/src/core/lib/channel/channelz_registry.h
+++ b/src/core/lib/channel/channelz_registry.h
@@ -30,6 +30,10 @@
namespace grpc_core {
namespace channelz {
+namespace testing {
+class ChannelzRegistryPeer;
+}
+
// singleton registry object to track all objects that are needed to support
// channelz bookkeeping. All objects share globally distributed uuids.
class ChannelzRegistry {
@@ -40,32 +44,11 @@ class ChannelzRegistry {
// To be called in grpc_shutdown();
static void Shutdown();
- // Register/Unregister/Get for ChannelNode
- static intptr_t RegisterChannelNode(ChannelNode* channel_node) {
- RegistryEntry entry(channel_node, EntityType::kChannelNode);
- return Default()->InternalRegisterEntry(entry);
- }
- static void UnregisterChannelNode(intptr_t uuid) {
- Default()->InternalUnregisterEntry(uuid, EntityType::kChannelNode);
- }
- static ChannelNode* GetChannelNode(intptr_t uuid) {
- void* gotten = Default()->InternalGetEntry(uuid, EntityType::kChannelNode);
- return gotten == nullptr ? nullptr : static_cast<ChannelNode*>(gotten);
- }
-
- // Register/Unregister/Get for SubchannelNode
- static intptr_t RegisterSubchannelNode(SubchannelNode* channel_node) {
- RegistryEntry entry(channel_node, EntityType::kSubchannelNode);
- return Default()->InternalRegisterEntry(entry);
- }
- static void UnregisterSubchannelNode(intptr_t uuid) {
- Default()->InternalUnregisterEntry(uuid, EntityType::kSubchannelNode);
- }
- static SubchannelNode* GetSubchannelNode(intptr_t uuid) {
- void* gotten =
- Default()->InternalGetEntry(uuid, EntityType::kSubchannelNode);
- return gotten == nullptr ? nullptr : static_cast<SubchannelNode*>(gotten);
+ static void Register(BaseNode* node) {
+ return Default()->InternalRegister(node);
}
+ static void Unregister(intptr_t uuid) { Default()->InternalUnregister(uuid); }
+ static BaseNode* Get(intptr_t uuid) { return Default()->InternalGet(uuid); }
// Returns the allocated JSON string that represents the proto
// GetTopChannelsResponse as per channelz.proto.
@@ -73,22 +56,20 @@ class ChannelzRegistry {
return Default()->InternalGetTopChannels(start_channel_id);
}
- private:
- enum class EntityType {
- kChannelNode,
- kSubchannelNode,
- kUnset,
- };
-
- struct RegistryEntry {
- RegistryEntry(void* object_in, EntityType type_in)
- : object(object_in), type(type_in) {}
- void* object;
- EntityType type;
- };
+ // Returns the allocated JSON string that represents the proto
+ // GetServersResponse as per channelz.proto.
+ static char* GetServers(intptr_t start_server_id) {
+ 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
+ friend class testing::ChannelzRegistryPeer;
ChannelzRegistry();
~ChannelzRegistry();
@@ -97,21 +78,35 @@ class ChannelzRegistry {
static ChannelzRegistry* Default();
// globally registers an Entry. Returns its unique uuid
- intptr_t InternalRegisterEntry(const RegistryEntry& entry);
+ void InternalRegister(BaseNode* node);
// globally unregisters the object that is associated to uuid. Also does
// sanity check that an object doesn't try to unregister the wrong type.
- void InternalUnregisterEntry(intptr_t uuid, EntityType type);
+ void InternalUnregister(intptr_t uuid);
// if object with uuid has previously been registered as the correct type,
// returns the void* associated with that uuid. Else returns nullptr.
- void* InternalGetEntry(intptr_t uuid, EntityType type);
+ BaseNode* InternalGet(intptr_t uuid);
char* InternalGetTopChannels(intptr_t start_channel_id);
+ char* InternalGetServers(intptr_t start_server_id);
+
+ // If entities_ has over a certain threshold of empty slots, it will
+ // compact the vector and move all used slots to the front.
+ void MaybePerformCompactionLocked();
+
+ // Performs binary search on entities_ to find the index with that uuid.
+ // If direct_hit_needed, then will return -1 in case of absence.
+ // Else, will return idx of the first uuid higher than the target.
+ int FindByUuidLocked(intptr_t uuid, bool direct_hit_needed);
+
+ void InternalLogAllEntities();
- // protects entities_ and uuid_
+ // protects members
gpr_mu mu_;
- InlinedVector<RegistryEntry, 20> entities_;
+ InlinedVector<BaseNode*, 20> entities_;
+ intptr_t uuid_generator_ = 0;
+ int num_empty_slots_ = 0;
};
} // namespace channelz
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/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc
index ad3250b7e9..e516b56b74 100644
--- a/src/core/lib/channel/handshaker.cc
+++ b/src/core/lib/channel/handshaker.cc
@@ -292,17 +292,18 @@ static void on_timeout(void* arg, grpc_error* error) {
grpc_handshake_manager_unref(mgr);
}
-void grpc_handshake_manager_do_handshake(
- grpc_handshake_manager* mgr, grpc_pollset_set* interested_parties,
- grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
- grpc_millis deadline, grpc_tcp_server_acceptor* acceptor,
- grpc_iomgr_cb_func on_handshake_done, void* user_data) {
+void grpc_handshake_manager_do_handshake(grpc_handshake_manager* mgr,
+ grpc_endpoint* endpoint,
+ const grpc_channel_args* channel_args,
+ grpc_millis deadline,
+ grpc_tcp_server_acceptor* acceptor,
+ grpc_iomgr_cb_func on_handshake_done,
+ void* user_data) {
gpr_mu_lock(&mgr->mu);
GPR_ASSERT(mgr->index == 0);
GPR_ASSERT(!mgr->shutdown);
// Construct handshaker args. These will be passed through all
// handshakers and eventually be freed by the on_handshake_done callback.
- mgr->args.interested_parties = interested_parties;
mgr->args.endpoint = endpoint;
mgr->args.args = grpc_channel_args_copy(channel_args);
mgr->args.user_data = user_data;
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index be7fd127e4..a65990fceb 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -56,7 +56,6 @@ typedef struct grpc_handshaker grpc_handshaker;
/// For the on_handshake_done callback, all members are input arguments,
/// which the callback takes ownership of.
typedef struct {
- grpc_pollset_set* interested_parties;
grpc_endpoint* endpoint;
grpc_channel_args* args;
grpc_slice_buffer* read_buffer;
@@ -132,8 +131,6 @@ void grpc_handshake_manager_shutdown(grpc_handshake_manager* mgr,
grpc_error* why);
/// Invokes handshakers in the order they were added.
-/// \a interested_parties may be non-nullptr to provide a pollset_set that
-/// may be used during handshaking. Ownership is not taken.
/// Takes ownership of \a endpoint, and then passes that ownership to
/// the \a on_handshake_done callback.
/// Does NOT take ownership of \a channel_args. Instead, makes a copy before
@@ -145,11 +142,13 @@ void grpc_handshake_manager_shutdown(grpc_handshake_manager* mgr,
/// GRPC_ERROR_NONE, then handshaking failed and the handshaker has done
/// the necessary clean-up. Otherwise, the callback takes ownership of
/// the arguments.
-void grpc_handshake_manager_do_handshake(
- grpc_handshake_manager* mgr, grpc_pollset_set* interested_parties,
- grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
- grpc_millis deadline, grpc_tcp_server_acceptor* acceptor,
- grpc_iomgr_cb_func on_handshake_done, void* user_data);
+void grpc_handshake_manager_do_handshake(grpc_handshake_manager* mgr,
+ grpc_endpoint* endpoint,
+ const grpc_channel_args* channel_args,
+ grpc_millis deadline,
+ grpc_tcp_server_acceptor* acceptor,
+ grpc_iomgr_cb_func on_handshake_done,
+ void* user_data);
/// Add \a mgr to the server side list of all pending handshake managers, the
/// list starts with \a *head.
diff --git a/src/core/lib/channel/handshaker_factory.cc b/src/core/lib/channel/handshaker_factory.cc
index 4fd43635b6..8ade8fe4e2 100644
--- a/src/core/lib/channel/handshaker_factory.cc
+++ b/src/core/lib/channel/handshaker_factory.cc
@@ -24,11 +24,12 @@
void grpc_handshaker_factory_add_handshakers(
grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
if (handshaker_factory != nullptr) {
GPR_ASSERT(handshaker_factory->vtable != nullptr);
- handshaker_factory->vtable->add_handshakers(handshaker_factory, args,
- handshake_mgr);
+ handshaker_factory->vtable->add_handshakers(
+ handshaker_factory, args, interested_parties, handshake_mgr);
}
}
diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h
index 3e45fcf20e..e17a678179 100644
--- a/src/core/lib/channel/handshaker_factory.h
+++ b/src/core/lib/channel/handshaker_factory.h
@@ -32,6 +32,7 @@ typedef struct grpc_handshaker_factory grpc_handshaker_factory;
typedef struct {
void (*add_handshakers)(grpc_handshaker_factory* handshaker_factory,
const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
void (*destroy)(grpc_handshaker_factory* handshaker_factory);
} grpc_handshaker_factory_vtable;
@@ -42,6 +43,7 @@ struct grpc_handshaker_factory {
void grpc_handshaker_factory_add_handshakers(
grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
void grpc_handshaker_factory_destroy(
diff --git a/src/core/lib/channel/handshaker_registry.cc b/src/core/lib/channel/handshaker_registry.cc
index eec3e1b352..fbafc43e79 100644
--- a/src/core/lib/channel/handshaker_registry.cc
+++ b/src/core/lib/channel/handshaker_registry.cc
@@ -51,9 +51,11 @@ static void grpc_handshaker_factory_list_register(
static void grpc_handshaker_factory_list_add_handshakers(
grpc_handshaker_factory_list* list, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
for (size_t i = 0; i < list->num_factories; ++i) {
- grpc_handshaker_factory_add_handshakers(list->list[i], args, handshake_mgr);
+ grpc_handshaker_factory_add_handshakers(list->list[i], args,
+ interested_parties, handshake_mgr);
}
}
@@ -91,7 +93,9 @@ void grpc_handshaker_factory_register(bool at_start,
void grpc_handshakers_add(grpc_handshaker_type handshaker_type,
const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_handshaker_factory_list_add_handshakers(
- &g_handshaker_factory_lists[handshaker_type], args, handshake_mgr);
+ &g_handshaker_factory_lists[handshaker_type], args, interested_parties,
+ handshake_mgr);
}
diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h
index 82ad9c5b9a..3dd4316de6 100644
--- a/src/core/lib/channel/handshaker_registry.h
+++ b/src/core/lib/channel/handshaker_registry.h
@@ -43,6 +43,7 @@ void grpc_handshaker_factory_register(bool at_start,
void grpc_handshakers_add(grpc_handshaker_type handshaker_type,
const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_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/gpr/mpscq.h b/src/core/lib/gpr/mpscq.h
index 6b67880d1b..5ded2522bd 100644
--- a/src/core/lib/gpr/mpscq.h
+++ b/src/core/lib/gpr/mpscq.h
@@ -38,9 +38,11 @@ typedef struct gpr_mpscq_node {
// Actual queue type
typedef struct gpr_mpscq {
- gpr_atm head;
// make sure head & tail don't share a cacheline
- char padding[GPR_CACHELINE_SIZE];
+ union {
+ char padding[GPR_CACHELINE_SIZE];
+ gpr_atm head;
+ };
gpr_mpscq_node* tail;
gpr_mpscq_node stub;
} gpr_mpscq;
diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc
index 848d23730c..69bd609485 100644
--- a/src/core/lib/gpr/sync_posix.cc
+++ b/src/core/lib/gpr/sync_posix.cc
@@ -27,6 +27,24 @@
#include <time.h>
#include "src/core/lib/profiling/timers.h"
+// For debug of the timer manager crash only.
+// TODO (mxyan): remove after bug is fixed.
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+void (*g_grpc_debug_timer_manager_stats)(
+ int64_t timer_manager_init_count, int64_t timer_manager_shutdown_count,
+ int64_t fork_count, int64_t timer_wait_err, int64_t timer_cv_value,
+ int64_t timer_mu_value, int64_t abstime_sec_value,
+ int64_t abstime_nsec_value) = nullptr;
+int64_t g_timer_manager_init_count = 0;
+int64_t g_timer_manager_shutdown_count = 0;
+int64_t g_fork_count = 0;
+int64_t g_timer_wait_err = 0;
+int64_t g_timer_cv_value = 0;
+int64_t g_timer_mu_value = 0;
+int64_t g_abstime_sec_value = -1;
+int64_t g_abstime_nsec_value = -1;
+#endif // GRPC_DEBUG_TIMER_MANAGER
+
#ifdef GPR_LOW_LEVEL_COUNTERS
gpr_atm gpr_mu_locks = 0;
gpr_atm gpr_counter_atm_cas = 0;
@@ -87,7 +105,31 @@ int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) {
abs_deadline_ts.tv_sec = static_cast<time_t>(abs_deadline.tv_sec);
abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+ // For debug of the timer manager crash only.
+ // TODO (mxyan): remove after bug is fixed.
+ if (GPR_UNLIKELY(!(err == 0 || err == ETIMEDOUT || err == EAGAIN))) {
+ g_abstime_sec_value = abs_deadline_ts.tv_sec;
+ g_abstime_nsec_value = abs_deadline_ts.tv_nsec;
+ }
+#endif
}
+
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+ // For debug of the timer manager crash only.
+ // TODO (mxyan): remove after bug is fixed.
+ if (GPR_UNLIKELY(!(err == 0 || err == ETIMEDOUT || err == EAGAIN))) {
+ if (g_grpc_debug_timer_manager_stats) {
+ g_timer_wait_err = err;
+ g_timer_cv_value = (int64_t)cv;
+ g_timer_mu_value = (int64_t)mu;
+ g_grpc_debug_timer_manager_stats(
+ g_timer_manager_init_count, g_timer_manager_shutdown_count,
+ g_fork_count, g_timer_wait_err, g_timer_cv_value, g_timer_mu_value,
+ g_abstime_sec_value, g_abstime_nsec_value);
+ }
+ }
+#endif
GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
return err == ETIMEDOUT;
}
diff --git a/src/core/lib/gprpp/inlined_vector.h b/src/core/lib/gprpp/inlined_vector.h
index 76e2f0a785..65c2b9634f 100644
--- a/src/core/lib/gprpp/inlined_vector.h
+++ b/src/core/lib/gprpp/inlined_vector.h
@@ -123,6 +123,14 @@ class InlinedVector {
void push_back(T&& value) { emplace_back(std::move(value)); }
+ void pop_back() {
+ assert(!empty());
+ size_t s = size();
+ T& value = data()[s - 1];
+ value.~T();
+ size_--;
+ }
+
void copy_from(const InlinedVector& v) {
// if v is allocated, copy over the buffer.
if (v.dynamic_ != nullptr) {
diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h
index 03c293f6ed..81772f3403 100644
--- a/src/core/lib/gprpp/ref_counted.h
+++ b/src/core/lib/gprpp/ref_counted.h
@@ -34,14 +34,58 @@
namespace grpc_core {
+// PolymorphicRefCount enforces polymorphic destruction of RefCounted.
+class PolymorphicRefCount {
+ public:
+ GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+ GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+ virtual ~PolymorphicRefCount() {}
+};
+
+// NonPolymorphicRefCount does not enforce polymorphic destruction of
+// RefCounted. Please refer to grpc_core::RefCounted for more details, and
+// when in doubt use PolymorphicRefCount.
+class NonPolymorphicRefCount {
+ public:
+ GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+ GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+ ~NonPolymorphicRefCount() {}
+};
+
// A base class for reference-counted objects.
// New objects should be created via New() and start with a refcount of 1.
// When the refcount reaches 0, the object will be deleted via Delete().
//
// This will commonly be used by CRTP (curiously-recurring template pattern)
// e.g., class MyClass : public RefCounted<MyClass>
-template <typename Child>
-class RefCounted {
+//
+// Use PolymorphicRefCount and NonPolymorphicRefCount to select between
+// different implementations of RefCounted.
+//
+// Note that NonPolymorphicRefCount does not support polymorphic destruction.
+// So, use NonPolymorphicRefCount only when both of the following conditions
+// are guaranteed to hold:
+// (a) Child is a concrete leaf class in RefCounted<Child>, and
+// (b) you are gauranteed to call Unref only on concrete leaf classes and not
+// their parents.
+//
+// The following example is illegal, because calling Unref() will not call
+// the dtor of Child.
+//
+// class Parent : public RefCounted<Parent, NonPolymorphicRefCount> {}
+// class Child : public Parent {}
+//
+// Child* ch;
+// ch->Unref();
+//
+template <typename Child, typename Impl = PolymorphicRefCount>
+class RefCounted : public Impl {
public:
RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
IncrementRefCount();
@@ -69,7 +113,8 @@ class RefCounted {
RefCounted() { gpr_ref_init(&refs_, 1); }
- virtual ~RefCounted() {}
+ // Note: Depending on the Impl used, this dtor can be implicitly virtual.
+ ~RefCounted() {}
private:
// Allow RefCountedPtr<> to access IncrementRefCount().
@@ -87,8 +132,8 @@ class RefCounted {
// pointers and legacy code that is manually calling Ref() and Unref().
// Once all of our code is converted to idiomatic C++, we may be able to
// eliminate this class.
-template <typename Child>
-class RefCountedWithTracing {
+template <typename Child, typename Impl = PolymorphicRefCount>
+class RefCountedWithTracing : public Impl {
public:
RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
IncrementRefCount();
@@ -149,7 +194,8 @@ class RefCountedWithTracing {
: RefCountedWithTracing() {}
#endif
- virtual ~RefCountedWithTracing() {}
+ // Note: Depending on the Impl used, this dtor can be implicitly virtual.
+ ~RefCountedWithTracing() {}
private:
// Allow RefCountedPtr<> to access IncrementRefCount().
diff --git a/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h
index c2dfbdd90f..facd7c6dce 100644
--- a/src/core/lib/gprpp/ref_counted_ptr.h
+++ b/src/core/lib/gprpp/ref_counted_ptr.h
@@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
+#include <type_traits>
#include <utility>
#include "src/core/lib/gprpp/memory.h"
@@ -74,6 +75,8 @@ class RefCountedPtr {
}
template <typename Y>
RefCountedPtr(const RefCountedPtr<Y>& other) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
if (other.value_ != nullptr) other.value_->IncrementRefCount();
value_ = other.value_;
}
@@ -89,6 +92,8 @@ class RefCountedPtr {
}
template <typename Y>
RefCountedPtr& operator=(const RefCountedPtr<Y>& other) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
// Note: Order of reffing and unreffing is important here in case value_
// and other.value_ are the same object.
if (other.value_ != nullptr) other.value_->IncrementRefCount();
@@ -102,8 +107,14 @@ class RefCountedPtr {
}
// If value is non-null, we take ownership of a ref to it.
+ void reset(T* value) {
+ if (value_ != nullptr) value_->Unref();
+ value_ = value;
+ }
template <typename Y>
void reset(Y* value) {
+ static_assert(std::has_virtual_destructor<T>::value,
+ "T does not have a virtual dtor");
if (value_ != nullptr) value_->Unref();
value_ = value;
}
diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc
index 50078c37a1..1c798d368b 100644
--- a/src/core/lib/http/httpcli_security_connector.cc
+++ b/src/core/lib/http/httpcli_security_connector.cc
@@ -29,6 +29,8 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/ssl_transport_security.h"
@@ -51,6 +53,7 @@ static void httpcli_ssl_destroy(grpc_security_connector* sc) {
}
static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_httpcli_ssl_channel_security_connector* c =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
@@ -189,11 +192,11 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base);
grpc_channel_args args = {1, &channel_arg};
c->handshake_mgr = grpc_handshake_manager_create();
- grpc_handshakers_add(HANDSHAKER_CLIENT, &args, c->handshake_mgr);
+ grpc_handshakers_add(HANDSHAKER_CLIENT, &args,
+ nullptr /* interested_parties */, c->handshake_mgr);
grpc_handshake_manager_do_handshake(
- c->handshake_mgr, nullptr /* interested_parties */, tcp,
- nullptr /* channel_args */, deadline, nullptr /* acceptor */,
- on_handshake_done, c /* user_data */);
+ c->handshake_mgr, tcp, nullptr /* channel_args */, deadline,
+ nullptr /* acceptor */, on_handshake_done, c /* user_data */);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
}
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/error.cc b/src/core/lib/iomgr/error.cc
index 90ed34da11..6ae077fd54 100644
--- a/src/core/lib/iomgr/error.cc
+++ b/src/core/lib/iomgr/error.cc
@@ -121,14 +121,8 @@ static const char* error_time_name(grpc_error_times key) {
GPR_UNREACHABLE_CODE(return "unknown");
}
-bool grpc_error_is_special(grpc_error* err) {
- return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM ||
- err == GRPC_ERROR_CANCELLED;
-}
-
#ifndef NDEBUG
-grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
- if (grpc_error_is_special(err)) return err;
+grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
if (grpc_trace_error_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -138,8 +132,7 @@ grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
return err;
}
#else
-grpc_error* grpc_error_ref(grpc_error* err) {
- if (grpc_error_is_special(err)) return err;
+grpc_error* grpc_error_do_ref(grpc_error* err) {
gpr_ref(&err->atomics.refs);
return err;
}
@@ -177,8 +170,7 @@ static void error_destroy(grpc_error* err) {
}
#ifndef NDEBUG
-void grpc_error_unref(grpc_error* err, const char* file, int line) {
- if (grpc_error_is_special(err)) return;
+void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
if (grpc_trace_error_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -189,8 +181,7 @@ void grpc_error_unref(grpc_error* err, const char* file, int line) {
}
}
#else
-void grpc_error_unref(grpc_error* err) {
- if (grpc_error_is_special(err)) return;
+void grpc_error_do_unref(grpc_error* err) {
if (gpr_unref(&err->atomics.refs)) {
error_destroy(err);
}
@@ -450,28 +441,23 @@ grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
}
typedef struct {
- grpc_error* error;
grpc_status_code code;
const char* msg;
} special_error_status_map;
-static special_error_status_map error_status_map[] = {
- {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""},
- {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"},
- {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"},
+static const special_error_status_map error_status_map[] = {
+ {GRPC_STATUS_OK, ""}, // GRPC_ERROR_NONE
+ {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_1
+ {GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, // GRPC_ERROR_OOM
+ {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_2
+ {GRPC_STATUS_CANCELLED, "Cancelled"}, // GRPC_ERROR_CANCELLED
};
bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
GPR_TIMER_SCOPE("grpc_error_get_int", 0);
if (grpc_error_is_special(err)) {
- if (which == GRPC_ERROR_INT_GRPC_STATUS) {
- for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
- if (error_status_map[i].error == err) {
- if (p != nullptr) *p = error_status_map[i].code;
- return true;
- }
- }
- }
- return false;
+ if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
+ *p = error_status_map[reinterpret_cast<size_t>(err)].code;
+ return true;
}
uint8_t slot = err->ints[which];
if (slot != UINT8_MAX) {
@@ -492,15 +478,10 @@ grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
grpc_slice* str) {
if (grpc_error_is_special(err)) {
- if (which == GRPC_ERROR_STR_GRPC_MESSAGE) {
- for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
- if (error_status_map[i].error == err) {
- *str = grpc_slice_from_static_string(error_status_map[i].msg);
- return true;
- }
- }
- }
- return false;
+ if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
+ *str = grpc_slice_from_static_string(
+ error_status_map[reinterpret_cast<size_t>(err)].msg);
+ return true;
}
uint8_t slot = err->strs[which];
if (slot != UINT8_MAX) {
@@ -513,9 +494,24 @@ bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) {
GPR_TIMER_SCOPE("grpc_error_add_child", 0);
- grpc_error* new_err = copy_error_and_unref(src);
- internal_add_error(&new_err, child);
- return new_err;
+ if (src != GRPC_ERROR_NONE) {
+ if (child == GRPC_ERROR_NONE) {
+ /* \a child is empty. Simply return the ref to \a src */
+ return src;
+ } else if (child != src) {
+ grpc_error* new_err = copy_error_and_unref(src);
+ internal_add_error(&new_err, child);
+ return new_err;
+ } else {
+ /* \a src and \a child are the same. Drop one of the references and return
+ * the other */
+ GRPC_ERROR_UNREF(child);
+ return src;
+ }
+ } else {
+ /* \a src is empty. Simply return the ref to \a child */
+ return child;
+ }
}
static const char* no_error_string = "\"No Error\"";
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 27c4d22fd1..cb740d5b01 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -120,8 +120,15 @@ typedef enum {
/// polling engines) can safely use the lower bit for themselves.
#define GRPC_ERROR_NONE ((grpc_error*)NULL)
+#define GRPC_ERROR_RESERVED_1 ((grpc_error*)1)
#define GRPC_ERROR_OOM ((grpc_error*)2)
+#define GRPC_ERROR_RESERVED_2 ((grpc_error*)3)
#define GRPC_ERROR_CANCELLED ((grpc_error*)4)
+#define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED
+
+inline bool grpc_error_is_special(struct grpc_error* err) {
+ return err <= GRPC_ERROR_SPECIAL_MAX;
+}
// debug only toggles that allow for a sanity to check that ensures we will
// never create any errors in the per-RPC hotpath.
@@ -158,19 +165,37 @@ grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
errs, count)
#ifndef NDEBUG
-grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line);
-void grpc_error_unref(grpc_error* err, const char* file, int line);
+grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line);
+void grpc_error_do_unref(grpc_error* err, const char* file, int line);
+inline grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
+ if (grpc_error_is_special(err)) return err;
+ return grpc_error_do_ref(err, file, line);
+}
+inline void grpc_error_unref(grpc_error* err, const char* file, int line) {
+ if (grpc_error_is_special(err)) return;
+ grpc_error_do_unref(err, file, line);
+}
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
#else
-grpc_error* grpc_error_ref(grpc_error* err);
-void grpc_error_unref(grpc_error* err);
+grpc_error* grpc_error_do_ref(grpc_error* err);
+void grpc_error_do_unref(grpc_error* err);
+inline grpc_error* grpc_error_ref(grpc_error* err) {
+ if (grpc_error_is_special(err)) return err;
+ return grpc_error_do_ref(err);
+}
+inline void grpc_error_unref(grpc_error* err) {
+ if (grpc_error_is_special(err)) return;
+ grpc_error_do_unref(err);
+}
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif
grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
intptr_t value) GRPC_MUST_USE_RESULT;
+/// It is an error to pass nullptr as `p`. Caller should allocate a dummy
+/// intptr_t for `p`, even if the value of `p` is not used.
bool grpc_error_get_int(grpc_error* error, grpc_error_ints which, intptr_t* p);
/// This call takes ownership of the slice; the error is responsible for
/// eventually unref-ing it.
@@ -185,8 +210,16 @@ bool grpc_error_get_str(grpc_error* error, grpc_error_strs which,
/// error occurring. Allows root causing high level errors from lower level
/// errors that contributed to them. The src error takes ownership of the
/// child error.
+///
+/// Edge Conditions -
+/// 1) If either of \a src or \a child is GRPC_ERROR_NONE, returns a reference
+/// to the other argument. 2) If both \a src and \a child are GRPC_ERROR_NONE,
+/// returns GRPC_ERROR_NONE. 3) If \a src and \a child point to the same error,
+/// returns a single reference. (Note that, 2 references should have been
+/// received to the error in this case.)
grpc_error* grpc_error_add_child(grpc_error* src,
grpc_error* child) GRPC_MUST_USE_RESULT;
+
grpc_error* grpc_os_error(const char* file, int line, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
index 7fde347abd..8027396019 100644
--- a/src/core/lib/iomgr/error_internal.h
+++ b/src/core/lib/iomgr/error_internal.h
@@ -58,6 +58,4 @@ struct grpc_error {
intptr_t arena[0];
};
-bool grpc_error_is_special(struct grpc_error* err);
-
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index aa5016bd8f..38571b1957 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -193,9 +193,13 @@ struct grpc_pollset_worker {
#define MAX_NEIGHBORHOODS 1024
typedef struct pollset_neighborhood {
- gpr_mu mu;
- grpc_pollset* active_root;
- char pad[GPR_CACHELINE_SIZE];
+ union {
+ char pad[GPR_CACHELINE_SIZE];
+ struct {
+ gpr_mu mu;
+ grpc_pollset* active_root;
+ };
+ };
} pollset_neighborhood;
struct grpc_pollset {
@@ -273,6 +277,10 @@ static gpr_mu fork_fd_list_mu;
static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
static void fd_global_shutdown(void) {
+ // TODO(guantaol): We don't have a reasonable explanation about this
+ // lock()/unlock() pattern. It can be a valid barrier if there is at most one
+ // pending lock() at this point. Otherwise, there is still a possibility of
+ // use-after-free race. Need to reason about the code and/or clean it up.
gpr_mu_lock(&fd_freelist_mu);
gpr_mu_unlock(&fd_freelist_mu);
while (fd_freelist != nullptr) {
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index b082634af1..06a382c556 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -403,6 +403,10 @@ static void unref_by(grpc_fd* fd, int n) {
static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
static void fd_global_shutdown(void) {
+ // TODO(guantaol): We don't have a reasonable explanation about this
+ // lock()/unlock() pattern. It can be a valid barrier if there is at most one
+ // pending lock() at this point. Otherwise, there is still a possibility of
+ // use-after-free race. Need to reason about the code and/or clean it up.
gpr_mu_lock(&fd_freelist_mu);
gpr_mu_unlock(&fd_freelist_mu);
while (fd_freelist != nullptr) {
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
deleted file mode 100644
index 5695ac795d..0000000000
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ /dev/null
@@ -1,1743 +0,0 @@
-/*
- *
- * Copyright 2016 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/lib/iomgr/port.h"
-
-#include <grpc/grpc_posix.h>
-#include <grpc/support/log.h>
-
-/* This polling engine is only relevant on linux kernels supporting epoll() */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <poll.h>
-#include <pthread.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/lib/debug/stats.h"
-#include "src/core/lib/gpr/tls.h"
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/iomgr/block_annotate.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/lockfree_event.h"
-#include "src/core/lib/iomgr/timer.h"
-#include "src/core/lib/iomgr/wakeup_fd_posix.h"
-#include "src/core/lib/profiling/timers.h"
-
-#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker*)1)
-
-#define GRPC_POLLING_TRACE(...) \
- if (grpc_polling_trace.enabled()) { \
- gpr_log(GPR_INFO, __VA_ARGS__); \
- }
-
-static int grpc_wakeup_signal = -1;
-static bool is_grpc_wakeup_signal_initialized = false;
-
-/* Implements the function defined in grpc_posix.h. This function might be
- * called before even calling grpc_init() to set either a different signal to
- * use. If signum == -1, then the use of signals is disabled */
-void grpc_use_signal(int signum) {
- grpc_wakeup_signal = signum;
- is_grpc_wakeup_signal_initialized = true;
-
- if (grpc_wakeup_signal < 0) {
- gpr_log(GPR_INFO,
- "Use of signals is disabled. Epoll engine will not be used");
- } else {
- gpr_log(GPR_INFO, "epoll engine will be using signal: %d",
- grpc_wakeup_signal);
- }
-}
-
-struct polling_island;
-
-typedef enum {
- POLL_OBJ_FD,
- POLL_OBJ_POLLSET,
- POLL_OBJ_POLLSET_SET
-} poll_obj_type;
-
-typedef struct poll_obj {
-#ifndef NDEBUG
- poll_obj_type obj_type;
-#endif
- gpr_mu mu;
- struct polling_island* pi;
-} poll_obj;
-
-const char* poll_obj_string(poll_obj_type po_type) {
- switch (po_type) {
- case POLL_OBJ_FD:
- return "fd";
- case POLL_OBJ_POLLSET:
- return "pollset";
- case POLL_OBJ_POLLSET_SET:
- return "pollset_set";
- }
-
- GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
- /*******************************************************************************
- * Fd Declarations
- */
-
-#define FD_FROM_PO(po) ((grpc_fd*)(po))
-
-struct grpc_fd {
- poll_obj po;
-
- int fd;
- /* refst format:
- bit 0 : 1=Active / 0=Orphaned
- bits 1-n : refcount
- Ref/Unref by two to avoid altering the orphaned bit */
- gpr_atm refst;
-
- /* The fd is either closed or we relinquished control of it. In either
- cases, this indicates that the 'fd' on this structure is no longer
- valid */
- bool orphaned;
-
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
-
- struct grpc_fd* freelist_next;
- grpc_closure* on_done_closure;
-
- grpc_iomgr_object iomgr_object;
-
- /* Do we need to track EPOLLERR events separately? */
- bool track_err;
-};
-
-/* Reference counting for fds */
-#ifndef NDEBUG
-static void fd_ref(grpc_fd* fd, const char* reason, const char* file, int line);
-static void fd_unref(grpc_fd* fd, const char* reason, const char* file,
- int line);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd, reason, __FILE__, __LINE__)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd, reason, __FILE__, __LINE__)
-#else
-static void fd_ref(grpc_fd* fd);
-static void fd_unref(grpc_fd* fd);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd)
-#endif
-
-static void fd_global_init(void);
-static void fd_global_shutdown(void);
-
-/*******************************************************************************
- * Polling island Declarations
- */
-
-#ifndef NDEBUG
-
-#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__)
-#define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__)
-
-#else
-
-#define PI_ADD_REF(p, r) pi_add_ref((p))
-#define PI_UNREF(p, r) pi_unref((p))
-
-#endif
-
-/* This is also used as grpc_workqueue (by directly casing it) */
-typedef struct polling_island {
- gpr_mu mu;
- /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement
- the refcount.
- Once the ref count becomes zero, this structure is destroyed which means
- we should ensure that there is never a scenario where a PI_ADD_REF() is
- racing with a PI_UNREF() that just made the ref_count zero. */
- gpr_atm ref_count;
-
- /* Pointer to the polling_island this merged into.
- * merged_to value is only set once in polling_island's lifetime (and that too
- * only if the island is merged with another island). Because of this, we can
- * use gpr_atm type here so that we can do atomic access on this and reduce
- * lock contention on 'mu' mutex.
- *
- * Note that if this field is not NULL (i.e not 0), all the remaining fields
- * (except mu and ref_count) are invalid and must be ignored. */
- gpr_atm merged_to;
-
- /* Number of threads currently polling on this island */
- gpr_atm poller_count;
-
- /* The fd of the underlying epoll set */
- int epoll_fd;
-
- /* The file descriptors in the epoll set */
- size_t fd_cnt;
- size_t fd_capacity;
- grpc_fd** fds;
-} polling_island;
-
-/*******************************************************************************
- * Pollset Declarations
- */
-struct grpc_pollset_worker {
- /* Thread id of this worker */
- pthread_t pt_id;
-
- /* Used to prevent a worker from getting kicked multiple times */
- gpr_atm is_kicked;
- struct grpc_pollset_worker* next;
- struct grpc_pollset_worker* prev;
-};
-
-struct grpc_pollset {
- poll_obj po;
-
- grpc_pollset_worker root_worker;
- bool kicked_without_pollers;
-
- bool shutting_down; /* Is the pollset shutting down ? */
- bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
- grpc_closure* shutdown_done; /* Called after after shutdown is complete */
-};
-
-/*******************************************************************************
- * Pollset-set Declarations
- */
-struct grpc_pollset_set {
- poll_obj po;
-};
-
-/*******************************************************************************
- * Common helpers
- */
-
-static bool append_error(grpc_error** composite, grpc_error* error,
- const char* desc) {
- if (error == GRPC_ERROR_NONE) return true;
- if (*composite == GRPC_ERROR_NONE) {
- *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
- }
- *composite = grpc_error_add_child(*composite, error);
- return false;
-}
-
-/*******************************************************************************
- * Polling island Definitions
- */
-
-/* The wakeup fd that is used to wake up all threads in a Polling island. This
- is useful in the polling island merge operation where we need to wakeup all
- the threads currently polling the smaller polling island (so that they can
- start polling the new/merged polling island)
-
- NOTE: This fd is initialized to be readable and MUST NOT be consumed i.e the
- threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */
-static grpc_wakeup_fd polling_island_wakeup_fd;
-
-/* The polling island being polled right now.
- See comments in workqueue_maybe_wakeup for why this is tracked. */
-static __thread polling_island* g_current_thread_polling_island;
-
-/* Forward declaration */
-static void polling_island_delete(polling_island* pi);
-
-#ifdef GRPC_TSAN
-/* Currently TSAN may incorrectly flag data races between epoll_ctl and
- epoll_wait for any grpc_fd structs that are added to the epoll set via
- epoll_ctl and are returned (within a very short window) via epoll_wait().
-
- To work-around this race, we establish a happens-before relation between
- the code just-before epoll_ctl() and the code after epoll_wait() by using
- this atomic */
-gpr_atm g_epoll_sync;
-#endif /* defined(GRPC_TSAN) */
-
-static void pi_add_ref(polling_island* pi);
-static void pi_unref(polling_island* pi);
-
-#ifndef NDEBUG
-static void pi_add_ref_dbg(polling_island* pi, const char* reason,
- const char* file, int line) {
- if (grpc_polling_trace.enabled()) {
- gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
- gpr_log(GPR_INFO,
- "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
- " (%s) - (%s, %d)",
- pi, old_cnt, old_cnt + 1, reason, file, line);
- }
- pi_add_ref(pi);
-}
-
-static void pi_unref_dbg(polling_island* pi, const char* reason,
- const char* file, int line) {
- if (grpc_polling_trace.enabled()) {
- gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
- gpr_log(GPR_INFO,
- "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
- " (%s) - (%s, %d)",
- pi, old_cnt, (old_cnt - 1), reason, file, line);
- }
- pi_unref(pi);
-}
-#endif
-
-static void pi_add_ref(polling_island* pi) {
- gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1);
-}
-
-static void pi_unref(polling_island* pi) {
- /* If ref count went to zero, delete the polling island.
- Note that this deletion not be done under a lock. Once the ref count goes
- to zero, we are guaranteed that no one else holds a reference to the
- polling island (and that there is no racing pi_add_ref() call either).
-
- Also, if we are deleting the polling island and the merged_to field is
- non-empty, we should remove a ref to the merged_to polling island
- */
- if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
- polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- polling_island_delete(pi);
- if (next != nullptr) {
- PI_UNREF(next, "pi_delete"); /* Recursive call */
- }
- }
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_add_fds_locked(polling_island* pi, grpc_fd** fds,
- size_t fd_count, bool add_fd_refs,
- grpc_error** error) {
- int err;
- size_t i;
- struct epoll_event ev;
- char* err_msg;
- const char* err_desc = "polling_island_add_fds";
-
-#ifdef GRPC_TSAN
- /* See the definition of g_epoll_sync for more context */
- gpr_atm_rel_store(&g_epoll_sync, (gpr_atm)0);
-#endif /* defined(GRPC_TSAN) */
-
- for (i = 0; i < fd_count; i++) {
- ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
- /* Use the least significant bit of ev.data.ptr to store track_err to avoid
- * synchronization issues when accessing it after receiving an event */
- ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fds[i]) |
- (fds[i]->track_err ? 1 : 0));
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
-
- if (err < 0) {
- if (errno != EEXIST) {
- gpr_asprintf(
- &err_msg,
- "epoll_ctl (epoll_fd: %d) add fd: %d failed with error: %d (%s)",
- pi->epoll_fd, fds[i]->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- continue;
- }
-
- if (pi->fd_cnt == pi->fd_capacity) {
- pi->fd_capacity = GPR_MAX(pi->fd_capacity + 8, pi->fd_cnt * 3 / 2);
- pi->fds = static_cast<grpc_fd**>(
- gpr_realloc(pi->fds, sizeof(grpc_fd*) * pi->fd_capacity));
- }
-
- pi->fds[pi->fd_cnt++] = fds[i];
- if (add_fd_refs) {
- GRPC_FD_REF(fds[i], "polling_island");
- }
- }
-}
-
-/* The caller is expected to hold pi->mu before calling this */
-static void polling_island_add_wakeup_fd_locked(polling_island* pi,
- grpc_wakeup_fd* wakeup_fd,
- grpc_error** error) {
- struct epoll_event ev;
- int err;
- char* err_msg;
- const char* err_desc = "polling_island_add_wakeup_fd";
-
- ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
- ev.data.ptr = wakeup_fd;
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD,
- GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev);
- if (err < 0 && errno != EEXIST) {
- gpr_asprintf(&err_msg,
- "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with "
- "error: %d (%s)",
- pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno,
- strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_remove_all_fds_locked(polling_island* pi,
- bool remove_fd_refs,
- grpc_error** error) {
- int err;
- size_t i;
- char* err_msg;
- const char* err_desc = "polling_island_remove_fds";
-
- for (i = 0; i < pi->fd_cnt; i++) {
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, pi->fds[i]->fd, nullptr);
- if (err < 0 && errno != ENOENT) {
- gpr_asprintf(&err_msg,
- "epoll_ctl (epoll_fd: %d) delete fds[%zu]: %d failed with "
- "error: %d (%s)",
- pi->epoll_fd, i, pi->fds[i]->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- if (remove_fd_refs) {
- GRPC_FD_UNREF(pi->fds[i], "polling_island");
- }
- }
-
- pi->fd_cnt = 0;
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
- grpc_error** error) {
- int err;
- size_t i;
- char* err_msg;
- const char* err_desc = "polling_island_remove_fd";
-
- /* If fd is already closed, then it would have been automatically been removed
- from the epoll set */
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
- if (err < 0 && errno != ENOENT) {
- gpr_asprintf(
- &err_msg,
- "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
- pi->epoll_fd, fd->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- for (i = 0; i < pi->fd_cnt; i++) {
- if (pi->fds[i] == fd) {
- pi->fds[i] = pi->fds[--pi->fd_cnt];
- GRPC_FD_UNREF(fd, "polling_island");
- break;
- }
- }
-}
-
-/* Might return NULL in case of an error */
-static polling_island* polling_island_create(grpc_fd* initial_fd,
- grpc_error** error) {
- polling_island* pi = nullptr;
- const char* err_desc = "polling_island_create";
-
- *error = GRPC_ERROR_NONE;
-
- pi = static_cast<polling_island*>(gpr_malloc(sizeof(*pi)));
- gpr_mu_init(&pi->mu);
- pi->fd_cnt = 0;
- pi->fd_capacity = 0;
- pi->fds = nullptr;
- pi->epoll_fd = -1;
-
- gpr_atm_rel_store(&pi->ref_count, 0);
- gpr_atm_rel_store(&pi->poller_count, 0);
- gpr_atm_rel_store(&pi->merged_to, (gpr_atm) nullptr);
-
- pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-
- if (pi->epoll_fd < 0) {
- append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc);
- goto done;
- }
-
- if (initial_fd != nullptr) {
- polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
- }
-
-done:
- if (*error != GRPC_ERROR_NONE) {
- polling_island_delete(pi);
- pi = nullptr;
- }
- return pi;
-}
-
-static void polling_island_delete(polling_island* pi) {
- GPR_ASSERT(pi->fd_cnt == 0);
-
- if (pi->epoll_fd >= 0) {
- close(pi->epoll_fd);
- }
- gpr_mu_destroy(&pi->mu);
- gpr_free(pi->fds);
- gpr_free(pi);
-}
-
-/* Attempts to gets the last polling island in the linked list (liked by the
- * 'merged_to' field). Since this does not lock the polling island, there are no
- * guarantees that the island returned is the last island */
-static polling_island* polling_island_maybe_get_latest(polling_island* pi) {
- polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- while (next != nullptr) {
- pi = next;
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- }
-
- return pi;
-}
-
-/* Gets the lock on the *latest* polling island i.e the last polling island in
- the linked list (linked by the 'merged_to' field). Call gpr_mu_unlock on the
- returned polling island's mu.
- Usage: To lock/unlock polling island "pi", do the following:
- polling_island *pi_latest = polling_island_lock(pi);
- ...
- ... critical section ..
- ...
- gpr_mu_unlock(&pi_latest->mu); // NOTE: use pi_latest->mu. NOT pi->mu */
-static polling_island* polling_island_lock(polling_island* pi) {
- polling_island* next = nullptr;
-
- while (true) {
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- if (next == nullptr) {
- /* Looks like 'pi' is the last node in the linked list but unless we check
- this by holding the pi->mu lock, we cannot be sure (i.e without the
- pi->mu lock, we don't prevent island merges).
- To be absolutely sure, check once more by holding the pi->mu lock */
- gpr_mu_lock(&pi->mu);
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- if (next == nullptr) {
- /* pi is infact the last node and we have the pi->mu lock. we're done */
- break;
- }
-
- /* pi->merged_to is not NULL i.e pi isn't the last node anymore. pi->mu
- * isn't the lock we are interested in. Continue traversing the list */
- gpr_mu_unlock(&pi->mu);
- }
-
- pi = next;
- }
-
- return pi;
-}
-
-/* Gets the lock on the *latest* polling islands in the linked lists pointed by
- *p and *q (and also updates *p and *q to point to the latest polling islands)
-
- This function is needed because calling the following block of code to obtain
- locks on polling islands (*p and *q) is prone to deadlocks.
- {
- polling_island_lock(*p, true);
- polling_island_lock(*q, true);
- }
-
- Usage/example:
- polling_island *p1;
- polling_island *p2;
- ..
- polling_island_lock_pair(&p1, &p2);
- ..
- .. Critical section with both p1 and p2 locked
- ..
- // Release locks: Always call polling_island_unlock_pair() to release locks
- polling_island_unlock_pair(p1, p2);
-*/
-static void polling_island_lock_pair(polling_island** p, polling_island** q) {
- polling_island* pi_1 = *p;
- polling_island* pi_2 = *q;
- polling_island* next_1 = nullptr;
- polling_island* next_2 = nullptr;
-
- /* The algorithm is simple:
- - Go to the last polling islands in the linked lists *pi_1 and *pi_2 (and
- keep updating pi_1 and pi_2)
- - Then obtain locks on the islands by following a lock order rule of
- locking polling_island with lower address first
- Special case: Before obtaining the locks, check if pi_1 and pi_2 are
- pointing to the same island. If that is the case, we can just call
- polling_island_lock()
- - After obtaining both the locks, double check that the polling islands
- are still the last polling islands in their respective linked lists
- (this is because there might have been polling island merges before
- we got the lock)
- - If the polling islands are the last islands, we are done. If not,
- release the locks and continue the process from the first step */
- while (true) {
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- while (next_1 != nullptr) {
- pi_1 = next_1;
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- }
-
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- while (next_2 != nullptr) {
- pi_2 = next_2;
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- }
-
- if (pi_1 == pi_2) {
- pi_1 = pi_2 = polling_island_lock(pi_1);
- break;
- }
-
- if (pi_1 < pi_2) {
- gpr_mu_lock(&pi_1->mu);
- gpr_mu_lock(&pi_2->mu);
- } else {
- gpr_mu_lock(&pi_2->mu);
- gpr_mu_lock(&pi_1->mu);
- }
-
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- if (next_1 == nullptr && next_2 == nullptr) {
- break;
- }
-
- gpr_mu_unlock(&pi_1->mu);
- gpr_mu_unlock(&pi_2->mu);
- }
-
- *p = pi_1;
- *q = pi_2;
-}
-
-static void polling_island_unlock_pair(polling_island* p, polling_island* q) {
- if (p == q) {
- gpr_mu_unlock(&p->mu);
- } else {
- gpr_mu_unlock(&p->mu);
- gpr_mu_unlock(&q->mu);
- }
-}
-
-static polling_island* polling_island_merge(polling_island* p,
- polling_island* q,
- grpc_error** error) {
- /* Get locks on both the polling islands */
- polling_island_lock_pair(&p, &q);
-
- if (p != q) {
- /* Make sure that p points to the polling island with fewer fds than q */
- if (p->fd_cnt > q->fd_cnt) {
- GPR_SWAP(polling_island*, p, q);
- }
-
- /* Merge p with q i.e move all the fds from p (The one with fewer fds) to q
- Note that the refcounts on the fds being moved will not change here.
- This is why the last param in the following two functions is 'false') */
- polling_island_add_fds_locked(q, p->fds, p->fd_cnt, false, error);
- polling_island_remove_all_fds_locked(p, false, error);
-
- /* Wakeup all the pollers (if any) on p so that they pickup this change */
- polling_island_add_wakeup_fd_locked(p, &polling_island_wakeup_fd, error);
-
- /* Add the 'merged_to' link from p --> q */
- gpr_atm_rel_store(&p->merged_to, (gpr_atm)q);
- PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */
- }
- /* else if p == q, nothing needs to be done */
-
- polling_island_unlock_pair(p, q);
-
- /* Return the merged polling island (Note that no merge would have happened
- if p == q which is ok) */
- return q;
-}
-
-static grpc_error* polling_island_global_init() {
- grpc_error* error = GRPC_ERROR_NONE;
-
- error = grpc_wakeup_fd_init(&polling_island_wakeup_fd);
- if (error == GRPC_ERROR_NONE) {
- error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd);
- }
-
- return error;
-}
-
-static void polling_island_global_shutdown() {
- grpc_wakeup_fd_destroy(&polling_island_wakeup_fd);
-}
-
-/*******************************************************************************
- * Fd Definitions
- */
-
-/* We need to keep a freelist not because of any concerns of malloc performance
- * but instead so that implementations with multiple threads in (for example)
- * epoll_wait deal with the race between pollset removal and incoming poll
- * notifications.
- *
- * The problem is that the poller ultimately holds a reference to this
- * object, so it is very difficult to know when is safe to free it, at least
- * without some expensive synchronization.
- *
- * If we keep the object freelisted, in the worst case losing this race just
- * becomes a spurious read notification on a reused fd.
- */
-
-/* The alarm system needs to be able to wakeup 'some poller' sometimes
- * (specifically when a new alarm needs to be triggered earlier than the next
- * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
- * case occurs. */
-
-static grpc_fd* fd_freelist = nullptr;
-static gpr_mu fd_freelist_mu;
-
-#ifndef NDEBUG
-#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
-static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file,
- int line) {
- if (grpc_trace_fd_refcount.enabled()) {
- gpr_log(GPR_DEBUG,
- "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
- fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
- }
-#else
-#define REF_BY(fd, n, reason) ref_by(fd, n)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n)
-static void ref_by(grpc_fd* fd, int n) {
-#endif
- GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
-}
-
-#ifndef NDEBUG
-static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file,
- int line) {
- if (grpc_trace_fd_refcount.enabled()) {
- gpr_log(GPR_DEBUG,
- "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
- fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line);
- }
-#else
-static void unref_by(grpc_fd* fd, int n) {
-#endif
- gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
- if (old == n) {
- /* Add the fd to the freelist */
- gpr_mu_lock(&fd_freelist_mu);
- fd->freelist_next = fd_freelist;
- fd_freelist = fd;
- grpc_iomgr_unregister_object(&fd->iomgr_object);
-
- fd->read_closure->DestroyEvent();
- fd->write_closure->DestroyEvent();
- fd->error_closure->DestroyEvent();
-
- gpr_mu_unlock(&fd_freelist_mu);
- } else {
- GPR_ASSERT(old > n);
- }
-}
-
-/* Increment refcount by two to avoid changing the orphan bit */
-#ifndef NDEBUG
-static void fd_ref(grpc_fd* fd, const char* reason, const char* file,
- int line) {
- ref_by(fd, 2, reason, file, line);
-}
-
-static void fd_unref(grpc_fd* fd, const char* reason, const char* file,
- int line) {
- unref_by(fd, 2, reason, file, line);
-}
-#else
-static void fd_ref(grpc_fd* fd) { ref_by(fd, 2); }
-static void fd_unref(grpc_fd* fd) { unref_by(fd, 2); }
-#endif
-
-static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
-
-static void fd_global_shutdown(void) {
- gpr_mu_lock(&fd_freelist_mu);
- gpr_mu_unlock(&fd_freelist_mu);
- while (fd_freelist != nullptr) {
- grpc_fd* fd = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- gpr_mu_destroy(&fd->po.mu);
- gpr_free(fd);
- }
- gpr_mu_destroy(&fd_freelist_mu);
-}
-
-static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
- grpc_fd* new_fd = nullptr;
-
- gpr_mu_lock(&fd_freelist_mu);
- if (fd_freelist != nullptr) {
- new_fd = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- }
- gpr_mu_unlock(&fd_freelist_mu);
-
- if (new_fd == nullptr) {
- new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
- gpr_mu_init(&new_fd->po.mu);
- new_fd->read_closure.Init();
- new_fd->write_closure.Init();
- new_fd->error_closure.Init();
- }
-
- /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
- * is a newly created fd (or an fd we got from the freelist), no one else
- * would be holding a lock to it anyway. */
- gpr_mu_lock(&new_fd->po.mu);
- new_fd->po.pi = nullptr;
-#ifndef NDEBUG
- new_fd->po.obj_type = POLL_OBJ_FD;
-#endif
-
- gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
- new_fd->fd = fd;
- new_fd->orphaned = false;
- new_fd->read_closure->InitEvent();
- new_fd->write_closure->InitEvent();
- new_fd->error_closure->InitEvent();
- new_fd->track_err = track_err;
-
- new_fd->freelist_next = nullptr;
- new_fd->on_done_closure = nullptr;
-
- gpr_mu_unlock(&new_fd->po.mu);
-
- char* fd_name;
- gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
- grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
- gpr_free(fd_name);
- return new_fd;
-}
-
-static int fd_wrapped_fd(grpc_fd* fd) {
- int ret_fd = -1;
- gpr_mu_lock(&fd->po.mu);
- if (!fd->orphaned) {
- ret_fd = fd->fd;
- }
- gpr_mu_unlock(&fd->po.mu);
-
- return ret_fd;
-}
-
-static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
- const char* reason) {
- grpc_error* error = GRPC_ERROR_NONE;
- polling_island* unref_pi = nullptr;
-
- gpr_mu_lock(&fd->po.mu);
- fd->on_done_closure = on_done;
-
- /* Remove the active status but keep referenced. We want this grpc_fd struct
- to be alive (and not added to freelist) until the end of this function */
- REF_BY(fd, 1, reason);
-
- /* Remove the fd from the polling island:
- - Get a lock on the latest polling island (i.e the last island in the
- linked list pointed by fd->po.pi). This is the island that
- would actually contain the fd
- - Remove the fd from the latest polling island
- - Unlock the latest polling island
- - Set fd->po.pi to NULL (but remove the ref on the polling island
- before doing this.) */
- if (fd->po.pi != nullptr) {
- polling_island* pi_latest = polling_island_lock(fd->po.pi);
- polling_island_remove_fd_locked(pi_latest, fd, &error);
- gpr_mu_unlock(&pi_latest->mu);
-
- unref_pi = fd->po.pi;
- fd->po.pi = nullptr;
- }
-
- /* If release_fd is not NULL, we should be relinquishing control of the file
- descriptor fd->fd (but we still own the grpc_fd structure). */
- if (release_fd != nullptr) {
- *release_fd = fd->fd;
- } else {
- close(fd->fd);
- }
-
- fd->orphaned = true;
-
- GRPC_CLOSURE_SCHED(fd->on_done_closure, GRPC_ERROR_REF(error));
-
- gpr_mu_unlock(&fd->po.mu);
- UNREF_BY(fd, 2, reason); /* Drop the reference */
- if (unref_pi != nullptr) {
- /* Unref stale polling island here, outside the fd lock above.
- The polling island owns a workqueue which owns an fd, and unreffing
- inside the lock can cause an eventual lock loop that makes TSAN very
- unhappy. */
- PI_UNREF(unref_pi, "fd_orphan");
- }
- if (error != GRPC_ERROR_NONE) {
- const char* msg = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "fd_orphan: %s", msg);
- }
- GRPC_ERROR_UNREF(error);
-}
-
-static bool fd_is_shutdown(grpc_fd* fd) {
- return fd->read_closure->IsShutdown();
-}
-
-/* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
- if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
- shutdown(fd->fd, SHUT_RDWR);
- fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
- fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
- }
- GRPC_ERROR_UNREF(why);
-}
-
-static void fd_notify_on_read(grpc_fd* fd, grpc_closure* closure) {
- fd->read_closure->NotifyOn(closure);
-}
-
-static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
- fd->write_closure->NotifyOn(closure);
-}
-
-static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
- fd->error_closure->NotifyOn(closure);
-}
-
-static void fd_become_readable(grpc_fd* fd) { fd->read_closure->SetReady(); }
-
-static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
-
-static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
-
-/*******************************************************************************
- * Pollset Definitions
- */
-GPR_TLS_DECL(g_current_thread_pollset);
-GPR_TLS_DECL(g_current_thread_worker);
-static __thread bool g_initialized_sigmask;
-static __thread sigset_t g_orig_sigmask;
-
-static void sig_handler(int sig_num) {
-#ifdef GRPC_EPOLL_DEBUG
- gpr_log(GPR_INFO, "Received signal %d", sig_num);
-#endif
-}
-
-static void poller_kick_init() { signal(grpc_wakeup_signal, sig_handler); }
-
-/* Global state management */
-static grpc_error* pollset_global_init(void) {
- gpr_tls_init(&g_current_thread_pollset);
- gpr_tls_init(&g_current_thread_worker);
- poller_kick_init();
- return GRPC_ERROR_NONE;
-}
-
-static void pollset_global_shutdown(void) {
- gpr_tls_destroy(&g_current_thread_pollset);
- gpr_tls_destroy(&g_current_thread_worker);
-}
-
-static grpc_error* pollset_worker_kick(grpc_pollset_worker* worker) {
- grpc_error* err = GRPC_ERROR_NONE;
-
- /* Kick the worker only if it was not already kicked */
- if (gpr_atm_no_barrier_cas(&worker->is_kicked, static_cast<gpr_atm>(0),
- static_cast<gpr_atm>(1))) {
- GRPC_POLLING_TRACE(
- "pollset_worker_kick: Kicking worker: %p (thread id: %ld)",
- (void*)worker, (long int)worker->pt_id);
- int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal);
- if (err_num != 0) {
- err = GRPC_OS_ERROR(err_num, "pthread_kill");
- }
- }
- return err;
-}
-
-/* Return 1 if the pollset has active threads in pollset_work (pollset must
- * be locked) */
-static int pollset_has_workers(grpc_pollset* p) {
- return p->root_worker.next != &p->root_worker;
-}
-
-static void remove_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->prev->next = worker->next;
- worker->next->prev = worker->prev;
-}
-
-static grpc_pollset_worker* pop_front_worker(grpc_pollset* p) {
- if (pollset_has_workers(p)) {
- grpc_pollset_worker* w = p->root_worker.next;
- remove_worker(p, w);
- return w;
- } else {
- return nullptr;
- }
-}
-
-static void push_back_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->next = &p->root_worker;
- worker->prev = worker->next->prev;
- worker->prev->next = worker->next->prev = worker;
-}
-
-static void push_front_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->prev = &p->root_worker;
- worker->next = worker->prev->next;
- worker->prev->next = worker->next->prev = worker;
-}
-
-/* p->mu must be held before calling this function */
-static grpc_error* pollset_kick(grpc_pollset* p,
- grpc_pollset_worker* specific_worker) {
- GPR_TIMER_SCOPE("pollset_kick", 0);
- grpc_error* error = GRPC_ERROR_NONE;
- GRPC_STATS_INC_POLLSET_KICK();
- const char* err_desc = "Kick Failure";
- grpc_pollset_worker* worker = specific_worker;
- if (worker != nullptr) {
- if (worker == GRPC_POLLSET_KICK_BROADCAST) {
- if (pollset_has_workers(p)) {
- GPR_TIMER_SCOPE("pollset_kick.broadcast", 0);
- for (worker = p->root_worker.next; worker != &p->root_worker;
- worker = worker->next) {
- if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) {
- append_error(&error, pollset_worker_kick(worker), err_desc);
- }
- }
- } else {
- p->kicked_without_pollers = true;
- }
- } else {
- GPR_TIMER_MARK("kicked_specifically", 0);
- if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) {
- append_error(&error, pollset_worker_kick(worker), err_desc);
- }
- }
- } else if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)p) {
- /* Since worker == NULL, it means that we can kick "any" worker on this
- pollset 'p'. If 'p' happens to be the same pollset this thread is
- currently polling (i.e in pollset_work() function), then there is no need
- to kick any other worker since the current thread can just absorb the
- kick. This is the reason why we enter this case only when
- g_current_thread_pollset is != p */
-
- GPR_TIMER_MARK("kick_anonymous", 0);
- worker = pop_front_worker(p);
- if (worker != nullptr) {
- GPR_TIMER_MARK("finally_kick", 0);
- push_back_worker(p, worker);
- append_error(&error, pollset_worker_kick(worker), err_desc);
- } else {
- GPR_TIMER_MARK("kicked_no_pollers", 0);
- p->kicked_without_pollers = true;
- }
- }
-
- GRPC_LOG_IF_ERROR("pollset_kick", GRPC_ERROR_REF(error));
- return error;
-}
-
-static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
- gpr_mu_init(&pollset->po.mu);
- *mu = &pollset->po.mu;
- pollset->po.pi = nullptr;
-#ifndef NDEBUG
- pollset->po.obj_type = POLL_OBJ_POLLSET;
-#endif
-
- pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
- pollset->kicked_without_pollers = false;
-
- pollset->shutting_down = false;
- pollset->finish_shutdown_called = false;
- pollset->shutdown_done = nullptr;
-}
-
-static int poll_deadline_to_millis_timeout(grpc_millis millis) {
- if (millis == GRPC_MILLIS_INF_FUTURE) return -1;
- grpc_millis delta = millis - grpc_core::ExecCtx::Get()->Now();
- if (delta > INT_MAX)
- return INT_MAX;
- else if (delta < 0)
- return 0;
- else
- return static_cast<int>(delta);
-}
-
-static void pollset_release_polling_island(grpc_pollset* ps,
- const char* reason) {
- if (ps->po.pi != nullptr) {
- PI_UNREF(ps->po.pi, reason);
- }
- ps->po.pi = nullptr;
-}
-
-static void finish_shutdown_locked(grpc_pollset* pollset) {
- /* The pollset cannot have any workers if we are at this stage */
- GPR_ASSERT(!pollset_has_workers(pollset));
-
- pollset->finish_shutdown_called = true;
-
- /* Release the ref and set pollset->po.pi to NULL */
- pollset_release_polling_island(pollset, "ps_shutdown");
- GRPC_CLOSURE_SCHED(pollset->shutdown_done, GRPC_ERROR_NONE);
-}
-
-/* pollset->po.mu lock must be held by the caller before calling this */
-static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
- GPR_TIMER_SCOPE("pollset_shutdown", 0);
- GPR_ASSERT(!pollset->shutting_down);
- pollset->shutting_down = true;
- pollset->shutdown_done = closure;
- pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-
- /* If the pollset has any workers, we cannot call finish_shutdown_locked()
- because it would release the underlying polling island. In such a case, we
- let the last worker call finish_shutdown_locked() from pollset_work() */
- if (!pollset_has_workers(pollset)) {
- GPR_ASSERT(!pollset->finish_shutdown_called);
- GPR_TIMER_MARK("pollset_shutdown.finish_shutdown_locked", 0);
- finish_shutdown_locked(pollset);
- }
-}
-
-/* pollset_shutdown is guaranteed to be called before pollset_destroy. So other
- * than destroying the mutexes, there is nothing special that needs to be done
- * here */
-static void pollset_destroy(grpc_pollset* pollset) {
- GPR_ASSERT(!pollset_has_workers(pollset));
- gpr_mu_destroy(&pollset->po.mu);
-}
-
-#define GRPC_EPOLL_MAX_EVENTS 100
-/* Note: sig_mask contains the signal mask to use *during* epoll_wait() */
-static void pollset_work_and_unlock(grpc_pollset* pollset,
- grpc_pollset_worker* worker, int timeout_ms,
- sigset_t* sig_mask, grpc_error** error) {
- GPR_TIMER_SCOPE("pollset_work_and_unlock", 0);
- struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
- int epoll_fd = -1;
- int ep_rv;
- polling_island* pi = nullptr;
- char* err_msg;
- const char* err_desc = "pollset_work_and_unlock";
-
- /* We need to get the epoll_fd to wait on. The epoll_fd is in inside the
- latest polling island pointed by pollset->po.pi
-
- Since epoll_fd is immutable, we can read it without obtaining the polling
- island lock. There is however a possibility that the polling island (from
- which we got the epoll_fd) got merged with another island while we are
- in this function. This is still okay because in such a case, we will wakeup
- right-away from epoll_wait() and pick up the latest polling_island the next
- this function (i.e pollset_work_and_unlock()) is called */
-
- if (pollset->po.pi == nullptr) {
- pollset->po.pi = polling_island_create(nullptr, error);
- if (pollset->po.pi == nullptr) {
- return; /* Fatal error. We cannot continue */
- }
-
- PI_ADD_REF(pollset->po.pi, "ps");
- GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p",
- (void*)pollset, (void*)pollset->po.pi);
- }
-
- pi = polling_island_maybe_get_latest(pollset->po.pi);
- epoll_fd = pi->epoll_fd;
-
- /* Update the pollset->po.pi since the island being pointed by
- pollset->po.pi maybe older than the one pointed by pi) */
- if (pollset->po.pi != pi) {
- /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
- polling island to be deleted */
- PI_ADD_REF(pi, "ps");
- PI_UNREF(pollset->po.pi, "ps");
- pollset->po.pi = pi;
- }
-
- /* Add an extra ref so that the island does not get destroyed (which means
- the epoll_fd won't be closed) while we are are doing an epoll_wait() on the
- epoll_fd */
- PI_ADD_REF(pi, "ps_work");
- gpr_mu_unlock(&pollset->po.mu);
-
- gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1);
- g_current_thread_polling_island = pi;
-
- GRPC_SCHEDULING_START_BLOCKING_REGION;
- GRPC_STATS_INC_SYSCALL_POLL();
- ep_rv =
- epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask);
- GRPC_SCHEDULING_END_BLOCKING_REGION;
- if (ep_rv < 0) {
- if (errno != EINTR) {
- gpr_asprintf(&err_msg,
- "epoll_wait() epoll fd: %d failed with error: %d (%s)",
- epoll_fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- } else {
- /* We were interrupted. Save an interation by doing a zero timeout
- epoll_wait to see if there are any other events of interest */
- GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker: %p received kick",
- (void*)pollset, (void*)worker);
- ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
- }
- }
-
-#ifdef GRPC_TSAN
- /* See the definition of g_poll_sync for more details */
- gpr_atm_acq_load(&g_epoll_sync);
-#endif /* defined(GRPC_TSAN) */
-
- for (int i = 0; i < ep_rv; ++i) {
- void* data_ptr = ep_ev[i].data.ptr;
- if (data_ptr == &polling_island_wakeup_fd) {
- GRPC_POLLING_TRACE(
- "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: "
- "%d) got merged",
- (void*)pollset, (void*)worker, epoll_fd);
- /* This means that our polling island is merged with a different
- island. We do not have to do anything here since the subsequent call
- to the function pollset_work_and_unlock() will pick up the correct
- epoll_fd */
- } else {
- grpc_fd* fd = reinterpret_cast<grpc_fd*>(
- reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
- bool track_err =
- reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1);
- bool cancel = (ep_ev[i].events & EPOLLHUP) != 0;
- bool error = (ep_ev[i].events & EPOLLERR) != 0;
- bool read_ev = (ep_ev[i].events & (EPOLLIN | EPOLLPRI)) != 0;
- bool write_ev = (ep_ev[i].events & EPOLLOUT) != 0;
- bool err_fallback = error && !track_err;
-
- if (error && !err_fallback) {
- fd_has_errors(fd);
- }
- if (read_ev || cancel || err_fallback) {
- fd_become_readable(fd);
- }
- if (write_ev || cancel || err_fallback) {
- fd_become_writable(fd);
- }
- }
- }
-
- g_current_thread_polling_island = nullptr;
- gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1);
-
- GPR_ASSERT(pi != nullptr);
-
- /* Before leaving, release the extra ref we added to the polling island. It
- is important to use "pi" here (i.e our old copy of pollset->po.pi
- that we got before releasing the polling island lock). This is because
- pollset->po.pi pointer might get udpated in other parts of the
- code when there is an island merge while we are doing epoll_wait() above */
- PI_UNREF(pi, "ps_work");
-}
-
-/* pollset->po.mu lock must be held by the caller before calling this.
- The function pollset_work() may temporarily release the lock (pollset->po.mu)
- during the course of its execution but it will always re-acquire the lock and
- ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* pollset,
- grpc_pollset_worker** worker_hdl,
- grpc_millis deadline) {
- GPR_TIMER_SCOPE("pollset_work", 0);
- grpc_error* error = GRPC_ERROR_NONE;
- int timeout_ms = poll_deadline_to_millis_timeout(deadline);
-
- sigset_t new_mask;
-
- grpc_pollset_worker worker;
- worker.next = worker.prev = nullptr;
- worker.pt_id = pthread_self();
- gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0);
-
- if (worker_hdl) *worker_hdl = &worker;
-
- gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
- gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
-
- if (pollset->kicked_without_pollers) {
- /* If the pollset was kicked without pollers, pretend that the current
- worker got the kick and skip polling. A kick indicates that there is some
- work that needs attention like an event on the completion queue or an
- alarm */
- GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0);
- pollset->kicked_without_pollers = 0;
- } else if (!pollset->shutting_down) {
- /* We use the posix-signal with number 'grpc_wakeup_signal' for waking up
- (i.e 'kicking') a worker in the pollset. A 'kick' is a way to inform the
- worker that there is some pending work that needs immediate attention
- (like an event on the completion queue, or a polling island merge that
- results in a new epoll-fd to wait on) and that the worker should not
- spend time waiting in epoll_pwait().
-
- A worker can be kicked anytime from the point it is added to the pollset
- via push_front_worker() (or push_back_worker()) to the point it is
- removed via remove_worker().
- If the worker is kicked before/during it calls epoll_pwait(), it should
- immediately exit from epoll_wait(). If the worker is kicked after it
- returns from epoll_wait(), then nothing really needs to be done.
-
- To accomplish this, we mask 'grpc_wakeup_signal' on this thread at all
- times *except* when it is in epoll_pwait(). This way, the worker never
- misses acting on a kick */
-
- if (!g_initialized_sigmask) {
- sigemptyset(&new_mask);
- sigaddset(&new_mask, grpc_wakeup_signal);
- pthread_sigmask(SIG_BLOCK, &new_mask, &g_orig_sigmask);
- sigdelset(&g_orig_sigmask, grpc_wakeup_signal);
- g_initialized_sigmask = true;
- /* new_mask: The new thread mask which blocks 'grpc_wakeup_signal'.
- This is the mask used at all times *except during
- epoll_wait()*"
- g_orig_sigmask: The thread mask which allows 'grpc_wakeup_signal' and
- this is the mask to use *during epoll_wait()*
-
- The new_mask is set on the worker before it is added to the pollset
- (i.e before it can be kicked) */
- }
-
- push_front_worker(pollset, &worker); /* Add worker to pollset */
-
- pollset_work_and_unlock(pollset, &worker, timeout_ms, &g_orig_sigmask,
- &error);
- grpc_core::ExecCtx::Get()->Flush();
-
- gpr_mu_lock(&pollset->po.mu);
-
- /* Note: There is no need to reset worker.is_kicked to 0 since we are no
- longer going to use this worker */
- remove_worker(pollset, &worker);
- }
-
- /* If we are the last worker on the pollset (i.e pollset_has_workers() is
- false at this point) and the pollset is shutting down, we may have to
- finish the shutdown process by calling finish_shutdown_locked().
- See pollset_shutdown() for more details.
-
- Note: Continuing to access pollset here is safe; it is the caller's
- responsibility to not destroy a pollset when it has outstanding calls to
- pollset_work() */
- if (pollset->shutting_down && !pollset_has_workers(pollset) &&
- !pollset->finish_shutdown_called) {
- GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0);
- finish_shutdown_locked(pollset);
-
- gpr_mu_unlock(&pollset->po.mu);
- grpc_core::ExecCtx::Get()->Flush();
- gpr_mu_lock(&pollset->po.mu);
- }
-
- if (worker_hdl) *worker_hdl = nullptr;
-
- gpr_tls_set(&g_current_thread_pollset, (intptr_t)0);
- gpr_tls_set(&g_current_thread_worker, (intptr_t)0);
-
- GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
- return error;
-}
-
-static void add_poll_object(poll_obj* bag, poll_obj_type bag_type,
- poll_obj* item, poll_obj_type item_type) {
- GPR_TIMER_SCOPE("add_poll_object", 0);
-
-#ifndef NDEBUG
- GPR_ASSERT(item->obj_type == item_type);
- GPR_ASSERT(bag->obj_type == bag_type);
-#endif
-
- grpc_error* error = GRPC_ERROR_NONE;
- polling_island* pi_new = nullptr;
-
- gpr_mu_lock(&bag->mu);
- gpr_mu_lock(&item->mu);
-
-retry:
- /*
- * 1) If item->pi and bag->pi are both non-NULL and equal, do nothing
- * 2) If item->pi and bag->pi are both NULL, create a new polling island (with
- * a refcount of 2) and point item->pi and bag->pi to the new island
- * 3) If exactly one of item->pi or bag->pi is NULL, update it to point to
- * the other's non-NULL pi
- * 4) Finally if item->pi and bag-pi are non-NULL and not-equal, merge the
- * polling islands and update item->pi and bag->pi to point to the new
- * island
- */
-
- /* Early out if we are trying to add an 'fd' to a 'bag' but the fd is already
- * orphaned */
- if (item_type == POLL_OBJ_FD && (FD_FROM_PO(item))->orphaned) {
- gpr_mu_unlock(&item->mu);
- gpr_mu_unlock(&bag->mu);
- return;
- }
-
- if (item->pi == bag->pi) {
- pi_new = item->pi;
- if (pi_new == nullptr) {
- /* GPR_ASSERT(item->pi == bag->pi == NULL) */
-
- /* If we are adding an fd to a bag (i.e pollset or pollset_set), then
- * we need to do some extra work to make TSAN happy */
- if (item_type == POLL_OBJ_FD) {
- /* Unlock before creating a new polling island: the polling island will
- create a workqueue which creates a file descriptor, and holding an fd
- lock here can eventually cause a loop to appear to TSAN (making it
- unhappy). We don't think it's a real loop (there's an epoch point
- where that loop possibility disappears), but the advantages of
- keeping TSAN happy outweigh any performance advantage we might have
- by keeping the lock held. */
- gpr_mu_unlock(&item->mu);
- pi_new = polling_island_create(FD_FROM_PO(item), &error);
- gpr_mu_lock(&item->mu);
-
- /* Need to reverify any assumptions made between the initial lock and
- getting to this branch: if they've changed, we need to throw away our
- work and figure things out again. */
- if (item->pi != nullptr) {
- GRPC_POLLING_TRACE(
- "add_poll_object: Raced creating new polling island. pi_new: %p "
- "(fd: %d, %s: %p)",
- (void*)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type),
- (void*)bag);
- /* No need to lock 'pi_new' here since this is a new polling island
- and no one has a reference to it yet */
- polling_island_remove_all_fds_locked(pi_new, true, &error);
-
- /* Ref and unref so that the polling island gets deleted during unref
- */
- PI_ADD_REF(pi_new, "dance_of_destruction");
- PI_UNREF(pi_new, "dance_of_destruction");
- goto retry;
- }
- } else {
- pi_new = polling_island_create(nullptr, &error);
- }
-
- GRPC_POLLING_TRACE(
- "add_poll_object: Created new polling island. pi_new: %p (%s: %p, "
- "%s: %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else {
- GRPC_POLLING_TRACE(
- "add_poll_object: Same polling island. pi: %p (%s, %s)",
- (void*)pi_new, poll_obj_string(item_type), poll_obj_string(bag_type));
- }
- } else if (item->pi == nullptr) {
- /* GPR_ASSERT(bag->pi != NULL) */
- /* Make pi_new point to latest pi*/
- pi_new = polling_island_lock(bag->pi);
-
- if (item_type == POLL_OBJ_FD) {
- grpc_fd* fd = FD_FROM_PO(item);
- polling_island_add_fds_locked(pi_new, &fd, 1, true, &error);
- }
-
- gpr_mu_unlock(&pi_new->mu);
- GRPC_POLLING_TRACE(
- "add_poll_obj: item->pi was NULL. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else if (bag->pi == nullptr) {
- /* GPR_ASSERT(item->pi != NULL) */
- /* Make pi_new to point to latest pi */
- pi_new = polling_island_lock(item->pi);
- gpr_mu_unlock(&pi_new->mu);
- GRPC_POLLING_TRACE(
- "add_poll_obj: bag->pi was NULL. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else {
- pi_new = polling_island_merge(item->pi, bag->pi, &error);
- GRPC_POLLING_TRACE(
- "add_poll_obj: polling islands merged. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- }
-
- /* At this point, pi_new is the polling island that both item->pi and bag->pi
- MUST be pointing to */
-
- if (item->pi != pi_new) {
- PI_ADD_REF(pi_new, poll_obj_string(item_type));
- if (item->pi != nullptr) {
- PI_UNREF(item->pi, poll_obj_string(item_type));
- }
- item->pi = pi_new;
- }
-
- if (bag->pi != pi_new) {
- PI_ADD_REF(pi_new, poll_obj_string(bag_type));
- if (bag->pi != nullptr) {
- PI_UNREF(bag->pi, poll_obj_string(bag_type));
- }
- bag->pi = pi_new;
- }
-
- gpr_mu_unlock(&item->mu);
- gpr_mu_unlock(&bag->mu);
-
- GRPC_LOG_IF_ERROR("add_poll_object", error);
-}
-
-static void pollset_add_fd(grpc_pollset* pollset, grpc_fd* fd) {
- add_poll_object(&pollset->po, POLL_OBJ_POLLSET, &fd->po, POLL_OBJ_FD);
-}
-
-/*******************************************************************************
- * Pollset-set Definitions
- */
-
-static grpc_pollset_set* pollset_set_create(void) {
- grpc_pollset_set* pss =
- static_cast<grpc_pollset_set*>(gpr_malloc(sizeof(*pss)));
- gpr_mu_init(&pss->po.mu);
- pss->po.pi = nullptr;
-#ifndef NDEBUG
- pss->po.obj_type = POLL_OBJ_POLLSET_SET;
-#endif
- return pss;
-}
-
-static void pollset_set_destroy(grpc_pollset_set* pss) {
- gpr_mu_destroy(&pss->po.mu);
-
- if (pss->po.pi != nullptr) {
- PI_UNREF(pss->po.pi, "pss_destroy");
- }
-
- gpr_free(pss);
-}
-
-static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) {
- add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &fd->po, POLL_OBJ_FD);
-}
-
-static void pollset_set_del_fd(grpc_pollset_set* pss, grpc_fd* fd) {
- /* Nothing to do */
-}
-
-static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
- add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &ps->po, POLL_OBJ_POLLSET);
-}
-
-static void pollset_set_del_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
- /* Nothing to do */
-}
-
-static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
- add_poll_object(&bag->po, POLL_OBJ_POLLSET_SET, &item->po,
- POLL_OBJ_POLLSET_SET);
-}
-
-static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
- /* Nothing to do */
-}
-
-/* Test helper functions
- * */
-void* grpc_fd_get_polling_island(grpc_fd* fd) {
- polling_island* pi;
-
- gpr_mu_lock(&fd->po.mu);
- pi = fd->po.pi;
- gpr_mu_unlock(&fd->po.mu);
-
- return pi;
-}
-
-void* grpc_pollset_get_polling_island(grpc_pollset* ps) {
- polling_island* pi;
-
- gpr_mu_lock(&ps->po.mu);
- pi = ps->po.pi;
- gpr_mu_unlock(&ps->po.mu);
-
- return pi;
-}
-
-bool grpc_are_polling_islands_equal(void* p, void* q) {
- polling_island* p1 = static_cast<polling_island*>(p);
- polling_island* p2 = static_cast<polling_island*>(q);
-
- /* Note: polling_island_lock_pair() may change p1 and p2 to point to the
- latest polling islands in their respective linked lists */
- polling_island_lock_pair(&p1, &p2);
- polling_island_unlock_pair(p1, p2);
-
- return p1 == p2;
-}
-
-/*******************************************************************************
- * Event engine binding
- */
-
-static void shutdown_engine(void) {
- fd_global_shutdown();
- pollset_global_shutdown();
- polling_island_global_shutdown();
-}
-
-static const grpc_event_engine_vtable vtable = {
- sizeof(grpc_pollset),
- true,
-
- fd_create,
- fd_wrapped_fd,
- fd_orphan,
- fd_shutdown,
- fd_notify_on_read,
- fd_notify_on_write,
- fd_notify_on_error,
- fd_become_readable,
- fd_become_writable,
- fd_has_errors,
- fd_is_shutdown,
-
- pollset_init,
- pollset_shutdown,
- pollset_destroy,
- pollset_work,
- pollset_kick,
- pollset_add_fd,
-
- pollset_set_create,
- pollset_set_destroy,
- pollset_set_add_pollset,
- pollset_set_del_pollset,
- pollset_set_add_pollset_set,
- pollset_set_del_pollset_set,
- pollset_set_add_fd,
- pollset_set_del_fd,
-
- shutdown_engine,
-};
-
-/* It is possible that GLIBC has epoll but the underlying kernel doesn't.
- * Create a dummy epoll_fd to make sure epoll support is available */
-static bool is_epoll_available() {
- int fd = epoll_create1(EPOLL_CLOEXEC);
- if (fd < 0) {
- gpr_log(
- GPR_ERROR,
- "epoll_create1 failed with error: %d. Not using epoll polling engine",
- fd);
- return false;
- }
- close(fd);
- return true;
-}
-
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(
- bool explicit_request) {
- /* If use of signals is disabled, we cannot use epoll engine*/
- if (is_grpc_wakeup_signal_initialized && grpc_wakeup_signal < 0) {
- gpr_log(GPR_ERROR, "Skipping epollsig because use of signals is disabled.");
- return nullptr;
- }
-
- if (!grpc_has_wakeup_fd()) {
- gpr_log(GPR_ERROR, "Skipping epollsig because of no wakeup fd.");
- return nullptr;
- }
-
- if (!is_epoll_available()) {
- gpr_log(GPR_ERROR, "Skipping epollsig because epoll is unavailable.");
- return nullptr;
- }
-
- if (!is_grpc_wakeup_signal_initialized) {
- if (explicit_request) {
- grpc_use_signal(SIGRTMIN + 6);
- } else {
- gpr_log(GPR_ERROR,
- "Skipping epollsig because uninitialized wakeup signal.");
- return nullptr;
- }
- }
-
- fd_global_init();
-
- if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
- return nullptr;
- }
-
- if (!GRPC_LOG_IF_ERROR("polling_island_global_init",
- polling_island_global_init())) {
- return nullptr;
- }
-
- return &vtable;
-}
-
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-#if defined(GRPC_POSIX_SOCKET_EV_EPOLLSIG)
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-/* If GRPC_LINUX_EPOLL_CREATE1 is not defined, it means
- epoll_create1 is not available. Return NULL */
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(
- bool explicit_request) {
- return nullptr;
-}
-#endif /* defined(GRPC_POSIX_SOCKET) */
-
-void grpc_use_signal(int signum) {}
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index d4377e2d50..8a7dc7b004 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -35,7 +35,6 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/ev_epoll1_linux.h"
#include "src/core/lib/iomgr/ev_epollex_linux.h"
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
#include "src/core/lib/iomgr/ev_poll_posix.h"
grpc_core::TraceFlag grpc_polling_trace(false,
@@ -123,13 +122,13 @@ const grpc_event_engine_vtable* init_non_polling(bool explicit_request) {
// environment variable if that variable is set (which should be a
// comma-separated list of one or more event engine names)
static event_engine_factory g_factories[] = {
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
- {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
- {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
- {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
+ {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
+ {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix},
+ {"none", init_non_polling}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_TAIL_CUSTOM, nullptr},
};
static void add(const char* beg, const char* end, char*** ss, size_t* ns) {
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index f3528d527a..e90eb54cd3 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -116,12 +116,7 @@ class ExecCtx {
ExecCtx(const ExecCtx&) = delete;
ExecCtx& operator=(const ExecCtx&) = delete;
- /** Return starting_cpu. This is only required for stats collection and is
- * hence only defined if GRPC_COLLECT_STATS is enabled.
- */
-#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
unsigned starting_cpu() const { return starting_cpu_; }
-#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */
struct CombinerData {
/* currently active combiner: updated only via combiner.c */
@@ -223,9 +218,7 @@ class ExecCtx {
CombinerData combiner_data_ = {nullptr, nullptr};
uintptr_t flags_;
-#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
unsigned starting_cpu_ = gpr_cpu_current_cpu();
-#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */
bool now_is_valid_ = false;
grpc_millis now_ = 0;
diff --git a/src/core/lib/iomgr/internal_errqueue.cc b/src/core/lib/iomgr/internal_errqueue.cc
index 8823737e49..99c22e9055 100644
--- a/src/core/lib/iomgr/internal_errqueue.cc
+++ b/src/core/lib/iomgr/internal_errqueue.cc
@@ -24,10 +24,6 @@
#ifdef GRPC_POSIX_SOCKET_TCP
-#ifdef GPR_LINUX
-#include <linux/version.h>
-#endif /* GPR_LINUX */
-
bool kernel_supports_errqueue() {
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
diff --git a/src/core/lib/iomgr/internal_errqueue.h b/src/core/lib/iomgr/internal_errqueue.h
index fc11be9a6d..9d122808f9 100644
--- a/src/core/lib/iomgr/internal_errqueue.h
+++ b/src/core/lib/iomgr/internal_errqueue.h
@@ -43,6 +43,27 @@
namespace grpc_core {
#ifdef GRPC_LINUX_ERRQUEUE
+
+/* Redefining scm_timestamping in the same way that <linux/errqueue.h> defines
+ * it, so that code compiles on systems that don't have it. */
+struct scm_timestamping {
+ struct timespec ts[3];
+};
+/* Also redefine timestamp types */
+/* The timestamp type for when the driver passed skb to NIC, or HW. */
+constexpr int SCM_TSTAMP_SND = 0;
+/* The timestamp type for when data entered the packet scheduler. */
+constexpr int SCM_TSTAMP_SCHED = 1;
+/* The timestamp type for when data acknowledged by peer. */
+constexpr int SCM_TSTAMP_ACK = 2;
+/* Redefine required constants from <linux/net_tstamp.h> */
+constexpr uint32_t SOF_TIMESTAMPING_TX_SOFTWARE = 1u << 1;
+constexpr uint32_t SOF_TIMESTAMPING_SOFTWARE = 1u << 4;
+constexpr uint32_t SOF_TIMESTAMPING_OPT_ID = 1u << 7;
+constexpr uint32_t SOF_TIMESTAMPING_TX_SCHED = 1u << 8;
+constexpr uint32_t SOF_TIMESTAMPING_TX_ACK = 1u << 9;
+constexpr uint32_t SOF_TIMESTAMPING_OPT_TSONLY = 1u << 11;
+
constexpr uint32_t kTimestampingSocketOptions = SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_OPT_ID |
SOF_TIMESTAMPING_OPT_TSONLY;
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/port.h b/src/core/lib/iomgr/port.h
index a4688fd0ef..bf56a7298d 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -60,10 +60,10 @@
#define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1
#define GRPC_HAVE_UNIX_SOCKET 1
-#include <linux/version.h>
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
-#define GRPC_LINUX_ERRQUEUE 1
+/* TODO(yashykt): Re-enable once Fathom changes are commited.
+#define GRPC_LINUX_ERRQUEUE 1 */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
#endif /* LINUX_VERSION_CODE */
#define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1
@@ -83,6 +83,11 @@
#define GRPC_LINUX_SOCKETUTILS 1
#endif
#endif
+#ifdef LINUX_VERSION_CODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#define GRPC_HAVE_TCP_USER_TIMEOUT
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */
+#endif /* LINUX_VERSION_CODE */
#ifndef __GLIBC__
#define GRPC_LINUX_EPOLL 1
#define GRPC_LINUX_EPOLL_CREATE1 1
@@ -111,7 +116,6 @@
#define GRPC_POSIX_SOCKET_EV 1
#define GRPC_POSIX_SOCKET_EV_EPOLL1 1
#define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
-#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
#define GRPC_POSIX_SOCKET_EV_POLL 1
#define GRPC_POSIX_SOCKET_RESOLVE_ADDRESS 1
#define GRPC_POSIX_SOCKET_SOCKADDR 1
@@ -179,7 +183,6 @@
#define GRPC_POSIX_SOCKET_ARES_EV_DRIVER 1
#define GRPC_POSIX_SOCKET_EV 1
#define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
-#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
#define GRPC_POSIX_SOCKET_EV_POLL 1
#define GRPC_POSIX_SOCKET_EV_EPOLL1 1
#define GRPC_POSIX_SOCKET_IOMGR 1
diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc
index b6fc7579f7..7e4b3c9b2f 100644
--- a/src/core/lib/iomgr/resource_quota.cc
+++ b/src/core/lib/iomgr/resource_quota.cc
@@ -90,7 +90,8 @@ struct grpc_resource_user {
grpc_closure_list on_allocated;
/* True if we are currently trying to allocate from the quota, false if not */
bool allocating;
- /* How many bytes of allocations are outstanding */
+ /* The amount of memory (in bytes) that has been requested from this user
+ * asynchronously but hasn't been granted yet. */
int64_t outstanding_allocations;
/* True if we are currently trying to add ourselves to the non-free quota
list, false otherwise */
@@ -135,6 +136,9 @@ struct grpc_resource_quota {
int64_t size;
/* Amount of free memory in the resource quota */
int64_t free_pool;
+ /* Used size of memory in the resource quota. Updated as soon as the resource
+ * users start to allocate or free the memory. */
+ gpr_atm used;
gpr_atm last_size;
@@ -371,6 +375,7 @@ static bool rq_reclaim_from_per_user_free_pool(
while ((resource_user = rulist_pop_head(resource_quota,
GRPC_RULIST_NON_EMPTY_FREE_POOL))) {
gpr_mu_lock(&resource_user->mu);
+ resource_user->added_to_free_pool = false;
if (resource_user->free_pool > 0) {
int64_t amt = resource_user->free_pool;
resource_user->free_pool = 0;
@@ -386,6 +391,13 @@ static bool rq_reclaim_from_per_user_free_pool(
gpr_mu_unlock(&resource_user->mu);
return true;
} else {
+ if (grpc_resource_quota_trace.enabled()) {
+ gpr_log(GPR_INFO,
+ "RQ %s %s: failed to reclaim_from_per_user_free_pool; "
+ "free_pool = %" PRId64 "; rq_free_pool = %" PRId64,
+ resource_quota->name, resource_user->name,
+ resource_user->free_pool, resource_quota->free_pool);
+ }
gpr_mu_unlock(&resource_user->mu);
}
}
@@ -622,6 +634,7 @@ grpc_resource_quota* grpc_resource_quota_create(const char* name) {
resource_quota->combiner = grpc_combiner_create();
resource_quota->free_pool = INT64_MAX;
resource_quota->size = INT64_MAX;
+ resource_quota->used = 0;
gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
gpr_mu_init(&resource_quota->thread_count_mu);
resource_quota->max_threads = INT_MAX;
@@ -712,7 +725,7 @@ size_t grpc_resource_quota_peek_size(grpc_resource_quota* resource_quota) {
*/
grpc_resource_quota* grpc_resource_quota_from_channel_args(
- const grpc_channel_args* channel_args) {
+ const grpc_channel_args* channel_args, bool create) {
for (size_t i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
if (channel_args->args[i].type == GRPC_ARG_POINTER) {
@@ -724,7 +737,7 @@ grpc_resource_quota* grpc_resource_quota_from_channel_args(
}
}
}
- return grpc_resource_quota_create(nullptr);
+ return create ? grpc_resource_quota_create(nullptr) : nullptr;
}
static void* rq_copy(void* rq) {
@@ -863,33 +876,68 @@ void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
gpr_mu_unlock(&resource_user->resource_quota->thread_count_mu);
}
-void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
- grpc_closure* optional_on_done) {
- gpr_mu_lock(&resource_user->mu);
+static void resource_user_alloc_locked(grpc_resource_user* resource_user,
+ size_t size,
+ grpc_closure* optional_on_done) {
ru_ref_by(resource_user, static_cast<gpr_atm>(size));
resource_user->free_pool -= static_cast<int64_t>(size);
- resource_user->outstanding_allocations += static_cast<int64_t>(size);
if (grpc_resource_quota_trace.enabled()) {
gpr_log(GPR_INFO, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
resource_user->resource_quota->name, resource_user->name, size,
resource_user->free_pool);
}
if (resource_user->free_pool < 0) {
- grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
- GRPC_ERROR_NONE);
+ if (optional_on_done != nullptr) {
+ resource_user->outstanding_allocations += static_cast<int64_t>(size);
+ grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
+ GRPC_ERROR_NONE);
+ }
if (!resource_user->allocating) {
resource_user->allocating = true;
GRPC_CLOSURE_SCHED(&resource_user->allocate_closure, GRPC_ERROR_NONE);
}
} else {
- resource_user->outstanding_allocations -= static_cast<int64_t>(size);
GRPC_CLOSURE_SCHED(optional_on_done, GRPC_ERROR_NONE);
}
+}
+
+bool grpc_resource_user_safe_alloc(grpc_resource_user* resource_user,
+ size_t size) {
+ if (gpr_atm_no_barrier_load(&resource_user->shutdown)) return false;
+ gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ bool cas_success;
+ do {
+ gpr_atm used = gpr_atm_no_barrier_load(&resource_quota->used);
+ gpr_atm new_used = used + size;
+ if (static_cast<size_t>(new_used) >
+ grpc_resource_quota_peek_size(resource_quota)) {
+ gpr_mu_unlock(&resource_user->mu);
+ return false;
+ }
+ cas_success = gpr_atm_full_cas(&resource_quota->used, used, new_used);
+ } while (!cas_success);
+ resource_user_alloc_locked(resource_user, size, nullptr);
+ gpr_mu_unlock(&resource_user->mu);
+ return true;
+}
+
+void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
+ grpc_closure* optional_on_done) {
+ // TODO(juanlishen): Maybe return immediately if shutting down. Deferring this
+ // because some tests become flaky after the change.
+ gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ gpr_atm_no_barrier_fetch_add(&resource_quota->used, size);
+ resource_user_alloc_locked(resource_user, size, optional_on_done);
gpr_mu_unlock(&resource_user->mu);
}
void grpc_resource_user_free(grpc_resource_user* resource_user, size_t size) {
gpr_mu_lock(&resource_user->mu);
+ grpc_resource_quota* resource_quota = resource_user->resource_quota;
+ gpr_atm prior = gpr_atm_no_barrier_fetch_add(&resource_quota->used, -size);
+ GPR_ASSERT(prior >= static_cast<long>(size));
bool was_zero_or_negative = resource_user->free_pool <= 0;
resource_user->free_pool += static_cast<int64_t>(size);
if (grpc_resource_quota_trace.enabled()) {
@@ -940,6 +988,12 @@ void grpc_resource_user_slice_allocator_init(
void grpc_resource_user_alloc_slices(
grpc_resource_user_slice_allocator* slice_allocator, size_t length,
size_t count, grpc_slice_buffer* dest) {
+ if (gpr_atm_no_barrier_load(&slice_allocator->resource_user->shutdown)) {
+ GRPC_CLOSURE_SCHED(
+ &slice_allocator->on_allocated,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource user shutdown"));
+ return;
+ }
slice_allocator->length = length;
slice_allocator->count = count;
slice_allocator->dest = dest;
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index 7b0ed7417a..1c79b52e3f 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -65,11 +65,16 @@
extern grpc_core::TraceFlag grpc_resource_quota_trace;
+// TODO(juanlishen): This is a hack. We need to do real accounting instead of
+// hard coding.
+constexpr size_t GRPC_RESOURCE_QUOTA_CALL_SIZE = 15 * 1024;
+constexpr size_t GRPC_RESOURCE_QUOTA_CHANNEL_SIZE = 50 * 1024;
+
grpc_resource_quota* grpc_resource_quota_ref_internal(
grpc_resource_quota* resource_quota);
void grpc_resource_quota_unref_internal(grpc_resource_quota* resource_quota);
grpc_resource_quota* grpc_resource_quota_from_channel_args(
- const grpc_channel_args* channel_args);
+ const grpc_channel_args* channel_args, bool create = true);
/* Return a number indicating current memory pressure:
0.0 ==> no memory usage
@@ -109,11 +114,21 @@ bool grpc_resource_user_allocate_threads(grpc_resource_user* resource_user,
void grpc_resource_user_free_threads(grpc_resource_user* resource_user,
int thread_count);
-/* Allocate from the resource user (and its quota).
- If optional_on_done is NULL, then allocate immediately. This may push the
- quota over-limit, at which point reclamation will kick in.
- If optional_on_done is non-NULL, it will be scheduled when the allocation has
- been granted by the quota. */
+/* Allocates from the resource user 'size' worth of memory if this won't exceed
+ * the resource quota's total size. Returns whether the allocation is done
+ * successfully. If allocated successfully, the memory should be freed by the
+ * caller eventually. */
+bool grpc_resource_user_safe_alloc(grpc_resource_user* resource_user,
+ size_t size);
+/* Allocates from the resource user 'size' worth of memory.
+ * If optional_on_done is NULL, then allocate immediately. This may push the
+ * quota over-limit, at which point reclamation will kick in. The caller is
+ * always responsible to free the memory eventually.
+ * If optional_on_done is non-NULL, it will be scheduled without error when the
+ * allocation has been granted by the quota, and the caller is responsible to
+ * free the memory eventually. Or it may be scheduled with an error, in which
+ * case the caller fails to allocate the memory and shouldn't free the memory.
+ */
void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
grpc_closure* optional_on_done);
/* Release memory back to the quota */
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index c4b991c94d..4c337a0521 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -41,6 +41,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/sockaddr.h"
@@ -222,6 +223,101 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
return GRPC_ERROR_NONE;
}
+/* The default values for TCP_USER_TIMEOUT are currently configured to be in
+ * line with the default values of KEEPALIVE_TIMEOUT as proposed in
+ * https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */
+#define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
+#define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
+
+static int g_default_client_tcp_user_timeout_ms =
+ DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
+static int g_default_server_tcp_user_timeout_ms =
+ DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
+static bool g_default_client_tcp_user_timeout_enabled = false;
+static bool g_default_server_tcp_user_timeout_enabled = true;
+
+void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
+ if (is_client) {
+ g_default_client_tcp_user_timeout_enabled = enable;
+ if (timeout > 0) {
+ g_default_client_tcp_user_timeout_ms = timeout;
+ }
+ } else {
+ g_default_server_tcp_user_timeout_enabled = enable;
+ if (timeout > 0) {
+ g_default_server_tcp_user_timeout_ms = timeout;
+ }
+ }
+}
+
+/* Set TCP_USER_TIMEOUT */
+grpc_error* grpc_set_socket_tcp_user_timeout(
+ int fd, const grpc_channel_args* channel_args, bool is_client) {
+#ifdef GRPC_HAVE_TCP_USER_TIMEOUT
+ bool enable;
+ int timeout;
+ if (is_client) {
+ enable = g_default_client_tcp_user_timeout_enabled;
+ timeout = g_default_client_tcp_user_timeout_ms;
+ } else {
+ enable = g_default_server_tcp_user_timeout_enabled;
+ timeout = g_default_server_tcp_user_timeout_ms;
+ }
+ if (channel_args) {
+ for (unsigned int i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
+ /* Continue using default if value is 0 */
+ if (value == 0) {
+ continue;
+ }
+ /* Disable if value is INT_MAX */
+ enable = value != INT_MAX;
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
+ /* Continue using default if value is 0 */
+ if (value == 0) {
+ continue;
+ }
+ timeout = value;
+ }
+ }
+ }
+ if (enable) {
+ extern grpc_core::TraceFlag grpc_tcp_trace;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
+ timeout);
+ }
+ int newval;
+ socklen_t len = sizeof(newval);
+ if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
+ sizeof(timeout))) {
+ gpr_log(GPR_ERROR, "setsockopt(TCP_USER_TIMEOUT) %s", strerror(errno));
+ return GRPC_ERROR_NONE;
+ }
+ if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
+ gpr_log(GPR_ERROR, "getsockopt(TCP_USER_TIMEOUT) %s", strerror(errno));
+ return GRPC_ERROR_NONE;
+ }
+ if (newval != 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
+ extern grpc_core::TraceFlag grpc_tcp_trace;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
+ }
+#endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
+ return GRPC_ERROR_NONE;
+}
+
/* set a socket using a grpc_socket_mutator */
grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
GPR_ASSERT(mutator);
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index b3fd58a530..71a304dc4e 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -53,6 +53,13 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
/* set SO_REUSEPORT */
grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
+/* Configure the default values for TCP_USER_TIMEOUT */
+void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
+
+/* Set TCP_USER_TIMEOUT */
+grpc_error* grpc_set_socket_tcp_user_timeout(
+ int fd, const grpc_channel_args* channel_args, bool is_client);
+
/* Returns true if this system can create AF_INET6 sockets bound to ::1.
The value is probed once, and cached for the life of the process.
diff --git a/src/core/lib/iomgr/tcp_client_custom.cc b/src/core/lib/iomgr/tcp_client_custom.cc
index 9389861d07..73344b18d8 100644
--- a/src/core/lib/iomgr/tcp_client_custom.cc
+++ b/src/core/lib/iomgr/tcp_client_custom.cc
@@ -81,9 +81,8 @@ static void on_alarm(void* acp, grpc_error* error) {
}
}
-static void custom_connect_callback(grpc_custom_socket* socket,
- grpc_error* error) {
- grpc_core::ExecCtx exec_ctx;
+static void custom_connect_callback_internal(grpc_custom_socket* socket,
+ grpc_error* error) {
grpc_custom_tcp_connect* connect = socket->connector;
int done;
grpc_closure* closure = connect->closure;
@@ -100,6 +99,18 @@ static void custom_connect_callback(grpc_custom_socket* socket,
GRPC_CLOSURE_SCHED(closure, error);
}
+static void custom_connect_callback(grpc_custom_socket* socket,
+ grpc_error* error) {
+ if (grpc_core::ExecCtx::Get() == nullptr) {
+ /* If we are being run on a thread which does not have an exec_ctx created
+ * yet, we should create one. */
+ grpc_core::ExecCtx exec_ctx;
+ custom_connect_callback_internal(socket, error);
+ } else {
+ custom_connect_callback_internal(socket, error);
+ }
+}
+
static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
grpc_pollset_set* interested_parties,
const grpc_channel_args* channel_args,
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 9c989b7dfe..0bff74e88b 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -76,6 +76,11 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_reuse_addr(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
+ true /* is_client */);
+ if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index 23cbc20910..78c8d1eed8 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -204,6 +204,13 @@ static void drop_uncovered(grpc_tcp* tcp) {
GPR_ASSERT(old_count != 1);
}
+// gRPC API considers a Write operation to be done the moment it clears ‘flow
+// control’ i.e., not necessarily sent on the wire. This means that the
+// application MIGHT not call `grpc_completion_queue_next/pluck` in a timely
+// manner when its `Write()` API is acked.
+//
+// We need to ensure that the fd is 'covered' (i.e being monitored by some
+// polling thread and progress is made) and hence add it to a backup poller here
static void cover_self(grpc_tcp* tcp) {
backup_poller* p;
gpr_atm old_count =
@@ -468,7 +475,9 @@ static void tcp_do_read(grpc_tcp* tcp) {
GRPC_STATS_INC_TCP_READ_SIZE(read_bytes);
add_to_estimate(tcp, static_cast<size_t>(read_bytes));
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
- if (static_cast<size_t>(read_bytes) < tcp->incoming_buffer->length) {
+ if (static_cast<size_t>(read_bytes) == tcp->incoming_buffer->length) {
+ finish_estimate(tcp);
+ } else if (static_cast<size_t>(read_bytes) < tcp->incoming_buffer->length) {
grpc_slice_buffer_trim_end(
tcp->incoming_buffer,
tcp->incoming_buffer->length - static_cast<size_t>(read_bytes),
@@ -498,7 +507,7 @@ static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
static void tcp_continue_read(grpc_tcp* tcp) {
size_t target_read_size = get_target_read_size(tcp);
- if (tcp->incoming_buffer->length < target_read_size &&
+ if (tcp->incoming_buffer->length < target_read_size / 2 &&
tcp->incoming_buffer->count < MAX_READ_IOVEC) {
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p alloc_slices", tcp);
@@ -655,7 +664,8 @@ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg,
return cmsg;
}
- auto tss = reinterpret_cast<struct scm_timestamping*>(CMSG_DATA(cmsg));
+ auto tss =
+ reinterpret_cast<struct grpc_core::scm_timestamping*>(CMSG_DATA(cmsg));
auto serr = reinterpret_cast<struct sock_extended_err*>(CMSG_DATA(next_cmsg));
if (serr->ee_errno != ENOMSG ||
serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index 9595c028ce..8d8d3f4273 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -166,6 +166,9 @@ grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd,
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_reuse_addr(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_tcp_user_timeout(fd, s->channel_args,
+ false /* is_client */);
+ if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc
index 4294162af7..6a925add80 100644
--- a/src/core/lib/iomgr/timer_generic.cc
+++ b/src/core/lib/iomgr/timer_generic.cc
@@ -48,22 +48,22 @@ grpc_core::TraceFlag grpc_timer_trace(false, "timer");
grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
/* A "timer shard". Contains a 'heap' and a 'list' of timers. All timers with
- * deadlines earlier than 'queue_deadline" cap are maintained in the heap and
+ * deadlines earlier than 'queue_deadline_cap' are maintained in the heap and
* others are maintained in the list (unordered). This helps to keep the number
* of elements in the heap low.
*
* The 'queue_deadline_cap' gets recomputed periodically based on the timer
* stats maintained in 'stats' and the relevant timers are then moved from the
- * 'list' to 'heap'
+ * 'list' to 'heap'.
*/
typedef struct {
gpr_mu mu;
grpc_time_averaged_stats stats;
- /* All and only timers with deadlines <= this will be in the heap. */
+ /* All and only timers with deadlines < this will be in the heap. */
grpc_millis queue_deadline_cap;
- /* The deadline of the next timer due in this shard */
+ /* The deadline of the next timer due in this shard. */
grpc_millis min_deadline;
- /* Index of this timer_shard in the g_shard_queue */
+ /* Index of this timer_shard in the g_shard_queue. */
uint32_t shard_queue_index;
/* This holds all timers with deadlines < queue_deadline_cap. Timers in this
list have the top bit of their deadline set to 0. */
@@ -85,7 +85,7 @@ static timer_shard** g_shard_queue;
#ifndef NDEBUG
-/* == Hash table for duplicate timer detection == */
+/* == DEBUG ONLY: hash table for duplicate timer detection == */
#define NUM_HASH_BUCKETS 1009 /* Prime number close to 1000 */
@@ -177,7 +177,7 @@ static void remove_from_ht(grpc_timer* t) {
t->hash_table_next = nullptr;
}
-/* If a timer is added to a timer shard (either heap or a list), it cannot
+/* If a timer is added to a timer shard (either heap or a list), it must
* be pending. A timer is added to hash table only-if it is added to the
* timer shard.
* Therefore, if timer->pending is false, it cannot be in hash table */
@@ -256,7 +256,7 @@ static grpc_millis compute_min_deadline(timer_shard* shard) {
static void timer_list_init() {
uint32_t i;
- g_num_shards = GPR_MIN(1, 2 * gpr_cpu_num_cores());
+ g_num_shards = GPR_CLAMP(2 * gpr_cpu_num_cores(), 1, 32);
g_shards =
static_cast<timer_shard*>(gpr_zalloc(g_num_shards * sizeof(*g_shards)));
g_shard_queue = static_cast<timer_shard**>(
@@ -291,7 +291,7 @@ static void timer_list_init() {
static void timer_list_shutdown() {
size_t i;
run_some_expired_timers(
- GPR_ATM_MAX, nullptr,
+ GRPC_MILLIS_INF_FUTURE, nullptr,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown"));
for (i = 0; i < g_num_shards; i++) {
timer_shard* shard = &g_shards[i];
@@ -489,7 +489,7 @@ static void timer_cancel(grpc_timer* timer) {
'queue_deadline_cap') into into shard->heap.
Returns 'true' if shard->heap has atleast ONE element
REQUIRES: shard->mu locked */
-static int refill_heap(timer_shard* shard, grpc_millis now) {
+static bool refill_heap(timer_shard* shard, grpc_millis now) {
/* Compute the new queue window width and bound by the limits: */
double computed_deadline_delta =
grpc_time_averaged_stats_update_average(&shard->stats) *
@@ -714,9 +714,10 @@ static grpc_timer_check_result timer_check(grpc_millis* next) {
#if GPR_ARCH_64
gpr_log(GPR_INFO,
"TIMER CHECK BEGIN: now=%" PRId64 " next=%s tls_min=%" PRId64
- " glob_min=%" PRIdPTR,
+ " glob_min=%" PRId64,
now, next_str, min_timer,
- gpr_atm_no_barrier_load((gpr_atm*)(&g_shared_mutables.min_timer)));
+ static_cast<grpc_millis>(gpr_atm_no_barrier_load(
+ (gpr_atm*)(&g_shared_mutables.min_timer))));
#else
gpr_log(GPR_INFO, "TIMER CHECK BEGIN: now=%" PRId64 " next=%s min=%" PRId64,
now, next_str, min_timer);
diff --git a/src/core/lib/iomgr/timer_heap.cc b/src/core/lib/iomgr/timer_heap.cc
index 0c17d607eb..2c6a599149 100644
--- a/src/core/lib/iomgr/timer_heap.cc
+++ b/src/core/lib/iomgr/timer_heap.cc
@@ -95,7 +95,7 @@ void grpc_timer_heap_init(grpc_timer_heap* heap) {
void grpc_timer_heap_destroy(grpc_timer_heap* heap) { gpr_free(heap->timers); }
-int grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer) {
+bool grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer) {
if (heap->timer_count == heap->timer_capacity) {
heap->timer_capacity =
GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2);
@@ -122,7 +122,7 @@ void grpc_timer_heap_remove(grpc_timer_heap* heap, grpc_timer* timer) {
note_changed_priority(heap, heap->timers[i]);
}
-int grpc_timer_heap_is_empty(grpc_timer_heap* heap) {
+bool grpc_timer_heap_is_empty(grpc_timer_heap* heap) {
return heap->timer_count == 0;
}
diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h
index 503365d4cd..7b983e7133 100644
--- a/src/core/lib/iomgr/timer_heap.h
+++ b/src/core/lib/iomgr/timer_heap.h
@@ -29,8 +29,8 @@ typedef struct {
uint32_t timer_capacity;
} grpc_timer_heap;
-/* return 1 if the new timer is the first timer in the heap */
-int grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer);
+/* return true if the new timer is the first timer in the heap */
+bool grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer);
void grpc_timer_heap_init(grpc_timer_heap* heap);
void grpc_timer_heap_destroy(grpc_timer_heap* heap);
@@ -39,6 +39,6 @@ void grpc_timer_heap_remove(grpc_timer_heap* heap, grpc_timer* timer);
grpc_timer* grpc_timer_heap_top(grpc_timer_heap* heap);
void grpc_timer_heap_pop(grpc_timer_heap* heap);
-int grpc_timer_heap_is_empty(grpc_timer_heap* heap);
+bool grpc_timer_heap_is_empty(grpc_timer_heap* heap);
#endif /* GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H */
diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc
index 26de216671..ceba79f678 100644
--- a/src/core/lib/iomgr/timer_manager.cc
+++ b/src/core/lib/iomgr/timer_manager.cc
@@ -61,6 +61,14 @@ static uint64_t g_timed_waiter_generation;
static void timer_thread(void* completed_thread_ptr);
+// For debug of the timer manager crash only.
+// TODO (mxyan): remove after bug is fixed.
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+extern int64_t g_timer_manager_init_count;
+extern int64_t g_timer_manager_shutdown_count;
+extern int64_t g_fork_count;
+#endif // GRPC_DEBUG_TIMER_MANAGER
+
static void gc_completed_threads(void) {
if (g_completed_threads != nullptr) {
completed_thread* to_gc = g_completed_threads;
@@ -92,8 +100,7 @@ static void start_timer_thread_and_unlock(void) {
void grpc_timer_manager_tick() {
grpc_core::ExecCtx exec_ctx;
- grpc_millis next = GRPC_MILLIS_INF_FUTURE;
- grpc_timer_check(&next);
+ grpc_timer_check(nullptr);
}
static void run_some_timers() {
@@ -102,9 +109,12 @@ static void run_some_timers() {
// remove a waiter from the pool, and start another thread if necessary
--g_waiter_count;
if (g_waiter_count == 0 && g_threaded) {
+ // The number of timer threads is always increasing until all the threads
+ // are stopped. In rare cases, if a large number of timers fire
+ // simultaneously, we may end up using a large number of threads.
start_timer_thread_and_unlock();
} else {
- // if there's no thread waiting with a timeout, kick an existing
+ // if there's no thread waiting with a timeout, kick an existing untimed
// waiter so that the next deadline is not missed
if (!g_has_timed_waiter) {
if (grpc_timer_check_trace.enabled()) {
@@ -235,7 +245,7 @@ static void timer_main_loop() {
gpr_log(GPR_INFO, "timers not checked: expect another thread to");
}
next = GRPC_MILLIS_INF_FUTURE;
- /* fall through */
+ // fallthrough
case GRPC_TIMERS_CHECKED_AND_EMPTY:
if (!wait_until(next)) {
return;
@@ -284,6 +294,11 @@ static void start_threads(void) {
void grpc_timer_manager_init(void) {
gpr_mu_init(&g_mu);
gpr_cv_init(&g_cv_wait);
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+ // For debug of the timer manager crash only.
+ // TODO (mxyan): remove after bug is fixed.
+ g_timer_manager_init_count++;
+#endif
gpr_cv_init(&g_cv_shutdown);
g_threaded = false;
g_thread_count = 0;
@@ -319,6 +334,11 @@ static void stop_threads(void) {
}
void grpc_timer_manager_shutdown(void) {
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+ // For debug of the timer manager crash only.
+ // TODO (mxyan): remove after bug is fixed.
+ g_timer_manager_shutdown_count++;
+#endif
stop_threads();
gpr_mu_destroy(&g_mu);
@@ -327,6 +347,11 @@ void grpc_timer_manager_shutdown(void) {
}
void grpc_timer_manager_set_threading(bool threaded) {
+#ifdef GRPC_DEBUG_TIMER_MANAGER
+ // For debug of the timer manager crash only.
+ // TODO (mxyan): remove after bug is fixed.
+ g_fork_count++;
+#endif
if (threaded) {
start_threads();
} else {
diff --git a/src/core/lib/iomgr/timer_manager.h b/src/core/lib/iomgr/timer_manager.h
index 3c4cdda2c8..00dcdc461b 100644
--- a/src/core/lib/iomgr/timer_manager.h
+++ b/src/core/lib/iomgr/timer_manager.h
@@ -23,8 +23,8 @@
#include <stdbool.h>
-/* Timer Manager tries to keep one thread waiting for the next timeout at all
- times */
+/* Timer Manager tries to keep only one thread waiting for the next timeout at
+ all times, and thus effectively preventing the thundering herd problem. */
void grpc_timer_manager_init(void);
void grpc_timer_manager_shutdown(void);
diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.cc b/src/core/lib/iomgr/wakeup_fd_eventfd.cc
index dcf7dab71f..d68c9ada1f 100644
--- a/src/core/lib/iomgr/wakeup_fd_eventfd.cc
+++ b/src/core/lib/iomgr/wakeup_fd_eventfd.cc
@@ -32,12 +32,11 @@
#include "src/core/lib/profiling/timers.h"
static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) {
- int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (efd < 0) {
+ fd_info->read_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+ fd_info->write_fd = -1;
+ if (fd_info->read_fd < 0) {
return GRPC_OS_ERROR(errno, "eventfd");
}
- fd_info->read_fd = efd;
- fd_info->write_fd = -1;
return GRPC_ERROR_NONE;
}
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/alts/alts_credentials.cc b/src/core/lib/security/credentials/alts/alts_credentials.cc
index fa05d901bf..1fbef4ae0c 100644
--- a/src/core/lib/security/credentials/alts/alts_credentials.cc
+++ b/src/core/lib/security/credentials/alts/alts_credentials.cc
@@ -28,7 +28,7 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
-#include "src/core/lib/security/security_connector/alts_security_connector.h"
+#include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
#define GRPC_CREDENTIALS_TYPE_ALTS "Alts"
#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080"
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
index 0a39c6c485..118d18d119 100644
--- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
@@ -72,7 +72,8 @@ static void target_service_account_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_client_options_copy, alts_client_options_destroy};
-grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() {
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create(
+ void) {
auto client_options = static_cast<grpc_alts_credentials_client_options*>(
gpr_zalloc(sizeof(grpc_alts_credentials_client_options)));
client_options->base.vtable = &vtable;
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
index 62aa7a620a..1a59c45675 100644
--- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
@@ -36,7 +36,8 @@ static void alts_server_options_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_server_options_copy, alts_server_options_destroy};
-grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() {
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create(
+ void) {
grpc_alts_credentials_server_options* server_options =
static_cast<grpc_alts_credentials_server_options*>(
gpr_zalloc(sizeof(*server_options)));
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/credentials/fake/fake_credentials.cc b/src/core/lib/security/credentials/fake/fake_credentials.cc
index 858ab6b41b..d3e0e8c816 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.cc
+++ b/src/core/lib/security/credentials/fake/fake_credentials.cc
@@ -29,6 +29,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/security/security_connector/fake/fake_security_connector.h"
/* -- Fake transport security credentials. -- */
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
index c456ffaf5d..fcab252959 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
@@ -49,8 +49,8 @@
/* -- Default credentials. -- */
-static grpc_channel_credentials* g_default_credentials = nullptr;
static int g_compute_engine_detection_done = 0;
+static int g_need_compute_engine_creds = 0;
static gpr_mu g_state_mu;
static gpr_once g_once = GPR_ONCE_INIT;
static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
@@ -182,19 +182,13 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Failed to create Google credentials");
grpc_error* err;
+ int need_compute_engine_creds = 0;
grpc_core::ExecCtx exec_ctx;
GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
gpr_once_init(&g_once, init_default_credentials);
- gpr_mu_lock(&g_state_mu);
-
- if (g_default_credentials != nullptr) {
- result = grpc_channel_credentials_ref(g_default_credentials);
- goto end;
- }
-
/* First, try the environment variable. */
err = create_default_creds_from_path(
gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
@@ -207,55 +201,50 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
if (err == GRPC_ERROR_NONE) goto end;
error = grpc_error_add_child(error, err);
+ gpr_mu_lock(&g_state_mu);
/* At last try to see if we're on compute engine (do the detection only once
since it requires a network test). */
if (!g_compute_engine_detection_done) {
- int need_compute_engine_creds = g_gce_tenancy_checker();
+ g_need_compute_engine_creds = g_gce_tenancy_checker();
g_compute_engine_detection_done = 1;
- if (need_compute_engine_creds) {
- call_creds = grpc_google_compute_engine_credentials_create(nullptr);
- if (call_creds == nullptr) {
- error = grpc_error_add_child(
- error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to get credentials from network"));
- }
- }
}
+ need_compute_engine_creds = g_need_compute_engine_creds;
+ gpr_mu_unlock(&g_state_mu);
-end:
- if (result == nullptr) {
- if (call_creds != nullptr) {
- /* Create google default credentials. */
- auto creds = static_cast<grpc_google_default_channel_credentials*>(
- gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
- creds->base.vtable = &google_default_credentials_vtable;
- creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
- gpr_ref_init(&creds->base.refcount, 1);
- creds->ssl_creds =
- grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
- GPR_ASSERT(creds->ssl_creds != nullptr);
- grpc_alts_credentials_options* options =
- grpc_alts_credentials_client_options_create();
- creds->alts_creds = grpc_alts_credentials_create(options);
- grpc_alts_credentials_options_destroy(options);
- /* Add a global reference so that it can be cached and re-served. */
- g_default_credentials = grpc_composite_channel_credentials_create(
- &creds->base, call_creds, nullptr);
- GPR_ASSERT(g_default_credentials != nullptr);
- grpc_channel_credentials_unref(&creds->base);
- grpc_call_credentials_unref(call_creds);
- result = grpc_channel_credentials_ref(g_default_credentials);
- } else {
- gpr_log(GPR_ERROR, "Could not create google default credentials.");
+ if (need_compute_engine_creds) {
+ call_creds = grpc_google_compute_engine_credentials_create(nullptr);
+ if (call_creds == nullptr) {
+ error = grpc_error_add_child(
+ error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Failed to get credentials from network"));
}
}
- gpr_mu_unlock(&g_state_mu);
- if (result == nullptr) {
- GRPC_LOG_IF_ERROR("grpc_google_default_credentials_create", error);
+
+end:
+ if (call_creds != nullptr) {
+ /* Create google default credentials. */
+ auto creds = static_cast<grpc_google_default_channel_credentials*>(
+ gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
+ creds->base.vtable = &google_default_credentials_vtable;
+ creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
+ gpr_ref_init(&creds->base.refcount, 1);
+ creds->ssl_creds =
+ grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
+ GPR_ASSERT(creds->ssl_creds != nullptr);
+ grpc_alts_credentials_options* options =
+ grpc_alts_credentials_client_options_create();
+ creds->alts_creds = grpc_alts_credentials_create(options);
+ grpc_alts_credentials_options_destroy(options);
+ result = grpc_composite_channel_credentials_create(&creds->base, call_creds,
+ nullptr);
+ GPR_ASSERT(result != nullptr);
+ grpc_channel_credentials_unref(&creds->base);
+ grpc_call_credentials_unref(call_creds);
} else {
- GRPC_ERROR_UNREF(error);
+ gpr_log(GPR_ERROR, "Could not create google default credentials: %s",
+ grpc_error_string(error));
}
-
+ GRPC_ERROR_UNREF(error);
return result;
}
@@ -266,21 +255,17 @@ void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker) {
g_gce_tenancy_checker = checker;
}
-} // namespace internal
-} // namespace grpc_core
-
void grpc_flush_cached_google_default_credentials(void) {
grpc_core::ExecCtx exec_ctx;
gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_state_mu);
- if (g_default_credentials != nullptr) {
- grpc_channel_credentials_unref(g_default_credentials);
- g_default_credentials = nullptr;
- }
g_compute_engine_detection_done = 0;
gpr_mu_unlock(&g_state_mu);
}
+} // namespace internal
+} // namespace grpc_core
+
/* -- Well known credentials path. -- */
static grpc_well_known_credentials_path_getter creds_path_getter = nullptr;
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.h b/src/core/lib/security/credentials/google_default/google_default_credentials.h
index a7dd0ea8ae..b9e2efb04f 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.h
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.h
@@ -45,8 +45,6 @@ typedef struct {
grpc_channel_credentials* ssl_creds;
} grpc_google_default_channel_credentials;
-void grpc_flush_cached_google_default_credentials(void);
-
namespace grpc_core {
namespace internal {
@@ -54,6 +52,9 @@ typedef bool (*grpc_gce_tenancy_checker)(void);
void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker);
+// TEST-ONLY. Reset the internal global state.
+void grpc_flush_cached_google_default_credentials(void);
+
} // namespace internal
} // namespace grpc_core
diff --git a/src/core/lib/security/credentials/local/local_credentials.cc b/src/core/lib/security/credentials/local/local_credentials.cc
index 9a2f646ba5..3ccfa2b908 100644
--- a/src/core/lib/security/credentials/local/local_credentials.cc
+++ b/src/core/lib/security/credentials/local/local_credentials.cc
@@ -25,7 +25,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/security/security_connector/local_security_connector.h"
+#include "src/core/lib/security/security_connector/local/local_security_connector.h"
#define GRPC_CREDENTIALS_TYPE_LOCAL "Local"
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
index 73946ce039..4015124298 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
@@ -102,8 +102,7 @@ static grpc_error* process_plugin_result(
} else {
for (size_t i = 0; i < num_md; ++i) {
grpc_mdelem mdelem =
- grpc_mdelem_from_slices(grpc_slice_ref_internal(md[i].key),
- grpc_slice_ref_internal(md[i].value));
+ grpc_mdelem_create(md[i].key, md[i].value, nullptr);
grpc_credentials_mdelem_array_add(r->md_array, mdelem);
GRPC_MDELEM_UNREF(mdelem);
}
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h
index 712d34c733..0fba413876 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.h
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h
@@ -22,6 +22,8 @@
#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/security_connector/ssl/ssl_security_connector.h"
+
typedef struct {
grpc_channel_credentials base;
grpc_ssl_config config;
diff --git a/src/core/lib/security/security_connector/alts_security_connector.cc b/src/core/lib/security/security_connector/alts/alts_security_connector.cc
index 35a787871a..dd71c8bc60 100644
--- a/src/core/lib/security/security_connector/alts_security_connector.cc
+++ b/src/core/lib/security/security_connector/alts/alts_security_connector.cc
@@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/security/security_connector/alts_security_connector.h"
+#include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
#include <stdbool.h>
#include <string.h>
@@ -33,6 +33,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/transport_security.h"
typedef struct {
grpc_channel_security_connector base;
@@ -64,29 +65,29 @@ static void alts_server_destroy(grpc_security_connector* sc) {
}
static void alts_channel_add_handshakers(
- grpc_channel_security_connector* sc,
+ grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
grpc_alts_credentials* creds =
reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
- GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name,
- creds->handshaker_service_url, true,
- &handshaker) == TSI_OK);
+ GPR_ASSERT(alts_tsi_handshaker_create(
+ creds->options, c->target_name, creds->handshaker_service_url,
+ true, interested_parties, &handshaker) == TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
static void alts_server_add_handshakers(
- grpc_server_security_connector* sc,
+ grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
grpc_alts_server_credentials* creds =
reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
- GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr,
- creds->handshaker_service_url, false,
- &handshaker) == TSI_OK);
+ GPR_ASSERT(alts_tsi_handshaker_create(
+ creds->options, nullptr, creds->handshaker_service_url, false,
+ interested_parties, &handshaker) == TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
diff --git a/src/core/lib/security/security_connector/alts_security_connector.h b/src/core/lib/security/security_connector/alts/alts_security_connector.h
index e7e4cffe2a..d2e057a76a 100644
--- a/src/core/lib/security/security_connector/alts_security_connector.h
+++ b/src/core/lib/security/security_connector/alts/alts_security_connector.h
@@ -16,8 +16,8 @@
*
*/
-#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
-#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_ALTS_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_ALTS_SECURITY_CONNECTOR_H
#include <grpc/support/port_platform.h>
@@ -65,5 +65,5 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer(
} // namespace internal
} // namespace grpc_core
-#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H \
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_ALTS_SECURITY_CONNECTOR_H \
*/
diff --git a/src/core/lib/security/security_connector/fake/fake_security_connector.cc b/src/core/lib/security/security_connector/fake/fake_security_connector.cc
new file mode 100644
index 0000000000..5c0c89b88f
--- /dev/null
+++ b/src/core/lib/security/security_connector/fake/fake_security_connector.cc
@@ -0,0 +1,310 @@
+/*
+ *
+ * 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/lib/security/security_connector/fake/fake_security_connector.h"
+
+#include <stdbool.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/alpn/alpn.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
+#include "src/core/tsi/fake_transport_security.h"
+
+typedef struct {
+ grpc_channel_security_connector base;
+ char* target;
+ char* expected_targets;
+ bool is_lb_channel;
+ char* target_name_override;
+} grpc_fake_channel_security_connector;
+
+static void fake_channel_destroy(grpc_security_connector* sc) {
+ grpc_fake_channel_security_connector* c =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
+ grpc_call_credentials_unref(c->base.request_metadata_creds);
+ gpr_free(c->target);
+ gpr_free(c->expected_targets);
+ gpr_free(c->target_name_override);
+ gpr_free(c);
+}
+
+static void fake_server_destroy(grpc_security_connector* sc) { gpr_free(sc); }
+
+static bool fake_check_target(const char* target_type, const char* target,
+ const char* set_str) {
+ GPR_ASSERT(target_type != nullptr);
+ GPR_ASSERT(target != nullptr);
+ char** set = nullptr;
+ size_t set_size = 0;
+ gpr_string_split(set_str, ",", &set, &set_size);
+ bool found = false;
+ for (size_t i = 0; i < set_size; ++i) {
+ if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true;
+ }
+ for (size_t i = 0; i < set_size; ++i) {
+ gpr_free(set[i]);
+ }
+ gpr_free(set);
+ return found;
+}
+
+static void fake_secure_name_check(const char* target,
+ const char* expected_targets,
+ bool is_lb_channel) {
+ if (expected_targets == nullptr) return;
+ char** lbs_and_backends = nullptr;
+ size_t lbs_and_backends_size = 0;
+ bool success = false;
+ gpr_string_split(expected_targets, ";", &lbs_and_backends,
+ &lbs_and_backends_size);
+ if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) {
+ gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'",
+ expected_targets);
+ goto done;
+ }
+ if (is_lb_channel) {
+ if (lbs_and_backends_size != 2) {
+ gpr_log(GPR_ERROR,
+ "Invalid expected targets arg value: '%s'. Expectations for LB "
+ "channels must be of the form 'be1,be2,be3,...;lb1,lb2,...",
+ expected_targets);
+ goto done;
+ }
+ if (!fake_check_target("LB", target, lbs_and_backends[1])) {
+ gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'",
+ target, lbs_and_backends[1]);
+ goto done;
+ }
+ success = true;
+ } else {
+ if (!fake_check_target("Backend", target, lbs_and_backends[0])) {
+ gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'",
+ target, lbs_and_backends[0]);
+ goto done;
+ }
+ success = true;
+ }
+done:
+ for (size_t i = 0; i < lbs_and_backends_size; ++i) {
+ gpr_free(lbs_and_backends[i]);
+ }
+ gpr_free(lbs_and_backends);
+ if (!success) abort();
+}
+
+static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ const char* prop_name;
+ grpc_error* error = GRPC_ERROR_NONE;
+ *auth_context = nullptr;
+ if (peer.property_count != 1) {
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Fake peers should only have 1 property.");
+ goto end;
+ }
+ prop_name = peer.properties[0].name;
+ if (prop_name == nullptr ||
+ strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
+ char* msg;
+ gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
+ prop_name == nullptr ? "<EMPTY>" : prop_name);
+ error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+ gpr_free(msg);
+ goto end;
+ }
+ if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
+ peer.properties[0].value.length)) {
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Invalid value for cert type property.");
+ goto end;
+ }
+ *auth_context = grpc_auth_context_create(nullptr);
+ grpc_auth_context_add_cstring_property(
+ *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
+end:
+ GRPC_CLOSURE_SCHED(on_peer_checked, error);
+ tsi_peer_destruct(&peer);
+}
+
+static void fake_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ fake_check_peer(sc, peer, auth_context, on_peer_checked);
+ grpc_fake_channel_security_connector* c =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
+ fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel);
+}
+
+static void fake_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ fake_check_peer(sc, peer, auth_context, on_peer_checked);
+}
+
+static int fake_channel_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ grpc_fake_channel_security_connector* c1 =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc1);
+ grpc_fake_channel_security_connector* c2 =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc2);
+ int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
+ if (c != 0) return c;
+ c = strcmp(c1->target, c2->target);
+ if (c != 0) return c;
+ if (c1->expected_targets == nullptr || c2->expected_targets == nullptr) {
+ c = GPR_ICMP(c1->expected_targets, c2->expected_targets);
+ } else {
+ c = strcmp(c1->expected_targets, c2->expected_targets);
+ }
+ if (c != 0) return c;
+ return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel);
+}
+
+static int fake_server_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ return grpc_server_security_connector_cmp(
+ reinterpret_cast<grpc_server_security_connector*>(sc1),
+ reinterpret_cast<grpc_server_security_connector*>(sc2));
+}
+
+static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
+ const char* host,
+ grpc_auth_context* auth_context,
+ grpc_closure* on_call_host_checked,
+ grpc_error** error) {
+ grpc_fake_channel_security_connector* c =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
+ char* authority_hostname = nullptr;
+ char* authority_ignored_port = nullptr;
+ char* target_hostname = nullptr;
+ char* target_ignored_port = nullptr;
+ gpr_split_host_port(host, &authority_hostname, &authority_ignored_port);
+ gpr_split_host_port(c->target, &target_hostname, &target_ignored_port);
+ if (c->target_name_override != nullptr) {
+ char* fake_security_target_name_override_hostname = nullptr;
+ char* fake_security_target_name_override_ignored_port = nullptr;
+ gpr_split_host_port(c->target_name_override,
+ &fake_security_target_name_override_hostname,
+ &fake_security_target_name_override_ignored_port);
+ if (strcmp(authority_hostname,
+ fake_security_target_name_override_hostname) != 0) {
+ gpr_log(GPR_ERROR,
+ "Authority (host) '%s' != Fake Security Target override '%s'",
+ host, fake_security_target_name_override_hostname);
+ abort();
+ }
+ gpr_free(fake_security_target_name_override_hostname);
+ gpr_free(fake_security_target_name_override_ignored_port);
+ } else if (strcmp(authority_hostname, target_hostname) != 0) {
+ gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'",
+ authority_hostname, target_hostname);
+ abort();
+ }
+ gpr_free(authority_hostname);
+ gpr_free(authority_ignored_port);
+ gpr_free(target_hostname);
+ gpr_free(target_ignored_port);
+ return true;
+}
+
+static void fake_channel_cancel_check_call_host(
+ grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
+ grpc_error* error) {
+ GRPC_ERROR_UNREF(error);
+}
+
+static void fake_channel_add_handshakers(
+ grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
+ grpc_handshake_manager* handshake_mgr) {
+ grpc_handshake_manager_add(
+ handshake_mgr,
+ grpc_security_handshaker_create(
+ tsi_create_fake_handshaker(true /* is_client */), &sc->base));
+}
+
+static void fake_server_add_handshakers(grpc_server_security_connector* sc,
+ grpc_pollset_set* interested_parties,
+ grpc_handshake_manager* handshake_mgr) {
+ grpc_handshake_manager_add(
+ handshake_mgr,
+ grpc_security_handshaker_create(
+ tsi_create_fake_handshaker(false /* is_client */), &sc->base));
+}
+
+static grpc_security_connector_vtable fake_channel_vtable = {
+ fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp};
+
+static grpc_security_connector_vtable fake_server_vtable = {
+ fake_server_destroy, fake_server_check_peer, fake_server_cmp};
+
+grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds, const char* target,
+ const grpc_channel_args* args) {
+ grpc_fake_channel_security_connector* c =
+ static_cast<grpc_fake_channel_security_connector*>(
+ gpr_zalloc(sizeof(*c)));
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+ c->base.base.vtable = &fake_channel_vtable;
+ c->base.channel_creds = channel_creds;
+ c->base.request_metadata_creds =
+ grpc_call_credentials_ref(request_metadata_creds);
+ c->base.check_call_host = fake_channel_check_call_host;
+ c->base.cancel_check_call_host = fake_channel_cancel_check_call_host;
+ c->base.add_handshakers = fake_channel_add_handshakers;
+ c->target = gpr_strdup(target);
+ const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
+ c->expected_targets = gpr_strdup(expected_targets);
+ c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
+ const grpc_arg* target_name_override_arg =
+ grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
+ if (target_name_override_arg != nullptr) {
+ c->target_name_override =
+ gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg));
+ }
+ return &c->base;
+}
+
+grpc_server_security_connector* grpc_fake_server_security_connector_create(
+ grpc_server_credentials* server_creds) {
+ grpc_server_security_connector* c =
+ static_cast<grpc_server_security_connector*>(
+ gpr_zalloc(sizeof(grpc_server_security_connector)));
+ gpr_ref_init(&c->base.refcount, 1);
+ c->base.vtable = &fake_server_vtable;
+ c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+ c->server_creds = server_creds;
+ c->add_handshakers = fake_server_add_handshakers;
+ return c;
+}
diff --git a/src/core/lib/security/security_connector/fake/fake_security_connector.h b/src/core/lib/security/security_connector/fake/fake_security_connector.h
new file mode 100644
index 0000000000..fdfe048c6e
--- /dev/null
+++ b/src/core/lib/security/security_connector/fake/fake_security_connector.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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_LIB_SECURITY_SECURITY_CONNECTOR_FAKE_FAKE_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_FAKE_FAKE_SECURITY_CONNECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc_security.h>
+
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
+
+#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
+
+/* Creates a fake connector that emulates real channel security. */
+grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds, const char* target,
+ const grpc_channel_args* args);
+
+/* Creates a fake connector that emulates real server security. */
+grpc_server_security_connector* grpc_fake_server_security_connector_create(
+ grpc_server_credentials* server_creds);
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_FAKE_FAKE_SECURITY_CONNECTOR_H \
+ */
diff --git a/src/core/lib/security/security_connector/local_security_connector.cc b/src/core/lib/security/security_connector/local/local_security_connector.cc
index c436a7906b..008a98df28 100644
--- a/src/core/lib/security/security_connector/local_security_connector.cc
+++ b/src/core/lib/security/security_connector/local/local_security_connector.cc
@@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/security/security_connector/local_security_connector.h"
+#include "src/core/lib/security/security_connector/local/local_security_connector.h"
#include <stdbool.h>
#include <string.h>
@@ -30,6 +30,7 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/security/credentials/local/local_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/tsi/local_transport_security.h"
@@ -68,7 +69,7 @@ static void local_server_destroy(grpc_security_connector* sc) {
}
static void local_channel_add_handshakers(
- grpc_channel_security_connector* sc,
+ grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
@@ -78,7 +79,7 @@ static void local_channel_add_handshakers(
}
static void local_server_add_handshakers(
- grpc_server_security_connector* sc,
+ grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, &handshaker) ==
diff --git a/src/core/lib/security/security_connector/local_security_connector.h b/src/core/lib/security/security_connector/local/local_security_connector.h
index a970a74788..5369a2127a 100644
--- a/src/core/lib/security/security_connector/local_security_connector.h
+++ b/src/core/lib/security/security_connector/local/local_security_connector.h
@@ -16,8 +16,8 @@
*
*/
-#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_SECURITY_CONNECTOR_H
-#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_SECURITY_CONNECTOR_H
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_LOCAL_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_LOCAL_SECURITY_CONNECTOR_H
#include <grpc/support/port_platform.h>
@@ -54,5 +54,5 @@ grpc_security_status grpc_local_channel_security_connector_create(
grpc_security_status grpc_local_server_security_connector_create(
grpc_server_credentials* server_creds, grpc_server_security_connector** sc);
-#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_SECURITY_CONNECTOR_H \
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_LOCAL_SECURITY_CONNECTOR_H \
*/
diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc
index 04b4c87c71..02cecb0eb1 100644
--- a/src/core/lib/security/security_connector/security_connector.cc
+++ b/src/core/lib/security/security_connector/security_connector.cc
@@ -20,8 +20,6 @@
#include "src/core/lib/security/security_connector/security_connector.h"
-#include <stdbool.h>
-
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@@ -36,101 +34,27 @@
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/credentials/fake/fake_credentials.h"
-#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
-#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
-#include "src/core/lib/security/transport/target_authority_table.h"
-#include "src/core/tsi/fake_transport_security.h"
-#include "src/core/tsi/ssl_transport_security.h"
grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount(
false, "security_connector_refcount");
-/* -- Constants. -- */
-
-#ifndef INSTALL_PREFIX
-static const char* installed_roots_path = "/usr/share/grpc/roots.pem";
-#else
-static const char* installed_roots_path =
- INSTALL_PREFIX "/share/grpc/roots.pem";
-#endif
-
-/** Environment variable used as a flag to enable/disable loading system root
- certificates from the OS trust store. */
-#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR
-#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS"
-#endif
-
-#ifndef TSI_OPENSSL_ALPN_SUPPORT
-#define TSI_OPENSSL_ALPN_SUPPORT 1
-#endif
-
-/* -- Overridden default roots. -- */
-
-static grpc_ssl_roots_override_callback ssl_roots_override_cb = nullptr;
-
-void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
- ssl_roots_override_cb = cb;
-}
-
-/* -- Cipher suites. -- */
-
-/* Defines the cipher suites that we accept by default. All these cipher suites
- are compliant with HTTP2. */
-#define GRPC_SSL_CIPHER_SUITES \
- "ECDHE-ECDSA-AES128-GCM-SHA256:" \
- "ECDHE-ECDSA-AES256-GCM-SHA384:" \
- "ECDHE-RSA-AES128-GCM-SHA256:" \
- "ECDHE-RSA-AES256-GCM-SHA384"
-
-static gpr_once cipher_suites_once = GPR_ONCE_INIT;
-static const char* cipher_suites = nullptr;
-
-static void init_cipher_suites(void) {
- char* overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES");
- cipher_suites = overridden != nullptr ? overridden : GRPC_SSL_CIPHER_SUITES;
-}
-
-static const char* ssl_cipher_suites(void) {
- gpr_once_init(&cipher_suites_once, init_cipher_suites);
- return cipher_suites;
-}
-
-/* -- Common methods. -- */
-
-/* Returns the first property with that name. */
-const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
- const char* name) {
- size_t i;
- if (peer == nullptr) return nullptr;
- for (i = 0; i < peer->property_count; i++) {
- const tsi_peer_property* property = &peer->properties[i];
- if (name == nullptr && property->name == nullptr) {
- return property;
- }
- if (name != nullptr && property->name != nullptr &&
- strcmp(property->name, name) == 0) {
- return property;
- }
- }
- return nullptr;
-}
-
void grpc_channel_security_connector_add_handshakers(
grpc_channel_security_connector* connector,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
if (connector != nullptr) {
- connector->add_handshakers(connector, handshake_mgr);
+ connector->add_handshakers(connector, interested_parties, handshake_mgr);
}
}
void grpc_server_security_connector_add_handshakers(
grpc_server_security_connector* connector,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
if (connector != nullptr) {
- connector->add_handshakers(connector, handshake_mgr);
+ connector->add_handshakers(connector, interested_parties, handshake_mgr);
}
}
@@ -286,962 +210,3 @@ grpc_security_connector* grpc_security_connector_find_in_args(
}
return nullptr;
}
-
-static tsi_client_certificate_request_type
-get_tsi_client_certificate_request_type(
- grpc_ssl_client_certificate_request_type grpc_request_type) {
- switch (grpc_request_type) {
- case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE:
- return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
-
- case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
- return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
-
- case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
- return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY;
-
- case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
- return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
-
- case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
- return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
-
- default:
- return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
- }
-}
-
-/* -- Fake implementation. -- */
-
-typedef struct {
- grpc_channel_security_connector base;
- char* target;
- char* expected_targets;
- bool is_lb_channel;
- char* target_name_override;
-} grpc_fake_channel_security_connector;
-
-static void fake_channel_destroy(grpc_security_connector* sc) {
- grpc_fake_channel_security_connector* c =
- reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
- grpc_call_credentials_unref(c->base.request_metadata_creds);
- gpr_free(c->target);
- gpr_free(c->expected_targets);
- gpr_free(c->target_name_override);
- gpr_free(c);
-}
-
-static void fake_server_destroy(grpc_security_connector* sc) { gpr_free(sc); }
-
-static bool fake_check_target(const char* target_type, const char* target,
- const char* set_str) {
- GPR_ASSERT(target_type != nullptr);
- GPR_ASSERT(target != nullptr);
- char** set = nullptr;
- size_t set_size = 0;
- gpr_string_split(set_str, ",", &set, &set_size);
- bool found = false;
- for (size_t i = 0; i < set_size; ++i) {
- if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true;
- }
- for (size_t i = 0; i < set_size; ++i) {
- gpr_free(set[i]);
- }
- gpr_free(set);
- return found;
-}
-
-static void fake_secure_name_check(const char* target,
- const char* expected_targets,
- bool is_lb_channel) {
- if (expected_targets == nullptr) return;
- char** lbs_and_backends = nullptr;
- size_t lbs_and_backends_size = 0;
- bool success = false;
- gpr_string_split(expected_targets, ";", &lbs_and_backends,
- &lbs_and_backends_size);
- if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) {
- gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'",
- expected_targets);
- goto done;
- }
- if (is_lb_channel) {
- if (lbs_and_backends_size != 2) {
- gpr_log(GPR_ERROR,
- "Invalid expected targets arg value: '%s'. Expectations for LB "
- "channels must be of the form 'be1,be2,be3,...;lb1,lb2,...",
- expected_targets);
- goto done;
- }
- if (!fake_check_target("LB", target, lbs_and_backends[1])) {
- gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'",
- target, lbs_and_backends[1]);
- goto done;
- }
- success = true;
- } else {
- if (!fake_check_target("Backend", target, lbs_and_backends[0])) {
- gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'",
- target, lbs_and_backends[0]);
- goto done;
- }
- success = true;
- }
-done:
- for (size_t i = 0; i < lbs_and_backends_size; ++i) {
- gpr_free(lbs_and_backends[i]);
- }
- gpr_free(lbs_and_backends);
- if (!success) abort();
-}
-
-static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer,
- grpc_auth_context** auth_context,
- grpc_closure* on_peer_checked) {
- const char* prop_name;
- grpc_error* error = GRPC_ERROR_NONE;
- *auth_context = nullptr;
- if (peer.property_count != 1) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Fake peers should only have 1 property.");
- goto end;
- }
- prop_name = peer.properties[0].name;
- if (prop_name == nullptr ||
- strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
- char* msg;
- gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
- prop_name == nullptr ? "<EMPTY>" : prop_name);
- error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
- gpr_free(msg);
- goto end;
- }
- if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
- peer.properties[0].value.length)) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Invalid value for cert type property.");
- goto end;
- }
- *auth_context = grpc_auth_context_create(nullptr);
- grpc_auth_context_add_cstring_property(
- *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
- GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
-end:
- GRPC_CLOSURE_SCHED(on_peer_checked, error);
- tsi_peer_destruct(&peer);
-}
-
-static void fake_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
- grpc_auth_context** auth_context,
- grpc_closure* on_peer_checked) {
- fake_check_peer(sc, peer, auth_context, on_peer_checked);
- grpc_fake_channel_security_connector* c =
- reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
- fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel);
-}
-
-static void fake_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
- grpc_auth_context** auth_context,
- grpc_closure* on_peer_checked) {
- fake_check_peer(sc, peer, auth_context, on_peer_checked);
-}
-
-static int fake_channel_cmp(grpc_security_connector* sc1,
- grpc_security_connector* sc2) {
- grpc_fake_channel_security_connector* c1 =
- reinterpret_cast<grpc_fake_channel_security_connector*>(sc1);
- grpc_fake_channel_security_connector* c2 =
- reinterpret_cast<grpc_fake_channel_security_connector*>(sc2);
- int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
- if (c != 0) return c;
- c = strcmp(c1->target, c2->target);
- if (c != 0) return c;
- if (c1->expected_targets == nullptr || c2->expected_targets == nullptr) {
- c = GPR_ICMP(c1->expected_targets, c2->expected_targets);
- } else {
- c = strcmp(c1->expected_targets, c2->expected_targets);
- }
- if (c != 0) return c;
- return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel);
-}
-
-static int fake_server_cmp(grpc_security_connector* sc1,
- grpc_security_connector* sc2) {
- return grpc_server_security_connector_cmp(
- reinterpret_cast<grpc_server_security_connector*>(sc1),
- reinterpret_cast<grpc_server_security_connector*>(sc2));
-}
-
-static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
- const char* host,
- grpc_auth_context* auth_context,
- grpc_closure* on_call_host_checked,
- grpc_error** error) {
- grpc_fake_channel_security_connector* c =
- reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
- char* authority_hostname = nullptr;
- char* authority_ignored_port = nullptr;
- char* target_hostname = nullptr;
- char* target_ignored_port = nullptr;
- gpr_split_host_port(host, &authority_hostname, &authority_ignored_port);
- gpr_split_host_port(c->target, &target_hostname, &target_ignored_port);
- if (c->target_name_override != nullptr) {
- char* fake_security_target_name_override_hostname = nullptr;
- char* fake_security_target_name_override_ignored_port = nullptr;
- gpr_split_host_port(c->target_name_override,
- &fake_security_target_name_override_hostname,
- &fake_security_target_name_override_ignored_port);
- if (strcmp(authority_hostname,
- fake_security_target_name_override_hostname) != 0) {
- gpr_log(GPR_ERROR,
- "Authority (host) '%s' != Fake Security Target override '%s'",
- host, fake_security_target_name_override_hostname);
- abort();
- }
- gpr_free(fake_security_target_name_override_hostname);
- gpr_free(fake_security_target_name_override_ignored_port);
- } else if (strcmp(authority_hostname, target_hostname) != 0) {
- gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'",
- authority_hostname, target_hostname);
- abort();
- }
- gpr_free(authority_hostname);
- gpr_free(authority_ignored_port);
- gpr_free(target_hostname);
- gpr_free(target_ignored_port);
- return true;
-}
-
-static void fake_channel_cancel_check_call_host(
- grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
- grpc_error* error) {
- GRPC_ERROR_UNREF(error);
-}
-
-static void fake_channel_add_handshakers(
- grpc_channel_security_connector* sc,
- grpc_handshake_manager* handshake_mgr) {
- grpc_handshake_manager_add(
- handshake_mgr,
- grpc_security_handshaker_create(
- tsi_create_fake_handshaker(true /* is_client */), &sc->base));
-}
-
-static void fake_server_add_handshakers(grpc_server_security_connector* sc,
- grpc_handshake_manager* handshake_mgr) {
- grpc_handshake_manager_add(
- handshake_mgr,
- grpc_security_handshaker_create(
- tsi_create_fake_handshaker(false /* is_client */), &sc->base));
-}
-
-static grpc_security_connector_vtable fake_channel_vtable = {
- fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp};
-
-static grpc_security_connector_vtable fake_server_vtable = {
- fake_server_destroy, fake_server_check_peer, fake_server_cmp};
-
-grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
- grpc_channel_credentials* channel_creds,
- grpc_call_credentials* request_metadata_creds, const char* target,
- const grpc_channel_args* args) {
- grpc_fake_channel_security_connector* c =
- static_cast<grpc_fake_channel_security_connector*>(
- gpr_zalloc(sizeof(*c)));
- gpr_ref_init(&c->base.base.refcount, 1);
- c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
- c->base.base.vtable = &fake_channel_vtable;
- c->base.channel_creds = channel_creds;
- c->base.request_metadata_creds =
- grpc_call_credentials_ref(request_metadata_creds);
- c->base.check_call_host = fake_channel_check_call_host;
- c->base.cancel_check_call_host = fake_channel_cancel_check_call_host;
- c->base.add_handshakers = fake_channel_add_handshakers;
- c->target = gpr_strdup(target);
- const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
- c->expected_targets = gpr_strdup(expected_targets);
- c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
- const grpc_arg* target_name_override_arg =
- grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
- if (target_name_override_arg != nullptr) {
- c->target_name_override =
- gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg));
- }
- return &c->base;
-}
-
-grpc_server_security_connector* grpc_fake_server_security_connector_create(
- grpc_server_credentials* server_creds) {
- grpc_server_security_connector* c =
- static_cast<grpc_server_security_connector*>(
- gpr_zalloc(sizeof(grpc_server_security_connector)));
- gpr_ref_init(&c->base.refcount, 1);
- c->base.vtable = &fake_server_vtable;
- c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
- c->server_creds = server_creds;
- c->add_handshakers = fake_server_add_handshakers;
- return c;
-}
-
-/* --- Ssl implementation. --- */
-
-grpc_ssl_session_cache* grpc_ssl_session_cache_create_lru(size_t capacity) {
- tsi_ssl_session_cache* cache = tsi_ssl_session_cache_create_lru(capacity);
- return reinterpret_cast<grpc_ssl_session_cache*>(cache);
-}
-
-void grpc_ssl_session_cache_destroy(grpc_ssl_session_cache* cache) {
- tsi_ssl_session_cache* tsi_cache =
- reinterpret_cast<tsi_ssl_session_cache*>(cache);
- tsi_ssl_session_cache_unref(tsi_cache);
-}
-
-static void* grpc_ssl_session_cache_arg_copy(void* p) {
- tsi_ssl_session_cache* tsi_cache =
- reinterpret_cast<tsi_ssl_session_cache*>(p);
- // destroy call below will unref the pointer.
- tsi_ssl_session_cache_ref(tsi_cache);
- return p;
-}
-
-static void grpc_ssl_session_cache_arg_destroy(void* p) {
- tsi_ssl_session_cache* tsi_cache =
- reinterpret_cast<tsi_ssl_session_cache*>(p);
- tsi_ssl_session_cache_unref(tsi_cache);
-}
-
-static int grpc_ssl_session_cache_arg_cmp(void* p, void* q) {
- return GPR_ICMP(p, q);
-}
-
-grpc_arg grpc_ssl_session_cache_create_channel_arg(
- grpc_ssl_session_cache* cache) {
- static const grpc_arg_pointer_vtable vtable = {
- grpc_ssl_session_cache_arg_copy,
- grpc_ssl_session_cache_arg_destroy,
- grpc_ssl_session_cache_arg_cmp,
- };
- return grpc_channel_arg_pointer_create(
- const_cast<char*>(GRPC_SSL_SESSION_CACHE_ARG), cache, &vtable);
-}
-
-typedef struct {
- grpc_channel_security_connector base;
- tsi_ssl_client_handshaker_factory* client_handshaker_factory;
- char* target_name;
- char* overridden_target_name;
- const verify_peer_options* verify_options;
-} grpc_ssl_channel_security_connector;
-
-typedef struct {
- grpc_server_security_connector base;
- tsi_ssl_server_handshaker_factory* server_handshaker_factory;
-} grpc_ssl_server_security_connector;
-
-static bool server_connector_has_cert_config_fetcher(
- grpc_ssl_server_security_connector* c) {
- GPR_ASSERT(c != nullptr);
- grpc_ssl_server_credentials* server_creds =
- reinterpret_cast<grpc_ssl_server_credentials*>(c->base.server_creds);
- GPR_ASSERT(server_creds != nullptr);
- return server_creds->certificate_config_fetcher.cb != nullptr;
-}
-
-static void ssl_channel_destroy(grpc_security_connector* sc) {
- grpc_ssl_channel_security_connector* c =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
- grpc_channel_credentials_unref(c->base.channel_creds);
- grpc_call_credentials_unref(c->base.request_metadata_creds);
- tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
- c->client_handshaker_factory = nullptr;
- if (c->target_name != nullptr) gpr_free(c->target_name);
- if (c->overridden_target_name != nullptr) gpr_free(c->overridden_target_name);
- gpr_free(sc);
-}
-
-static void ssl_server_destroy(grpc_security_connector* sc) {
- grpc_ssl_server_security_connector* c =
- reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
- grpc_server_credentials_unref(c->base.server_creds);
- tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
- c->server_handshaker_factory = nullptr;
- gpr_free(sc);
-}
-
-static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc,
- grpc_handshake_manager* handshake_mgr) {
- grpc_ssl_channel_security_connector* c =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
- // Instantiate TSI handshaker.
- tsi_handshaker* tsi_hs = nullptr;
- tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
- c->client_handshaker_factory,
- c->overridden_target_name != nullptr ? c->overridden_target_name
- : c->target_name,
- &tsi_hs);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
- tsi_result_to_string(result));
- return;
- }
- // Create handshakers.
- grpc_handshake_manager_add(
- handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
-}
-
-static const char** fill_alpn_protocol_strings(size_t* num_alpn_protocols) {
- GPR_ASSERT(num_alpn_protocols != nullptr);
- *num_alpn_protocols = grpc_chttp2_num_alpn_versions();
- const char** alpn_protocol_strings = static_cast<const char**>(
- gpr_malloc(sizeof(const char*) * (*num_alpn_protocols)));
- for (size_t i = 0; i < *num_alpn_protocols; i++) {
- alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i);
- }
- return alpn_protocol_strings;
-}
-
-/* Attempts to replace the server_handshaker_factory with a new factory using
- * the provided grpc_ssl_server_certificate_config. Should new factory creation
- * fail, the existing factory will not be replaced. Returns true on success (new
- * factory created). */
-static bool try_replace_server_handshaker_factory(
- grpc_ssl_server_security_connector* sc,
- const grpc_ssl_server_certificate_config* config) {
- if (config == nullptr) {
- gpr_log(GPR_ERROR,
- "Server certificate config callback returned invalid (NULL) "
- "config.");
- return false;
- }
- gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config);
-
- size_t num_alpn_protocols = 0;
- const char** alpn_protocol_strings =
- fill_alpn_protocol_strings(&num_alpn_protocols);
- tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
- config->pem_key_cert_pairs, config->num_key_cert_pairs);
- tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
- grpc_ssl_server_credentials* server_creds =
- reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
- tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
- cert_pairs, config->num_key_cert_pairs, config->pem_root_certs,
- get_tsi_client_certificate_request_type(
- server_creds->config.client_certificate_request),
- ssl_cipher_suites(), alpn_protocol_strings,
- static_cast<uint16_t>(num_alpn_protocols), &new_handshaker_factory);
- gpr_free(cert_pairs);
- gpr_free((void*)alpn_protocol_strings);
-
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
- tsi_result_to_string(result));
- return false;
- }
- tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory);
- sc->server_handshaker_factory = new_handshaker_factory;
- return true;
-}
-
-/* Attempts to fetch the server certificate config if a callback is available.
- * Current certificate config will continue to be used if the callback returns
- * an error. Returns true if new credentials were sucessfully loaded. */
-static bool try_fetch_ssl_server_credentials(
- grpc_ssl_server_security_connector* sc) {
- grpc_ssl_server_certificate_config* certificate_config = nullptr;
- bool status;
-
- GPR_ASSERT(sc != nullptr);
- if (!server_connector_has_cert_config_fetcher(sc)) return false;
-
- grpc_ssl_server_credentials* server_creds =
- reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
- grpc_ssl_certificate_config_reload_status cb_result =
- server_creds->certificate_config_fetcher.cb(
- server_creds->certificate_config_fetcher.user_data,
- &certificate_config);
- if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) {
- gpr_log(GPR_DEBUG, "No change in SSL server credentials.");
- status = false;
- } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) {
- status = try_replace_server_handshaker_factory(sc, certificate_config);
- } else {
- // Log error, continue using previously-loaded credentials.
- gpr_log(GPR_ERROR,
- "Failed fetching new server credentials, continuing to "
- "use previously-loaded credentials.");
- status = false;
- }
-
- if (certificate_config != nullptr) {
- grpc_ssl_server_certificate_config_destroy(certificate_config);
- }
- return status;
-}
-
-static void ssl_server_add_handshakers(grpc_server_security_connector* sc,
- grpc_handshake_manager* handshake_mgr) {
- grpc_ssl_server_security_connector* c =
- reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
- // Instantiate TSI handshaker.
- try_fetch_ssl_server_credentials(c);
- tsi_handshaker* tsi_hs = nullptr;
- tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
- c->server_handshaker_factory, &tsi_hs);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
- tsi_result_to_string(result));
- return;
- }
- // Create handshakers.
- grpc_handshake_manager_add(
- handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
-}
-
-int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name) {
- char* allocated_name = nullptr;
- int r;
-
- char* ignored_port;
- gpr_split_host_port(peer_name, &allocated_name, &ignored_port);
- gpr_free(ignored_port);
- peer_name = allocated_name;
- if (!peer_name) return 0;
-
- // IPv6 zone-id should not be included in comparisons.
- char* const zone_id = strchr(allocated_name, '%');
- if (zone_id != nullptr) *zone_id = '\0';
-
- r = tsi_ssl_peer_matches_name(peer, peer_name);
- gpr_free(allocated_name);
- return r;
-}
-
-grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) {
- size_t i;
- grpc_auth_context* ctx = nullptr;
- const char* peer_identity_property_name = nullptr;
-
- /* The caller has checked the certificate type property. */
- GPR_ASSERT(peer->property_count >= 1);
- ctx = grpc_auth_context_create(nullptr);
- grpc_auth_context_add_cstring_property(
- ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
- GRPC_SSL_TRANSPORT_SECURITY_TYPE);
- for (i = 0; i < peer->property_count; i++) {
- const tsi_peer_property* prop = &peer->properties[i];
- if (prop->name == nullptr) continue;
- if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
- /* If there is no subject alt name, have the CN as the identity. */
- if (peer_identity_property_name == nullptr) {
- peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
- }
- grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
- prop->value.data, prop->value.length);
- } else if (strcmp(prop->name,
- TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
- peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
- grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
- prop->value.data, prop->value.length);
- } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
- grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
- prop->value.data, prop->value.length);
- } else if (strcmp(prop->name, TSI_SSL_SESSION_REUSED_PEER_PROPERTY) == 0) {
- grpc_auth_context_add_property(ctx, GRPC_SSL_SESSION_REUSED_PROPERTY,
- prop->value.data, prop->value.length);
- }
- }
- if (peer_identity_property_name != nullptr) {
- GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
- ctx, peer_identity_property_name) == 1);
- }
- return ctx;
-}
-
-static grpc_error* ssl_check_peer(grpc_security_connector* sc,
- const char* peer_name, const tsi_peer* peer,
- grpc_auth_context** auth_context) {
-#if TSI_OPENSSL_ALPN_SUPPORT
- /* Check the ALPN if ALPN is supported. */
- const tsi_peer_property* p =
- tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
- if (p == nullptr) {
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Cannot check peer: missing selected ALPN property.");
- }
- if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Cannot check peer: invalid ALPN value.");
- }
-#endif /* TSI_OPENSSL_ALPN_SUPPORT */
- /* Check the peer name if specified. */
- if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
- char* msg;
- gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name);
- grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
- gpr_free(msg);
- return error;
- }
- *auth_context = grpc_ssl_peer_to_auth_context(peer);
- return GRPC_ERROR_NONE;
-}
-
-static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
- grpc_auth_context** auth_context,
- grpc_closure* on_peer_checked) {
- grpc_ssl_channel_security_connector* c =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
- const char* target_name = c->overridden_target_name != nullptr
- ? c->overridden_target_name
- : c->target_name;
- grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context);
- if (error == GRPC_ERROR_NONE &&
- c->verify_options->verify_peer_callback != nullptr) {
- const tsi_peer_property* p =
- tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
- if (p == nullptr) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Cannot check peer: missing pem cert property.");
- } else {
- char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
- memcpy(peer_pem, p->value.data, p->value.length);
- peer_pem[p->value.length] = '\0';
- int callback_status = c->verify_options->verify_peer_callback(
- target_name, peer_pem,
- c->verify_options->verify_peer_callback_userdata);
- gpr_free(peer_pem);
- if (callback_status) {
- char* msg;
- gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
- callback_status);
- error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
- gpr_free(msg);
- }
- }
- }
- GRPC_CLOSURE_SCHED(on_peer_checked, error);
- tsi_peer_destruct(&peer);
-}
-
-static void ssl_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
- grpc_auth_context** auth_context,
- grpc_closure* on_peer_checked) {
- grpc_error* error = ssl_check_peer(sc, nullptr, &peer, auth_context);
- tsi_peer_destruct(&peer);
- GRPC_CLOSURE_SCHED(on_peer_checked, error);
-}
-
-static int ssl_channel_cmp(grpc_security_connector* sc1,
- grpc_security_connector* sc2) {
- grpc_ssl_channel_security_connector* c1 =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc1);
- grpc_ssl_channel_security_connector* c2 =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc2);
- int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
- if (c != 0) return c;
- c = strcmp(c1->target_name, c2->target_name);
- if (c != 0) return c;
- return (c1->overridden_target_name == nullptr ||
- c2->overridden_target_name == nullptr)
- ? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name)
- : strcmp(c1->overridden_target_name, c2->overridden_target_name);
-}
-
-static int ssl_server_cmp(grpc_security_connector* sc1,
- grpc_security_connector* sc2) {
- return grpc_server_security_connector_cmp(
- reinterpret_cast<grpc_server_security_connector*>(sc1),
- reinterpret_cast<grpc_server_security_connector*>(sc2));
-}
-
-static void add_shallow_auth_property_to_peer(tsi_peer* peer,
- const grpc_auth_property* prop,
- const char* tsi_prop_name) {
- tsi_peer_property* tsi_prop = &peer->properties[peer->property_count++];
- tsi_prop->name = const_cast<char*>(tsi_prop_name);
- tsi_prop->value.data = prop->value;
- tsi_prop->value.length = prop->value_length;
-}
-
-tsi_peer grpc_shallow_peer_from_ssl_auth_context(
- const grpc_auth_context* auth_context) {
- size_t max_num_props = 0;
- grpc_auth_property_iterator it;
- const grpc_auth_property* prop;
- tsi_peer peer;
- memset(&peer, 0, sizeof(peer));
-
- it = grpc_auth_context_property_iterator(auth_context);
- while (grpc_auth_property_iterator_next(&it) != nullptr) max_num_props++;
-
- if (max_num_props > 0) {
- peer.properties = static_cast<tsi_peer_property*>(
- gpr_malloc(max_num_props * sizeof(tsi_peer_property)));
- it = grpc_auth_context_property_iterator(auth_context);
- while ((prop = grpc_auth_property_iterator_next(&it)) != nullptr) {
- if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
- add_shallow_auth_property_to_peer(
- &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
- } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
- add_shallow_auth_property_to_peer(
- &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
- } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
- add_shallow_auth_property_to_peer(&peer, prop,
- TSI_X509_PEM_CERT_PROPERTY);
- }
- }
- }
- return peer;
-}
-
-void grpc_shallow_peer_destruct(tsi_peer* peer) {
- if (peer->properties != nullptr) gpr_free(peer->properties);
-}
-
-static bool ssl_channel_check_call_host(grpc_channel_security_connector* sc,
- const char* host,
- grpc_auth_context* auth_context,
- grpc_closure* on_call_host_checked,
- grpc_error** error) {
- grpc_ssl_channel_security_connector* c =
- reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
- grpc_security_status status = GRPC_SECURITY_ERROR;
- tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
- if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
- /* If the target name was overridden, then the original target_name was
- 'checked' transitively during the previous peer check at the end of the
- handshake. */
- if (c->overridden_target_name != nullptr &&
- strcmp(host, c->target_name) == 0) {
- status = GRPC_SECURITY_OK;
- }
- if (status != GRPC_SECURITY_OK) {
- *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "call host does not match SSL server name");
- }
- grpc_shallow_peer_destruct(&peer);
- return true;
-}
-
-static void ssl_channel_cancel_check_call_host(
- grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
- grpc_error* error) {
- GRPC_ERROR_UNREF(error);
-}
-
-static grpc_security_connector_vtable ssl_channel_vtable = {
- ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp};
-
-static grpc_security_connector_vtable ssl_server_vtable = {
- ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
-
-grpc_security_status grpc_ssl_channel_security_connector_create(
- grpc_channel_credentials* channel_creds,
- grpc_call_credentials* request_metadata_creds,
- const grpc_ssl_config* config, const char* target_name,
- const char* overridden_target_name,
- tsi_ssl_session_cache* ssl_session_cache,
- grpc_channel_security_connector** sc) {
- tsi_result result = TSI_OK;
- grpc_ssl_channel_security_connector* c;
- char* port;
- bool has_key_cert_pair;
- tsi_ssl_client_handshaker_options options;
- memset(&options, 0, sizeof(options));
- options.alpn_protocols =
- fill_alpn_protocol_strings(&options.num_alpn_protocols);
-
- if (config == nullptr || target_name == nullptr) {
- gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
- goto error;
- }
- if (config->pem_root_certs == nullptr) {
- // Use default root certificates.
- options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
- options.root_store = grpc_core::DefaultSslRootStore::GetRootStore();
- if (options.pem_root_certs == nullptr) {
- gpr_log(GPR_ERROR, "Could not get default pem root certs.");
- goto error;
- }
- } else {
- options.pem_root_certs = config->pem_root_certs;
- }
- c = static_cast<grpc_ssl_channel_security_connector*>(
- gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)));
-
- gpr_ref_init(&c->base.base.refcount, 1);
- c->base.base.vtable = &ssl_channel_vtable;
- c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
- c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
- c->base.request_metadata_creds =
- grpc_call_credentials_ref(request_metadata_creds);
- c->base.check_call_host = ssl_channel_check_call_host;
- c->base.cancel_check_call_host = ssl_channel_cancel_check_call_host;
- c->base.add_handshakers = ssl_channel_add_handshakers;
- gpr_split_host_port(target_name, &c->target_name, &port);
- gpr_free(port);
- if (overridden_target_name != nullptr) {
- c->overridden_target_name = gpr_strdup(overridden_target_name);
- }
- c->verify_options = &config->verify_options;
-
- has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
- config->pem_key_cert_pair->private_key != nullptr &&
- config->pem_key_cert_pair->cert_chain != nullptr;
- if (has_key_cert_pair) {
- options.pem_key_cert_pair = config->pem_key_cert_pair;
- }
- options.cipher_suites = ssl_cipher_suites();
- options.session_cache = ssl_session_cache;
- result = tsi_create_ssl_client_handshaker_factory_with_options(
- &options, &c->client_handshaker_factory);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
- tsi_result_to_string(result));
- ssl_channel_destroy(&c->base.base);
- *sc = nullptr;
- goto error;
- }
- *sc = &c->base;
- gpr_free((void*)options.alpn_protocols);
- return GRPC_SECURITY_OK;
-
-error:
- gpr_free((void*)options.alpn_protocols);
- return GRPC_SECURITY_ERROR;
-}
-
-static grpc_ssl_server_security_connector*
-grpc_ssl_server_security_connector_initialize(
- grpc_server_credentials* server_creds) {
- grpc_ssl_server_security_connector* c =
- static_cast<grpc_ssl_server_security_connector*>(
- gpr_zalloc(sizeof(grpc_ssl_server_security_connector)));
- gpr_ref_init(&c->base.base.refcount, 1);
- c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
- c->base.base.vtable = &ssl_server_vtable;
- c->base.add_handshakers = ssl_server_add_handshakers;
- c->base.server_creds = grpc_server_credentials_ref(server_creds);
- return c;
-}
-
-grpc_security_status grpc_ssl_server_security_connector_create(
- grpc_server_credentials* gsc, grpc_server_security_connector** sc) {
- tsi_result result = TSI_OK;
- grpc_ssl_server_credentials* server_credentials =
- reinterpret_cast<grpc_ssl_server_credentials*>(gsc);
- grpc_security_status retval = GRPC_SECURITY_OK;
-
- GPR_ASSERT(server_credentials != nullptr);
- GPR_ASSERT(sc != nullptr);
-
- grpc_ssl_server_security_connector* c =
- grpc_ssl_server_security_connector_initialize(gsc);
- if (server_connector_has_cert_config_fetcher(c)) {
- // Load initial credentials from certificate_config_fetcher:
- if (!try_fetch_ssl_server_credentials(c)) {
- gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher.");
- retval = GRPC_SECURITY_ERROR;
- }
- } else {
- size_t num_alpn_protocols = 0;
- const char** alpn_protocol_strings =
- fill_alpn_protocol_strings(&num_alpn_protocols);
- result = tsi_create_ssl_server_handshaker_factory_ex(
- server_credentials->config.pem_key_cert_pairs,
- server_credentials->config.num_key_cert_pairs,
- server_credentials->config.pem_root_certs,
- get_tsi_client_certificate_request_type(
- server_credentials->config.client_certificate_request),
- ssl_cipher_suites(), alpn_protocol_strings,
- static_cast<uint16_t>(num_alpn_protocols),
- &c->server_handshaker_factory);
- gpr_free((void*)alpn_protocol_strings);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
- tsi_result_to_string(result));
- retval = GRPC_SECURITY_ERROR;
- }
- }
-
- if (retval == GRPC_SECURITY_OK) {
- *sc = &c->base;
- } else {
- if (c != nullptr) ssl_server_destroy(&c->base.base);
- if (sc != nullptr) *sc = nullptr;
- }
- return retval;
-}
-
-namespace grpc_core {
-
-tsi_ssl_root_certs_store* DefaultSslRootStore::default_root_store_;
-grpc_slice DefaultSslRootStore::default_pem_root_certs_;
-
-const tsi_ssl_root_certs_store* DefaultSslRootStore::GetRootStore() {
- InitRootStore();
- return default_root_store_;
-}
-
-const char* DefaultSslRootStore::GetPemRootCerts() {
- InitRootStore();
- return GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)
- ? nullptr
- : reinterpret_cast<const char*>
- GRPC_SLICE_START_PTR(default_pem_root_certs_);
-}
-
-grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
- grpc_slice result = grpc_empty_slice();
- char* use_system_roots_env_value =
- gpr_getenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
- const bool use_system_roots = gpr_is_true(use_system_roots_env_value);
- gpr_free(use_system_roots_env_value);
- // First try to load the roots from the environment.
- char* default_root_certs_path =
- gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
- if (default_root_certs_path != nullptr) {
- GRPC_LOG_IF_ERROR("load_file",
- grpc_load_file(default_root_certs_path, 1, &result));
- gpr_free(default_root_certs_path);
- }
- // Try overridden roots if needed.
- grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
- if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
- char* pem_root_certs = nullptr;
- ovrd_res = ssl_roots_override_cb(&pem_root_certs);
- if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
- GPR_ASSERT(pem_root_certs != nullptr);
- result = grpc_slice_from_copied_buffer(
- pem_root_certs,
- strlen(pem_root_certs) + 1); // nullptr terminator.
- }
- gpr_free(pem_root_certs);
- }
- // Try loading roots from OS trust store if flag is enabled.
- if (GRPC_SLICE_IS_EMPTY(result) && use_system_roots) {
- result = LoadSystemRootCerts();
- }
- // Fallback to roots manually shipped with gRPC.
- if (GRPC_SLICE_IS_EMPTY(result) &&
- ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
- GRPC_LOG_IF_ERROR("load_file",
- grpc_load_file(installed_roots_path, 1, &result));
- }
- return result;
-}
-
-void DefaultSslRootStore::InitRootStore() {
- static gpr_once once = GPR_ONCE_INIT;
- gpr_once_init(&once, DefaultSslRootStore::InitRootStoreOnce);
-}
-
-void DefaultSslRootStore::InitRootStoreOnce() {
- default_pem_root_certs_ = ComputePemRootCerts();
- if (!GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)) {
- default_root_store_ =
- tsi_ssl_root_certs_store_create(reinterpret_cast<const char*>(
- GRPC_SLICE_START_PTR(default_pem_root_certs_)));
- }
-}
-
-} // namespace grpc_core
diff --git a/src/core/lib/security/security_connector/security_connector.h b/src/core/lib/security/security_connector/security_connector.h
index 67a506b576..4c921a8793 100644
--- a/src/core/lib/security/security_connector/security_connector.h
+++ b/src/core/lib/security/security_connector/security_connector.h
@@ -27,6 +27,7 @@
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
@@ -37,11 +38,6 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount;
typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
-/* --- URL schemes. --- */
-
-#define GRPC_SSL_URL_SCHEME "https"
-#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
-
/* --- security_connector object. ---
A security connector object represents away to configure the underlying
@@ -125,6 +121,7 @@ struct grpc_channel_security_connector {
grpc_closure* on_call_host_checked,
grpc_error* error);
void (*add_handshakers)(grpc_channel_security_connector* sc,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
};
@@ -151,6 +148,7 @@ void grpc_channel_security_connector_cancel_check_call_host(
/* Registers handshakers with \a handshake_mgr. */
void grpc_channel_security_connector_add_handshakers(
grpc_channel_security_connector* connector,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
/* --- server_security_connector object. ---
@@ -164,6 +162,7 @@ struct grpc_server_security_connector {
grpc_security_connector base;
grpc_server_credentials* server_creds;
void (*add_handshakers)(grpc_server_security_connector* sc,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
};
@@ -172,114 +171,7 @@ int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1,
grpc_server_security_connector* sc2);
void grpc_server_security_connector_add_handshakers(
- grpc_server_security_connector* sc, grpc_handshake_manager* handshake_mgr);
-
-/* --- Creation security connectors. --- */
-
-/* For TESTING ONLY!
- Creates a fake connector that emulates real channel security. */
-grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
- grpc_channel_credentials* channel_creds,
- grpc_call_credentials* request_metadata_creds, const char* target,
- const grpc_channel_args* args);
-
-/* For TESTING ONLY!
- Creates a fake connector that emulates real server security. */
-grpc_server_security_connector* grpc_fake_server_security_connector_create(
- grpc_server_credentials* server_creds);
-
-/* Config for ssl clients. */
-
-typedef struct {
- tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
- char* pem_root_certs;
- verify_peer_options verify_options;
-} grpc_ssl_config;
-
-/* Creates an SSL channel_security_connector.
- - request_metadata_creds is the credentials object which metadata
- will be sent with each request. This parameter can be NULL.
- - config is the SSL config to be used for the SSL channel establishment.
- - is_client should be 0 for a server or a non-0 value for a client.
- - secure_peer_name is the secure peer name that should be checked in
- grpc_channel_security_connector_check_peer. This parameter may be NULL in
- which case the peer name will not be checked. Note that if this parameter
- is not NULL, then, pem_root_certs should not be NULL either.
- - sc is a pointer on the connector to be created.
- This function returns GRPC_SECURITY_OK in case of success or a
- specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_channel_security_connector_create(
- grpc_channel_credentials* channel_creds,
- grpc_call_credentials* request_metadata_creds,
- const grpc_ssl_config* config, const char* target_name,
- const char* overridden_target_name,
- tsi_ssl_session_cache* ssl_session_cache,
- grpc_channel_security_connector** sc);
-
-/* Config for ssl servers. */
-typedef struct {
- tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs;
- size_t num_key_cert_pairs;
- char* pem_root_certs;
- grpc_ssl_client_certificate_request_type client_certificate_request;
-} grpc_ssl_server_config;
-
-/* Creates an SSL server_security_connector.
- - config is the SSL config to be used for the SSL channel establishment.
- - sc is a pointer on the connector to be created.
- This function returns GRPC_SECURITY_OK in case of success or a
- specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_server_security_connector_create(
- grpc_server_credentials* server_credentials,
- grpc_server_security_connector** sc);
-
-/* Util. */
-const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
- const char* name);
-
-/* Exposed for testing only. */
-grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer);
-tsi_peer grpc_shallow_peer_from_ssl_auth_context(
- const grpc_auth_context* auth_context);
-void grpc_shallow_peer_destruct(tsi_peer* peer);
-int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name);
-
-/* --- Default SSL Root Store. --- */
-namespace grpc_core {
-
-// The class implements default SSL root store.
-class DefaultSslRootStore {
- public:
- // Gets the default SSL root store. Returns nullptr if not found.
- static const tsi_ssl_root_certs_store* GetRootStore();
-
- // Gets the default PEM root certificate.
- static const char* GetPemRootCerts();
-
- protected:
- // Returns default PEM root certificates in nullptr terminated grpc_slice.
- // This function is protected instead of private, so that it can be tested.
- static grpc_slice ComputePemRootCerts();
-
- private:
- // Construct me not!
- DefaultSslRootStore();
-
- // Initialization of default SSL root store.
- static void InitRootStore();
-
- // One-time initialization of default SSL root store.
- static void InitRootStoreOnce();
-
- // SSL root store in tsi_ssl_root_certs_store object.
- static tsi_ssl_root_certs_store* default_root_store_;
-
- // Default PEM root certificates.
- static grpc_slice default_pem_root_certs_;
-};
-
-} // namespace grpc_core
+ grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
+ grpc_handshake_manager* handshake_mgr);
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */
diff --git a/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
new file mode 100644
index 0000000000..20a9533dd1
--- /dev/null
+++ b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
@@ -0,0 +1,474 @@
+/*
+ *
+ * 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/lib/security/security_connector/ssl/ssl_security_connector.h"
+
+#include <stdbool.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/alpn/alpn.h"
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
+#include "src/core/lib/security/security_connector/load_system_roots.h"
+#include "src/core/lib/security/security_connector/ssl_utils.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security.h"
+
+typedef struct {
+ grpc_channel_security_connector base;
+ tsi_ssl_client_handshaker_factory* client_handshaker_factory;
+ char* target_name;
+ char* overridden_target_name;
+ const verify_peer_options* verify_options;
+} grpc_ssl_channel_security_connector;
+
+typedef struct {
+ grpc_server_security_connector base;
+ tsi_ssl_server_handshaker_factory* server_handshaker_factory;
+} grpc_ssl_server_security_connector;
+
+static bool server_connector_has_cert_config_fetcher(
+ grpc_ssl_server_security_connector* c) {
+ GPR_ASSERT(c != nullptr);
+ grpc_ssl_server_credentials* server_creds =
+ reinterpret_cast<grpc_ssl_server_credentials*>(c->base.server_creds);
+ GPR_ASSERT(server_creds != nullptr);
+ return server_creds->certificate_config_fetcher.cb != nullptr;
+}
+
+static void ssl_channel_destroy(grpc_security_connector* sc) {
+ grpc_ssl_channel_security_connector* c =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
+ grpc_channel_credentials_unref(c->base.channel_creds);
+ grpc_call_credentials_unref(c->base.request_metadata_creds);
+ tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
+ c->client_handshaker_factory = nullptr;
+ if (c->target_name != nullptr) gpr_free(c->target_name);
+ if (c->overridden_target_name != nullptr) gpr_free(c->overridden_target_name);
+ gpr_free(sc);
+}
+
+static void ssl_server_destroy(grpc_security_connector* sc) {
+ grpc_ssl_server_security_connector* c =
+ reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
+ grpc_server_credentials_unref(c->base.server_creds);
+ tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
+ c->server_handshaker_factory = nullptr;
+ gpr_free(sc);
+}
+
+static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc,
+ grpc_pollset_set* interested_parties,
+ grpc_handshake_manager* handshake_mgr) {
+ grpc_ssl_channel_security_connector* c =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
+ // Instantiate TSI handshaker.
+ tsi_handshaker* tsi_hs = nullptr;
+ tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
+ c->client_handshaker_factory,
+ c->overridden_target_name != nullptr ? c->overridden_target_name
+ : c->target_name,
+ &tsi_hs);
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+ tsi_result_to_string(result));
+ return;
+ }
+ // Create handshakers.
+ grpc_handshake_manager_add(
+ handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
+}
+
+/* Attempts to replace the server_handshaker_factory with a new factory using
+ * the provided grpc_ssl_server_certificate_config. Should new factory creation
+ * fail, the existing factory will not be replaced. Returns true on success (new
+ * factory created). */
+static bool try_replace_server_handshaker_factory(
+ grpc_ssl_server_security_connector* sc,
+ const grpc_ssl_server_certificate_config* config) {
+ if (config == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Server certificate config callback returned invalid (NULL) "
+ "config.");
+ return false;
+ }
+ gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config);
+
+ size_t num_alpn_protocols = 0;
+ const char** alpn_protocol_strings =
+ grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
+ tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
+ config->pem_key_cert_pairs, config->num_key_cert_pairs);
+ tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
+ grpc_ssl_server_credentials* server_creds =
+ reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
+ tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
+ cert_pairs, config->num_key_cert_pairs, config->pem_root_certs,
+ grpc_get_tsi_client_certificate_request_type(
+ server_creds->config.client_certificate_request),
+ grpc_get_ssl_cipher_suites(), alpn_protocol_strings,
+ static_cast<uint16_t>(num_alpn_protocols), &new_handshaker_factory);
+ gpr_free(cert_pairs);
+ gpr_free((void*)alpn_protocol_strings);
+
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+ tsi_result_to_string(result));
+ return false;
+ }
+ tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory);
+ sc->server_handshaker_factory = new_handshaker_factory;
+ return true;
+}
+
+/* Attempts to fetch the server certificate config if a callback is available.
+ * Current certificate config will continue to be used if the callback returns
+ * an error. Returns true if new credentials were sucessfully loaded. */
+static bool try_fetch_ssl_server_credentials(
+ grpc_ssl_server_security_connector* sc) {
+ grpc_ssl_server_certificate_config* certificate_config = nullptr;
+ bool status;
+
+ GPR_ASSERT(sc != nullptr);
+ if (!server_connector_has_cert_config_fetcher(sc)) return false;
+
+ grpc_ssl_server_credentials* server_creds =
+ reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
+ grpc_ssl_certificate_config_reload_status cb_result =
+ server_creds->certificate_config_fetcher.cb(
+ server_creds->certificate_config_fetcher.user_data,
+ &certificate_config);
+ if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) {
+ gpr_log(GPR_DEBUG, "No change in SSL server credentials.");
+ status = false;
+ } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) {
+ status = try_replace_server_handshaker_factory(sc, certificate_config);
+ } else {
+ // Log error, continue using previously-loaded credentials.
+ gpr_log(GPR_ERROR,
+ "Failed fetching new server credentials, continuing to "
+ "use previously-loaded credentials.");
+ status = false;
+ }
+
+ if (certificate_config != nullptr) {
+ grpc_ssl_server_certificate_config_destroy(certificate_config);
+ }
+ return status;
+}
+
+static void ssl_server_add_handshakers(grpc_server_security_connector* sc,
+ grpc_pollset_set* interested_parties,
+ grpc_handshake_manager* handshake_mgr) {
+ grpc_ssl_server_security_connector* c =
+ reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
+ // Instantiate TSI handshaker.
+ try_fetch_ssl_server_credentials(c);
+ tsi_handshaker* tsi_hs = nullptr;
+ tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
+ c->server_handshaker_factory, &tsi_hs);
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+ tsi_result_to_string(result));
+ return;
+ }
+ // Create handshakers.
+ grpc_handshake_manager_add(
+ handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
+}
+
+static grpc_error* ssl_check_peer(grpc_security_connector* sc,
+ const char* peer_name, const tsi_peer* peer,
+ grpc_auth_context** auth_context) {
+#if TSI_OPENSSL_ALPN_SUPPORT
+ /* Check the ALPN if ALPN is supported. */
+ const tsi_peer_property* p =
+ tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
+ if (p == nullptr) {
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Cannot check peer: missing selected ALPN property.");
+ }
+ if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Cannot check peer: invalid ALPN value.");
+ }
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
+ /* Check the peer name if specified. */
+ if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
+ char* msg;
+ gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name);
+ grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+ gpr_free(msg);
+ return error;
+ }
+ *auth_context = grpc_ssl_peer_to_auth_context(peer);
+ return GRPC_ERROR_NONE;
+}
+
+static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ grpc_ssl_channel_security_connector* c =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
+ const char* target_name = c->overridden_target_name != nullptr
+ ? c->overridden_target_name
+ : c->target_name;
+ grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context);
+ if (error == GRPC_ERROR_NONE &&
+ c->verify_options->verify_peer_callback != nullptr) {
+ const tsi_peer_property* p =
+ tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
+ if (p == nullptr) {
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Cannot check peer: missing pem cert property.");
+ } else {
+ char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
+ memcpy(peer_pem, p->value.data, p->value.length);
+ peer_pem[p->value.length] = '\0';
+ int callback_status = c->verify_options->verify_peer_callback(
+ target_name, peer_pem,
+ c->verify_options->verify_peer_callback_userdata);
+ gpr_free(peer_pem);
+ if (callback_status) {
+ char* msg;
+ gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
+ callback_status);
+ error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+ gpr_free(msg);
+ }
+ }
+ }
+ GRPC_CLOSURE_SCHED(on_peer_checked, error);
+ tsi_peer_destruct(&peer);
+}
+
+static void ssl_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ grpc_error* error = ssl_check_peer(sc, nullptr, &peer, auth_context);
+ tsi_peer_destruct(&peer);
+ GRPC_CLOSURE_SCHED(on_peer_checked, error);
+}
+
+static int ssl_channel_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ grpc_ssl_channel_security_connector* c1 =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc1);
+ grpc_ssl_channel_security_connector* c2 =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc2);
+ int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
+ if (c != 0) return c;
+ c = strcmp(c1->target_name, c2->target_name);
+ if (c != 0) return c;
+ return (c1->overridden_target_name == nullptr ||
+ c2->overridden_target_name == nullptr)
+ ? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name)
+ : strcmp(c1->overridden_target_name, c2->overridden_target_name);
+}
+
+static int ssl_server_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ return grpc_server_security_connector_cmp(
+ reinterpret_cast<grpc_server_security_connector*>(sc1),
+ reinterpret_cast<grpc_server_security_connector*>(sc2));
+}
+
+static bool ssl_channel_check_call_host(grpc_channel_security_connector* sc,
+ const char* host,
+ grpc_auth_context* auth_context,
+ grpc_closure* on_call_host_checked,
+ grpc_error** error) {
+ grpc_ssl_channel_security_connector* c =
+ reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
+ grpc_security_status status = GRPC_SECURITY_ERROR;
+ tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
+ if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
+ /* If the target name was overridden, then the original target_name was
+ 'checked' transitively during the previous peer check at the end of the
+ handshake. */
+ if (c->overridden_target_name != nullptr &&
+ strcmp(host, c->target_name) == 0) {
+ status = GRPC_SECURITY_OK;
+ }
+ if (status != GRPC_SECURITY_OK) {
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "call host does not match SSL server name");
+ }
+ grpc_shallow_peer_destruct(&peer);
+ return true;
+}
+
+static void ssl_channel_cancel_check_call_host(
+ grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
+ grpc_error* error) {
+ GRPC_ERROR_UNREF(error);
+}
+
+static grpc_security_connector_vtable ssl_channel_vtable = {
+ ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp};
+
+static grpc_security_connector_vtable ssl_server_vtable = {
+ ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
+
+grpc_security_status grpc_ssl_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds,
+ const grpc_ssl_config* config, const char* target_name,
+ const char* overridden_target_name,
+ tsi_ssl_session_cache* ssl_session_cache,
+ grpc_channel_security_connector** sc) {
+ tsi_result result = TSI_OK;
+ grpc_ssl_channel_security_connector* c;
+ char* port;
+ bool has_key_cert_pair;
+ tsi_ssl_client_handshaker_options options;
+ memset(&options, 0, sizeof(options));
+ options.alpn_protocols =
+ grpc_fill_alpn_protocol_strings(&options.num_alpn_protocols);
+
+ if (config == nullptr || target_name == nullptr) {
+ gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
+ goto error;
+ }
+ if (config->pem_root_certs == nullptr) {
+ // Use default root certificates.
+ options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
+ options.root_store = grpc_core::DefaultSslRootStore::GetRootStore();
+ if (options.pem_root_certs == nullptr) {
+ gpr_log(GPR_ERROR, "Could not get default pem root certs.");
+ goto error;
+ }
+ } else {
+ options.pem_root_certs = config->pem_root_certs;
+ }
+ c = static_cast<grpc_ssl_channel_security_connector*>(
+ gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)));
+
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.vtable = &ssl_channel_vtable;
+ c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
+ c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
+ c->base.request_metadata_creds =
+ grpc_call_credentials_ref(request_metadata_creds);
+ c->base.check_call_host = ssl_channel_check_call_host;
+ c->base.cancel_check_call_host = ssl_channel_cancel_check_call_host;
+ c->base.add_handshakers = ssl_channel_add_handshakers;
+ gpr_split_host_port(target_name, &c->target_name, &port);
+ gpr_free(port);
+ if (overridden_target_name != nullptr) {
+ c->overridden_target_name = gpr_strdup(overridden_target_name);
+ }
+ c->verify_options = &config->verify_options;
+
+ has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
+ config->pem_key_cert_pair->private_key != nullptr &&
+ config->pem_key_cert_pair->cert_chain != nullptr;
+ if (has_key_cert_pair) {
+ options.pem_key_cert_pair = config->pem_key_cert_pair;
+ }
+ options.cipher_suites = grpc_get_ssl_cipher_suites();
+ options.session_cache = ssl_session_cache;
+ result = tsi_create_ssl_client_handshaker_factory_with_options(
+ &options, &c->client_handshaker_factory);
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+ tsi_result_to_string(result));
+ ssl_channel_destroy(&c->base.base);
+ *sc = nullptr;
+ goto error;
+ }
+ *sc = &c->base;
+ gpr_free((void*)options.alpn_protocols);
+ return GRPC_SECURITY_OK;
+
+error:
+ gpr_free((void*)options.alpn_protocols);
+ return GRPC_SECURITY_ERROR;
+}
+
+static grpc_ssl_server_security_connector*
+grpc_ssl_server_security_connector_initialize(
+ grpc_server_credentials* server_creds) {
+ grpc_ssl_server_security_connector* c =
+ static_cast<grpc_ssl_server_security_connector*>(
+ gpr_zalloc(sizeof(grpc_ssl_server_security_connector)));
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
+ c->base.base.vtable = &ssl_server_vtable;
+ c->base.add_handshakers = ssl_server_add_handshakers;
+ c->base.server_creds = grpc_server_credentials_ref(server_creds);
+ return c;
+}
+
+grpc_security_status grpc_ssl_server_security_connector_create(
+ grpc_server_credentials* gsc, grpc_server_security_connector** sc) {
+ tsi_result result = TSI_OK;
+ grpc_ssl_server_credentials* server_credentials =
+ reinterpret_cast<grpc_ssl_server_credentials*>(gsc);
+ grpc_security_status retval = GRPC_SECURITY_OK;
+
+ GPR_ASSERT(server_credentials != nullptr);
+ GPR_ASSERT(sc != nullptr);
+
+ grpc_ssl_server_security_connector* c =
+ grpc_ssl_server_security_connector_initialize(gsc);
+ if (server_connector_has_cert_config_fetcher(c)) {
+ // Load initial credentials from certificate_config_fetcher:
+ if (!try_fetch_ssl_server_credentials(c)) {
+ gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher.");
+ retval = GRPC_SECURITY_ERROR;
+ }
+ } else {
+ size_t num_alpn_protocols = 0;
+ const char** alpn_protocol_strings =
+ grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
+ result = tsi_create_ssl_server_handshaker_factory_ex(
+ server_credentials->config.pem_key_cert_pairs,
+ server_credentials->config.num_key_cert_pairs,
+ server_credentials->config.pem_root_certs,
+ grpc_get_tsi_client_certificate_request_type(
+ server_credentials->config.client_certificate_request),
+ grpc_get_ssl_cipher_suites(), alpn_protocol_strings,
+ static_cast<uint16_t>(num_alpn_protocols),
+ &c->server_handshaker_factory);
+ gpr_free((void*)alpn_protocol_strings);
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+ tsi_result_to_string(result));
+ retval = GRPC_SECURITY_ERROR;
+ }
+ }
+
+ if (retval == GRPC_SECURITY_OK) {
+ *sc = &c->base;
+ } else {
+ if (c != nullptr) ssl_server_destroy(&c->base.base);
+ if (sc != nullptr) *sc = nullptr;
+ }
+ return retval;
+}
diff --git a/src/core/lib/security/security_connector/ssl/ssl_security_connector.h b/src/core/lib/security/security_connector/ssl/ssl_security_connector.h
new file mode 100644
index 0000000000..9b80590606
--- /dev/null
+++ b/src/core/lib/security/security_connector/ssl/ssl_security_connector.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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_LIB_SECURITY_SECURITY_CONNECTOR_SSL_SSL_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_SSL_SECURITY_CONNECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc_security.h>
+
+#include "src/core/lib/security/security_connector/security_connector.h"
+
+#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+typedef struct {
+ tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
+ char* pem_root_certs;
+ verify_peer_options verify_options;
+} grpc_ssl_config;
+
+/* Creates an SSL channel_security_connector.
+ - request_metadata_creds is the credentials object which metadata
+ will be sent with each request. This parameter can be NULL.
+ - config is the SSL config to be used for the SSL channel establishment.
+ - is_client should be 0 for a server or a non-0 value for a client.
+ - secure_peer_name is the secure peer name that should be checked in
+ grpc_channel_security_connector_check_peer. This parameter may be NULL in
+ which case the peer name will not be checked. Note that if this parameter
+ is not NULL, then, pem_root_certs should not be NULL either.
+ - sc is a pointer on the connector to be created.
+ This function returns GRPC_SECURITY_OK in case of success or a
+ specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds,
+ const grpc_ssl_config* config, const char* target_name,
+ const char* overridden_target_name,
+ tsi_ssl_session_cache* ssl_session_cache,
+ grpc_channel_security_connector** sc);
+
+/* Config for ssl servers. */
+typedef struct {
+ tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs;
+ size_t num_key_cert_pairs;
+ char* pem_root_certs;
+ grpc_ssl_client_certificate_request_type client_certificate_request;
+} grpc_ssl_server_config;
+
+/* Creates an SSL server_security_connector.
+ - config is the SSL config to be used for the SSL channel establishment.
+ - sc is a pointer on the connector to be created.
+ This function returns GRPC_SECURITY_OK in case of success or a
+ specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_server_security_connector_create(
+ grpc_server_credentials* server_credentials,
+ grpc_server_security_connector** sc);
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_SSL_SECURITY_CONNECTOR_H \
+ */
diff --git a/src/core/lib/security/security_connector/ssl_utils.cc b/src/core/lib/security/security_connector/ssl_utils.cc
new file mode 100644
index 0000000000..fbf41cfbc7
--- /dev/null
+++ b/src/core/lib/security/security_connector/ssl_utils.cc
@@ -0,0 +1,345 @@
+/*
+ *
+ * Copyright 2015 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/lib/security/security_connector/ssl_utils.h"
+
+#include <grpc/slice_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/alpn/alpn.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/iomgr/load_file.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/security_connector/load_system_roots.h"
+#include "src/core/tsi/ssl_transport_security.h"
+
+/* -- Constants. -- */
+
+#ifndef INSTALL_PREFIX
+static const char* installed_roots_path = "/usr/share/grpc/roots.pem";
+#else
+static const char* installed_roots_path =
+ INSTALL_PREFIX "/share/grpc/roots.pem";
+#endif
+
+/** Environment variable used as a flag to enable/disable loading system root
+ certificates from the OS trust store. */
+#ifndef GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR
+#define GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_NOT_USE_SYSTEM_SSL_ROOTS"
+#endif
+
+#ifndef TSI_OPENSSL_ALPN_SUPPORT
+#define TSI_OPENSSL_ALPN_SUPPORT 1
+#endif
+
+/* -- Overridden default roots. -- */
+
+static grpc_ssl_roots_override_callback ssl_roots_override_cb = nullptr;
+
+void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
+ ssl_roots_override_cb = cb;
+}
+
+/* -- Cipher suites. -- */
+
+/* Defines the cipher suites that we accept by default. All these cipher suites
+ are compliant with HTTP2. */
+#define GRPC_SSL_CIPHER_SUITES \
+ "ECDHE-ECDSA-AES128-GCM-SHA256:" \
+ "ECDHE-ECDSA-AES256-GCM-SHA384:" \
+ "ECDHE-RSA-AES128-GCM-SHA256:" \
+ "ECDHE-RSA-AES256-GCM-SHA384"
+
+static gpr_once cipher_suites_once = GPR_ONCE_INIT;
+static const char* cipher_suites = nullptr;
+
+static void init_cipher_suites(void) {
+ char* overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES");
+ cipher_suites = overridden != nullptr ? overridden : GRPC_SSL_CIPHER_SUITES;
+}
+
+/* --- Util --- */
+
+const char* grpc_get_ssl_cipher_suites(void) {
+ gpr_once_init(&cipher_suites_once, init_cipher_suites);
+ return cipher_suites;
+}
+
+tsi_client_certificate_request_type
+grpc_get_tsi_client_certificate_request_type(
+ grpc_ssl_client_certificate_request_type grpc_request_type) {
+ switch (grpc_request_type) {
+ case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE:
+ return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
+
+ case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
+ return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
+
+ case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
+ return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY;
+
+ case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
+ return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
+
+ case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
+ return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
+
+ default:
+ return TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
+ }
+}
+
+const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols) {
+ GPR_ASSERT(num_alpn_protocols != nullptr);
+ *num_alpn_protocols = grpc_chttp2_num_alpn_versions();
+ const char** alpn_protocol_strings = static_cast<const char**>(
+ gpr_malloc(sizeof(const char*) * (*num_alpn_protocols)));
+ for (size_t i = 0; i < *num_alpn_protocols; i++) {
+ alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i);
+ }
+ return alpn_protocol_strings;
+}
+
+int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name) {
+ char* allocated_name = nullptr;
+ int r;
+
+ char* ignored_port;
+ gpr_split_host_port(peer_name, &allocated_name, &ignored_port);
+ gpr_free(ignored_port);
+ peer_name = allocated_name;
+ if (!peer_name) return 0;
+
+ // IPv6 zone-id should not be included in comparisons.
+ char* const zone_id = strchr(allocated_name, '%');
+ if (zone_id != nullptr) *zone_id = '\0';
+
+ r = tsi_ssl_peer_matches_name(peer, peer_name);
+ gpr_free(allocated_name);
+ return r;
+}
+
+grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) {
+ size_t i;
+ grpc_auth_context* ctx = nullptr;
+ const char* peer_identity_property_name = nullptr;
+
+ /* The caller has checked the certificate type property. */
+ GPR_ASSERT(peer->property_count >= 1);
+ ctx = grpc_auth_context_create(nullptr);
+ grpc_auth_context_add_cstring_property(
+ ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+ for (i = 0; i < peer->property_count; i++) {
+ const tsi_peer_property* prop = &peer->properties[i];
+ if (prop->name == nullptr) continue;
+ if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
+ /* If there is no subject alt name, have the CN as the identity. */
+ if (peer_identity_property_name == nullptr) {
+ peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
+ }
+ grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
+ prop->value.data, prop->value.length);
+ } else if (strcmp(prop->name,
+ TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+ peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
+ grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
+ prop->value.data, prop->value.length);
+ } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
+ grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
+ prop->value.data, prop->value.length);
+ } else if (strcmp(prop->name, TSI_SSL_SESSION_REUSED_PEER_PROPERTY) == 0) {
+ grpc_auth_context_add_property(ctx, GRPC_SSL_SESSION_REUSED_PROPERTY,
+ prop->value.data, prop->value.length);
+ }
+ }
+ if (peer_identity_property_name != nullptr) {
+ GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
+ ctx, peer_identity_property_name) == 1);
+ }
+ return ctx;
+}
+
+static void add_shallow_auth_property_to_peer(tsi_peer* peer,
+ const grpc_auth_property* prop,
+ const char* tsi_prop_name) {
+ tsi_peer_property* tsi_prop = &peer->properties[peer->property_count++];
+ tsi_prop->name = const_cast<char*>(tsi_prop_name);
+ tsi_prop->value.data = prop->value;
+ tsi_prop->value.length = prop->value_length;
+}
+
+tsi_peer grpc_shallow_peer_from_ssl_auth_context(
+ const grpc_auth_context* auth_context) {
+ size_t max_num_props = 0;
+ grpc_auth_property_iterator it;
+ const grpc_auth_property* prop;
+ tsi_peer peer;
+ memset(&peer, 0, sizeof(peer));
+
+ it = grpc_auth_context_property_iterator(auth_context);
+ while (grpc_auth_property_iterator_next(&it) != nullptr) max_num_props++;
+
+ if (max_num_props > 0) {
+ peer.properties = static_cast<tsi_peer_property*>(
+ gpr_malloc(max_num_props * sizeof(tsi_peer_property)));
+ it = grpc_auth_context_property_iterator(auth_context);
+ while ((prop = grpc_auth_property_iterator_next(&it)) != nullptr) {
+ if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
+ add_shallow_auth_property_to_peer(
+ &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
+ } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
+ add_shallow_auth_property_to_peer(
+ &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
+ } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
+ add_shallow_auth_property_to_peer(&peer, prop,
+ TSI_X509_PEM_CERT_PROPERTY);
+ }
+ }
+ }
+ return peer;
+}
+
+void grpc_shallow_peer_destruct(tsi_peer* peer) {
+ if (peer->properties != nullptr) gpr_free(peer->properties);
+}
+
+/* --- Ssl cache implementation. --- */
+
+grpc_ssl_session_cache* grpc_ssl_session_cache_create_lru(size_t capacity) {
+ tsi_ssl_session_cache* cache = tsi_ssl_session_cache_create_lru(capacity);
+ return reinterpret_cast<grpc_ssl_session_cache*>(cache);
+}
+
+void grpc_ssl_session_cache_destroy(grpc_ssl_session_cache* cache) {
+ tsi_ssl_session_cache* tsi_cache =
+ reinterpret_cast<tsi_ssl_session_cache*>(cache);
+ tsi_ssl_session_cache_unref(tsi_cache);
+}
+
+static void* grpc_ssl_session_cache_arg_copy(void* p) {
+ tsi_ssl_session_cache* tsi_cache =
+ reinterpret_cast<tsi_ssl_session_cache*>(p);
+ // destroy call below will unref the pointer.
+ tsi_ssl_session_cache_ref(tsi_cache);
+ return p;
+}
+
+static void grpc_ssl_session_cache_arg_destroy(void* p) {
+ tsi_ssl_session_cache* tsi_cache =
+ reinterpret_cast<tsi_ssl_session_cache*>(p);
+ tsi_ssl_session_cache_unref(tsi_cache);
+}
+
+static int grpc_ssl_session_cache_arg_cmp(void* p, void* q) {
+ return GPR_ICMP(p, q);
+}
+
+grpc_arg grpc_ssl_session_cache_create_channel_arg(
+ grpc_ssl_session_cache* cache) {
+ static const grpc_arg_pointer_vtable vtable = {
+ grpc_ssl_session_cache_arg_copy,
+ grpc_ssl_session_cache_arg_destroy,
+ grpc_ssl_session_cache_arg_cmp,
+ };
+ return grpc_channel_arg_pointer_create(
+ const_cast<char*>(GRPC_SSL_SESSION_CACHE_ARG), cache, &vtable);
+}
+
+/* --- Default SSL root store implementation. --- */
+
+namespace grpc_core {
+
+tsi_ssl_root_certs_store* DefaultSslRootStore::default_root_store_;
+grpc_slice DefaultSslRootStore::default_pem_root_certs_;
+
+const tsi_ssl_root_certs_store* DefaultSslRootStore::GetRootStore() {
+ InitRootStore();
+ return default_root_store_;
+}
+
+const char* DefaultSslRootStore::GetPemRootCerts() {
+ InitRootStore();
+ return GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)
+ ? nullptr
+ : reinterpret_cast<const char*>
+ GRPC_SLICE_START_PTR(default_pem_root_certs_);
+}
+
+grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
+ grpc_slice result = grpc_empty_slice();
+ char* not_use_system_roots_env_value =
+ gpr_getenv(GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
+ const bool not_use_system_roots = gpr_is_true(not_use_system_roots_env_value);
+ gpr_free(not_use_system_roots_env_value);
+ // First try to load the roots from the environment.
+ char* default_root_certs_path =
+ gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
+ if (default_root_certs_path != nullptr) {
+ GRPC_LOG_IF_ERROR("load_file",
+ grpc_load_file(default_root_certs_path, 1, &result));
+ gpr_free(default_root_certs_path);
+ }
+ // Try overridden roots if needed.
+ grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+ if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
+ char* pem_root_certs = nullptr;
+ ovrd_res = ssl_roots_override_cb(&pem_root_certs);
+ if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
+ GPR_ASSERT(pem_root_certs != nullptr);
+ result = grpc_slice_from_copied_buffer(
+ pem_root_certs,
+ strlen(pem_root_certs) + 1); // nullptr terminator.
+ }
+ gpr_free(pem_root_certs);
+ }
+ // Try loading roots from OS trust store if flag is enabled.
+ if (GRPC_SLICE_IS_EMPTY(result) && !not_use_system_roots) {
+ result = LoadSystemRootCerts();
+ }
+ // Fallback to roots manually shipped with gRPC.
+ if (GRPC_SLICE_IS_EMPTY(result) &&
+ ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
+ GRPC_LOG_IF_ERROR("load_file",
+ grpc_load_file(installed_roots_path, 1, &result));
+ }
+ return result;
+}
+
+void DefaultSslRootStore::InitRootStore() {
+ static gpr_once once = GPR_ONCE_INIT;
+ gpr_once_init(&once, DefaultSslRootStore::InitRootStoreOnce);
+}
+
+void DefaultSslRootStore::InitRootStoreOnce() {
+ default_pem_root_certs_ = ComputePemRootCerts();
+ if (!GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)) {
+ default_root_store_ =
+ tsi_ssl_root_certs_store_create(reinterpret_cast<const char*>(
+ GRPC_SLICE_START_PTR(default_pem_root_certs_)));
+ }
+}
+
+} // namespace grpc_core
diff --git a/src/core/lib/security/security_connector/ssl_utils.h b/src/core/lib/security/security_connector/ssl_utils.h
new file mode 100644
index 0000000000..6f6d473311
--- /dev/null
+++ b/src/core/lib/security/security_connector/ssl_utils.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2015 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_LIB_SECURITY_SECURITY_CONNECTOR_SSL_UTILS_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_UTILS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include <grpc/grpc_security.h>
+#include <grpc/slice_buffer.h>
+
+#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/* --- Util. --- */
+
+/* --- URL schemes. --- */
+#define GRPC_SSL_URL_SCHEME "https"
+
+/* Return HTTP2-compliant cipher suites that gRPC accepts by default. */
+const char* grpc_get_ssl_cipher_suites(void);
+
+/* Map from grpc_ssl_client_certificate_request_type to
+ * tsi_client_certificate_request_type. */
+tsi_client_certificate_request_type
+grpc_get_tsi_client_certificate_request_type(
+ grpc_ssl_client_certificate_request_type grpc_request_type);
+
+/* Return an array of strings containing alpn protocols. */
+const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols);
+
+/* Exposed for testing only. */
+grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer);
+tsi_peer grpc_shallow_peer_from_ssl_auth_context(
+ const grpc_auth_context* auth_context);
+void grpc_shallow_peer_destruct(tsi_peer* peer);
+int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name);
+
+/* --- Default SSL Root Store. --- */
+namespace grpc_core {
+
+// The class implements default SSL root store.
+class DefaultSslRootStore {
+ public:
+ // Gets the default SSL root store. Returns nullptr if not found.
+ static const tsi_ssl_root_certs_store* GetRootStore();
+
+ // Gets the default PEM root certificate.
+ static const char* GetPemRootCerts();
+
+ protected:
+ // Returns default PEM root certificates in nullptr terminated grpc_slice.
+ // This function is protected instead of private, so that it can be tested.
+ static grpc_slice ComputePemRootCerts();
+
+ private:
+ // Construct me not!
+ DefaultSslRootStore();
+
+ // Initialization of default SSL root store.
+ static void InitRootStore();
+
+ // One-time initialization of default SSL root store.
+ static void InitRootStoreOnce();
+
+ // SSL root store in tsi_ssl_root_certs_store object.
+ static tsi_ssl_root_certs_store* default_root_store_;
+
+ // Default PEM root certificates.
+ static grpc_slice default_pem_root_certs_;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_UTILS_H \
+ */
diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc
index 0f125e7c26..6955e8698e 100644
--- a/src/core/lib/security/transport/client_auth_filter.cc
+++ b/src/core/lib/security/transport/client_auth_filter.cc
@@ -32,6 +32,7 @@
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/security_connector.h"
+#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/call.h"
@@ -42,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;
@@ -333,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;
}
@@ -353,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 9b103834e1..14fb55884f 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) \
@@ -411,25 +438,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 d76d582638..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);
@@ -475,22 +472,24 @@ static grpc_handshaker* fail_handshaker_create() {
static void client_handshaker_factory_add_handshakers(
grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_channel_security_connector* security_connector =
reinterpret_cast<grpc_channel_security_connector*>(
grpc_security_connector_find_in_args(args));
- grpc_channel_security_connector_add_handshakers(security_connector,
- handshake_mgr);
+ grpc_channel_security_connector_add_handshakers(
+ security_connector, interested_parties, handshake_mgr);
}
static void server_handshaker_factory_add_handshakers(
grpc_handshaker_factory* hf, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_server_security_connector* security_connector =
reinterpret_cast<grpc_server_security_connector*>(
grpc_security_connector_find_in_args(args));
- grpc_server_security_connector_add_handshakers(security_connector,
- handshake_mgr);
+ grpc_server_security_connector_add_handshakers(
+ security_connector, interested_parties, handshake_mgr);
}
static void handshaker_factory_destroy(
diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc
index 19cbb03b63..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,23 +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_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 = 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(
@@ -111,7 +146,16 @@ static void on_md_processing_done_inner(grpc_call_element* elem,
batch->payload->recv_initial_metadata.recv_initial_metadata,
remove_consumed_md, elem, "Response metadata filtering error");
}
- GRPC_CLOSURE_SCHED(calld->original_recv_initial_metadata_ready, error);
+ calld->recv_initial_metadata_error = GRPC_ERROR_REF(error);
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_SCHED(closure, error);
}
// Called from application code.
@@ -180,8 +224,31 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
return;
}
}
- GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready,
- GRPC_ERROR_REF(error));
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, GRPC_ERROR_REF(error));
+}
+
+static void recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
+ grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->original_recv_initial_metadata_ready != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(err);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_initial_metadata_ready");
+ return;
+ }
+ err = grpc_error_add_child(
+ GRPC_ERROR_REF(err), GRPC_ERROR_REF(calld->recv_initial_metadata_error));
+ GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err);
}
static void auth_start_transport_stream_op_batch(
@@ -195,39 +262,29 @@ static void auth_start_transport_stream_op_batch(
batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
&calld->recv_initial_metadata_ready;
}
+ if (batch->recv_trailing_metadata) {
+ calld->original_recv_trailing_metadata_ready =
+ batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+ batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+ &calld->recv_trailing_metadata_ready;
+ }
grpc_call_next_op(elem, 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);
- // 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;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
- grpc_closure* ignored) {}
+ grpc_closure* ignored) {
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ calld->~call_data();
+}
/* Constructor for channel_data */
static grpc_error* init_channel_elem(grpc_channel_element* elem,
diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc
index 419474129b..e842d84f11 100644
--- a/src/core/lib/slice/slice.cc
+++ b/src/core/lib/slice/slice.cc
@@ -88,6 +88,14 @@ static const grpc_slice_refcount_vtable noop_refcount_vtable = {
static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable,
&noop_refcount};
+size_t grpc_slice_memory_usage(grpc_slice s) {
+ if (s.refcount == nullptr || s.refcount == &noop_refcount) {
+ return 0;
+ } else {
+ return s.data.refcounted.length;
+ }
+}
+
grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
grpc_slice slice;
slice.refcount = &noop_refcount;
diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h
index 5d3d26b67b..5b05951522 100644
--- a/src/core/lib/slice/slice_internal.h
+++ b/src/core/lib/slice/slice_internal.h
@@ -46,4 +46,9 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
uint32_t grpc_static_slice_hash(grpc_slice s);
int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
+// Returns the memory used by this slice, not counting the slice structure
+// itself. This means that inlined and slices from static strings will return
+// 0. All other slices will return the size of the allocated chars.
+size_t grpc_slice_memory_usage(grpc_slice s);
+
#endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 2923a86646..89b3f77822 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -48,6 +48,7 @@
#include "src/core/lib/surface/call_test_only.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/server.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata.h"
@@ -71,48 +72,11 @@
// Used to create arena for the first call.
#define ESTIMATED_MDELEM_COUNT 16
-/* Status data for a request can come from several sources; this
- enumerates them all, and acts as a priority sorting for which
- status to return to the application - earlier entries override
- later ones */
-typedef enum {
- /* Status came from the application layer overriding whatever
- the wire says */
- STATUS_FROM_API_OVERRIDE = 0,
- /* Status came from 'the wire' - or somewhere below the surface
- layer */
- STATUS_FROM_WIRE,
- /* Status was created by some internal channel stack operation: must come via
- add_batch_error */
- STATUS_FROM_CORE,
- /* Status was created by some surface error */
- STATUS_FROM_SURFACE,
- /* Status came from the server sending status */
- STATUS_FROM_SERVER_STATUS,
- STATUS_SOURCE_COUNT
-} status_source;
+struct batch_control {
+ batch_control() { gpr_ref_init(&steps_to_complete, 0); }
-typedef struct {
- bool is_set;
- grpc_error* error;
-} received_status;
-
-static gpr_atm pack_received_status(received_status r) {
- return r.is_set ? (1 | (gpr_atm)r.error) : 0;
-}
-
-static received_status unpack_received_status(gpr_atm atm) {
- if ((atm & 1) == 0) {
- return {false, GRPC_ERROR_NONE};
- } else {
- return {true, (grpc_error*)(atm & ~static_cast<gpr_atm>(1))};
- }
-}
-
-#define MAX_ERRORS_PER_BATCH 4
-
-typedef struct batch_control {
- grpc_call* call;
+ 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,
@@ -135,90 +99,110 @@ typedef struct batch_control {
grpc_closure start_batch;
grpc_closure finish_batch;
gpr_refcount steps_to_complete;
+ gpr_atm batch_error = reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE);
+};
- grpc_error* errors[MAX_ERRORS_PER_BATCH];
- gpr_atm num_errors;
-
- grpc_transport_stream_op_batch op;
-} batch_control;
+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;
-
- /* Packed received call statuses from various sources */
- gpr_atm status[STATUS_SOURCE_COUNT];
+ 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 */
@@ -229,13 +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;
+ uint32_t test_only_last_message_flags = 0;
+ gpr_atm cancelled = 0;
grpc_closure release_call;
@@ -247,8 +232,11 @@ struct grpc_call {
} client;
struct {
int* cancelled;
+ // backpointer to owning server if this is a server side call.
+ grpc_server* server;
} server;
} final_op;
+ gpr_atm status_error = 0;
/* recv_state can contain one of the following values:
RECV_NONE : : no initial metadata and messages received
@@ -266,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");
@@ -286,23 +274,15 @@ grpc_core::TraceFlag grpc_compression_trace(false, "compression");
static void execute_batch(grpc_call* call, grpc_transport_stream_op_batch* op,
grpc_closure* start_batch_closure);
-static void cancel_with_status(grpc_call* c, status_source source,
- grpc_status_code status,
+
+static void cancel_with_status(grpc_call* c, grpc_status_code status,
const char* description);
-static void cancel_with_error(grpc_call* c, status_source source,
- grpc_error* error);
+static void cancel_with_error(grpc_call* c, grpc_error* error);
static void destroy_call(void* call_stack, grpc_error* error);
static void receiving_slice_ready(void* bctlp, grpc_error* error);
-static void get_final_status(
- grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data),
- void* set_value_user_data, grpc_slice* details, const char** error_string);
-static void set_status_value_directly(grpc_status_code status, void* dest);
-static void set_status_from_error(grpc_call* call, status_source source,
- grpc_error* error);
+static void set_final_status(grpc_call* call, grpc_error* error);
static void process_data_after_md(batch_control* bctl);
static void post_batch_completion(batch_control* bctl);
-static void add_batch_error(batch_control* bctl, grpc_error* error,
- bool has_cancelled);
static void add_init_error(grpc_error** composite, grpc_error* new_err) {
if (new_err == GRPC_ERROR_NONE) return;
@@ -318,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);
}
}
@@ -341,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);
@@ -349,30 +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);
- 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;
- if (call->is_client) {
- GRPC_STATS_INC_CLIENT_CALLS_CREATED();
- } else {
- GRPC_STATS_INC_SERVER_CALLS_CREATED();
- }
- 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)) {
@@ -383,22 +353,19 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
call->send_extra_metadata_count =
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);
@@ -432,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,
@@ -463,11 +427,12 @@ 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, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
+ cancel_with_error(call, GRPC_ERROR_REF(error));
}
if (immediately_cancel) {
- cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
}
if (args->cq != nullptr) {
GPR_ASSERT(args->pollset_set_alternative == nullptr &&
@@ -486,10 +451,18 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
&call->pollent);
}
- grpc_core::channelz::ChannelNode* channelz_channel =
- grpc_channel_get_channelz_node(call->channel);
- if (channelz_channel != nullptr) {
- channelz_channel->RecordCallStarted();
+ if (call->is_client) {
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(call->channel);
+ if (channelz_channel != nullptr) {
+ channelz_channel->RecordCallStarted();
+ }
+ } else {
+ grpc_core::channelz::ServerNode* channelz_server =
+ grpc_server_get_channelz_node(call->final_op.server.server);
+ if (channelz_server != nullptr) {
+ channelz_server->RecordCallStarted();
+ }
}
grpc_slice_unref_internal(path);
@@ -529,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");
}
@@ -547,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);
@@ -561,16 +534,15 @@ static void destroy_call(void* call, grpc_error* error) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
- get_final_status(c, set_status_value_directly, &c->final_info.final_status,
- nullptr, &(c->final_info.error_string));
+ grpc_error* status_error =
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error));
+ grpc_error_get_status(status_error, c->send_deadline,
+ &c->final_info.final_status, nullptr, nullptr,
+ &(c->final_info.error_string));
+ GRPC_ERROR_UNREF(status_error);
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- GRPC_ERROR_UNREF(
- unpack_received_status(gpr_atm_acq_load(&c->status[i])).error);
- }
-
grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c), &c->final_info,
GRPC_CLOSURE_INIT(&c->release_call, release_call, c,
grpc_schedule_on_exec_ctx));
@@ -608,7 +580,7 @@ void grpc_call_unref(grpc_call* c) {
bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 &&
gpr_atm_acq_load(&c->received_final_op_atm) == 0;
if (cancel) {
- cancel_with_error(c, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
+ cancel_with_error(c, GRPC_ERROR_CANCELLED);
} else {
// Unset the call combiner cancellation closure. This has the
// effect of scheduling the previously set cancellation closure, if
@@ -626,8 +598,7 @@ grpc_call_error grpc_call_cancel(grpc_call* call, void* reserved) {
GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
GPR_ASSERT(!reserved);
grpc_core::ExecCtx exec_ctx;
- cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
-
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
return GRPC_CALL_OK;
}
@@ -681,8 +652,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call* c,
"c=%p, status=%d, description=%s, reserved=%p)",
4, (c, (int)status, description, reserved));
GPR_ASSERT(reserved == nullptr);
- cancel_with_status(c, STATUS_FROM_API_OVERRIDE, status, description);
-
+ cancel_with_status(c, status, description);
return GRPC_CALL_OK;
}
@@ -702,15 +672,17 @@ static void done_termination(void* arg, grpc_error* error) {
gpr_free(state);
}
-static void cancel_with_error(grpc_call* c, status_source source,
- grpc_error* error) {
+static void cancel_with_error(grpc_call* c, grpc_error* error) {
+ if (!gpr_atm_rel_cas(&c->cancelled, 0, 1)) {
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
GRPC_CALL_INTERNAL_REF(c, "termination");
// Inform the call combiner of the cancellation, so that it can cancel
// any in-flight asynchronous actions that may be holding the call
// combiner. This ensures that the cancel_stream batch can be sent
// down the filter stack in a timely manner.
grpc_call_combiner_cancel(&c->call_combiner, GRPC_ERROR_REF(error));
- set_status_from_error(c, source, GRPC_ERROR_REF(error));
cancel_state* state = static_cast<cancel_state*>(gpr_malloc(sizeof(*state)));
state->call = c;
GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state,
@@ -722,6 +694,10 @@ static void cancel_with_error(grpc_call* c, status_source source,
execute_batch(c, op, &state->start_batch);
}
+void grpc_call_cancel_internal(grpc_call* call) {
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
+}
+
static grpc_error* error_from_status(grpc_status_code status,
const char* description) {
// copying 'description' is needed to ensure the grpc_call_cancel_with_status
@@ -733,90 +709,47 @@ static grpc_error* error_from_status(grpc_status_code status,
GRPC_ERROR_INT_GRPC_STATUS, status);
}
-static void cancel_with_status(grpc_call* c, status_source source,
- grpc_status_code status,
+static void cancel_with_status(grpc_call* c, grpc_status_code status,
const char* description) {
- cancel_with_error(c, source, error_from_status(status, description));
-}
-
-/*******************************************************************************
- * FINAL STATUS CODE MANIPULATION
- */
-
-static bool get_final_status_from(
- grpc_call* call, grpc_error* error, bool allow_ok_status,
- void (*set_value)(grpc_status_code code, void* user_data),
- void* set_value_user_data, grpc_slice* details, const char** error_string) {
- grpc_status_code code;
- grpc_slice slice = grpc_empty_slice();
- grpc_error_get_status(error, call->send_deadline, &code, &slice, nullptr,
- error_string);
- if (code == GRPC_STATUS_OK && !allow_ok_status) {
- return false;
- }
-
- set_value(code, set_value_user_data);
- if (details != nullptr) {
- *details = grpc_slice_ref_internal(slice);
- }
- return true;
+ cancel_with_error(c, error_from_status(status, description));
}
-static void get_final_status(
- grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data),
- void* set_value_user_data, grpc_slice* details, const char** error_string) {
- int i;
- received_status status[STATUS_SOURCE_COUNT];
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i]));
- }
+static void set_final_status(grpc_call* call, grpc_error* error) {
if (grpc_call_error_trace.enabled()) {
- gpr_log(GPR_INFO, "get_final_status %s", call->is_client ? "CLI" : "SVR");
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (status[i].is_set) {
- gpr_log(GPR_INFO, " %d: %s", i, grpc_error_string(status[i].error));
- }
- }
+ gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR");
+ gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
}
- /* first search through ignoring "OK" statuses: if something went wrong,
- * ensure we report it */
- for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) {
- /* search for the best status we can present: ideally the error we use has a
- clearly defined grpc-status, and we'll prefer that. */
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (status[i].is_set &&
- grpc_error_has_clear_grpc_status(status[i].error)) {
- if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
- set_value, set_value_user_data, details,
- error_string)) {
- return;
- }
+ if (call->is_client) {
+ grpc_error_get_status(error, call->send_deadline,
+ call->final_op.client.status,
+ call->final_op.client.status_details, nullptr,
+ call->final_op.client.error_string);
+ // explicitly take a ref
+ grpc_slice_ref_internal(*call->final_op.client.status_details);
+ gpr_atm_rel_store(&call->status_error, reinterpret_cast<gpr_atm>(error));
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(call->channel);
+ if (channelz_channel != nullptr) {
+ if (*call->final_op.client.status != GRPC_STATUS_OK) {
+ channelz_channel->RecordCallFailed();
+ } else {
+ channelz_channel->RecordCallSucceeded();
}
}
- /* If no clearly defined status exists, search for 'anything' */
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
- if (status[i].is_set) {
- if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
- set_value, set_value_user_data, details,
- error_string)) {
- return;
- }
+ } else {
+ *call->final_op.server.cancelled =
+ error != GRPC_ERROR_NONE ||
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&call->status_error)) !=
+ GRPC_ERROR_NONE;
+ grpc_core::channelz::ServerNode* channelz_server =
+ grpc_server_get_channelz_node(call->final_op.server.server);
+ if (channelz_server != nullptr) {
+ if (*call->final_op.server.cancelled) {
+ channelz_server->RecordCallFailed();
+ } else {
+ channelz_server->RecordCallSucceeded();
}
}
- }
- /* If nothing exists, set some default */
- if (call->is_client) {
- set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
- } else {
- set_value(GRPC_STATUS_OK, set_value_user_data);
- }
-}
-
-static void set_status_from_error(grpc_call* call, status_source source,
- grpc_error* error) {
- if (!gpr_atm_rel_cas(&call->status[source],
- pack_received_status({false, GRPC_ERROR_NONE}),
- pack_received_status({true, error}))) {
GRPC_ERROR_UNREF(error);
}
}
@@ -1035,6 +968,7 @@ static grpc_stream_compression_algorithm decode_stream_compression(
static void publish_app_metadata(grpc_call* call, grpc_metadata_batch* b,
int is_trailing) {
if (b->list.count == 0) return;
+ if (!call->is_client && is_trailing) return;
if (is_trailing && call->buffered_metadata[1] == nullptr) return;
GPR_TIMER_SCOPE("publish_app_metadata", 0);
grpc_metadata_array* dest;
@@ -1088,9 +1022,12 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) {
publish_app_metadata(call, b, false);
}
-static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
+static void recv_trailing_filter(void* args, grpc_metadata_batch* b,
+ grpc_error* batch_error) {
grpc_call* call = static_cast<grpc_call*>(args);
- if (b->idx.named.grpc_status != nullptr) {
+ if (batch_error != GRPC_ERROR_NONE) {
+ set_final_status(call, batch_error);
+ } else if (b->idx.named.grpc_status != nullptr) {
grpc_status_code status_code =
grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
grpc_error* error = GRPC_ERROR_NONE;
@@ -1108,8 +1045,18 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
grpc_empty_slice());
}
- set_status_from_error(call, STATUS_FROM_WIRE, error);
+ set_final_status(call, GRPC_ERROR_REF(error));
grpc_metadata_batch_remove(b, b->idx.named.grpc_status);
+ GRPC_ERROR_UNREF(error);
+ } else if (!call->is_client) {
+ set_final_status(call, GRPC_ERROR_NONE);
+ } else {
+ gpr_log(GPR_DEBUG,
+ "Received trailing metadata with no error and no status");
+ set_final_status(
+ call, grpc_error_set_int(
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("No status received"),
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNKNOWN));
}
publish_app_metadata(call, b, true);
}
@@ -1124,14 +1071,6 @@ grpc_call_stack* grpc_call_get_call_stack(grpc_call* call) {
* BATCH API IMPLEMENTATION
*/
-static void set_status_value_directly(grpc_status_code status, void* dest) {
- *static_cast<grpc_status_code*>(dest) = status;
-}
-
-static void set_cancelled_value(grpc_status_code status, void* dest) {
- *static_cast<int*>(dest) = (status != GRPC_STATUS_OK);
-}
-
static bool are_write_flags_valid(uint32_t flags) {
/* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
const uint32_t allowed_write_positions =
@@ -1180,10 +1119,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;
@@ -1199,31 +1139,18 @@ static void finish_batch_completion(void* user_data,
GRPC_CALL_INTERNAL_UNREF(call, "completion");
}
-static grpc_error* consolidate_batch_errors(batch_control* bctl) {
- size_t n = static_cast<size_t>(gpr_atm_acq_load(&bctl->num_errors));
- if (n == 0) {
- return GRPC_ERROR_NONE;
- } else if (n == 1) {
- /* Skip creating a composite error in the case that only one error was
- logged */
- grpc_error* e = bctl->errors[0];
- bctl->errors[0] = nullptr;
- return e;
- } else {
- grpc_error* error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
- "Call batch failed", bctl->errors, n);
- for (size_t i = 0; i < n; i++) {
- GRPC_ERROR_UNREF(bctl->errors[i]);
- bctl->errors[i] = nullptr;
- }
- return error;
- }
+static void reset_batch_errors(batch_control* bctl) {
+ GRPC_ERROR_UNREF(
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
+ gpr_atm_rel_store(&bctl->batch_error,
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE));
}
static void post_batch_completion(batch_control* bctl) {
grpc_call* next_child_call;
grpc_call* call = bctl->call;
- grpc_error* error = consolidate_batch_errors(bctl);
+ grpc_error* error = GRPC_ERROR_REF(
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
if (bctl->op.send_initial_metadata) {
grpc_metadata_batch_destroy(
@@ -1249,8 +1176,7 @@ static void post_batch_completion(batch_control* bctl) {
next_child_call = child->child->sibling_next;
if (child->cancellation_is_inherited) {
GRPC_CALL_INTERNAL_REF(child, "propagate_cancel");
- cancel_with_error(child, STATUS_FROM_API_OVERRIDE,
- GRPC_ERROR_CANCELLED);
+ cancel_with_error(child, GRPC_ERROR_CANCELLED);
GRPC_CALL_INTERNAL_UNREF(child, "propagate_cancel");
}
child = next_child_call;
@@ -1258,24 +1184,6 @@ static void post_batch_completion(batch_control* bctl) {
}
gpr_mu_unlock(&pc->child_list_mu);
}
- if (call->is_client) {
- get_final_status(call, set_status_value_directly,
- call->final_op.client.status,
- call->final_op.client.status_details,
- call->final_op.client.error_string);
- } else {
- get_final_status(call, set_cancelled_value,
- call->final_op.server.cancelled, nullptr, nullptr);
- }
- grpc_core::channelz::ChannelNode* channelz_channel =
- grpc_channel_get_channelz_node(call->channel);
- if (channelz_channel != nullptr) {
- if (*call->final_op.client.status != GRPC_STATUS_OK) {
- channelz_channel->RecordCallFailed();
- } else {
- channelz_channel->RecordCallSucceeded();
- }
- }
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
}
@@ -1284,9 +1192,10 @@ static void post_batch_completion(batch_control* bctl) {
grpc_byte_buffer_destroy(*call->receiving_buffer);
*call->receiving_buffer = nullptr;
}
+ reset_batch_errors(bctl);
if (bctl->completion_data.notify_tag.is_closure) {
- /* unrefs bctl->error */
+ /* unrefs error */
bctl->call = nullptr;
/* This closure may be meant to be run within some combiner. Since we aren't
* running in any combiner here, we need to use GRPC_CLOSURE_SCHED instead
@@ -1296,7 +1205,7 @@ static void post_batch_completion(batch_control* bctl) {
error);
GRPC_CALL_INTERNAL_UNREF(call, "completion");
} else {
- /* unrefs bctl->error */
+ /* unrefs error */
grpc_cq_end_op(bctl->call->cq, bctl->completion_data.notify_tag.tag, error,
finish_batch_completion, bctl,
&bctl->completion_data.cq_completion);
@@ -1405,8 +1314,12 @@ static void receiving_stream_ready(void* bctlp, grpc_error* error) {
grpc_call* call = bctl->call;
if (error != GRPC_ERROR_NONE) {
call->receiving_stream.reset();
- add_batch_error(bctl, GRPC_ERROR_REF(error), true);
- cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
+ GRPC_ERROR_NONE) {
+ gpr_atm_rel_store(&bctl->batch_error,
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
+ }
+ cancel_with_error(call, GRPC_ERROR_REF(error));
}
/* If recv_state is RECV_NONE, we will save the batch_control
* object with rel_cas, and will not use it after the cas. Its corresponding
@@ -1442,8 +1355,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
call->incoming_stream_compression_algorithm,
call->incoming_message_compression_algorithm);
gpr_log(GPR_ERROR, "%s", error_msg);
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL,
- error_msg);
+ cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg);
gpr_free(error_msg);
} else if (
grpc_compression_algorithm_from_message_stream_compression_algorithm(
@@ -1455,8 +1367,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
"compression (%d).",
call->incoming_stream_compression_algorithm,
call->incoming_message_compression_algorithm);
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL,
- error_msg);
+ cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg);
gpr_free(error_msg);
} else {
char* error_msg = nullptr;
@@ -1466,8 +1377,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
compression_algorithm);
gpr_log(GPR_ERROR, "%s", error_msg);
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED,
- error_msg);
+ cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
} else if (grpc_compression_options_is_algorithm_enabled(
&compression_options, compression_algorithm) == 0) {
/* check if algorithm is supported by current channel config */
@@ -1476,8 +1386,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
algo_name);
gpr_log(GPR_ERROR, "%s", error_msg);
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED,
- error_msg);
+ cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
}
gpr_free(error_msg);
@@ -1495,23 +1404,12 @@ static void validate_filtered_metadata(batch_control* bctl) {
}
}
-static void add_batch_error(batch_control* bctl, grpc_error* error,
- bool has_cancelled) {
- if (error == GRPC_ERROR_NONE) return;
- int idx = static_cast<int>(gpr_atm_full_fetch_add(&bctl->num_errors, 1));
- if (idx == 0 && !has_cancelled) {
- cancel_with_error(bctl->call, STATUS_FROM_CORE, GRPC_ERROR_REF(error));
- }
- bctl->errors[idx] = error;
-}
-
static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_initial_metadata_ready");
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
if (error == GRPC_ERROR_NONE) {
grpc_metadata_batch* md =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
@@ -1524,6 +1422,13 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
if (md->deadline != GRPC_MILLIS_INF_FUTURE && !call->is_client) {
call->send_deadline = md->deadline;
}
+ } else {
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
+ GRPC_ERROR_NONE) {
+ gpr_atm_rel_store(&bctl->batch_error,
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
+ }
+ cancel_with_error(call, GRPC_ERROR_REF(error));
}
grpc_closure* saved_rsr_closure = nullptr;
@@ -1561,10 +1466,9 @@ static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) {
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready");
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
grpc_metadata_batch* md =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- recv_trailing_filter(call, md);
+ recv_trailing_filter(call, md, GRPC_ERROR_REF(error));
finish_batch_step(bctl);
}
@@ -1572,7 +1476,14 @@ static void finish_batch(void* bctlp, grpc_error* error) {
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete");
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
+ GRPC_ERROR_NONE) {
+ gpr_atm_rel_store(&bctl->batch_error,
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
+ }
+ if (error != GRPC_ERROR_NONE) {
+ cancel_with_error(call, GRPC_ERROR_REF(error));
+ }
finish_batch_step(bctl);
}
@@ -1774,28 +1685,33 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
call->send_extra_metadata_count = 1;
call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
call->channel, op->data.send_status_from_server.status);
- {
- grpc_error* override_error = GRPC_ERROR_NONE;
- if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
- override_error =
- error_from_status(op->data.send_status_from_server.status,
- "Returned non-ok status");
- }
- if (op->data.send_status_from_server.status_details != nullptr) {
- call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
- GRPC_MDSTR_GRPC_MESSAGE,
- grpc_slice_ref_internal(
- *op->data.send_status_from_server.status_details));
- call->send_extra_metadata_count++;
+ grpc_error* status_error =
+ op->data.send_status_from_server.status == GRPC_STATUS_OK
+ ? GRPC_ERROR_NONE
+ : grpc_error_set_int(
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Server returned error"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ static_cast<intptr_t>(
+ op->data.send_status_from_server.status));
+ if (op->data.send_status_from_server.status_details != nullptr) {
+ call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
+ GRPC_MDSTR_GRPC_MESSAGE,
+ grpc_slice_ref_internal(
+ *op->data.send_status_from_server.status_details));
+ call->send_extra_metadata_count++;
+ if (status_error != GRPC_ERROR_NONE) {
char* msg = grpc_slice_to_c_string(
GRPC_MDVALUE(call->send_extra_metadata[1].md));
- override_error =
- grpc_error_set_str(override_error, GRPC_ERROR_STR_GRPC_MESSAGE,
+ status_error =
+ grpc_error_set_str(status_error, GRPC_ERROR_STR_GRPC_MESSAGE,
grpc_slice_from_copied_string(msg));
gpr_free(msg);
}
- set_status_from_error(call, STATUS_FROM_API_OVERRIDE, override_error);
}
+
+ gpr_atm_rel_store(&call->status_error,
+ reinterpret_cast<gpr_atm>(status_error));
if (!prepare_application_metadata(
call,
static_cast<int>(
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index b3b06059d4..bd7295fe11 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -33,6 +33,7 @@ typedef void (*grpc_ioreq_completion_func)(grpc_call* call, int success,
typedef struct grpc_call_create_args {
grpc_channel* channel;
+ grpc_server* server;
grpc_call* parent;
uint32_t propagation_mask;
@@ -80,6 +81,10 @@ grpc_call_error grpc_call_start_batch_and_execute(grpc_call* call,
size_t nops,
grpc_closure* closure);
+/* gRPC core internal version of grpc_call_cancel that does not create
+ * exec_ctx. */
+void grpc_call_cancel_internal(grpc_call* call);
+
/* Given the top call_element, get the call object. */
grpc_call* grpc_call_from_top_element(grpc_call_element* surface_element);
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index 82635d3c21..e47cb4360e 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -39,6 +39,7 @@
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -63,6 +64,7 @@ struct grpc_channel {
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
+ grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
@@ -82,6 +84,8 @@ grpc_channel* grpc_channel_create_with_builder(
char* target = gpr_strdup(grpc_channel_stack_builder_get_target(builder));
grpc_channel_args* args = grpc_channel_args_copy(
grpc_channel_stack_builder_get_channel_arguments(builder));
+ grpc_resource_user* resource_user =
+ grpc_channel_stack_builder_get_resource_user(builder);
grpc_channel* channel;
if (channel_stack_type == GRPC_SERVER_CHANNEL) {
GRPC_STATS_INC_SERVER_CHANNELS_CREATED();
@@ -100,11 +104,12 @@ grpc_channel* grpc_channel_create_with_builder(
return channel;
}
- memset(channel, 0, sizeof(*channel));
channel->target = target;
+ channel->resource_user = resource_user;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
- size_t channel_tracer_max_nodes = 0; // default to off
- bool channelz_enabled = false;
+ bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT;
+ 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.
@@ -142,16 +147,16 @@ grpc_channel* grpc_channel_create_with_builder(
static_cast<uint32_t>(args->args[i].value.integer) |
0x1; /* always support no compression */
} else if (0 == strcmp(args->args[i].key,
- GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE)) {
- GPR_ASSERT(channel_tracer_max_nodes == 0);
- // max_nodes defaults to 0 (which is off), clamped between 0 and INT_MAX
- const grpc_integer_options options = {0, 0, INT_MAX};
- channel_tracer_max_nodes =
+ GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) {
+ const grpc_integer_options options = {
+ GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX};
+ channel_tracer_max_memory =
(size_t)grpc_channel_arg_get_integer(&args->args[i], options);
} else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
// channelz will not be enabled by default until all concerns in
// https://github.com/grpc/grpc/issues/15986 are addressed.
- channelz_enabled = grpc_channel_arg_get_bool(&args->args[i], false);
+ channelz_enabled = grpc_channel_arg_get_bool(
+ &args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT);
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC)) {
GPR_ASSERT(args->args[i].type == GRPC_ARG_POINTER);
@@ -166,11 +171,12 @@ grpc_channel* grpc_channel_create_with_builder(
}
grpc_channel_args_destroy(args);
- if (channelz_enabled) {
- bool is_top_level_channel = channel->is_client && !internal_channel;
+ // we only need to do the channelz bookkeeping for clients here. The channelz
+ // bookkeeping for server channels occurs in src/core/lib/surface/server.cc
+ if (channelz_enabled && channel->is_client) {
channel->channelz_channel = channel_node_create_func(
- channel, channel_tracer_max_nodes, is_top_level_channel);
- channel->channelz_channel->trace()->AddTraceEvent(
+ channel, channel_tracer_max_memory, !internal_channel);
+ channel->channelz_channel->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel created"));
}
@@ -216,7 +222,8 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
- grpc_transport* optional_transport) {
+ grpc_transport* optional_transport,
+ grpc_resource_user* resource_user) {
grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
const grpc_core::UniquePtr<char> default_authority =
get_default_authority(input_args);
@@ -226,11 +233,17 @@ grpc_channel* grpc_channel_create(const char* target,
grpc_channel_args_destroy(args);
grpc_channel_stack_builder_set_target(builder, target);
grpc_channel_stack_builder_set_transport(builder, optional_transport);
+ grpc_channel_stack_builder_set_resource_user(builder, resource_user);
if (!grpc_channel_init_create_stack(builder, channel_stack_type)) {
grpc_channel_stack_builder_destroy(builder);
+ if (resource_user != nullptr) {
+ grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
return nullptr;
}
- return grpc_channel_create_with_builder(builder, channel_stack_type);
+ grpc_channel* channel =
+ grpc_channel_create_with_builder(builder, channel_stack_type);
+ return channel;
}
size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) {
@@ -309,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;
@@ -335,9 +348,8 @@ grpc_call* grpc_channel_create_call(grpc_channel* channel,
grpc_core::ExecCtx exec_ctx;
grpc_call* call = grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, cq, nullptr,
- grpc_mdelem_from_slices(GRPC_MDSTR_PATH, grpc_slice_ref_internal(method)),
- host != nullptr ? grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
- grpc_slice_ref_internal(*host))
+ grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr),
+ host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr)
: GRPC_MDNULL,
grpc_timespec_to_millis_round_up(deadline));
@@ -346,14 +358,13 @@ grpc_call* grpc_channel_create_call(grpc_channel* channel,
grpc_call* grpc_channel_create_pollset_set_call(
grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
- grpc_pollset_set* pollset_set, grpc_slice method, const grpc_slice* host,
- grpc_millis deadline, void* reserved) {
+ grpc_pollset_set* pollset_set, const grpc_slice& method,
+ const grpc_slice* host, grpc_millis deadline, void* reserved) {
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, nullptr, pollset_set,
- grpc_mdelem_from_slices(GRPC_MDSTR_PATH, grpc_slice_ref_internal(method)),
- host != nullptr ? grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
- grpc_slice_ref_internal(*host))
+ grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr),
+ host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr)
: GRPC_MDNULL,
deadline);
}
@@ -428,6 +439,9 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg);
if (channel->channelz_channel != nullptr) {
+ channel->channelz_channel->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("Channel destroyed"));
channel->channelz_channel->MarkChannelDestroyed();
channel->channelz_channel.reset();
}
@@ -439,6 +453,10 @@ static void destroy_channel(void* arg, grpc_error* error) {
GRPC_MDELEM_UNREF(rc->authority);
gpr_free(rc);
}
+ if (channel->resource_user != nullptr) {
+ grpc_resource_user_free(channel->resource_user,
+ GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
+ }
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index e5ff2c3596..ab00b8e94f 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -29,7 +29,8 @@
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* args,
grpc_channel_stack_type channel_stack_type,
- grpc_transport* optional_transport);
+ grpc_transport* optional_transport,
+ grpc_resource_user* resource_user = nullptr);
grpc_channel* grpc_channel_create_with_builder(
grpc_channel_stack_builder* builder,
@@ -45,8 +46,8 @@ grpc_channel* grpc_channel_create_with_builder(
value of \a propagation_mask (see propagation_bits.h for possible values) */
grpc_call* grpc_channel_create_pollset_set_call(
grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
- grpc_pollset_set* pollset_set, grpc_slice method, const grpc_slice* host,
- grpc_millis deadline, void* reserved);
+ grpc_pollset_set* pollset_set, const grpc_slice& method,
+ const grpc_slice* host, grpc_millis deadline, void* reserved);
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel);
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index 0769d9e4f6..661022ec5f 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -79,6 +79,7 @@ typedef struct non_polling_worker {
typedef struct {
gpr_mu mu;
+ bool kicked_without_poller;
non_polling_worker* root;
grpc_closure* shutdown;
} non_polling_poller;
@@ -103,6 +104,10 @@ static grpc_error* non_polling_poller_work(grpc_pollset* pollset,
grpc_millis deadline) {
non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
if (npp->shutdown) return GRPC_ERROR_NONE;
+ if (npp->kicked_without_poller) {
+ npp->kicked_without_poller = false;
+ return GRPC_ERROR_NONE;
+ }
non_polling_worker w;
gpr_cv_init(&w.cv);
if (worker != nullptr) *worker = reinterpret_cast<grpc_pollset_worker*>(&w);
@@ -148,6 +153,8 @@ static grpc_error* non_polling_poller_kick(
w->kicked = true;
gpr_cv_signal(&w->cv);
}
+ } else {
+ p->kicked_without_poller = true;
}
return GRPC_ERROR_NONE;
}
@@ -184,7 +191,8 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
typedef struct cq_vtable {
grpc_cq_completion_type cq_completion_type;
size_t data_size;
- void (*init)(void* data, grpc_core::CQCallbackInterface* shutdown_callback);
+ void (*init)(void* data,
+ grpc_experimental_completion_queue_functor* shutdown_callback);
void (*shutdown)(grpc_completion_queue* cq);
void (*destroy)(void* data);
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
@@ -267,7 +275,7 @@ typedef struct cq_callback_data {
bool shutdown_called;
/** A callback that gets invoked when the CQ completes shutdown */
- grpc_core::CQCallbackInterface* shutdown_callback;
+ grpc_experimental_completion_queue_functor* shutdown_callback;
} cq_callback_data;
/* Completion queue structure */
@@ -333,12 +341,12 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, void* reserved);
// Note that cq_init_next and cq_init_pluck do not use the shutdown_callback
-static void cq_init_next(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
-static void cq_init_pluck(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
-static void cq_init_callback(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
+static void cq_init_next(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
+static void cq_init_pluck(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
+static void cq_init_callback(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
static void cq_destroy_next(void* data);
static void cq_destroy_pluck(void* data);
static void cq_destroy_callback(void* data);
@@ -462,7 +470,7 @@ static long cq_event_queue_num_items(grpc_cq_event_queue* q) {
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+ grpc_experimental_completion_queue_functor* shutdown_callback) {
GPR_TIMER_SCOPE("grpc_completion_queue_create_internal", 0);
grpc_completion_queue* cq;
@@ -497,8 +505,8 @@ grpc_completion_queue* grpc_completion_queue_create_internal(
return cq;
}
-static void cq_init_next(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+static void cq_init_next(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_next_data* cqd = static_cast<cq_next_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -513,8 +521,8 @@ static void cq_destroy_next(void* data) {
cq_event_queue_destroy(&cqd->queue);
}
-static void cq_init_pluck(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+static void cq_init_pluck(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -532,7 +540,7 @@ static void cq_destroy_pluck(void* data) {
}
static void cq_init_callback(
- void* data, grpc_core::CQCallbackInterface* shutdown_callback) {
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_callback_data* cqd = static_cast<cq_callback_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -851,15 +859,16 @@ 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);
}
GRPC_ERROR_UNREF(error);
- (static_cast<grpc_core::CQCallbackInterface*>(tag))->Run(is_success);
+ auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
+ (*functor->functor_run)(functor, is_success);
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
@@ -1343,7 +1352,7 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
GPR_ASSERT(cqd->shutdown_called);
cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
- callback->Run(true);
+ (*callback->functor_run)(callback, true);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {
@@ -1364,9 +1373,11 @@ static void cq_shutdown_callback(grpc_completion_queue* cq) {
}
cqd->shutdown_called = true;
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
+ gpr_mu_unlock(cq->mu);
cq_finish_shutdown_callback(cq);
+ } else {
+ gpr_mu_unlock(cq->mu);
}
- gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (callback cq)");
}
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index a7c524d8e8..d60fe6d6ef 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -48,23 +48,6 @@ typedef struct grpc_cq_completion {
uintptr_t next;
} grpc_cq_completion;
-/// For callback CQs, the tag that is passed in for an operation must
-/// actually be a pointer to an implementation of the following class.
-/// When the operation completes, the tag will be typecasted from void*
-/// to grpc_core::CQCallbackInterface* and then the Run method will be
-/// invoked on it. In practice, the language binding (e.g., C++ API
-/// implementation) is responsible for providing and using an implementation
-/// of this abstract base class.
-namespace grpc_core {
-class CQCallbackInterface {
- public:
- virtual ~CQCallbackInterface() {}
- virtual void Run(bool) GRPC_ABSTRACT;
-
- GRPC_ABSTRACT_BASE_CLASS
-};
-} // namespace grpc_core
-
#ifndef NDEBUG
void grpc_cq_internal_ref(grpc_completion_queue* cc, const char* reason,
const char* file, int line);
@@ -106,6 +89,6 @@ int grpc_get_cq_poll_num(grpc_completion_queue* cc);
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
- grpc_core::CQCallbackInterface* shutdown_callback);
+ grpc_experimental_completion_queue_functor* shutdown_callback);
#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/completion_queue_factory.cc b/src/core/lib/surface/completion_queue_factory.cc
index ed92dd7eba..2616c156e4 100644
--- a/src/core/lib/surface/completion_queue_factory.cc
+++ b/src/core/lib/surface/completion_queue_factory.cc
@@ -31,8 +31,7 @@ static grpc_completion_queue* default_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attr) {
return grpc_completion_queue_create_internal(
- attr->cq_completion_type, attr->cq_polling_type,
- static_cast<grpc_core::CQCallbackInterface*>(attr->cq_shutdown_cb));
+ attr->cq_completion_type, attr->cq_polling_type, attr->cq_shutdown_cb);
}
static grpc_completion_queue_factory_vtable default_vtable = {default_create};
@@ -73,7 +72,8 @@ grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) {
}
grpc_completion_queue* grpc_completion_queue_create_for_callback(
- void* shutdown_callback, void* reserved) {
+ grpc_experimental_completion_queue_functor* shutdown_callback,
+ void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {
2, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback};
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/init_secure.cc b/src/core/lib/surface/init_secure.cc
index 28c6f7b121..765350cced 100644
--- a/src/core/lib/surface/init_secure.cc
+++ b/src/core/lib/surface/init_secure.cc
@@ -74,7 +74,7 @@ void grpc_register_security_filters(void) {
maybe_prepend_client_auth_filter, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX - 1,
maybe_prepend_client_auth_filter, nullptr);
- grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+ grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX - 1,
maybe_prepend_server_auth_filter, nullptr);
}
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index cb34def740..5dc81b29bb 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -47,6 +47,10 @@
grpc_core::TraceFlag grpc_server_channel_trace(false, "server_channel");
+static void server_on_recv_initial_metadata(void* ptr, grpc_error* error);
+static void server_recv_trailing_metadata_ready(void* user_data,
+ grpc_error* error);
+
namespace {
struct listener {
void* arg;
@@ -54,6 +58,7 @@ struct listener {
size_t pollset_count);
void (*destroy)(grpc_server* server, void* arg, grpc_closure* closure);
struct listener* next;
+ intptr_t socket_uuid;
grpc_closure destroy_done;
};
@@ -104,6 +109,7 @@ struct channel_data {
uint32_t registered_method_max_probes;
grpc_closure finish_destroy_channel_closure;
grpc_closure channel_connectivity_changed;
+ intptr_t socket_uuid;
};
typedef struct shutdown_tag {
@@ -126,33 +132,63 @@ typedef enum {
typedef struct request_matcher request_matcher;
struct call_data {
+ call_data(grpc_call_element* elem, const grpc_call_element_args& args)
+ : call(grpc_call_from_top_element(elem)),
+ call_combiner(args.call_combiner) {
+ GRPC_CLOSURE_INIT(&server_on_recv_initial_metadata,
+ ::server_on_recv_initial_metadata, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready,
+ server_recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ }
+ ~call_data() {
+ GPR_ASSERT(state != PENDING);
+ GRPC_ERROR_UNREF(recv_initial_metadata_error);
+ if (host_set) {
+ grpc_slice_unref_internal(host);
+ }
+ if (path_set) {
+ grpc_slice_unref_internal(path);
+ }
+ grpc_metadata_array_destroy(&initial_metadata);
+ grpc_byte_buffer_destroy(payload);
+ }
+
grpc_call* call;
- gpr_atm state;
+ gpr_atm state = NOT_STARTED;
- bool path_set;
- bool host_set;
+ bool path_set = false;
+ bool host_set = false;
grpc_slice path;
grpc_slice host;
- grpc_millis deadline;
+ grpc_millis deadline = GRPC_MILLIS_INF_FUTURE;
- grpc_completion_queue* cq_new;
+ grpc_completion_queue* cq_new = nullptr;
- grpc_metadata_batch* recv_initial_metadata;
- uint32_t recv_initial_metadata_flags;
- grpc_metadata_array initial_metadata;
+ grpc_metadata_batch* recv_initial_metadata = nullptr;
+ uint32_t recv_initial_metadata_flags = 0;
+ grpc_metadata_array initial_metadata =
+ grpc_metadata_array(); // Zero-initialize the C struct.
- request_matcher* matcher;
- grpc_byte_buffer* payload;
+ request_matcher* matcher = nullptr;
+ grpc_byte_buffer* payload = nullptr;
grpc_closure got_initial_metadata;
grpc_closure server_on_recv_initial_metadata;
grpc_closure kill_zombie_closure;
grpc_closure* on_done_recv_initial_metadata;
+ grpc_closure recv_trailing_metadata_ready;
+ grpc_error* recv_initial_metadata_error = GRPC_ERROR_NONE;
+ grpc_closure* original_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error = GRPC_ERROR_NONE;
+ bool seen_recv_trailing_metadata_ready = false;
grpc_closure publish;
- call_data* pending_next;
+ call_data* pending_next = nullptr;
+ grpc_call_combiner* call_combiner;
};
struct request_matcher {
@@ -181,6 +217,8 @@ typedef struct {
struct grpc_server {
grpc_channel_args* channel_args;
+ grpc_resource_user* default_resource_user;
+
grpc_completion_queue** cqs;
grpc_pollset** pollsets;
size_t cq_count;
@@ -219,6 +257,8 @@ struct grpc_server {
/** when did we print the last shutdown progress message */
gpr_timespec last_shutdown_message_time;
+
+ grpc_core::RefCountedPtr<grpc_core::channelz::ServerNode> channelz_server;
};
#define SERVER_FROM_CALL_ELEM(elem) \
@@ -364,6 +404,7 @@ static void server_ref(grpc_server* server) {
static void server_delete(grpc_server* server) {
registered_method* rm;
size_t i;
+ server->channelz_server.reset();
grpc_channel_args_destroy(server->channel_args);
gpr_mu_destroy(&server->mu_global);
gpr_mu_destroy(&server->mu_call);
@@ -721,13 +762,43 @@ static void server_on_recv_initial_metadata(void* ptr, grpc_error* error) {
if (calld->host_set && calld->path_set) {
/* do nothing */
} else {
+ /* Pass the error reference to calld->recv_initial_metadata_error */
grpc_error* src_error = error;
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
- "Missing :authority or :path", &error, 1);
+ "Missing :authority or :path", &src_error, 1);
GRPC_ERROR_UNREF(src_error);
+ calld->recv_initial_metadata_error = GRPC_ERROR_REF(error);
}
+ grpc_closure* closure = calld->on_done_recv_initial_metadata;
+ calld->on_done_recv_initial_metadata = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue server_recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
+}
- GRPC_CLOSURE_RUN(calld->on_done_recv_initial_metadata, error);
+static void server_recv_trailing_metadata_ready(void* user_data,
+ grpc_error* error) {
+ grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+ call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->on_done_recv_initial_metadata != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
+ server_recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring server_recv_trailing_metadata_ready "
+ "until after server_on_recv_initial_metadata");
+ return;
+ }
+ error =
+ grpc_error_add_child(GRPC_ERROR_REF(error),
+ GRPC_ERROR_REF(calld->recv_initial_metadata_error));
+ GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error);
}
static void server_mutate_op(grpc_call_element* elem,
@@ -745,6 +816,12 @@ static void server_mutate_op(grpc_call_element* elem,
op->payload->recv_initial_metadata.recv_flags =
&calld->recv_initial_metadata_flags;
}
+ if (op->recv_trailing_metadata) {
+ calld->original_recv_trailing_metadata_ready =
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+ op->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+ &calld->recv_trailing_metadata_ready;
+ }
}
static void server_start_transport_stream_op_batch(
@@ -775,9 +852,15 @@ 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;
grpc_call* call;
grpc_error* error = grpc_call_create(&args, &call);
@@ -790,8 +873,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,
@@ -819,37 +903,18 @@ static void channel_connectivity_changed(void* cd, 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);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
- memset(calld, 0, sizeof(call_data));
- calld->deadline = GRPC_MILLIS_INF_FUTURE;
- calld->call = grpc_call_from_top_element(elem);
-
- GRPC_CLOSURE_INIT(&calld->server_on_recv_initial_metadata,
- server_on_recv_initial_metadata, elem,
- grpc_schedule_on_exec_ctx);
-
server_ref(chand->server);
+ new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
}
static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
- channel_data* chand = static_cast<channel_data*>(elem->channel_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
-
- GPR_ASSERT(calld->state != PENDING);
-
- if (calld->host_set) {
- grpc_slice_unref_internal(calld->host);
- }
- if (calld->path_set) {
- grpc_slice_unref_internal(calld->path);
- }
- grpc_metadata_array_destroy(&calld->initial_metadata);
- grpc_byte_buffer_destroy(calld->payload);
-
+ calld->~call_data();
+ channel_data* chand = static_cast<channel_data*>(elem->channel_data);
server_unref(chand->server);
}
@@ -941,6 +1006,7 @@ void grpc_server_register_completion_queue(grpc_server* server,
}
grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) {
+ grpc_core::ExecCtx exec_ctx;
GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
grpc_server* server =
@@ -957,6 +1023,30 @@ grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) {
server->channel_args = grpc_channel_args_copy(args);
+ const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ);
+ if (grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT)) {
+ arg = grpc_channel_args_find(
+ args, GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE);
+ size_t channel_tracer_max_memory = grpc_channel_arg_get_integer(
+ arg,
+ {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX});
+ server->channelz_server =
+ grpc_core::MakeRefCounted<grpc_core::channelz::ServerNode>(
+ server, channel_tracer_max_memory);
+ server->channelz_server->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("Server created"));
+ }
+
+ if (args != nullptr) {
+ grpc_resource_quota* resource_quota =
+ grpc_resource_quota_from_channel_args(args, false /* create */);
+ if (resource_quota != nullptr) {
+ server->default_resource_user =
+ grpc_resource_user_create(resource_quota, "default");
+ }
+ }
+
return server;
}
@@ -1054,7 +1144,9 @@ void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets,
void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
grpc_pollset* accepting_pollset,
- const grpc_channel_args* args) {
+ const grpc_channel_args* args,
+ intptr_t socket_uuid,
+ grpc_resource_user* resource_user) {
size_t num_registered_methods;
size_t alloc;
registered_method* rm;
@@ -1067,13 +1159,15 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
uint32_t max_probes = 0;
grpc_transport_op* op = nullptr;
- channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport);
+ channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport,
+ resource_user);
chand = static_cast<channel_data*>(
grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0)
->channel_data);
chand->server = s;
server_ref(s);
chand->channel = channel;
+ chand->socket_uuid = socket_uuid;
size_t cq_idx;
for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) {
@@ -1148,6 +1242,29 @@ void grpc_server_setup_transport(grpc_server* s, grpc_transport* transport,
grpc_transport_perform_op(transport, op);
}
+void grpc_server_populate_server_sockets(
+ grpc_server* s, grpc_core::channelz::ChildRefsList* server_sockets,
+ intptr_t start_idx) {
+ gpr_mu_lock(&s->mu_global);
+ channel_data* c = nullptr;
+ for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
+ intptr_t socket_uuid = c->socket_uuid;
+ if (socket_uuid >= start_idx) {
+ server_sockets->push_back(socket_uuid);
+ }
+ }
+ gpr_mu_unlock(&s->mu_global);
+}
+
+void grpc_server_populate_listen_sockets(
+ grpc_server* server, grpc_core::channelz::ChildRefsList* listen_sockets) {
+ gpr_mu_lock(&server->mu_global);
+ for (listener* l = server->listeners; l != nullptr; l = l->next) {
+ listen_sockets->push_back(l->socket_uuid);
+ }
+ gpr_mu_unlock(&server->mu_global);
+}
+
void done_published_shutdown(void* done_arg, grpc_cq_completion* storage) {
(void)done_arg;
gpr_free(storage);
@@ -1238,6 +1355,13 @@ void grpc_server_shutdown_and_notify(grpc_server* server,
channel_broadcaster_shutdown(&broadcaster, true /* send_goaway */,
GRPC_ERROR_NONE);
+
+ if (server->default_resource_user != nullptr) {
+ grpc_resource_quota_unref(
+ grpc_resource_user_quota(server->default_resource_user));
+ grpc_resource_user_shutdown(server->default_resource_user);
+ grpc_resource_user_unref(server->default_resource_user);
+ }
}
void grpc_server_cancel_all_calls(grpc_server* server) {
@@ -1281,11 +1405,13 @@ void grpc_server_add_listener(grpc_server* server, void* arg,
grpc_pollset** pollsets,
size_t pollset_count),
void (*destroy)(grpc_server* server, void* arg,
- grpc_closure* on_done)) {
+ grpc_closure* on_done),
+ intptr_t socket_uuid) {
listener* l = static_cast<listener*>(gpr_malloc(sizeof(listener)));
l->arg = arg;
l->start = start;
l->destroy = destroy;
+ l->socket_uuid = socket_uuid;
l->next = server->listeners;
server->listeners = l;
}
@@ -1452,6 +1578,10 @@ const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server) {
return server->channel_args;
}
+grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server) {
+ return server->default_resource_user;
+}
+
int grpc_server_has_open_connections(grpc_server* server) {
int r;
gpr_mu_lock(&server->mu_global);
@@ -1459,3 +1589,11 @@ int grpc_server_has_open_connections(grpc_server* server) {
gpr_mu_unlock(&server->mu_global);
return r;
}
+
+grpc_core::channelz::ServerNode* grpc_server_get_channelz_node(
+ grpc_server* server) {
+ if (server == nullptr) {
+ return nullptr;
+ }
+ return server->channelz_server.get();
+}
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
index c617cc223e..27038fdb7a 100644
--- a/src/core/lib/surface/server.h
+++ b/src/core/lib/surface/server.h
@@ -23,6 +23,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/transport.h"
@@ -38,16 +39,33 @@ void grpc_server_add_listener(grpc_server* server, void* listener,
grpc_pollset** pollsets,
size_t npollsets),
void (*destroy)(grpc_server* server, void* arg,
- grpc_closure* on_done));
+ grpc_closure* on_done),
+ intptr_t socket_uuid);
/* Setup a transport - creates a channel stack, binds the transport to the
server */
void grpc_server_setup_transport(grpc_server* server, grpc_transport* transport,
grpc_pollset* accepting_pollset,
- const grpc_channel_args* args);
+ const grpc_channel_args* args,
+ intptr_t socket_uuid,
+ grpc_resource_user* resource_user = nullptr);
+
+/* fills in the uuids of all sockets used for connections on this server */
+void grpc_server_populate_server_sockets(
+ grpc_server* server, grpc_core::channelz::ChildRefsList* server_sockets,
+ intptr_t start_idx);
+
+/* fills in the uuids of all listen sockets on this server */
+void grpc_server_populate_listen_sockets(
+ grpc_server* server, grpc_core::channelz::ChildRefsList* listen_sockets);
+
+grpc_core::channelz::ServerNode* grpc_server_get_channelz_node(
+ grpc_server* server);
const grpc_channel_args* grpc_server_get_channel_args(grpc_server* server);
+grpc_resource_user* grpc_server_get_default_resource_user(grpc_server* server);
+
int grpc_server_has_open_connections(grpc_server* server);
/* Do not call this before grpc_server_start. Returns the pollsets and the
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index e92fe2c5a1..66890ce65a 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -23,6 +23,6 @@
#include <grpc/grpc.h>
-const char* grpc_version_string(void) { return "6.0.0-dev"; }
+const char* grpc_version_string(void) { return "7.0.0-dev"; }
-const char* grpc_g_stands_for(void) { return "glider"; }
+const char* grpc_g_stands_for(void) { return "gizmo"; }
diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc
index 2eff8b2916..558f1d494c 100644
--- a/src/core/lib/transport/error_utils.cc
+++ b/src/core/lib/transport/error_utils.cc
@@ -26,8 +26,9 @@
static grpc_error* recursively_find_error_with_field(grpc_error* error,
grpc_error_ints which) {
+ intptr_t unused;
// If the error itself has a status code, return it.
- if (grpc_error_get_int(error, which, nullptr)) {
+ if (grpc_error_get_int(error, which, &unused)) {
return error;
}
if (grpc_error_is_special(error)) return nullptr;
@@ -102,7 +103,8 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
}
bool grpc_error_has_clear_grpc_status(grpc_error* error) {
- if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, nullptr)) {
+ intptr_t unused;
+ if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &unused)) {
return true;
}
uint8_t slot = error->first_err;
diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc
index d10194a2fe..60af22393e 100644
--- a/src/core/lib/transport/metadata.cc
+++ b/src/core/lib/transport/metadata.cc
@@ -237,7 +237,7 @@ static void rehash_mdtab(mdtab_shard* shard) {
}
grpc_mdelem grpc_mdelem_create(
- grpc_slice key, grpc_slice value,
+ const grpc_slice& key, const grpc_slice& value,
grpc_mdelem_data* compatible_external_backing_store) {
if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) {
if (compatible_external_backing_store != nullptr) {
@@ -324,7 +324,8 @@ grpc_mdelem grpc_mdelem_create(
return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED);
}
-grpc_mdelem grpc_mdelem_from_slices(grpc_slice key, grpc_slice value) {
+grpc_mdelem grpc_mdelem_from_slices(const grpc_slice& key,
+ const grpc_slice& value) {
grpc_mdelem out = grpc_mdelem_create(key, value, nullptr);
grpc_slice_unref_internal(key);
grpc_slice_unref_internal(value);
@@ -342,24 +343,6 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata) {
changed ? nullptr : reinterpret_cast<grpc_mdelem_data*>(metadata));
}
-static size_t get_base64_encoded_size(size_t raw_length) {
- static const uint8_t tail_xtra[3] = {0, 2, 3};
- return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
-}
-
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
- bool use_true_binary_metadata) {
- size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
- size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
- if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
- return overhead_and_key + (use_true_binary_metadata
- ? value_len + 1
- : get_base64_encoded_size(value_len));
- } else {
- return overhead_and_key + value_len;
- }
-}
-
grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) {
switch (GRPC_MDELEM_STORAGE(gmd)) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 78df4bc3a3..989c7544c1 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -109,7 +109,8 @@ struct grpc_mdelem {
(uintptr_t)GRPC_MDELEM_STORAGE_INTERNED_BIT))
/* Unrefs the slices. */
-grpc_mdelem grpc_mdelem_from_slices(grpc_slice key, grpc_slice value);
+grpc_mdelem grpc_mdelem_from_slices(const grpc_slice& key,
+ const grpc_slice& value);
/* Cheaply convert a grpc_metadata to a grpc_mdelem; may use the grpc_metadata
object as backing storage (so lifetimes should align) */
@@ -120,14 +121,11 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata);
compatible_external_backing_store if it is non-NULL (in which case it's the
users responsibility to ensure that it outlives usage) */
grpc_mdelem grpc_mdelem_create(
- grpc_slice key, grpc_slice value,
+ const grpc_slice& key, const grpc_slice& value,
grpc_mdelem_data* compatible_external_backing_store);
bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
- bool use_true_binary_metadata);
-
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void*));
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index 49740fcd1e..928ed73cda 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -105,7 +105,7 @@ static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
return GRPC_ERROR_NONE;
}
if (batch->idx.array[idx] == nullptr) {
- if (grpc_static_callout_is_default[idx]) ++batch->list.default_count;
+ ++batch->list.default_count;
batch->idx.array[idx] = storage;
return GRPC_ERROR_NONE;
}
@@ -121,7 +121,7 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch,
if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
return;
}
- if (grpc_static_callout_is_default[idx]) --batch->list.default_count;
+ --batch->list.default_count;
GPR_ASSERT(batch->idx.array[idx] != nullptr);
batch->idx.array[idx] = nullptr;
}
@@ -139,6 +139,7 @@ static void link_head(grpc_mdelem_list* list, grpc_linked_mdelem* storage) {
GPR_ASSERT(!GRPC_MDISNULL(storage->md));
storage->prev = nullptr;
storage->next = list->head;
+ storage->reserved = nullptr;
if (list->head != nullptr) {
list->head->prev = storage;
} else {
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 7068750b6f..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;
@@ -82,6 +84,7 @@ void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage)
GRPC_MUST_USE_RESULT;
+
/** Add \a storage to the end of \a batch. storage->md is
assumed to be valid.
\a storage is owned by the caller and must survive for the
@@ -100,6 +103,7 @@ grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
grpc_error* grpc_metadata_batch_add_head(
grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
+
/** Add \a elem_to_add as the last element in \a batch, using
\a storage as backing storage for the linked list element.
\a storage is owned by the caller and must survive for the
diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc
index 6a5144f21a..4ebe73f82a 100644
--- a/src/core/lib/transport/static_metadata.cc
+++ b/src/core/lib/transport/static_metadata.cc
@@ -63,51 +63,53 @@ static uint8_t g_bytes[] = {
115, 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 47, 103, 114, 112,
99, 46, 108, 98, 46, 118, 49, 46, 76, 111, 97, 100, 66, 97, 108,
97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111,
- 97, 100, 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116,
- 114, 101, 97, 109, 47, 103, 122, 105, 112, 48, 105, 100, 101, 110, 116,
- 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97, 112, 112, 108,
- 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99, 80, 79, 83,
- 84, 50, 48, 48, 52, 48, 52, 104, 116, 116, 112, 104, 116, 116, 112,
- 115, 103, 114, 112, 99, 71, 69, 84, 80, 85, 84, 47, 47, 105, 110,
- 100, 101, 120, 46, 104, 116, 109, 108, 50, 48, 52, 50, 48, 54, 51,
- 48, 52, 52, 48, 48, 53, 48, 48, 97, 99, 99, 101, 112, 116, 45,
- 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44, 32, 100, 101,
- 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45, 108, 97, 110,
- 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45, 114, 97, 110,
- 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99, 101, 115, 115,
- 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108, 111, 119, 45,
- 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108, 111, 119, 97,
- 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 99, 97, 99,
- 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111, 110, 116, 101,
- 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99,
- 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
- 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 99,
- 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116, 105, 111, 110,
- 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103, 101, 99, 111,
- 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103, 101, 120, 112,
- 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105,
- 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111, 100, 105, 102,
- 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45, 110, 111, 110,
- 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97, 110, 103, 101,
- 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
- 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100, 105, 102, 105,
- 101, 100, 108, 98, 45, 99, 111, 115, 116, 45, 98, 105, 110, 108, 105,
- 110, 107, 108, 111, 99, 97, 116, 105, 111, 110, 109, 97, 120, 45, 102,
- 111, 114, 119, 97, 114, 100, 115, 112, 114, 111, 120, 121, 45, 97, 117,
- 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 112, 114, 111, 120, 121,
- 45, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 114,
- 97, 110, 103, 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114,
- 101, 115, 104, 114, 101, 116, 114, 121, 45, 97, 102, 116, 101, 114, 115,
- 101, 114, 118, 101, 114, 115, 101, 116, 45, 99, 111, 111, 107, 105, 101,
- 115, 116, 114, 105, 99, 116, 45, 116, 114, 97, 110, 115, 112, 111, 114,
- 116, 45, 115, 101, 99, 117, 114, 105, 116, 121, 116, 114, 97, 110, 115,
- 102, 101, 114, 45, 101, 110, 99, 111, 100, 105, 110, 103, 118, 97, 114,
- 121, 118, 105, 97, 119, 119, 119, 45, 97, 117, 116, 104, 101, 110, 116,
- 105, 99, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100,
- 101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44,
- 103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105,
- 112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97,
- 116, 101, 44, 103, 122, 105, 112};
+ 97, 100, 47, 103, 114, 112, 99, 46, 104, 101, 97, 108, 116, 104, 46,
+ 118, 49, 46, 72, 101, 97, 108, 116, 104, 47, 87, 97, 116, 99, 104,
+ 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116, 114, 101,
+ 97, 109, 47, 103, 122, 105, 112, 71, 69, 84, 80, 79, 83, 84, 47,
+ 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 104, 116, 116, 112,
+ 104, 116, 116, 112, 115, 50, 48, 48, 50, 48, 52, 50, 48, 54, 51,
+ 48, 52, 52, 48, 48, 52, 48, 52, 53, 48, 48, 97, 99, 99, 101,
+ 112, 116, 45, 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44,
+ 32, 100, 101, 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45,
+ 108, 97, 110, 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45,
+ 114, 97, 110, 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99,
+ 101, 115, 115, 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108,
+ 111, 119, 45, 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108,
+ 111, 119, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110,
+ 99, 97, 99, 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111,
+ 110, 116, 101, 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105,
+ 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117,
+ 97, 103, 101, 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103,
+ 116, 104, 99, 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116,
+ 105, 111, 110, 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103,
+ 101, 99, 111, 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103,
+ 101, 120, 112, 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114,
+ 111, 109, 105, 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111,
+ 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45,
+ 110, 111, 110, 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97,
+ 110, 103, 101, 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101,
+ 100, 45, 115, 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100,
+ 105, 102, 105, 101, 100, 108, 105, 110, 107, 108, 111, 99, 97, 116, 105,
+ 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114, 100, 115, 112,
+ 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97,
+ 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 111, 114, 105,
+ 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114, 101, 102, 101,
+ 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121,
+ 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116,
+ 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99, 116, 45, 116,
+ 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99, 117, 114, 105,
+ 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101, 110, 99, 111,
+ 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119, 119, 119, 45,
+ 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 48, 105, 100,
+ 101, 110, 116, 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97,
+ 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99,
+ 103, 114, 112, 99, 80, 85, 84, 108, 98, 45, 99, 111, 115, 116, 45,
+ 98, 105, 110, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102,
+ 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 103, 122,
+ 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112, 105,
+ 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101,
+ 44, 103, 122, 105, 112};
static void static_ref(void* unused) {}
static void static_unref(void* unused) {}
@@ -224,6 +226,7 @@ grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
};
const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@@ -262,76 +265,77 @@ const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_refcounts[32], {{g_bytes + 385, 30}}},
{&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 493, 11}}},
- {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}},
- {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}},
- {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}},
- {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}},
- {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}},
- {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}},
- {&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
- {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}},
- {&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
- {&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
- {&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
- {&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
- {&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
- {&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
- {&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
- {&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
- {&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
- {&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
- {&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
- {&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
- {&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
- {&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
- {&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
- {&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
- {&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
- {&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
- {&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
- {&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
- {&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
- {&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
- {&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
- {&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
- {&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
- {&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
- {&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
- {&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
- {&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
- {&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
- {&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
- {&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
- {&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
- {&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
- {&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
- {&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
- {&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
- {&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
- {&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
- {&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
- {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}},
- {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}},
- {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}},
- {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}},
+ {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 28}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 521, 11}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 532, 3}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 535, 4}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 539, 1}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 540, 11}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 551, 4}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 555, 5}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 560, 3}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 563, 3}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 566, 3}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 569, 3}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 572, 3}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 575, 3}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 578, 3}}},
+ {&grpc_static_metadata_refcounts[52], {{g_bytes + 581, 14}}},
+ {&grpc_static_metadata_refcounts[53], {{g_bytes + 595, 13}}},
+ {&grpc_static_metadata_refcounts[54], {{g_bytes + 608, 15}}},
+ {&grpc_static_metadata_refcounts[55], {{g_bytes + 623, 13}}},
+ {&grpc_static_metadata_refcounts[56], {{g_bytes + 636, 6}}},
+ {&grpc_static_metadata_refcounts[57], {{g_bytes + 642, 27}}},
+ {&grpc_static_metadata_refcounts[58], {{g_bytes + 669, 3}}},
+ {&grpc_static_metadata_refcounts[59], {{g_bytes + 672, 5}}},
+ {&grpc_static_metadata_refcounts[60], {{g_bytes + 677, 13}}},
+ {&grpc_static_metadata_refcounts[61], {{g_bytes + 690, 13}}},
+ {&grpc_static_metadata_refcounts[62], {{g_bytes + 703, 19}}},
+ {&grpc_static_metadata_refcounts[63], {{g_bytes + 722, 16}}},
+ {&grpc_static_metadata_refcounts[64], {{g_bytes + 738, 14}}},
+ {&grpc_static_metadata_refcounts[65], {{g_bytes + 752, 16}}},
+ {&grpc_static_metadata_refcounts[66], {{g_bytes + 768, 13}}},
+ {&grpc_static_metadata_refcounts[67], {{g_bytes + 781, 6}}},
+ {&grpc_static_metadata_refcounts[68], {{g_bytes + 787, 4}}},
+ {&grpc_static_metadata_refcounts[69], {{g_bytes + 791, 4}}},
+ {&grpc_static_metadata_refcounts[70], {{g_bytes + 795, 6}}},
+ {&grpc_static_metadata_refcounts[71], {{g_bytes + 801, 7}}},
+ {&grpc_static_metadata_refcounts[72], {{g_bytes + 808, 4}}},
+ {&grpc_static_metadata_refcounts[73], {{g_bytes + 812, 8}}},
+ {&grpc_static_metadata_refcounts[74], {{g_bytes + 820, 17}}},
+ {&grpc_static_metadata_refcounts[75], {{g_bytes + 837, 13}}},
+ {&grpc_static_metadata_refcounts[76], {{g_bytes + 850, 8}}},
+ {&grpc_static_metadata_refcounts[77], {{g_bytes + 858, 19}}},
+ {&grpc_static_metadata_refcounts[78], {{g_bytes + 877, 13}}},
+ {&grpc_static_metadata_refcounts[79], {{g_bytes + 890, 4}}},
+ {&grpc_static_metadata_refcounts[80], {{g_bytes + 894, 8}}},
+ {&grpc_static_metadata_refcounts[81], {{g_bytes + 902, 12}}},
+ {&grpc_static_metadata_refcounts[82], {{g_bytes + 914, 18}}},
+ {&grpc_static_metadata_refcounts[83], {{g_bytes + 932, 19}}},
+ {&grpc_static_metadata_refcounts[84], {{g_bytes + 951, 5}}},
+ {&grpc_static_metadata_refcounts[85], {{g_bytes + 956, 7}}},
+ {&grpc_static_metadata_refcounts[86], {{g_bytes + 963, 7}}},
+ {&grpc_static_metadata_refcounts[87], {{g_bytes + 970, 11}}},
+ {&grpc_static_metadata_refcounts[88], {{g_bytes + 981, 6}}},
+ {&grpc_static_metadata_refcounts[89], {{g_bytes + 987, 10}}},
+ {&grpc_static_metadata_refcounts[90], {{g_bytes + 997, 25}}},
+ {&grpc_static_metadata_refcounts[91], {{g_bytes + 1022, 17}}},
+ {&grpc_static_metadata_refcounts[92], {{g_bytes + 1039, 4}}},
+ {&grpc_static_metadata_refcounts[93], {{g_bytes + 1043, 3}}},
+ {&grpc_static_metadata_refcounts[94], {{g_bytes + 1046, 16}}},
+ {&grpc_static_metadata_refcounts[95], {{g_bytes + 1062, 1}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1071, 8}}},
+ {&grpc_static_metadata_refcounts[98], {{g_bytes + 1079, 16}}},
+ {&grpc_static_metadata_refcounts[99], {{g_bytes + 1095, 4}}},
+ {&grpc_static_metadata_refcounts[100], {{g_bytes + 1099, 3}}},
+ {&grpc_static_metadata_refcounts[101], {{g_bytes + 1102, 11}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1113, 16}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1142, 12}}},
+ {&grpc_static_metadata_refcounts[105], {{g_bytes + 1154, 21}}},
};
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@@ -341,16 +345,17 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4};
static const int8_t elems_r[] = {
- 16, 11, -1, 0, 15, 2, -78, 24, 0, 18, -5, 0, 0, 0, 17, 14, -8, 0,
- 0, 27, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, -64, 0, -44, -43, -70, 0, 34, 33, 33, 32, 31, 30, 29, 28, 27,
- 27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12,
- 11, 14, 13, 12, 11, 10, 9, 9, 8, 7, 6, 5, 0};
+ 16, 11, -8, 0, 3, -42, -81, -43, 0, 6, -8, 0, 0, 0, -7,
+ -3, -10, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -63, 0, -47, -68, -69, -70, 0, 33,
+ 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 20,
+ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
+ 4, 4, 4, 3, 10, 9, 0, 0, 0, 0, 0, 0, -3, 0};
static uint32_t elems_phash(uint32_t i) {
- i -= 50;
- uint32_t x = i % 103;
- uint32_t y = i / 103;
+ i -= 41;
+ uint32_t x = i % 104;
+ uint32_t y = i / 104;
uint32_t h = x;
if (y < GPR_ARRAY_SIZE(elems_r)) {
uint32_t delta = (uint32_t)elems_r[y];
@@ -360,32 +365,29 @@ static uint32_t elems_phash(uint32_t i) {
}
static const uint16_t elem_keys[] = {
- 1085, 1086, 565, 1709, 1089, 262, 263, 264, 265, 266, 1716,
- 153, 154, 1719, 760, 761, 50, 51, 465, 466, 467, 980,
- 981, 1604, 1499, 984, 773, 2129, 2234, 6014, 1611, 6434, 1738,
- 1614, 6539, 6644, 1511, 6749, 6854, 6959, 7064, 7169, 7274, 7379,
- 2024, 7484, 7589, 7694, 7799, 7904, 8009, 8114, 8219, 6224, 8324,
- 8429, 6329, 8534, 8639, 8744, 8849, 8954, 9059, 9164, 9269, 9374,
- 1151, 1152, 1153, 1154, 9479, 9584, 9689, 9794, 9899, 10004, 1782,
- 10109, 10214, 10319, 10424, 10529, 0, 0, 0, 0, 0, 344,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 253, 254, 147, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0};
+ 257, 258, 259, 260, 261, 262, 263, 1096, 1097, 1513, 1725, 145,
+ 146, 467, 468, 1619, 41, 42, 1733, 990, 991, 767, 768, 1627,
+ 627, 837, 2043, 2149, 2255, 5541, 5859, 5965, 6071, 6177, 1749, 6283,
+ 6389, 6495, 6601, 6707, 6813, 6919, 7025, 7131, 7237, 7343, 7449, 7555,
+ 7661, 5753, 7767, 7873, 7979, 8085, 8191, 8297, 8403, 8509, 8615, 8721,
+ 8827, 8933, 9039, 9145, 9251, 9357, 9463, 1156, 9569, 523, 9675, 9781,
+ 206, 1162, 1163, 1164, 1165, 1792, 1582, 1050, 9887, 9993, 1686, 10735,
+ 1799, 0, 0, 0, 0, 0, 347, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
static const uint8_t elem_idxs[] = {
- 77, 79, 6, 25, 76, 19, 20, 21, 22, 23, 84, 15, 16, 83, 1,
- 2, 17, 18, 11, 12, 13, 5, 4, 38, 43, 3, 0, 50, 57, 24,
- 37, 29, 26, 36, 30, 31, 7, 32, 33, 34, 35, 39, 40, 41, 72,
- 42, 44, 45, 46, 47, 48, 49, 51, 27, 52, 53, 28, 54, 55, 56,
- 58, 59, 60, 61, 62, 63, 78, 80, 81, 82, 64, 65, 66, 67, 68,
- 69, 85, 70, 71, 73, 74, 75, 255, 255, 255, 255, 255, 14, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 9, 10, 8};
+ 7, 8, 9, 10, 11, 12, 13, 77, 79, 30, 71, 1, 2, 5, 6, 25,
+ 3, 4, 84, 66, 65, 62, 63, 73, 67, 61, 57, 37, 74, 14, 17, 18,
+ 19, 20, 15, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 34, 35,
+ 36, 16, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 76, 55, 69, 56, 58, 70, 78, 80, 81, 82, 83, 68, 64,
+ 59, 60, 72, 75, 85, 255, 255, 255, 255, 255, 0};
grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
if (a == -1 || b == -1) return GRPC_MDNULL;
- uint32_t k = (uint32_t)(a * 105 + b);
+ uint32_t k = (uint32_t)(a * 106 + b);
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
@@ -395,206 +397,179 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
}
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
- {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}},
- {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
- {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
- {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
- {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
- {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
- {{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}},
- {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}},
- {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}},
- {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}},
- {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}},
- {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}},
- {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}},
- {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}},
{{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 532, 3}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 535, 4}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 539, 1}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 540, 11}}}},
+ {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 551, 4}}}},
+ {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 555, 5}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 560, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 563, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 566, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 569, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}},
- {{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
- {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 572, 3}}}},
+ {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 575, 3}}}},
+ {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 578, 3}}}},
+ {{&grpc_static_metadata_refcounts[52], {{g_bytes + 581, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}},
- {{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
+ {&grpc_static_metadata_refcounts[53], {{g_bytes + 595, 13}}}},
+ {{&grpc_static_metadata_refcounts[54], {{g_bytes + 608, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
+ {{&grpc_static_metadata_refcounts[55], {{g_bytes + 623, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
+ {{&grpc_static_metadata_refcounts[56], {{g_bytes + 636, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
+ {{&grpc_static_metadata_refcounts[57], {{g_bytes + 642, 27}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
+ {{&grpc_static_metadata_refcounts[58], {{g_bytes + 669, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
+ {{&grpc_static_metadata_refcounts[59], {{g_bytes + 672, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
+ {{&grpc_static_metadata_refcounts[60], {{g_bytes + 677, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
+ {{&grpc_static_metadata_refcounts[61], {{g_bytes + 690, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
+ {{&grpc_static_metadata_refcounts[62], {{g_bytes + 703, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
- {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
- {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
+ {{&grpc_static_metadata_refcounts[63], {{g_bytes + 722, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
+ {{&grpc_static_metadata_refcounts[64], {{g_bytes + 738, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
+ {{&grpc_static_metadata_refcounts[65], {{g_bytes + 752, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
+ {{&grpc_static_metadata_refcounts[66], {{g_bytes + 768, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
+ {{&grpc_static_metadata_refcounts[67], {{g_bytes + 781, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
+ {{&grpc_static_metadata_refcounts[68], {{g_bytes + 787, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
+ {{&grpc_static_metadata_refcounts[69], {{g_bytes + 791, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
+ {{&grpc_static_metadata_refcounts[70], {{g_bytes + 795, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
+ {{&grpc_static_metadata_refcounts[71], {{g_bytes + 801, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
+ {{&grpc_static_metadata_refcounts[72], {{g_bytes + 808, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
+ {{&grpc_static_metadata_refcounts[73], {{g_bytes + 812, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
+ {{&grpc_static_metadata_refcounts[74], {{g_bytes + 820, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
+ {{&grpc_static_metadata_refcounts[75], {{g_bytes + 837, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
+ {{&grpc_static_metadata_refcounts[76], {{g_bytes + 850, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
+ {{&grpc_static_metadata_refcounts[77], {{g_bytes + 858, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
+ {{&grpc_static_metadata_refcounts[78], {{g_bytes + 877, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
+ {{&grpc_static_metadata_refcounts[79], {{g_bytes + 890, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
+ {{&grpc_static_metadata_refcounts[80], {{g_bytes + 894, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
+ {{&grpc_static_metadata_refcounts[81], {{g_bytes + 902, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
+ {{&grpc_static_metadata_refcounts[82], {{g_bytes + 914, 18}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
+ {{&grpc_static_metadata_refcounts[83], {{g_bytes + 932, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
+ {{&grpc_static_metadata_refcounts[84], {{g_bytes + 951, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
+ {{&grpc_static_metadata_refcounts[85], {{g_bytes + 956, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
+ {{&grpc_static_metadata_refcounts[86], {{g_bytes + 963, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
+ {{&grpc_static_metadata_refcounts[87], {{g_bytes + 970, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
+ {{&grpc_static_metadata_refcounts[88], {{g_bytes + 981, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
+ {{&grpc_static_metadata_refcounts[89], {{g_bytes + 987, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
+ {{&grpc_static_metadata_refcounts[90], {{g_bytes + 997, 25}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
+ {{&grpc_static_metadata_refcounts[91], {{g_bytes + 1022, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
+ {{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
+ {{&grpc_static_metadata_refcounts[92], {{g_bytes + 1039, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
+ {{&grpc_static_metadata_refcounts[93], {{g_bytes + 1043, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
+ {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1046, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
+ {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
+ {&grpc_static_metadata_refcounts[95], {{g_bytes + 1062, 1}}}},
+ {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
+ {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
+ {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
+ {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
+ {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}}},
+ {{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1071, 8}}}},
+ {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
+ {&grpc_static_metadata_refcounts[98], {{g_bytes + 1079, 16}}}},
+ {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
+ {&grpc_static_metadata_refcounts[99], {{g_bytes + 1095, 4}}}},
+ {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
+ {&grpc_static_metadata_refcounts[100], {{g_bytes + 1099, 3}}}},
+ {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
- {{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
+ {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
+ {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
+ {{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[101], {{g_bytes + 1102, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 510, 7}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1113, 16}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1142, 12}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}}},
+ {&grpc_static_metadata_refcounts[105], {{g_bytes + 1154, 21}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1063, 8}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 517, 4}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1129, 13}}}},
};
-bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
- true, // :path
- true, // :method
- true, // :status
- true, // :authority
- true, // :scheme
- true, // te
- true, // grpc-message
- true, // grpc-status
- true, // grpc-payload-bin
- true, // grpc-encoding
- true, // grpc-accept-encoding
- true, // grpc-server-stats-bin
- true, // grpc-tags-bin
- true, // grpc-trace-bin
- true, // content-type
- true, // content-encoding
- true, // accept-encoding
- true, // grpc-internal-encoding-request
- true, // grpc-internal-stream-encoding-request
- true, // user-agent
- true, // host
- true, // lb-token
- true, // grpc-previous-rpc-attempts
- true, // grpc-retry-pushback-ms
-};
-
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index b3a10f5873..2bb9f72838 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -31,7 +31,7 @@
#include "src/core/lib/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 105
+#define GRPC_STATIC_MDSTR_COUNT 106
extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* ":path" */
#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@@ -107,147 +107,150 @@ extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
(grpc_static_slice_table[34])
+/* "/grpc.health.v1.Health/Watch" */
+#define GRPC_MDSTR_SLASH_GRPC_DOT_HEALTH_DOT_V1_DOT_HEALTH_SLASH_WATCH \
+ (grpc_static_slice_table[35])
/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[35])
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[36])
/* "gzip" */
-#define GRPC_MDSTR_GZIP (grpc_static_slice_table[36])
+#define GRPC_MDSTR_GZIP (grpc_static_slice_table[37])
/* "stream/gzip" */
-#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[37])
-/* "0" */
-#define GRPC_MDSTR_0 (grpc_static_slice_table[38])
-/* "identity" */
-#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[39])
-/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[40])
-/* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[41])
-/* "POST" */
-#define GRPC_MDSTR_POST (grpc_static_slice_table[42])
-/* "200" */
-#define GRPC_MDSTR_200 (grpc_static_slice_table[43])
-/* "404" */
-#define GRPC_MDSTR_404 (grpc_static_slice_table[44])
-/* "http" */
-#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45])
-/* "https" */
-#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46])
-/* "grpc" */
-#define GRPC_MDSTR_GRPC (grpc_static_slice_table[47])
+#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[38])
/* "GET" */
-#define GRPC_MDSTR_GET (grpc_static_slice_table[48])
-/* "PUT" */
-#define GRPC_MDSTR_PUT (grpc_static_slice_table[49])
+#define GRPC_MDSTR_GET (grpc_static_slice_table[39])
+/* "POST" */
+#define GRPC_MDSTR_POST (grpc_static_slice_table[40])
/* "/" */
-#define GRPC_MDSTR_SLASH (grpc_static_slice_table[50])
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[41])
/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[51])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[42])
+/* "http" */
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[43])
+/* "https" */
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[44])
+/* "200" */
+#define GRPC_MDSTR_200 (grpc_static_slice_table[45])
/* "204" */
-#define GRPC_MDSTR_204 (grpc_static_slice_table[52])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[46])
/* "206" */
-#define GRPC_MDSTR_206 (grpc_static_slice_table[53])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[47])
/* "304" */
-#define GRPC_MDSTR_304 (grpc_static_slice_table[54])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[48])
/* "400" */
-#define GRPC_MDSTR_400 (grpc_static_slice_table[55])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[49])
+/* "404" */
+#define GRPC_MDSTR_404 (grpc_static_slice_table[50])
/* "500" */
-#define GRPC_MDSTR_500 (grpc_static_slice_table[56])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[51])
/* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[57])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[52])
/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[58])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[53])
/* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[59])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[54])
/* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[60])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[55])
/* "accept" */
-#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[61])
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[56])
/* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[62])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[57])
/* "age" */
-#define GRPC_MDSTR_AGE (grpc_static_slice_table[63])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[58])
/* "allow" */
-#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[64])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[59])
/* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[65])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[60])
/* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[66])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[61])
/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[67])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[62])
/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[68])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[63])
/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[69])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[64])
/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[70])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[65])
/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[71])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[66])
/* "cookie" */
-#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[72])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[67])
/* "date" */
-#define GRPC_MDSTR_DATE (grpc_static_slice_table[73])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[68])
/* "etag" */
-#define GRPC_MDSTR_ETAG (grpc_static_slice_table[74])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[69])
/* "expect" */
-#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[75])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[70])
/* "expires" */
-#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[76])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[71])
/* "from" */
-#define GRPC_MDSTR_FROM (grpc_static_slice_table[77])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[72])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[78])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[73])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[79])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[74])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[80])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[75])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[81])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[76])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[82])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[77])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[83])
-/* "lb-cost-bin" */
-#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[84])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[78])
/* "link" */
-#define GRPC_MDSTR_LINK (grpc_static_slice_table[85])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[79])
/* "location" */
-#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[86])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[80])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[87])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[81])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[88])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[82])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[89])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[83])
/* "range" */
-#define GRPC_MDSTR_RANGE (grpc_static_slice_table[90])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[84])
/* "referer" */
-#define GRPC_MDSTR_REFERER (grpc_static_slice_table[91])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[85])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[92])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[86])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[93])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[87])
/* "server" */
-#define GRPC_MDSTR_SERVER (grpc_static_slice_table[94])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[88])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[95])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[89])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[96])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[90])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[97])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[91])
/* "vary" */
-#define GRPC_MDSTR_VARY (grpc_static_slice_table[98])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[92])
/* "via" */
-#define GRPC_MDSTR_VIA (grpc_static_slice_table[99])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[93])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[100])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[94])
+/* "0" */
+#define GRPC_MDSTR_0 (grpc_static_slice_table[95])
+/* "identity" */
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[96])
+/* "trailers" */
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[97])
+/* "application/grpc" */
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[98])
+/* "grpc" */
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[99])
+/* "PUT" */
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[100])
+/* "lb-cost-bin" */
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[101])
/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[101])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[102])
/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[102])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[103])
/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[103])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[104])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (grpc_static_slice_table[104])
+ (grpc_static_slice_table[105])
extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
extern grpc_slice_refcount
@@ -262,233 +265,233 @@ extern grpc_slice_refcount
#define GRPC_STATIC_MDELEM_COUNT 86
extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
-/* "grpc-status": "0" */
-#define GRPC_MDELEM_GRPC_STATUS_0 \
+/* ":authority": "" */
+#define GRPC_MDELEM_AUTHORITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC))
-/* "grpc-status": "1" */
-#define GRPC_MDELEM_GRPC_STATUS_1 \
+/* ":method": "GET" */
+#define GRPC_MDELEM_METHOD_GET \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC))
-/* "grpc-status": "2" */
-#define GRPC_MDELEM_GRPC_STATUS_2 \
+/* ":method": "POST" */
+#define GRPC_MDELEM_METHOD_POST \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC))
-/* "grpc-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
+/* ":path": "/" */
+#define GRPC_MDELEM_PATH_SLASH \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC))
-/* "grpc-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
+/* ":path": "/index.html" */
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC))
-/* "grpc-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
-/* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
-/* "content-type": "application/grpc" */
-#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
-/* ":method": "POST" */
-#define GRPC_MDELEM_METHOD_POST \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
-/* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
-/* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "http" */
#define GRPC_MDELEM_SCHEME_HTTP \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "https" */
#define GRPC_MDELEM_SCHEME_HTTPS \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
-/* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
-/* ":authority": "" */
-#define GRPC_MDELEM_AUTHORITY_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
-/* ":method": "GET" */
-#define GRPC_MDELEM_METHOD_GET \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
-/* ":method": "PUT" */
-#define GRPC_MDELEM_METHOD_PUT \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
-/* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
-/* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "200" */
+#define GRPC_MDELEM_STATUS_200 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "204" */
#define GRPC_MDELEM_STATUS_204 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "206" */
#define GRPC_MDELEM_STATUS_206 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "304" */
#define GRPC_MDELEM_STATUS_304 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "400" */
#define GRPC_MDELEM_STATUS_400 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
+/* ":status": "404" */
+#define GRPC_MDELEM_STATUS_404 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "500" */
#define GRPC_MDELEM_STATUS_500 \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-charset": "" */
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
-/* "accept-encoding": "" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-language": "" */
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
/* "accept-ranges": "" */
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
/* "accept": "" */
#define GRPC_MDELEM_ACCEPT_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
/* "age": "" */
#define GRPC_MDELEM_AGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
/* "allow": "" */
#define GRPC_MDELEM_ALLOW_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
/* "authorization": "" */
#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
/* "cache-control": "" */
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
/* "content-disposition": "" */
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
-/* "content-encoding": "identity" */
-#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
-/* "content-encoding": "gzip" */
-#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "" */
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
/* "content-language": "" */
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
/* "content-length": "" */
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
/* "content-location": "" */
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
/* "content-range": "" */
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "" */
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
/* "cookie": "" */
#define GRPC_MDELEM_COOKIE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
/* "date": "" */
#define GRPC_MDELEM_DATE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
/* "etag": "" */
#define GRPC_MDELEM_ETAG_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
/* "expect": "" */
#define GRPC_MDELEM_EXPECT_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
/* "expires": "" */
#define GRPC_MDELEM_EXPIRES_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
/* "from": "" */
#define GRPC_MDELEM_FROM_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
/* "host": "" */
#define GRPC_MDELEM_HOST_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
/* "if-match": "" */
#define GRPC_MDELEM_IF_MATCH_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
/* "if-modified-since": "" */
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
/* "if-none-match": "" */
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
/* "if-range": "" */
#define GRPC_MDELEM_IF_RANGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
/* "if-unmodified-since": "" */
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
/* "last-modified": "" */
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
-/* "lb-token": "" */
-#define GRPC_MDELEM_LB_TOKEN_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
-/* "lb-cost-bin": "" */
-#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
/* "link": "" */
#define GRPC_MDELEM_LINK_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
/* "location": "" */
#define GRPC_MDELEM_LOCATION_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
/* "max-forwards": "" */
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authenticate": "" */
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authorization": "" */
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
/* "range": "" */
#define GRPC_MDELEM_RANGE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
/* "referer": "" */
#define GRPC_MDELEM_REFERER_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
/* "refresh": "" */
#define GRPC_MDELEM_REFRESH_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
/* "retry-after": "" */
#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
/* "server": "" */
#define GRPC_MDELEM_SERVER_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
/* "set-cookie": "" */
#define GRPC_MDELEM_SET_COOKIE_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
/* "transfer-encoding": "" */
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
/* "user-agent": "" */
#define GRPC_MDELEM_USER_AGENT_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
/* "vary": "" */
#define GRPC_MDELEM_VARY_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
/* "via": "" */
#define GRPC_MDELEM_VIA_EMPTY \
- (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
/* "www-authenticate": "" */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-status": "0" */
+#define GRPC_MDELEM_GRPC_STATUS_0 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-status": "1" */
+#define GRPC_MDELEM_GRPC_STATUS_1 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-status": "2" */
+#define GRPC_MDELEM_GRPC_STATUS_2 \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "identity" */
+#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "gzip" */
+#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
+/* "grpc-encoding": "deflate" */
+#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
+/* "te": "trailers" */
+#define GRPC_MDELEM_TE_TRAILERS \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
+/* "content-type": "application/grpc" */
+#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
+/* ":scheme": "grpc" */
+#define GRPC_MDELEM_SCHEME_GRPC \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
+/* ":method": "PUT" */
+#define GRPC_MDELEM_METHOD_PUT \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
+/* "accept-encoding": "" */
+#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
+/* "content-encoding": "identity" */
+#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
+/* "content-encoding": "gzip" */
+#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
+/* "lb-token": "" */
+#define GRPC_MDELEM_LB_TOKEN_EMPTY \
+ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
+/* "lb-cost-bin": "" */
+#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
@@ -587,8 +590,6 @@ typedef union {
GRPC_BATCH_CALLOUTS_COUNT) \
: GRPC_BATCH_CALLOUTS_COUNT)
-extern bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT];
-
extern const uint8_t grpc_static_accept_encoding_metadata[8];
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_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/plugin_registry/grpc_cronet_plugin_registry.cc b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
index c0c17b0a4b..92085d31d7 100644
--- a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
@@ -28,8 +28,6 @@ void grpc_deadline_filter_init(void);
void grpc_deadline_filter_shutdown(void);
void grpc_client_channel_init(void);
void grpc_client_channel_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
void grpc_register_built_in_plugins(void) {
grpc_register_plugin(grpc_http_filters_init,
@@ -40,6 +38,4 @@ void grpc_register_built_in_plugins(void) {
grpc_deadline_filter_shutdown);
grpc_register_plugin(grpc_client_channel_init,
grpc_client_channel_shutdown);
- grpc_register_plugin(grpc_tsi_alts_init,
- grpc_tsi_alts_shutdown);
}
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index fb523a173d..cde40ef65c 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -28,14 +28,14 @@ void grpc_deadline_filter_init(void);
void grpc_deadline_filter_shutdown(void);
void grpc_client_channel_init(void);
void grpc_client_channel_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
void grpc_inproc_plugin_init(void);
void grpc_inproc_plugin_shutdown(void);
void grpc_resolver_fake_init(void);
void grpc_resolver_fake_shutdown(void);
void grpc_lb_policy_grpclb_init(void);
void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_xds_init(void);
+void grpc_lb_policy_xds_shutdown(void);
void grpc_lb_policy_pick_first_init(void);
void grpc_lb_policy_pick_first_shutdown(void);
void grpc_lb_policy_round_robin_init(void);
@@ -64,14 +64,14 @@ void grpc_register_built_in_plugins(void) {
grpc_deadline_filter_shutdown);
grpc_register_plugin(grpc_client_channel_init,
grpc_client_channel_shutdown);
- grpc_register_plugin(grpc_tsi_alts_init,
- grpc_tsi_alts_shutdown);
grpc_register_plugin(grpc_inproc_plugin_init,
grpc_inproc_plugin_shutdown);
grpc_register_plugin(grpc_resolver_fake_init,
grpc_resolver_fake_shutdown);
grpc_register_plugin(grpc_lb_policy_grpclb_init,
grpc_lb_policy_grpclb_shutdown);
+ grpc_register_plugin(grpc_lb_policy_xds_init,
+ grpc_lb_policy_xds_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
index 80214aebe2..5749ab6b95 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
@@ -40,6 +40,8 @@ void grpc_resolver_fake_init(void);
void grpc_resolver_fake_shutdown(void);
void grpc_lb_policy_grpclb_init(void);
void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_xds_init(void);
+void grpc_lb_policy_xds_shutdown(void);
void grpc_lb_policy_pick_first_init(void);
void grpc_lb_policy_pick_first_shutdown(void);
void grpc_lb_policy_round_robin_init(void);
@@ -74,6 +76,8 @@ void grpc_register_built_in_plugins(void) {
grpc_resolver_fake_shutdown);
grpc_register_plugin(grpc_lb_policy_grpclb_init,
grpc_lb_policy_grpclb_shutdown);
+ grpc_register_plugin(grpc_lb_policy_xds_init,
+ grpc_lb_policy_xds_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
index b5268add0d..1de6264183 100644
--- a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
@@ -24,30 +24,166 @@
#include <grpc/support/alloc.h>
#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;
@@ -58,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;
}
@@ -81,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);
@@ -90,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);
@@ -109,25 +249,27 @@ static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
if (ok) {
buffer = grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */);
}
- grpc_slice_unref(slice);
+ grpc_slice_unref_internal(slice);
gpr_free(target_name);
grpc_gcp_handshaker_req_destroy(req);
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");
}
@@ -136,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(
@@ -147,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);
@@ -157,25 +302,27 @@ static grpc_byte_buffer* get_serialized_start_server(
if (ok) {
buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
}
- grpc_slice_unref(req_slice);
+ grpc_slice_unref_internal(req_slice);
grpc_gcp_handshaker_req_destroy(req);
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");
}
@@ -195,45 +342,53 @@ static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) {
if (ok) {
buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
}
- grpc_slice_unref(req_slice);
+ grpc_slice_unref_internal(req_slice);
grpc_gcp_handshaker_req_destroy(req);
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) {
+ grpc_call_cancel_internal(client->call);
+ }
}
-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 = {
@@ -242,23 +397,46 @@ 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;
- grpc_slice_unref(slice);
+ 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;
}
@@ -266,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");
@@ -288,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");
@@ -300,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");
@@ -318,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_handshaker_service_api_util.cc b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
index e0e4184686..d63d3538c5 100644
--- a/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
@@ -20,6 +20,8 @@
#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h"
+#include "src/core/lib/slice/slice_internal.h"
+
void add_repeated_field(repeated_field** head, const void* data) {
repeated_field* field =
static_cast<repeated_field*>(gpr_zalloc(sizeof(*field)));
@@ -67,7 +69,7 @@ grpc_slice* create_slice(const char* data, size_t size) {
void destroy_slice(grpc_slice* slice) {
if (slice != nullptr) {
- grpc_slice_unref(*slice);
+ grpc_slice_unref_internal(*slice);
gpr_free(slice);
}
}
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..3501257f05
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_shared_resource.cc
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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;
+
+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;
+ gpr_mu_init(&g_alts_resource_dedicated.mu);
+}
+
+void grpc_alts_shared_resource_dedicated_start(
+ const char* handshaker_service_url) {
+ gpr_mu_lock(&g_alts_resource_dedicated.mu);
+ if (g_alts_resource_dedicated.cq == nullptr) {
+ g_alts_resource_dedicated.channel =
+ grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr);
+ 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();
+ }
+ gpr_mu_unlock(&g_alts_resource_dedicated.mu);
+}
+
+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);
+ grpc_channel_destroy(g_alts_resource_dedicated.channel);
+ }
+ gpr_mu_destroy(&g_alts_resource_dedicated.mu);
+}
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..8ae0089a11
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_shared_resource.h
@@ -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.
+ *
+ */
+
+#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;
+ gpr_mu mu;
+ grpc_channel* channel;
+} 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(
+ const char* handshaker_service_url);
+
+#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 ec0bf12b95..0000000000
--- a/src/core/tsi/alts/handshaker/alts_tsi_event.cc
+++ /dev/null
@@ -1,73 +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>
-
-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(event->details);
- grpc_slice_unref(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 1df1021bb1..1b7e58d3ce 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
@@ -26,33 +26,34 @@
#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();
/* 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;
+ 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;
+ grpc_channel* channel;
+};
/* Main struct for ALTS TSI handshaker result. */
typedef struct alts_tsi_handshaker_result {
@@ -182,7 +183,7 @@ static void handshaker_result_destroy(tsi_handshaker_result* self) {
gpr_free(result->peer_identity);
gpr_free(result->key_data);
gpr_free(result->unused_bytes);
- grpc_slice_unref(result->rpc_versions);
+ grpc_slice_unref_internal(result->rpc_versions);
gpr_free(result);
}
@@ -192,9 +193,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;
@@ -233,6 +234,27 @@ static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp,
return TSI_OK;
}
+/* 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,
@@ -249,12 +271,36 @@ 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) {
+ if (handshaker->channel == nullptr) {
+ grpc_alts_shared_resource_dedicated_start(
+ handshaker->handshaker_service_url);
+ handshaker->interested_parties =
+ grpc_alts_get_shared_resource_dedicated()->interested_parties;
+ GPR_ASSERT(handshaker->interested_parties != nullptr);
+ }
+ grpc_iomgr_cb_func grpc_cb = handshaker->channel == nullptr
+ ? on_handshaker_service_resp_recv_dedicated
+ : on_handshaker_service_resp_recv;
+ grpc_channel* channel =
+ handshaker->channel == nullptr
+ ? grpc_alts_get_shared_resource_dedicated()->channel
+ : handshaker->channel;
+ handshaker->client = alts_grpc_handshaker_client_create(
+ handshaker, 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->channel == nullptr &&
+ 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()
@@ -263,18 +309,13 @@ 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(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(slice);
+ grpc_slice_unref_internal(slice);
if (ok != TSI_OK) {
gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests");
return ok;
@@ -282,6 +323,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) {
@@ -299,10 +356,12 @@ 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(handshaker->recv_bytes);
- grpc_slice_unref(handshaker->target_name);
+ grpc_slice_unref_internal(handshaker->target_name);
grpc_alts_credentials_options_destroy(handshaker->options);
- gpr_free(handshaker->buffer);
+ if (handshaker->channel != nullptr) {
+ grpc_channel_destroy(handshaker->channel);
+ }
+ gpr_free(handshaker->handshaker_service_url);
gpr_free(handshaker);
}
@@ -312,80 +371,57 @@ 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(
const grpc_alts_credentials_options* options, const char* target_name,
- const char* handshaker_service_url, bool is_client, tsi_handshaker** self) {
+ const char* handshaker_service_url, bool is_client,
+ grpc_pollset_set* interested_parties, tsi_handshaker** self) {
if (handshaker_service_url == nullptr || self == nullptr ||
options == nullptr || (is_client && target_name == nullptr)) {
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));
+ bool 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 =
+ use_dedicated_cq ? &handshaker_vtable_dedicated : &handshaker_vtable;
+ handshaker->channel =
+ use_dedicated_cq
+ ? nullptr
+ : grpc_insecure_channel_create(handshaker->handshaker_service_url,
+ nullptr, nullptr);
*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;
@@ -400,81 +436,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 {
@@ -484,29 +445,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;
-}
-
-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);
+ handshaker->client_vtable_for_testing = vtable;
}
-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 227b30ce53..32f94bc9d3 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
@@ -23,8 +23,10 @@
#include <grpc/grpc.h>
+#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_transport_security.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/transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
@@ -34,10 +36,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;
/**
@@ -51,33 +49,46 @@ typedef struct alts_tsi_handshaker alts_tsi_handshaker;
* "host:port".
* - is_client: boolean value indicating if the handshaker is used at the client
* (is_client = true) or server (is_client = false) side.
+ * - interested_parties: set of pollsets interested in this connection.
* - 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,
- const char* handshaker_service_url, bool is_client, tsi_handshaker** self);
+ const char* handshaker_service_url, bool is_client,
+ 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/handshaker/alts_tsi_utils.cc b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc
index d9b5e6c945..1747f1ad04 100644
--- a/src/core/tsi/alts/handshaker/alts_tsi_utils.cc
+++ b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc
@@ -22,6 +22,8 @@
#include <grpc/byte_buffer_reader.h>
+#include "src/core/lib/slice/slice_internal.h"
+
tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code) {
switch (code) {
case GRPC_STATUS_OK:
@@ -47,7 +49,7 @@ grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response(
grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr);
grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
bool ok = grpc_gcp_handshaker_resp_decode(slice, resp);
- grpc_slice_unref(slice);
+ grpc_slice_unref_internal(slice);
grpc_byte_buffer_reader_destroy(&bbr);
if (!ok) {
grpc_gcp_handshaker_resp_destroy(resp);
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
index d4fd88d1e2..e7890903d5 100644
--- a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
@@ -61,7 +61,7 @@ static tsi_result alts_grpc_privacy_integrity_protect(
if (status != GRPC_STATUS_OK) {
gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
gpr_free(error_details);
- grpc_slice_unref(protected_slice);
+ grpc_slice_unref_internal(protected_slice);
return TSI_INTERNAL_ERROR;
}
grpc_slice_buffer_add(protected_slices, protected_slice);
@@ -106,7 +106,7 @@ static tsi_result alts_grpc_privacy_integrity_unprotect(
if (status != GRPC_STATUS_OK) {
gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details);
gpr_free(error_details);
- grpc_slice_unref(unprotected_slice);
+ grpc_slice_unref_internal(unprotected_slice);
return TSI_INTERNAL_ERROR;
}
grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
diff --git a/src/core/tsi/alts_transport_security.cc b/src/core/tsi/alts_transport_security.cc
deleted file mode 100644
index 2fd408103b..0000000000
--- a/src/core/tsi/alts_transport_security.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *
- * Copyright 2017 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_transport_security.h"
-
-#include <string.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() {
- memset(&g_alts_resource, 0, sizeof(alts_shared_resource));
- 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);
- 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
deleted file mode 100644
index d6b8e11137..0000000000
--- a/src/core/tsi/alts_transport_security.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *
- * Copyright 2017 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_TRANSPORT_SECURITY_H
-#define GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/sync.h>
-
-#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/core/tsi/ssl/session_cache/ssl_session_cache.cc b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
index ce74fde343..f9184bcc34 100644
--- a/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
+++ b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
@@ -19,6 +19,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/mutex_lock.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/ssl/session_cache/ssl_session.h"
#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
@@ -53,7 +54,7 @@ class SslSessionLRUCache::Node {
SetSession(std::move(session));
}
- ~Node() { grpc_slice_unref(key_); }
+ ~Node() { grpc_slice_unref_internal(key_); }
// Not copyable nor movable.
Node(const Node&) = delete;
diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc
index 3ff3557286..d6a72ada0d 100644
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -1051,9 +1051,9 @@ static tsi_result ssl_handshaker_result_extract_peer(
}
const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false";
- result = tsi_construct_string_peer_property(
+ result = tsi_construct_string_peer_property_from_cstring(
TSI_SSL_SESSION_REUSED_PEER_PROPERTY, session_reused,
- strlen(session_reused) + 1, &peer->properties[peer->property_count]);
+ &peer->properties[peer->property_count]);
if (result != TSI_OK) return result;
peer->property_count++;
diff --git a/src/core/tsi/transport_security.cc b/src/core/tsi/transport_security.cc
index 99b3229e88..078a917bba 100644
--- a/src/core/tsi/transport_security.cc
+++ b/src/core/tsi/transport_security.cc
@@ -213,10 +213,10 @@ tsi_result tsi_handshaker_next(
void tsi_handshaker_shutdown(tsi_handshaker* self) {
if (self == nullptr || self->vtable == nullptr) return;
- self->handshake_shutdown = true;
if (self->vtable->shutdown != nullptr) {
self->vtable->shutdown(self);
}
+ self->handshake_shutdown = true;
}
void tsi_handshaker_destroy(tsi_handshaker* self) {
@@ -338,3 +338,20 @@ tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) {
}
return TSI_OK;
}
+
+const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
+ const char* name) {
+ size_t i;
+ if (peer == nullptr) return nullptr;
+ for (i = 0; i < peer->property_count; i++) {
+ const tsi_peer_property* property = &peer->properties[i];
+ if (name == nullptr && property->name == nullptr) {
+ return property;
+ }
+ if (name != nullptr && property->name != nullptr &&
+ strcmp(property->name, name) == 0) {
+ return property;
+ }
+ }
+ return nullptr;
+}
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index 1923a702e5..482d300a05 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -122,7 +122,8 @@ tsi_result tsi_construct_allocated_string_peer_property(
const char* name, size_t value_length, tsi_peer_property* property);
tsi_result tsi_construct_string_peer_property_from_cstring(
const char* name, const char* value, tsi_peer_property* property);
-
+const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
+ const char* name);
/* Utils. */
char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */
diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc
index 39b891c2e1..8e1cea0269 100644
--- a/src/cpp/client/channel_cc.cc
+++ b/src/cpp/client/channel_cc.cc
@@ -20,6 +20,7 @@
#include <chrono>
#include <condition_variable>
+#include <cstring>
#include <memory>
#include <mutex>
@@ -32,6 +33,7 @@
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/rpc_method.h>
@@ -42,21 +44,39 @@
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/surface/completion_queue.h"
namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
-Channel::Channel(const grpc::string& host, grpc_channel* channel)
+Channel::Channel(
+ const grpc::string& host, grpc_channel* channel,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators)
: host_(host), c_channel_(channel) {
+ if (interceptor_creators != nullptr) {
+ interceptor_creators_ = std::move(*interceptor_creators);
+ }
g_gli_initializer.summon();
}
-Channel::~Channel() { grpc_channel_destroy(c_channel_); }
+Channel::~Channel() {
+ grpc_channel_destroy(c_channel_);
+ if (callback_cq_ != nullptr) {
+ callback_cq_->Shutdown();
+ }
+}
namespace {
+inline grpc_slice SliceFromArray(const char* arr, size_t len) {
+ return g_core_codegen_interface->grpc_slice_from_copied_buffer(arr, len);
+}
+
grpc::string GetChannelInfoField(grpc_channel* channel,
grpc_channel_info* channel_info,
char*** channel_info_field) {
@@ -92,9 +112,10 @@ void ChannelResetConnectionBackoff(Channel* channel) {
} // namespace experimental
-internal::Call Channel::CreateCall(const internal::RpcMethod& method,
- ClientContext* context,
- CompletionQueue* cq) {
+internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq,
+ size_t interceptor_pos) {
const bool kRegistered = method.channel_tag() && context->authority().empty();
grpc_call* c_call = nullptr;
if (kRegistered) {
@@ -103,16 +124,17 @@ internal::Call Channel::CreateCall(const internal::RpcMethod& method,
context->propagation_options_.c_bitmask(), cq->cq(),
method.channel_tag(), context->raw_deadline(), nullptr);
} else {
- const char* host_str = nullptr;
- if (!context->authority().empty()) {
- host_str = context->authority_.c_str();
+ const string* host_str = nullptr;
+ if (!context->authority_.empty()) {
+ host_str = &context->authority_;
} else if (!host_.empty()) {
- host_str = host_.c_str();
+ host_str = &host_;
}
- grpc_slice method_slice = SliceFromCopiedString(method.name());
+ grpc_slice method_slice =
+ SliceFromArray(method.name(), strlen(method.name()));
grpc_slice host_slice;
if (host_str != nullptr) {
- host_slice = SliceFromCopiedString(host_str);
+ host_slice = SliceFromCopiedString(*host_str);
}
c_call = grpc_channel_create_call(
c_channel_, context->propagate_from_call_,
@@ -125,18 +147,27 @@ internal::Call Channel::CreateCall(const internal::RpcMethod& method,
}
}
grpc_census_call_set_context(c_call, context->census_context());
+
+ // ClientRpcInfo should be set before call because set_call also checks
+ // whether the call has been cancelled, and if the call was cancelled, we
+ // should notify the interceptors too/
+ auto* info = context->set_client_rpc_info(
+ method.name(), this, interceptor_creators_, interceptor_pos);
context->set_call(c_call, shared_from_this());
- return internal::Call(c_call, this, cq);
+
+ return internal::Call(c_call, this, cq, info);
+}
+
+internal::Call Channel::CreateCall(const internal::RpcMethod& method,
+ ClientContext* context,
+ CompletionQueue* cq) {
+ return CreateCallInternal(method, context, cq, 0);
}
void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) {
- static const size_t MAX_OPS = 8;
- size_t nops = 0;
- grpc_op cops[MAX_OPS];
- ops->FillOps(call->call(), cops, &nops);
- GPR_ASSERT(GRPC_CALL_OK ==
- grpc_call_start_batch(call->call(), cops, nops, ops, nullptr));
+ ops->FillOps(
+ call); // Make a copy of call. It's fine since Call just has pointers
}
void* Channel::RegisterMethod(const char* method) {
@@ -185,4 +216,41 @@ bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
return ok;
}
+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* Channel::CallbackCQ() {
+ // TODO(vjpai): Consider using a single global CQ for the default CQ
+ // if there is no explicit per-channel 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/client/client_context.cc b/src/cpp/client/client_context.cc
index 07a04e4268..50da75f09c 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -24,6 +24,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpcpp/impl/codegen/interceptor_common.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/server_context.h>
@@ -86,10 +87,13 @@ void ClientContext::set_call(grpc_call* call,
call_ = call;
channel_ = channel;
if (creds_ && !creds_->ApplyToCall(call_)) {
+ // TODO(yashykt): should interceptors also see this status?
+ SendCancelToInterceptors();
grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
"Failed to set credentials to rpc.", nullptr);
}
if (call_canceled_) {
+ SendCancelToInterceptors();
grpc_call_cancel(call_, nullptr);
}
}
@@ -110,12 +114,20 @@ void ClientContext::set_compression_algorithm(
void ClientContext::TryCancel() {
std::unique_lock<std::mutex> lock(mu_);
if (call_) {
+ SendCancelToInterceptors();
grpc_call_cancel(call_, nullptr);
} else {
call_canceled_ = true;
}
}
+void ClientContext::SendCancelToInterceptors() {
+ internal::CancelInterceptorBatchMethods cancel_methods;
+ for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) {
+ rpc_info_.RunInterceptor(&cancel_methods, i);
+ }
+}
+
grpc::string ClientContext::peer() const {
grpc::string peer;
if (call_) {
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/create_channel.cc b/src/cpp/client/create_channel.cc
index 67a46ce0e1..efdff6c265 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -39,11 +39,43 @@ std::shared_ptr<Channel> CreateCustomChannel(
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args) {
GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds.
- return creds ? creds->CreateChannel(target, args)
- : CreateChannelInternal(
- "", grpc_lame_client_channel_create(
- nullptr, GRPC_STATUS_INVALID_ARGUMENT,
- "Invalid credentials."));
+ return creds
+ ? creds->CreateChannel(target, args)
+ : CreateChannelInternal("",
+ grpc_lame_client_channel_create(
+ nullptr, GRPC_STATUS_INVALID_ARGUMENT,
+ "Invalid credentials."),
+ nullptr);
}
+namespace experimental {
+/// Create a new \em custom \a Channel pointing to \a target with \a
+/// interceptors being invoked per call.
+///
+/// \warning For advanced use and testing ONLY. Override default channel
+/// arguments only if necessary.
+///
+/// \param target The URI of the endpoint to connect to.
+/// \param creds Credentials to use for the created channel. If it does not
+/// hold an object or is invalid, a lame channel (one on which all operations
+/// fail) is returned.
+/// \param args Options for channel creation.
+std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
+ const grpc::string& target,
+ const std::shared_ptr<ChannelCredentials>& creds,
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
+ return creds
+ ? creds->CreateChannelWithInterceptors(
+ target, args, std::move(interceptor_creators))
+ : CreateChannelInternal("",
+ grpc_lame_client_channel_create(
+ nullptr, GRPC_STATUS_INVALID_ARGUMENT,
+ "Invalid credentials."),
+ nullptr);
+}
+} // namespace experimental
+
} // namespace grpc
diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc
index aa96edfcff..313d682aae 100644
--- a/src/cpp/client/create_channel_internal.cc
+++ b/src/cpp/client/create_channel_internal.cc
@@ -24,8 +24,12 @@ struct grpc_channel;
namespace grpc {
-std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host,
- grpc_channel* c_channel) {
- return std::shared_ptr<Channel>(new Channel(host, c_channel));
+std::shared_ptr<Channel> CreateChannelInternal(
+ const grpc::string& host, grpc_channel* c_channel,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
+ return std::shared_ptr<Channel>(
+ new Channel(host, c_channel, std::move(interceptor_creators)));
}
} // namespace grpc
diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h
index 86e8167277..512fc22866 100644
--- a/src/cpp/client/create_channel_internal.h
+++ b/src/cpp/client/create_channel_internal.h
@@ -21,6 +21,7 @@
#include <memory>
+#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/support/config.h>
struct grpc_channel;
@@ -28,8 +29,11 @@ struct grpc_channel;
namespace grpc {
class Channel;
-std::shared_ptr<Channel> CreateChannelInternal(const grpc::string& host,
- grpc_channel* c_channel);
+std::shared_ptr<Channel> CreateChannelInternal(
+ const grpc::string& host, grpc_channel* c_channel,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators);
} // namespace grpc
diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc
index f9285c9b28..8d775e7a87 100644
--- a/src/cpp/client/create_channel_posix.cc
+++ b/src/cpp/client/create_channel_posix.cc
@@ -33,7 +33,8 @@ std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
internal::GrpcLibrary init_lib;
init_lib.init();
return CreateChannelInternal(
- "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr));
+ "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr),
+ nullptr);
}
std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
@@ -42,10 +43,31 @@ std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
init_lib.init();
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
- return CreateChannelInternal("", grpc_insecure_channel_create_from_fd(
- target.c_str(), fd, &channel_args));
+ return CreateChannelInternal(
+ "",
+ grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args),
+ nullptr);
+}
+
+namespace experimental {
+
+std::shared_ptr<Channel> CreateCustomInsecureChannelWithInterceptorsFromFd(
+ const grpc::string& target, int fd, const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
+ internal::GrpcLibrary init_lib;
+ init_lib.init();
+ grpc_channel_args channel_args;
+ args.SetChannelArgs(&channel_args);
+ return CreateChannelInternal(
+ "",
+ grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args),
+ std::move(interceptor_creators));
}
+} // namespace experimental
+
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
} // namespace grpc
diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc
index 5c65ad05ea..09a76b428c 100644
--- a/src/cpp/client/cronet_credentials.cc
+++ b/src/cpp/client/cronet_credentials.cc
@@ -31,16 +31,25 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials {
std::shared_ptr<grpc::Channel> CreateChannel(
const string& target, const grpc::ChannelArguments& args) override {
- grpc_channel_args channel_args;
- args.SetChannelArgs(&channel_args);
- return CreateChannelInternal(
- "", grpc_cronet_secure_channel_create(engine_, target.c_str(),
- &channel_args, nullptr));
+ return CreateChannelWithInterceptors(target, args, nullptr);
}
SecureChannelCredentials* AsSecureCredentials() override { return nullptr; }
private:
+ std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
+ const string& target, const grpc::ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) override {
+ grpc_channel_args channel_args;
+ args.SetChannelArgs(&channel_args);
+ return CreateChannelInternal(
+ "",
+ grpc_cronet_secure_channel_create(engine_, target.c_str(),
+ &channel_args, nullptr),
+ std::move(interceptor_creators));
+ }
void* engine_;
};
diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc
index 67ef46bebe..87902b26f0 100644
--- a/src/cpp/client/generic_stub.cc
+++ b/src/cpp/client/generic_stub.cc
@@ -16,9 +16,11 @@
*
*/
-#include <grpcpp/generic/generic_stub.h>
+#include <functional>
+#include <grpcpp/generic/generic_stub.h>
#include <grpcpp/impl/rpc_method.h>
+#include <grpcpp/support/client_callback.h>
namespace grpc {
@@ -60,4 +62,14 @@ std::unique_ptr<GenericClientAsyncResponseReader> GenericStub::PrepareUnaryCall(
context, request, false));
}
+void GenericStub::experimental_type::UnaryCall(
+ ClientContext* context, const grpc::string& method,
+ const ByteBuffer* request, ByteBuffer* response,
+ std::function<void(Status)> on_completion) {
+ internal::CallbackUnaryCall(
+ stub_->channel_.get(),
+ internal::RpcMethod(method.c_str(), internal::RpcMethod::NORMAL_RPC),
+ context, request, response, std::move(on_completion));
+}
+
} // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 04dc5c0bcc..b816e0c59a 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -32,11 +32,20 @@ class InsecureChannelCredentialsImpl final : public ChannelCredentials {
public:
std::shared_ptr<grpc::Channel> CreateChannel(
const string& target, const grpc::ChannelArguments& args) override {
+ return CreateChannelWithInterceptors(target, args, nullptr);
+ }
+
+ std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
+ const string& target, const grpc::ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) override {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return CreateChannelInternal(
"",
- grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr));
+ grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr),
+ std::move(interceptor_creators));
}
SecureChannelCredentials* AsSecureCredentials() override { return nullptr; }
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index e48fbeb86d..7faaa20e78 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -36,12 +36,22 @@ SecureChannelCredentials::SecureChannelCredentials(
std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel(
const string& target, const grpc::ChannelArguments& args) {
+ return CreateChannelWithInterceptors(target, args, nullptr);
+}
+
+std::shared_ptr<grpc::Channel>
+SecureChannelCredentials::CreateChannelWithInterceptors(
+ const string& target, const grpc::ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return CreateChannelInternal(
args.GetSslTargetNameOverride(),
grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args,
- nullptr));
+ nullptr),
+ std::move(interceptor_creators));
}
SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
@@ -218,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/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index 85cb54227c..bfb6e17ee9 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -36,9 +36,15 @@ class SecureChannelCredentials final : public ChannelCredentials {
std::shared_ptr<grpc::Channel> CreateChannel(
const string& target, const grpc::ChannelArguments& args) override;
+
SecureChannelCredentials* AsSecureCredentials() override { return this; }
private:
+ std::shared_ptr<grpc::Channel> CreateChannelWithInterceptors(
+ const string& target, const grpc::ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) override;
grpc_channel_credentials* const c_creds_;
};
diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc
index 15a373d8a5..5819a4210b 100644
--- a/src/cpp/common/alarm.cc
+++ b/src/cpp/common/alarm.cc
@@ -39,17 +39,6 @@ class AlarmImpl : public CompletionQueueTag {
AlarmImpl() : cq_(nullptr), tag_(nullptr) {
gpr_ref_init(&refs_, 1);
grpc_timer_init_unset(&timer_);
- GRPC_CLOSURE_INIT(&on_alarm_,
- [](void* arg, grpc_error* error) {
- // queue the op on the completion queue
- AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
- alarm->Ref();
- grpc_cq_end_op(
- alarm->cq_, alarm, error,
- [](void* arg, grpc_cq_completion* completion) {},
- arg, &alarm->completion_);
- },
- this, grpc_schedule_on_exec_ctx);
}
~AlarmImpl() {
grpc_core::ExecCtx exec_ctx;
@@ -68,6 +57,32 @@ class AlarmImpl : public CompletionQueueTag {
cq_ = cq->cq();
tag_ = tag;
GPR_ASSERT(grpc_cq_begin_op(cq_, this));
+ GRPC_CLOSURE_INIT(&on_alarm_,
+ [](void* arg, grpc_error* error) {
+ // queue the op on the completion queue
+ AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
+ alarm->Ref();
+ grpc_cq_end_op(
+ alarm->cq_, alarm, error,
+ [](void* arg, grpc_cq_completion* completion) {},
+ arg, &alarm->completion_);
+ },
+ this, grpc_schedule_on_exec_ctx);
+ grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
+ &on_alarm_);
+ }
+ void Set(gpr_timespec deadline, std::function<void(bool)> f) {
+ grpc_core::ExecCtx exec_ctx;
+ // Don't use any CQ at all. Instead just use the timer to fire the function
+ callback_ = std::move(f);
+ Ref();
+ GRPC_CLOSURE_INIT(&on_alarm_,
+ [](void* arg, grpc_error* error) {
+ AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
+ alarm->callback_(error == GRPC_ERROR_NONE);
+ alarm->Unref();
+ },
+ this, grpc_schedule_on_exec_ctx);
grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
&on_alarm_);
}
@@ -95,6 +110,7 @@ class AlarmImpl : public CompletionQueueTag {
// completion queue where events about this alarm will be posted
grpc_completion_queue* cq_;
void* tag_;
+ std::function<void(bool)> callback_;
};
} // namespace internal
@@ -113,6 +129,15 @@ void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) {
static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag);
}
+void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) {
+ // Note that we know that alarm_ is actually an internal::AlarmImpl
+ // but we declared it as the base pointer to avoid a forward declaration
+ // or exposing core data structures in the C++ public headers.
+ // Thus it is safe to use a static_cast to the subclass here, and the
+ // C++ style guide allows us to do so in this case
+ static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f));
+}
+
Alarm::~Alarm() {
if (alarm_ != nullptr) {
static_cast<internal::AlarmImpl*>(alarm_)->Destroy();
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/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 619aacadaa..cfaa2e7b19 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -102,6 +102,13 @@ size_t CoreCodegen::grpc_byte_buffer_length(grpc_byte_buffer* bb) {
return ::grpc_byte_buffer_length(bb);
}
+grpc_call_error CoreCodegen::grpc_call_start_batch(grpc_call* call,
+ const grpc_op* ops,
+ size_t nops, void* tag,
+ void* reserved) {
+ return ::grpc_call_start_batch(call, ops, nops, tag, reserved);
+}
+
grpc_call_error CoreCodegen::grpc_call_cancel_with_status(
grpc_call* call, grpc_status_code status, const char* description,
void* reserved) {
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index b8fca9a6ee..8abd45efb7 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
#include <grpcpp/grpcpp.h>
namespace grpc {
-grpc::string Version() { return "1.15.0-dev"; }
+grpc::string Version() { return "1.17.0-dev"; }
} // namespace grpc
diff --git a/src/cpp/ext/filters/census/context.cc b/src/cpp/ext/filters/census/context.cc
index 4b3250236d..78fc69a805 100644
--- a/src/cpp/ext/filters/census/context.cc
+++ b/src/cpp/ext/filters/census/context.cc
@@ -29,9 +29,15 @@ void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
absl::string_view primary_role,
absl::string_view method, CensusContext* context) {
GrpcTraceContext trace_ctxt;
- TraceContextEncoding::Decode(tracing, &trace_ctxt);
- SpanContext parent_ctx = trace_ctxt.ToSpanContext();
- new (context) CensusContext(method, parent_ctx);
+ if (TraceContextEncoding::Decode(tracing, &trace_ctxt) !=
+ TraceContextEncoding::kEncodeDecodeFailure) {
+ SpanContext parent_ctx = trace_ctxt.ToSpanContext();
+ if (parent_ctx.IsValid()) {
+ new (context) CensusContext(method, parent_ctx);
+ return;
+ }
+ }
+ new (context) CensusContext(method);
}
void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
diff --git a/src/cpp/ext/filters/census/server_filter.cc b/src/cpp/ext/filters/census/server_filter.cc
index c7c62eefe5..b5f3d5a13a 100644
--- a/src/cpp/ext/filters/census/server_filter.cc
+++ b/src/cpp/ext/filters/census/server_filter.cc
@@ -93,7 +93,7 @@ void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data,
FilterInitialMetadata(initial_metadata, &sml);
calld->path_ = grpc_slice_ref_internal(sml.path);
calld->method_ = GetMethod(&calld->path_);
- calld->qualified_method_ = StrCat("Recv.", calld->method_);
+ calld->qualified_method_ = absl::StrCat("Recv.", calld->method_);
const char* tracing_str =
GRPC_SLICE_IS_EMPTY(sml.tracing_slice)
? ""
diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc
index 77c175e5b8..9ecb9de7e4 100644
--- a/src/cpp/server/channelz/channelz_service.cc
+++ b/src/cpp/server/channelz/channelz_service.cc
@@ -20,9 +20,6 @@
#include "src/cpp/server/channelz/channelz_service.h"
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/util/json_util.h>
-
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
@@ -32,11 +29,67 @@ Status ChannelzService::GetTopChannels(
ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request,
channelz::v1::GetTopChannelsResponse* response) {
char* json_str = grpc_channelz_get_top_channels(request->start_channel_id());
- google::protobuf::util::Status s =
- google::protobuf::util::JsonStringToMessage(json_str, response);
+ if (json_str == nullptr) {
+ return Status(StatusCode::INTERNAL,
+ "grpc_channelz_get_top_channels returned null");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
gpr_free(json_str);
- if (s != google::protobuf::util::Status::OK) {
- return Status(INTERNAL, s.ToString());
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetServers(
+ ServerContext* unused, const channelz::v1::GetServersRequest* request,
+ channelz::v1::GetServersResponse* response) {
+ char* json_str = grpc_channelz_get_servers(request->start_server_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::INTERNAL,
+ "grpc_channelz_get_servers returned null");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetServer(ServerContext* unused,
+ const channelz::v1::GetServerRequest* request,
+ channelz::v1::GetServerResponse* response) {
+ char* json_str = grpc_channelz_get_server(request->server_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::INTERNAL,
+ "grpc_channelz_get_server returned null");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetServerSockets(
+ ServerContext* unused, const channelz::v1::GetServerSocketsRequest* request,
+ channelz::v1::GetServerSocketsResponse* response) {
+ char* json_str = grpc_channelz_get_server_sockets(request->server_id(),
+ request->start_socket_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::INTERNAL,
+ "grpc_channelz_get_server_sockets returned null");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
}
return Status::OK;
}
@@ -45,11 +98,47 @@ Status ChannelzService::GetChannel(
ServerContext* unused, const channelz::v1::GetChannelRequest* request,
channelz::v1::GetChannelResponse* response) {
char* json_str = grpc_channelz_get_channel(request->channel_id());
- google::protobuf::util::Status s =
- google::protobuf::util::JsonStringToMessage(json_str, response);
+ if (json_str == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "No object found for that ChannelId");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetSubchannel(
+ ServerContext* unused, const channelz::v1::GetSubchannelRequest* request,
+ channelz::v1::GetSubchannelResponse* response) {
+ char* json_str = grpc_channelz_get_subchannel(request->subchannel_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::NOT_FOUND,
+ "No object found for that SubchannelId");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetSocket(ServerContext* unused,
+ const channelz::v1::GetSocketRequest* request,
+ channelz::v1::GetSocketResponse* response) {
+ char* json_str = grpc_channelz_get_socket(request->socket_id());
+ if (json_str == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "No object found for that SocketId");
+ }
+ grpc::protobuf::util::Status s =
+ grpc::protobuf::json::JsonStringToMessage(json_str, response);
gpr_free(json_str);
- if (s != google::protobuf::util::Status::OK) {
- return Status(INTERNAL, s.ToString());
+ if (!s.ok()) {
+ return Status(StatusCode::INTERNAL, s.ToString());
}
return Status::OK;
}
diff --git a/src/cpp/server/channelz/channelz_service.h b/src/cpp/server/channelz/channelz_service.h
index f619ea49e0..b4a66ba1c6 100644
--- a/src/cpp/server/channelz/channelz_service.h
+++ b/src/cpp/server/channelz/channelz_service.h
@@ -32,10 +32,31 @@ class ChannelzService final : public channelz::v1::Channelz::Service {
Status GetTopChannels(
ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request,
channelz::v1::GetTopChannelsResponse* response) override;
+ // implementation of GetServers rpc
+ Status GetServers(ServerContext* unused,
+ const channelz::v1::GetServersRequest* request,
+ channelz::v1::GetServersResponse* response) override;
+ // implementation of GetServer rpc
+ Status GetServer(ServerContext* unused,
+ const channelz::v1::GetServerRequest* request,
+ channelz::v1::GetServerResponse* response) override;
+ // implementation of GetServerSockets rpc
+ Status GetServerSockets(
+ ServerContext* unused,
+ const channelz::v1::GetServerSocketsRequest* request,
+ channelz::v1::GetServerSocketsResponse* response) override;
// implementation of GetChannel rpc
Status GetChannel(ServerContext* unused,
const channelz::v1::GetChannelRequest* request,
channelz::v1::GetChannelResponse* response) override;
+ // implementation of GetSubchannel rpc
+ Status GetSubchannel(ServerContext* unused,
+ const channelz::v1::GetSubchannelRequest* request,
+ channelz::v1::GetSubchannelResponse* response) override;
+ // implementation of GetSocket rpc
+ Status GetSocket(ServerContext* unused,
+ const channelz::v1::GetSocketRequest* request,
+ channelz::v1::GetSocketResponse* response) override;
};
} // namespace grpc
diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc
index bfda67d086..c951c69d51 100644
--- a/src/cpp/server/health/default_health_check_service.cc
+++ b/src/cpp/server/health/default_health_check_service.cc
@@ -26,79 +26,199 @@
#include "pb_decode.h"
#include "pb_encode.h"
+#include "src/core/ext/filters/client_channel/health/health.pb.h"
#include "src/cpp/server/health/default_health_check_service.h"
-#include "src/cpp/server/health/health.pb.h"
namespace grpc {
+
+//
+// DefaultHealthCheckService
+//
+
+DefaultHealthCheckService::DefaultHealthCheckService() {
+ services_map_[""].SetServingStatus(SERVING);
+}
+
+void DefaultHealthCheckService::SetServingStatus(
+ const grpc::string& service_name, bool serving) {
+ std::unique_lock<std::mutex> lock(mu_);
+ services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING);
+}
+
+void DefaultHealthCheckService::SetServingStatus(bool serving) {
+ const ServingStatus status = serving ? SERVING : NOT_SERVING;
+ std::unique_lock<std::mutex> lock(mu_);
+ for (auto& p : services_map_) {
+ ServiceData& service_data = p.second;
+ service_data.SetServingStatus(status);
+ }
+}
+
+DefaultHealthCheckService::ServingStatus
+DefaultHealthCheckService::GetServingStatus(
+ const grpc::string& service_name) const {
+ std::lock_guard<std::mutex> lock(mu_);
+ auto it = services_map_.find(service_name);
+ if (it == services_map_.end()) {
+ return NOT_FOUND;
+ }
+ const ServiceData& service_data = it->second;
+ return service_data.GetServingStatus();
+}
+
+void DefaultHealthCheckService::RegisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ std::unique_lock<std::mutex> lock(mu_);
+ ServiceData& service_data = services_map_[service_name];
+ service_data.AddCallHandler(handler /* copies ref */);
+ HealthCheckServiceImpl::CallHandler* h = handler.get();
+ h->SendHealth(std::move(handler), service_data.GetServingStatus());
+}
+
+void DefaultHealthCheckService::UnregisterCallHandler(
+ const grpc::string& service_name,
+ const std::shared_ptr<HealthCheckServiceImpl::CallHandler>& handler) {
+ std::unique_lock<std::mutex> lock(mu_);
+ auto it = services_map_.find(service_name);
+ if (it == services_map_.end()) return;
+ ServiceData& service_data = it->second;
+ service_data.RemoveCallHandler(handler);
+ if (service_data.Unused()) {
+ services_map_.erase(it);
+ }
+}
+
+DefaultHealthCheckService::HealthCheckServiceImpl*
+DefaultHealthCheckService::GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue> cq) {
+ GPR_ASSERT(impl_ == nullptr);
+ impl_.reset(new HealthCheckServiceImpl(this, std::move(cq)));
+ return impl_.get();
+}
+
+//
+// DefaultHealthCheckService::ServiceData
+//
+
+void DefaultHealthCheckService::ServiceData::SetServingStatus(
+ ServingStatus status) {
+ status_ = status;
+ for (auto& call_handler : call_handlers_) {
+ call_handler->SendHealth(call_handler /* copies ref */, status);
+ }
+}
+
+void DefaultHealthCheckService::ServiceData::AddCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ call_handlers_.insert(std::move(handler));
+}
+
+void DefaultHealthCheckService::ServiceData::RemoveCallHandler(
+ const std::shared_ptr<HealthCheckServiceImpl::CallHandler>& handler) {
+ call_handlers_.erase(handler);
+}
+
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl
+//
+
namespace {
const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check";
+const char kHealthWatchMethodName[] = "/grpc.health.v1.Health/Watch";
} // namespace
DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl(
- DefaultHealthCheckService* service)
- : service_(service), method_(nullptr) {
- internal::MethodHandler* handler =
- new internal::RpcMethodHandler<HealthCheckServiceImpl, ByteBuffer,
- ByteBuffer>(
- std::mem_fn(&HealthCheckServiceImpl::Check), this);
- method_ = new internal::RpcServiceMethod(
- kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, handler);
- AddMethod(method_);
-}
-
-Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
- ServerContext* context, const ByteBuffer* request, ByteBuffer* response) {
- // Decode request.
- std::vector<Slice> slices;
- if (!request->Dump(&slices).ok()) {
- return Status(StatusCode::INVALID_ARGUMENT, "");
+ DefaultHealthCheckService* database,
+ std::unique_ptr<ServerCompletionQueue> cq)
+ : database_(database), cq_(std::move(cq)) {
+ // Add Check() method.
+ AddMethod(new internal::RpcServiceMethod(
+ kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, nullptr));
+ // Add Watch() method.
+ AddMethod(new internal::RpcServiceMethod(
+ kHealthWatchMethodName, internal::RpcMethod::SERVER_STREAMING, nullptr));
+ // Create serving thread.
+ thread_ = std::unique_ptr<::grpc_core::Thread>(
+ new ::grpc_core::Thread("grpc_health_check_service", Serve, this));
+}
+
+DefaultHealthCheckService::HealthCheckServiceImpl::~HealthCheckServiceImpl() {
+ // We will reach here after the server starts shutting down.
+ shutdown_ = true;
+ {
+ std::unique_lock<std::mutex> lock(cq_shutdown_mu_);
+ cq_->Shutdown();
}
+ thread_->Join();
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::StartServingThread() {
+ // Request the calls we're interested in.
+ // We do this before starting the serving thread, so that we know it's
+ // done before server startup is complete.
+ CheckCallHandler::CreateAndStart(cq_.get(), database_, this);
+ WatchCallHandler::CreateAndStart(cq_.get(), database_, this);
+ // Start serving thread.
+ thread_->Start();
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::Serve(void* arg) {
+ HealthCheckServiceImpl* service =
+ reinterpret_cast<HealthCheckServiceImpl*>(arg);
+ void* tag;
+ bool ok;
+ while (true) {
+ if (!service->cq_->Next(&tag, &ok)) {
+ // The completion queue is shutting down.
+ GPR_ASSERT(service->shutdown_);
+ break;
+ }
+ auto* next_step = static_cast<CallableTag*>(tag);
+ next_step->Run(ok);
+ }
+}
+
+bool DefaultHealthCheckService::HealthCheckServiceImpl::DecodeRequest(
+ const ByteBuffer& request, grpc::string* service_name) {
+ std::vector<Slice> slices;
+ if (!request.Dump(&slices).ok()) return false;
uint8_t* request_bytes = nullptr;
- bool request_bytes_owned = false;
size_t request_size = 0;
grpc_health_v1_HealthCheckRequest request_struct;
- if (slices.empty()) {
- request_struct.has_service = false;
- } else if (slices.size() == 1) {
+ request_struct.has_service = false;
+ if (slices.size() == 1) {
request_bytes = const_cast<uint8_t*>(slices[0].begin());
request_size = slices[0].size();
- } else {
- request_bytes_owned = true;
- request_bytes = static_cast<uint8_t*>(gpr_malloc(request->Length()));
+ } else if (slices.size() > 1) {
+ request_bytes = static_cast<uint8_t*>(gpr_malloc(request.Length()));
uint8_t* copy_to = request_bytes;
for (size_t i = 0; i < slices.size(); i++) {
memcpy(copy_to, slices[i].begin(), slices[i].size());
copy_to += slices[i].size();
}
}
-
- if (request_bytes != nullptr) {
- pb_istream_t istream = pb_istream_from_buffer(request_bytes, request_size);
- bool decode_status = pb_decode(
- &istream, grpc_health_v1_HealthCheckRequest_fields, &request_struct);
- if (request_bytes_owned) {
- gpr_free(request_bytes);
- }
- if (!decode_status) {
- return Status(StatusCode::INVALID_ARGUMENT, "");
- }
- }
-
- // Check status from the associated default health checking service.
- DefaultHealthCheckService::ServingStatus serving_status =
- service_->GetServingStatus(
- request_struct.has_service ? request_struct.service : "");
- if (serving_status == DefaultHealthCheckService::NOT_FOUND) {
- return Status(StatusCode::NOT_FOUND, "");
+ pb_istream_t istream = pb_istream_from_buffer(request_bytes, request_size);
+ bool decode_status = pb_decode(
+ &istream, grpc_health_v1_HealthCheckRequest_fields, &request_struct);
+ if (slices.size() > 1) {
+ gpr_free(request_bytes);
}
+ if (!decode_status) return false;
+ *service_name = request_struct.has_service ? request_struct.service : "";
+ return true;
+}
- // Encode response
+bool DefaultHealthCheckService::HealthCheckServiceImpl::EncodeResponse(
+ ServingStatus status, ByteBuffer* response) {
grpc_health_v1_HealthCheckResponse response_struct;
response_struct.has_status = true;
response_struct.status =
- serving_status == DefaultHealthCheckService::SERVING
- ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING
- : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING;
+ status == NOT_FOUND
+ ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN
+ : status == SERVING
+ ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING
+ : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING;
pb_ostream_t ostream;
memset(&ostream, 0, sizeof(ostream));
pb_encode(&ostream, grpc_health_v1_HealthCheckResponse_fields,
@@ -108,48 +228,253 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
GRPC_SLICE_LENGTH(response_slice));
bool encode_status = pb_encode(
&ostream, grpc_health_v1_HealthCheckResponse_fields, &response_struct);
- if (!encode_status) {
- return Status(StatusCode::INTERNAL, "Failed to encode response.");
- }
+ if (!encode_status) return false;
Slice encoded_response(response_slice, Slice::STEAL_REF);
ByteBuffer response_buffer(&encoded_response, 1);
response->Swap(&response_buffer);
- return Status::OK;
+ return true;
}
-DefaultHealthCheckService::DefaultHealthCheckService() {
- services_map_.emplace("", true);
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler
+//
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service) {
+ std::shared_ptr<CallHandler> self =
+ std::make_shared<CheckCallHandler>(cq, database, service);
+ CheckCallHandler* handler = static_cast<CheckCallHandler*>(self.get());
+ {
+ std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_);
+ if (service->shutdown_) return;
+ // Request a Check() call.
+ handler->next_ =
+ CallableTag(std::bind(&CheckCallHandler::OnCallReceived, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ service->RequestAsyncUnary(0, &handler->ctx_, &handler->request_,
+ &handler->writer_, cq, cq, &handler->next_);
+ }
}
-void DefaultHealthCheckService::SetServingStatus(
- const grpc::string& service_name, bool serving) {
- std::lock_guard<std::mutex> lock(mu_);
- services_map_[service_name] = serving;
+DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ CheckCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service)
+ : cq_(cq), database_(database), service_(service), writer_(&ctx_) {}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ // The value of ok being false means that the server is shutting down.
+ return;
+ }
+ // Spawn a new handler instance to serve the next new client. Every handler
+ // instance will deallocate itself when it's done.
+ CreateAndStart(cq_, database_, service_);
+ // Process request.
+ gpr_log(GPR_DEBUG, "[HCS %p] Health check started for handler %p", service_,
+ this);
+ grpc::string service_name;
+ grpc::Status status = Status::OK;
+ ByteBuffer response;
+ if (!service_->DecodeRequest(request_, &service_name)) {
+ status = Status(StatusCode::INVALID_ARGUMENT, "could not parse request");
+ } else {
+ ServingStatus serving_status = database_->GetServingStatus(service_name);
+ if (serving_status == NOT_FOUND) {
+ status = Status(StatusCode::NOT_FOUND, "service name unknown");
+ } else if (!service_->EncodeResponse(serving_status, &response)) {
+ status = Status(StatusCode::INTERNAL, "could not encode response");
+ }
+ }
+ // Send response.
+ {
+ std::unique_lock<std::mutex> lock(service_->cq_shutdown_mu_);
+ if (!service_->shutdown_) {
+ next_ =
+ CallableTag(std::bind(&CheckCallHandler::OnFinishDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ if (status.ok()) {
+ writer_.Finish(response, status, &next_);
+ } else {
+ writer_.FinishWithError(status, &next_);
+ }
+ }
+ }
}
-void DefaultHealthCheckService::SetServingStatus(bool serving) {
- std::lock_guard<std::mutex> lock(mu_);
- for (auto iter = services_map_.begin(); iter != services_map_.end(); ++iter) {
- iter->second = serving;
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (ok) {
+ gpr_log(GPR_DEBUG, "[HCS %p] Health check call finished for handler %p",
+ service_, this);
}
+ self.reset(); // To appease clang-tidy.
}
-DefaultHealthCheckService::ServingStatus
-DefaultHealthCheckService::GetServingStatus(
- const grpc::string& service_name) const {
- std::lock_guard<std::mutex> lock(mu_);
- const auto& iter = services_map_.find(service_name);
- if (iter == services_map_.end()) {
- return NOT_FOUND;
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler
+//
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service) {
+ std::shared_ptr<CallHandler> self =
+ std::make_shared<WatchCallHandler>(cq, database, service);
+ WatchCallHandler* handler = static_cast<WatchCallHandler*>(self.get());
+ {
+ std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_);
+ if (service->shutdown_) return;
+ // Request AsyncNotifyWhenDone().
+ handler->on_done_notified_ =
+ CallableTag(std::bind(&WatchCallHandler::OnDoneNotified, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ self /* copies ref */);
+ handler->ctx_.AsyncNotifyWhenDone(&handler->on_done_notified_);
+ // Request a Watch() call.
+ handler->next_ =
+ CallableTag(std::bind(&WatchCallHandler::OnCallReceived, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ service->RequestAsyncServerStreaming(1, &handler->ctx_, &handler->request_,
+ &handler->stream_, cq, cq,
+ &handler->next_);
}
- return iter->second ? SERVING : NOT_SERVING;
}
-DefaultHealthCheckService::HealthCheckServiceImpl*
-DefaultHealthCheckService::GetHealthCheckService() {
- GPR_ASSERT(impl_ == nullptr);
- impl_.reset(new HealthCheckServiceImpl(this));
- return impl_.get();
+DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ WatchCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service)
+ : cq_(cq), database_(database), service_(service), stream_(&ctx_) {}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ // Server shutting down.
+ //
+ // AsyncNotifyWhenDone() needs to be called before the call starts, but the
+ // tag will not pop out if the call never starts (
+ // https://github.com/grpc/grpc/issues/10136). So we need to manually
+ // release the ownership of the handler in this case.
+ GPR_ASSERT(on_done_notified_.ReleaseHandler() != nullptr);
+ return;
+ }
+ // Spawn a new handler instance to serve the next new client. Every handler
+ // instance will deallocate itself when it's done.
+ CreateAndStart(cq_, database_, service_);
+ // Parse request.
+ if (!service_->DecodeRequest(request_, &service_name_)) {
+ SendFinish(std::move(self),
+ Status(StatusCode::INVALID_ARGUMENT, "could not parse request"));
+ return;
+ }
+ // Register the call for updates to the service.
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Health watch started for service \"%s\" (handler: %p)",
+ service_, service_name_.c_str(), this);
+ database_->RegisterCallHandler(service_name_, std::move(self));
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendHealth(std::shared_ptr<CallHandler> self, ServingStatus status) {
+ std::unique_lock<std::mutex> lock(send_mu_);
+ // If there's already a send in flight, cache the new status, and
+ // we'll start a new send for it when the one in flight completes.
+ if (send_in_flight_) {
+ pending_status_ = status;
+ return;
+ }
+ // Start a send.
+ SendHealthLocked(std::move(self), status);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendHealthLocked(std::shared_ptr<CallHandler> self, ServingStatus status) {
+ send_in_flight_ = true;
+ // Construct response.
+ ByteBuffer response;
+ bool success = service_->EncodeResponse(status, &response);
+ // Grab shutdown lock and send response.
+ std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_);
+ if (service_->shutdown_) {
+ SendFinishLocked(std::move(self), Status::CANCELLED);
+ return;
+ }
+ if (!success) {
+ SendFinishLocked(std::move(self),
+ Status(StatusCode::INTERNAL, "could not encode response"));
+ return;
+ }
+ next_ = CallableTag(std::bind(&WatchCallHandler::OnSendHealthDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ stream_.Write(response, &next_);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ SendFinish(std::move(self), Status::CANCELLED);
+ return;
+ }
+ std::unique_lock<std::mutex> lock(send_mu_);
+ send_in_flight_ = false;
+ // If we got a new status since we started the last send, start a
+ // new send for it.
+ if (pending_status_ != NOT_FOUND) {
+ auto status = pending_status_;
+ pending_status_ = NOT_FOUND;
+ SendHealthLocked(std::move(self), status);
+ }
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendFinish(std::shared_ptr<CallHandler> self, const Status& status) {
+ if (finish_called_) return;
+ std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_);
+ if (service_->shutdown_) return;
+ SendFinishLocked(std::move(self), status);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendFinishLocked(std::shared_ptr<CallHandler> self, const Status& status) {
+ on_finish_done_ =
+ CallableTag(std::bind(&WatchCallHandler::OnFinishDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ stream_.Finish(status, &on_finish_done_);
+ finish_called_ = true;
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (ok) {
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Health watch call finished (service_name: \"%s\", "
+ "handler: %p).",
+ service_, service_name_.c_str(), this);
+ }
+ self.reset(); // To appease clang-tidy.
+}
+
+// TODO(roth): This method currently assumes that there will be only one
+// thread polling the cq and invoking the corresponding callbacks. If
+// that changes, we will need to add synchronization here.
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok) {
+ GPR_ASSERT(ok);
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Health watch call is notified done (handler: %p, "
+ "is_cancelled: %d).",
+ service_, this, static_cast<int>(ctx_.IsCancelled()));
+ database_->UnregisterCallHandler(service_name_, self);
+ SendFinish(std::move(self), Status::CANCELLED);
}
} // namespace grpc
diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h
index a1ce5aa64e..450bd543f5 100644
--- a/src/cpp/server/health/default_health_check_service.h
+++ b/src/cpp/server/health/default_health_check_service.h
@@ -19,42 +19,260 @@
#ifndef GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
#define GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
+#include <atomic>
#include <mutex>
+#include <set>
+#include <grpc/support/log.h>
+#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/impl/codegen/async_generic_service.h>
+#include <grpcpp/impl/codegen/async_unary_call.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/support/byte_buffer.h>
+#include "src/core/lib/gprpp/thd.h"
+
namespace grpc {
// Default implementation of HealthCheckServiceInterface. Server will create and
// own it.
class DefaultHealthCheckService final : public HealthCheckServiceInterface {
public:
+ enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
+
// The service impl to register with the server.
class HealthCheckServiceImpl : public Service {
public:
- explicit HealthCheckServiceImpl(DefaultHealthCheckService* service);
+ // Base class for call handlers.
+ class CallHandler {
+ public:
+ virtual ~CallHandler() = default;
+ virtual void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) = 0;
+ };
- Status Check(ServerContext* context, const ByteBuffer* request,
- ByteBuffer* response);
+ HealthCheckServiceImpl(DefaultHealthCheckService* database,
+ std::unique_ptr<ServerCompletionQueue> cq);
+
+ ~HealthCheckServiceImpl();
+
+ void StartServingThread();
private:
- const DefaultHealthCheckService* const service_;
- internal::RpcServiceMethod* method_;
+ // A tag that can be called with a bool argument. It's tailored for
+ // CallHandler's use. Before being used, it should be constructed with a
+ // method of CallHandler and a shared pointer to the handler. The
+ // shared pointer will be moved to the invoked function and the function
+ // can only be invoked once. That makes ref counting of the handler easier,
+ // because the shared pointer is not bound to the function and can be gone
+ // once the invoked function returns (if not used any more).
+ class CallableTag {
+ public:
+ using HandlerFunction =
+ std::function<void(std::shared_ptr<CallHandler>, bool)>;
+
+ CallableTag() {}
+
+ CallableTag(HandlerFunction func, std::shared_ptr<CallHandler> handler)
+ : handler_function_(std::move(func)), handler_(std::move(handler)) {
+ GPR_ASSERT(handler_function_ != nullptr);
+ GPR_ASSERT(handler_ != nullptr);
+ }
+
+ // Runs the tag. This should be called only once. The handler is no
+ // longer owned by this tag after this method is invoked.
+ void Run(bool ok) {
+ GPR_ASSERT(handler_function_ != nullptr);
+ GPR_ASSERT(handler_ != nullptr);
+ handler_function_(std::move(handler_), ok);
+ }
+
+ // Releases and returns the shared pointer to the handler.
+ std::shared_ptr<CallHandler> ReleaseHandler() {
+ return std::move(handler_);
+ }
+
+ private:
+ HandlerFunction handler_function_ = nullptr;
+ std::shared_ptr<CallHandler> handler_;
+ };
+
+ // Call handler for Check method.
+ // Each handler takes care of one call. It contains per-call data and it
+ // will access the members of the parent class (i.e.,
+ // DefaultHealthCheckService) for per-service health data.
+ class CheckCallHandler : public CallHandler {
+ public:
+ // Instantiates a CheckCallHandler and requests the next health check
+ // call. The handler object will manage its own lifetime, so no action is
+ // needed from the caller any more regarding that object.
+ static void CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // This ctor is public because we want to use std::make_shared<> in
+ // CreateAndStart(). This ctor shouldn't be used elsewhere.
+ CheckCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // Not used for Check.
+ void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) override {}
+
+ private:
+ // Called when we receive a call.
+ // Spawns a new handler so that we can keep servicing future calls.
+ void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Called when Finish() is done.
+ void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ // The members passed down from HealthCheckServiceImpl.
+ ServerCompletionQueue* cq_;
+ DefaultHealthCheckService* database_;
+ HealthCheckServiceImpl* service_;
+
+ ByteBuffer request_;
+ GenericServerAsyncResponseWriter writer_;
+ ServerContext ctx_;
+
+ CallableTag next_;
+ };
+
+ // Call handler for Watch method.
+ // Each handler takes care of one call. It contains per-call data and it
+ // will access the members of the parent class (i.e.,
+ // DefaultHealthCheckService) for per-service health data.
+ class WatchCallHandler : public CallHandler {
+ public:
+ // Instantiates a WatchCallHandler and requests the next health check
+ // call. The handler object will manage its own lifetime, so no action is
+ // needed from the caller any more regarding that object.
+ static void CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // This ctor is public because we want to use std::make_shared<> in
+ // CreateAndStart(). This ctor shouldn't be used elsewhere.
+ WatchCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) override;
+
+ private:
+ // Called when we receive a call.
+ // Spawns a new handler so that we can keep servicing future calls.
+ void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Requires holding send_mu_.
+ void SendHealthLocked(std::shared_ptr<CallHandler> self,
+ ServingStatus status);
+
+ // When sending a health result finishes.
+ void OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ void SendFinish(std::shared_ptr<CallHandler> self, const Status& status);
+
+ // Requires holding service_->cq_shutdown_mu_.
+ void SendFinishLocked(std::shared_ptr<CallHandler> self,
+ const Status& status);
+
+ // Called when Finish() is done.
+ void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Called when AsyncNotifyWhenDone() notifies us.
+ void OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok);
+
+ // The members passed down from HealthCheckServiceImpl.
+ ServerCompletionQueue* cq_;
+ DefaultHealthCheckService* database_;
+ HealthCheckServiceImpl* service_;
+
+ ByteBuffer request_;
+ grpc::string service_name_;
+ GenericServerAsyncWriter stream_;
+ ServerContext ctx_;
+
+ std::mutex send_mu_;
+ bool send_in_flight_ = false; // Guarded by mu_.
+ ServingStatus pending_status_ = NOT_FOUND; // Guarded by mu_.
+
+ bool finish_called_ = false;
+ CallableTag next_;
+ CallableTag on_done_notified_;
+ CallableTag on_finish_done_;
+ };
+
+ // Handles the incoming requests and drives the completion queue in a loop.
+ static void Serve(void* arg);
+
+ // Returns true on success.
+ static bool DecodeRequest(const ByteBuffer& request,
+ grpc::string* service_name);
+ static bool EncodeResponse(ServingStatus status, ByteBuffer* response);
+
+ // Needed to appease Windows compilers, which don't seem to allow
+ // nested classes to access protected members in the parent's
+ // superclass.
+ using Service::RequestAsyncServerStreaming;
+ using Service::RequestAsyncUnary;
+
+ DefaultHealthCheckService* database_;
+ std::unique_ptr<ServerCompletionQueue> cq_;
+
+ // To synchronize the operations related to shutdown state of cq_, so that
+ // we don't enqueue new tags into cq_ after it is already shut down.
+ std::mutex cq_shutdown_mu_;
+ std::atomic_bool shutdown_{false};
+ std::unique_ptr<::grpc_core::Thread> thread_;
};
DefaultHealthCheckService();
+
void SetServingStatus(const grpc::string& service_name,
bool serving) override;
void SetServingStatus(bool serving) override;
- enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
+
ServingStatus GetServingStatus(const grpc::string& service_name) const;
- HealthCheckServiceImpl* GetHealthCheckService();
+
+ HealthCheckServiceImpl* GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue> cq);
private:
+ // Stores the current serving status of a service and any call
+ // handlers registered for updates when the service's status changes.
+ class ServiceData {
+ public:
+ void SetServingStatus(ServingStatus status);
+ ServingStatus GetServingStatus() const { return status_; }
+ void AddCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+ void RemoveCallHandler(
+ const std::shared_ptr<HealthCheckServiceImpl::CallHandler>& handler);
+ bool Unused() const {
+ return call_handlers_.empty() && status_ == NOT_FOUND;
+ }
+
+ private:
+ ServingStatus status_ = NOT_FOUND;
+ std::set<std::shared_ptr<HealthCheckServiceImpl::CallHandler>>
+ call_handlers_;
+ };
+
+ void RegisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+
+ void UnregisterCallHandler(
+ const grpc::string& service_name,
+ const std::shared_ptr<HealthCheckServiceImpl::CallHandler>& handler);
+
mutable std::mutex mu_;
- std::map<grpc::string, bool> services_map_;
+ std::map<grpc::string, ServiceData> services_map_; // Guarded by mu_.
std::unique_ptr<HealthCheckServiceImpl> impl_;
};
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 8417c45e64..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,14 +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_));
+ // == 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
@@ -275,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
@@ -288,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 36c709eb45..7a98bce507 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -27,7 +27,9 @@
#include <grpcpp/completion_queue.h>
#include <grpcpp/generic/async_generic_service.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
+#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/method_handler_impl.h>
#include <grpcpp/impl/rpc_service_method.h>
@@ -38,8 +40,10 @@
#include <grpcpp/support/time.h>
#include "src/core/ext/transport/inproc/inproc_transport.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/completion_queue.h"
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/server/health/default_health_check_service.h"
#include "src/cpp/thread_manager/thread_manager.h"
@@ -54,6 +58,9 @@ namespace {
// max-threads set) to the server builder.
#define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX
+// How many callback requests of each method should we pre-register at start
+#define DEFAULT_CALLBACK_REQS_PER_METHOD 32
+
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
public:
~DefaultGlobalCallbacks() override {}
@@ -127,10 +134,13 @@ class Server::UnimplementedAsyncResponse final
~UnimplementedAsyncResponse() { delete request_; }
bool FinalizeResult(void** tag, bool* status) override {
- internal::CallOpSet<
- internal::CallOpSendInitialMetadata,
- internal::CallOpServerSendStatus>::FinalizeResult(tag, status);
- delete this;
+ if (internal::CallOpSet<
+ internal::CallOpSendInitialMetadata,
+ internal::CallOpServerSendStatus>::FinalizeResult(tag, status)) {
+ delete this;
+ } else {
+ // The tag was swallowed due to interception. We will see it again.
+ }
return false;
}
@@ -140,9 +150,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 ||
@@ -169,10 +179,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();
@@ -192,9 +202,21 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
}
}
+ void PostShutdownCleanup() {
+ if (call_) {
+ grpc_call_unref(call_);
+ call_ = nullptr;
+ }
+ if (cq_) {
+ grpc_completion_queue_destroy(cq_);
+ cq_ = nullptr;
+ }
+ }
+
bool FinalizeResult(void** tag, bool* status) override {
if (!*status) {
grpc_completion_queue_destroy(cq_);
+ cq_ = nullptr;
}
if (call_details_) {
deadline_ = call_details_->deadline;
@@ -204,17 +226,25 @@ 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)
: cq_(mrd->cq_),
- call_(mrd->call_, server, &cq_, server->max_receive_message_size()),
ctx_(mrd->deadline_, &mrd->request_metadata_),
has_request_payload_(mrd->has_request_payload_),
request_payload_(has_request_payload_ ? mrd->request_payload_
: nullptr),
+ request_(nullptr),
method_(mrd->method_),
- server_(server) {
+ call_(mrd->call_, server, &cq_, server->max_receive_message_size(),
+ ctx_.set_server_rpc_info(method_->name(),
+ server->interceptor_creators_)),
+ server_(server),
+ global_callbacks_(nullptr),
+ resources_(false) {
ctx_.set_call(mrd->call_);
ctx_.cq_ = &cq_;
GPR_ASSERT(mrd->in_flight_);
@@ -230,38 +260,79 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
bool resources) {
- ctx_.BeginCompletionOp(&call_);
- global_callbacks->PreSynchronousRequest(&ctx_);
- auto* handler = resources ? method_->handler()
- : server_->resource_exhausted_handler_.get();
- handler->RunHandler(internal::MethodHandler::HandlerParameter(
- &call_, &ctx_, request_payload_));
- global_callbacks->PostSynchronousRequest(&ctx_);
- request_payload_ = nullptr;
-
- cq_.Shutdown();
+ global_callbacks_ = global_callbacks;
+ resources_ = resources;
+
+ interceptor_methods_.SetCall(&call_);
+ interceptor_methods_.SetReverse();
+ // Set interception point for RECV INITIAL METADATA
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ interceptor_methods_.SetRecvInitialMetadata(&ctx_.client_metadata_);
+
+ if (has_request_payload_) {
+ // Set interception point for RECV MESSAGE
+ auto* handler = resources_ ? method_->handler()
+ : server_->resource_exhausted_handler_.get();
+ request_ = handler->Deserialize(call_.call(), request_payload_,
+ &request_status_);
+
+ request_payload_ = nullptr;
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
+ interceptor_methods_.SetRecvMessage(request_);
+ }
- internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
- cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+ if (interceptor_methods_.RunInterceptors(
+ [this]() { ContinueRunAfterInterception(); })) {
+ ContinueRunAfterInterception();
+ } else {
+ // There were interceptors to be run, so ContinueRunAfterInterception
+ // will be run when interceptors are done.
+ }
+ }
- /* Ensure the cq_ is shutdown */
- DummyTag ignored_tag;
- GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
+ void ContinueRunAfterInterception() {
+ {
+ 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_, nullptr));
+ request_ = nullptr;
+ global_callbacks_->PostSynchronousRequest(&ctx_);
+
+ cq_.Shutdown();
+
+ internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag();
+ cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+ /* Ensure the cq_ is shutdown */
+ DummyTag ignored_tag;
+ GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
+ }
+ delete this;
}
private:
CompletionQueue cq_;
- internal::Call call_;
ServerContext ctx_;
const bool has_request_payload_;
grpc_byte_buffer* request_payload_;
+ void* request_;
+ Status request_status_;
internal::RpcServiceMethod* const method_;
+ internal::Call call_;
Server* server_;
+ std::shared_ptr<GlobalCallbacks> global_callbacks_;
+ bool resources_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
private:
internal::RpcServiceMethod* const method_;
- void* const tag_;
+ void* const method_tag_;
bool in_flight_;
const bool has_request_payload_;
grpc_call* call_;
@@ -272,6 +343,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
@@ -318,8 +559,9 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
if (ok) {
- // Calldata takes ownership of the completion queue inside sync_req
- SyncRequest::CallData cd(server_, sync_req);
+ // Calldata takes ownership of the completion queue and interceptors
+ // inside sync_req
+ auto* cd = new SyncRequest::CallData(server_, sync_req);
// Prepare for the next request
if (!IsShutdown()) {
sync_req->SetupRequest(); // Create new completion queue for sync_req
@@ -327,7 +569,7 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
GPR_TIMER_SCOPE("cd.Run()", 0);
- cd.Run(global_callbacks_, resources);
+ cd->Run(global_callbacks_, resources);
}
// TODO (sreek) If ok is false here (which it isn't in case of
// grpc_request_registered_call), we should still re-queue the request
@@ -359,7 +601,17 @@ class Server::SyncRequestThreadManager : public ThreadManager {
void* tag;
bool ok;
while (server_cq_->Next(&tag, &ok)) {
- // Do nothing
+ if (ok) {
+ // If a request was pulled off the queue, it means that the thread
+ // handling the request added it to the completion queue after shutdown
+ // was called - because the thread had already started and checked the
+ // shutdown flag before shutdown was called. In this case, we simply
+ // clean it up here, *after* calling wait on all the worker threads, at
+ // which point we are certain no in-flight requests will add more to the
+ // queue. This fixes an intermittent memory leak on shutdown.
+ SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
+ sync_req->PostShutdownCleanup();
+ }
}
}
@@ -380,7 +632,6 @@ class Server::SyncRequestThreadManager : public ThreadManager {
int cq_timeout_msec_;
std::vector<std::unique_ptr<SyncRequest>> sync_requests_;
std::unique_ptr<internal::RpcServiceMethod> unknown_method_;
- std::unique_ptr<internal::RpcServiceMethod> health_check_;
std::shared_ptr<Server::GlobalCallbacks> global_callbacks_;
};
@@ -390,8 +641,12 @@ Server::Server(
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
- grpc_resource_quota* server_rq)
- : max_receive_message_size_(max_receive_message_size),
+ grpc_resource_quota* server_rq,
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ interceptor_creators)
+ : interceptor_creators_(std::move(interceptor_creators)),
+ max_receive_message_size_(max_receive_message_size),
sync_server_cqs_(std::move(sync_server_cqs)),
started_(false),
shutdown_(false),
@@ -447,6 +702,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();
@@ -473,7 +731,21 @@ std::shared_ptr<Channel> Server::InProcessChannel(
const ChannelArguments& args) {
grpc_channel_args channel_args = args.c_channel_args();
return CreateChannelInternal(
- "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr));
+ "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr),
+ nullptr);
+}
+
+std::shared_ptr<Channel>
+Server::experimental_type::InProcessChannelWithInterceptors(
+ const ChannelArguments& args,
+ std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+ interceptor_creators) {
+ grpc_channel_args channel_args = args.c_channel_args();
+ return CreateChannelInternal(
+ "inproc",
+ grpc_inproc_channel_create(server_->server_, &channel_args, nullptr),
+ std::move(interceptor_creators));
}
static grpc_server_register_method_payload_handling PayloadHandlingForMethod(
@@ -505,21 +777,31 @@ 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. Register at least some callback requests
+ // TODO(vjpai): Register these dynamically based on need
+ for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) {
+ 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();
@@ -559,16 +841,25 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
// Only create default health check service when user did not provide an
// explicit one.
+ ServerCompletionQueue* health_check_cq = nullptr;
+ DefaultHealthCheckService::HealthCheckServiceImpl*
+ default_health_check_service_impl = nullptr;
if (health_check_service_ == nullptr && !health_check_service_disabled_ &&
DefaultHealthCheckServiceEnabled()) {
- if (sync_server_cqs_ == nullptr || sync_server_cqs_->empty()) {
- gpr_log(GPR_INFO,
- "Default health check service disabled at async-only server.");
- } else {
- auto* default_hc_service = new DefaultHealthCheckService;
- health_check_service_.reset(default_hc_service);
- RegisterService(nullptr, default_hc_service->GetHealthCheckService());
- }
+ auto* default_hc_service = new DefaultHealthCheckService;
+ health_check_service_.reset(default_hc_service);
+ // We create a non-polling CQ to avoid impacting application
+ // 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_NEXT, GRPC_CQ_NON_POLLING, nullptr);
+ grpc_server_register_completion_queue(server_, health_check_cq->cq(),
+ nullptr);
+ default_health_check_service_impl =
+ default_hc_service->GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue>(health_check_cq));
+ RegisterService(nullptr, default_health_check_service_impl);
}
grpc_server_start(server_);
@@ -583,6 +874,9 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
new UnimplementedAsyncRequest(this, cqs[i]);
}
}
+ if (health_check_cq != nullptr) {
+ new UnimplementedAsyncRequest(this, health_check_cq);
+ }
}
// If this server has any support for synchronous methods (has any sync
@@ -595,6 +889,14 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}
+
+ for (auto& cbreq : callback_reqs_) {
+ cbreq->Request();
+ }
+
+ if (default_health_check_service_impl != nullptr) {
+ default_health_check_service_impl->StartServingThread();
+ }
}
void Server::ShutdownInternal(gpr_timespec deadline) {
@@ -653,30 +955,27 @@ void Server::Wait() {
void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) {
- static const size_t MAX_OPS = 8;
- size_t nops = 0;
- grpc_op cops[MAX_OPS];
- ops->FillOps(call->call(), cops, &nops);
- auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr);
- if (result != GRPC_CALL_OK) {
- gpr_log(GPR_ERROR, "Fatal: grpc_call_start_batch returned %d", result);
- grpc_call_log_batch(__FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR,
- call->call(), cops, nops, ops);
- abort();
- }
+ ops->FillOps(call);
}
ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
- void* tag, bool delete_on_finalize)
+ ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
: server_(server),
context_(context),
stream_(stream),
call_cq_(call_cq),
+ notification_cq_(notification_cq),
tag_(tag),
delete_on_finalize_(delete_on_finalize),
- call_(nullptr) {
+ call_(nullptr),
+ done_intercepting_(false) {
+ /* Set up interception state partially for the receive ops. call_wrapper_ is
+ * not filled at this point, but it will be filled before the interceptors are
+ * run. */
+ interceptor_methods_.SetCall(&call_wrapper_);
+ interceptor_methods_.SetReverse();
call_cq_->RegisterAvalanching(); // This op will trigger more ops
}
@@ -686,18 +985,43 @@ ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() {
bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
bool* status) {
- if (*status) {
- context_->client_metadata_.FillMap();
+ if (done_intercepting_) {
+ *tag = tag_;
+ if (delete_on_finalize_) {
+ delete this;
+ }
+ return true;
}
context_->set_call(call_);
context_->cq_ = call_cq_;
- internal::Call call(call_, server_, call_cq_,
- server_->max_receive_message_size());
- if (*status && call_) {
- context_->BeginCompletionOp(&call);
+ if (call_wrapper_.call() == nullptr) {
+ // Fill it since it is empty.
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(), nullptr);
}
+
// just the pointers inside call are copied here
- stream_->BindCall(&call);
+ stream_->BindCall(&call_wrapper_);
+
+ if (*status && call_ && call_wrapper_.server_rpc_info()) {
+ done_intercepting_ = true;
+ // Set interception point for RECV INITIAL METADATA
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
+ interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_);
+ if (interceptor_methods_.RunInterceptors(
+ [this]() { ContinueFinalizeResultAfterInterception(); })) {
+ // There are no interceptors to run. Continue
+ } else {
+ // There were interceptors to be run, so
+ // ContinueFinalizeResultAfterInterception will be run when interceptors
+ // are done.
+ return false;
+ }
+ }
+ if (*status && call_) {
+ context_->BeginCompletionOp(&call_wrapper_, false);
+ }
*tag = tag_;
if (delete_on_finalize_) {
delete this;
@@ -705,11 +1029,25 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
return true;
}
+void ServerInterface::BaseAsyncRequest::
+ ContinueFinalizeResultAfterInterception() {
+ 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);
+ grpc_cq_end_op(
+ notification_cq_->cq(), this, GRPC_ERROR_NONE,
+ [](void* arg, grpc_cq_completion* completion) { delete completion; },
+ nullptr, new grpc_cq_completion());
+}
+
ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest(
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
- void* tag)
- : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {}
+ ServerCompletionQueue* notification_cq, void* tag, const char* name)
+ : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
+ true),
+ name_(name) {}
void ServerInterface::RegisteredAsyncRequest::IssueRequest(
void* registered_method, grpc_byte_buffer** payload,
@@ -725,7 +1063,7 @@ ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
ServerInterface* server, GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
- : BaseAsyncRequest(server, context, stream, call_cq, tag,
+ : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
delete_on_finalize) {
grpc_call_details_init(&call_details_);
GPR_ASSERT(notification_cq);
@@ -738,6 +1076,10 @@ ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
bool* status) {
+ // If we are done intercepting, there is nothing more for us to do
+ if (done_intercepting_) {
+ return BaseAsyncRequest::FinalizeResult(tag, status);
+ }
// TODO(yangg) remove the copy here.
if (*status) {
static_cast<GenericServerContext*>(context_)->method_ =
@@ -748,16 +1090,26 @@ bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
}
grpc_slice_unref(call_details_.method);
grpc_slice_unref(call_details_.host);
+ call_wrapper_ = internal::Call(
+ call_, server_, call_cq_, server_->max_receive_message_size(),
+ context_->set_server_rpc_info(
+ static_cast<GenericServerContext*>(context_)->method_.c_str(),
+ *server_->interceptor_creators()));
return BaseAsyncRequest::FinalizeResult(tag, status);
}
bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag,
bool* status) {
- if (GenericAsyncRequest::FinalizeResult(tag, status) && *status) {
- new UnimplementedAsyncRequest(server_, cq_);
- new UnimplementedAsyncResponse(this);
+ if (GenericAsyncRequest::FinalizeResult(tag, status)) {
+ // We either had no interceptors run or we are done intercepting
+ if (*status) {
+ new UnimplementedAsyncRequest(server_, cq_);
+ new UnimplementedAsyncResponse(this);
+ } else {
+ delete this;
+ }
} else {
- delete this;
+ // The tag was swallowed due to interception. We will see it again.
}
return false;
}
@@ -772,4 +1124,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 6f5bde0d9f..9c01f896e6 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -40,14 +40,45 @@ namespace grpc {
class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
public:
// initial refs: one in the server context, one in the cq
- CompletionOp()
- : has_tag_(false),
+ // must ref the call before calling constructor and after deleting this
+ CompletionOp(internal::Call* call)
+ : call_(*call),
+ has_tag_(false),
tag_(nullptr),
+ core_cq_tag_(this),
refs_(2),
finalized_(false),
- cancelled_(0) {}
+ 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();
+ }
+ }
+
+ void FillOps(internal::Call* call) override;
+
+ // This should always be arena allocated in the call, so override delete.
+ // But this class is not trivially destructible, so must actually call delete
+ // before allowing the arena to be freed
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(CompletionOp));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
- void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override;
bool FinalizeResult(void** tag, bool* status) override;
bool CheckCancelled(CompletionQueue* cq) {
@@ -61,95 +92,192 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
tag_ = tag;
}
+ 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();
+ // 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.
+ void SetHijackingState() override {
+ /* Servers don't allow hijacking */
+ GPR_CODEGEN_ASSERT(false);
+ }
+
+ /* Should be called after interceptors are done running */
+ void ContinueFillOpsAfterInterception() override {}
+
+ /* Should be called after interceptors are done running on the finalize result
+ * path */
+ void ContinueFinalizeResultAfterInterception() override {
+ done_intercepting_ = true;
+ if (!has_tag_) {
+ /* We don't have a tag to return. */
+ std::unique_lock<std::mutex> lock(mu_);
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return;
+ }
+ /* Start a dummy op so that we can return the tag */
+ GPR_CODEGEN_ASSERT(GRPC_CALL_OK ==
+ g_core_codegen_interface->grpc_call_start_batch(
+ call_.call(), nullptr, 0, this, nullptr));
+ }
+
private:
bool CheckCancelledNoPluck() {
std::lock_guard<std::mutex> g(mu_);
return finalized_ ? (cancelled_ != 0) : false;
}
+ internal::Call call_;
bool has_tag_;
void* tag_;
+ void* core_cq_tag_;
std::mutex mu_;
int refs_;
bool finalized_;
int cancelled_;
+ bool done_intercepting_;
+ internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
void ServerContext::CompletionOp::Unref() {
std::unique_lock<std::mutex> lock(mu_);
if (--refs_ == 0) {
lock.unlock();
+ grpc_call* call = call_.call();
delete this;
+ grpc_call_unref(call);
}
}
-void ServerContext::CompletionOp::FillOps(grpc_call* call, grpc_op* ops,
- size_t* nops) {
- ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
- ops->data.recv_close_on_server.cancelled = &cancelled_;
- ops->flags = 0;
- ops->reserved = nullptr;
- *nops = 1;
+void ServerContext::CompletionOp::FillOps(internal::Call* call) {
+ grpc_op ops;
+ ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ ops.data.recv_close_on_server.cancelled = &cancelled_;
+ ops.flags = 0;
+ ops.reserved = nullptr;
+ interceptor_methods_.SetCall(&call_);
+ interceptor_methods_.SetReverse();
+ interceptor_methods_.SetCallOpSetInterface(this);
+ GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), &ops, 1,
+ core_cq_tag_, nullptr));
+ /* No interceptors to run here */
}
bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
- std::unique_lock<std::mutex> lock(mu_);
- finalized_ = true;
bool ret = false;
- if (has_tag_) {
- *tag = tag_;
- ret = true;
+ std::unique_lock<std::mutex> lock(mu_);
+ if (done_intercepting_) {
+ /* We are done intercepting. */
+ if (has_tag_) {
+ *tag = tag_;
+ ret = true;
+ }
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return ret;
}
+ finalized_ = true;
+
if (!*status) cancelled_ = 1;
- if (--refs_ == 0) {
- lock.unlock();
- delete this;
+ /* Release the lock since we are going to be running through interceptors now
+ */
+ lock.unlock();
+ /* Add interception point and run through interceptors */
+ interceptor_methods_.AddInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_CLOSE);
+ if (interceptor_methods_.RunInterceptors()) {
+ /* No interceptors were run */
+ if (has_tag_) {
+ *tag = tag_;
+ ret = true;
+ }
+ lock.lock();
+ if (--refs_ == 0) {
+ lock.unlock();
+ grpc_call* call = call_.call();
+ delete this;
+ grpc_call_unref(call);
+ }
+ return ret;
}
- return ret;
+ /* There are interceptors to be run. Return false for now */
+ return false;
}
// 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);
+}
+
+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);
- client_metadata_.FillMap();
}
-ServerContext::~ServerContext() {
+ServerContext::~ServerContext() { Clear(); }
+
+void ServerContext::Clear() {
+ auth_context_.reset();
+ initial_metadata_.clear();
+ trailing_metadata_.clear();
+ client_metadata_.Reset();
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_);
- completion_op_ = new CompletionOp();
- if (has_notify_when_done_tag_) {
+ if (rpc_info_) {
+ rpc_info_->Ref();
+ }
+ grpc_call_ref(call->call());
+ completion_op_ =
+ new (grpc_call_arena_alloc(call->call(), sizeof(CompletionOp)))
+ CompletionOp(call);
+ 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_);
@@ -170,6 +298,12 @@ void ServerContext::AddTrailingMetadata(const grpc::string& key,
}
void ServerContext::TryCancel() const {
+ internal::CancelInterceptorBatchMethods cancel_methods;
+ if (rpc_info_) {
+ for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) {
+ rpc_info_->RunInterceptor(&cancel_methods, i);
+ }
+ }
grpc_call_error err = grpc_call_cancel_with_status(
call_, GRPC_STATUS_CANCELLED, "Cancelled on the server side", nullptr);
if (err != GRPC_CALL_OK) {
@@ -178,12 +312,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/.editorconfig b/src/csharp/.editorconfig
index fabce7f5ba..c9a2c48a7d 100644
--- a/src/csharp/.editorconfig
+++ b/src/csharp/.editorconfig
@@ -6,3 +6,26 @@ indent_style = space
indent_size = 4
insert_final_newline = true
tab_width = 4
+
+; https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference
+[*.cs]
+dotnet_sort_system_directives_first = true
+csharp_new_line_before_open_brace = accessors, anonymous_methods, control_blocks, events, indexers, local_functions, methods, properties, types
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
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/Grpc.Core.Tests/ChannelConnectivityTest.cs b/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs
index a43040f01a..0834ddadda 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelConnectivityTest.cs
@@ -57,19 +57,23 @@ namespace Grpc.Core.Tests
[Test]
public async Task Channel_WaitForStateChangedAsync()
{
- helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
- {
- return Task.FromResult(request);
- });
-
Assert.ThrowsAsync(typeof(TaskCanceledException),
- async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(10)));
+ async () => await channel.WaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(0)));
var stateChangedTask = channel.WaitForStateChangedAsync(channel.State);
+ await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(5000));
+ await stateChangedTask;
+ Assert.AreEqual(ChannelState.Ready, channel.State);
+ }
- await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "abc");
+ [Test]
+ public async Task Channel_TryWaitForStateChangedAsync()
+ {
+ Assert.IsFalse(await channel.TryWaitForStateChangedAsync(channel.State, DateTime.UtcNow.AddMilliseconds(0)));
- await stateChangedTask;
+ var stateChangedTask = channel.TryWaitForStateChangedAsync(channel.State);
+ await channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(5000));
+ Assert.IsTrue(await stateChangedTask);
Assert.AreEqual(ChannelState.Ready, channel.State);
}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
index 62cc904a61..843d88bfb6 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
@@ -17,13 +17,7 @@
#endregion
using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core;
using Grpc.Core.Internal;
-using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Tests
@@ -44,9 +38,38 @@ namespace Grpc.Core.Tests
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
-
+
// forbid composing non-composable
Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
}
+
+ [Test]
+ public void ChannelCredentials_NativeCredentialsAreReused()
+ {
+ // always returning the same native object is critical for subchannel sharing to work with secure channels
+ var creds = new SslCredentials();
+ var nativeCreds1 = creds.GetNativeCredentials();
+ var nativeCreds2 = creds.GetNativeCredentials();
+ Assert.AreSame(nativeCreds1, nativeCreds2);
+ }
+
+ [Test]
+ public void ChannelCredentials_CreateExceptionIsCached()
+ {
+ var creds = new ChannelCredentialsWithCreateNativeThrows();
+ var ex1 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials());
+ var ex2 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials());
+ Assert.AreSame(ex1, ex2);
+ }
+
+ internal class ChannelCredentialsWithCreateNativeThrows : ChannelCredentials
+ {
+ internal override bool IsComposable => false;
+
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
+ {
+ throw new Exception("Creation of native credentials has failed on purpose.");
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs b/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs
new file mode 100644
index 0000000000..c3aee726f2
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ContextualMarshallerTest.cs
@@ -0,0 +1,119 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class ContextualMarshallerTest
+ {
+ const string Host = "127.0.0.1";
+
+ MockServiceHelper helper;
+ Server server;
+ Channel channel;
+
+ [SetUp]
+ public void Init()
+ {
+ var contextualMarshaller = new Marshaller<string>(
+ (str, serializationContext) =>
+ {
+ if (str == "UNSERIALIZABLE_VALUE")
+ {
+ // Google.Protobuf throws exception inherited from IOException
+ throw new IOException("Error serializing the message.");
+ }
+ if (str == "SERIALIZE_TO_NULL")
+ {
+ return;
+ }
+ var bytes = System.Text.Encoding.UTF8.GetBytes(str);
+ serializationContext.Complete(bytes);
+ },
+ (deserializationContext) =>
+ {
+ var buffer = deserializationContext.PayloadAsNewBuffer();
+ Assert.AreEqual(buffer.Length, deserializationContext.PayloadLength);
+ var s = System.Text.Encoding.UTF8.GetString(buffer);
+ if (s == "UNPARSEABLE_VALUE")
+ {
+ // Google.Protobuf throws exception inherited from IOException
+ throw new IOException("Error parsing the message.");
+ }
+ return s;
+ });
+ helper = new MockServiceHelper(Host, contextualMarshaller);
+ server = helper.GetServer();
+ server.Start();
+ channel = helper.GetChannel();
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void UnaryCall()
+ {
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ return Task.FromResult(request);
+ });
+ Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC"));
+ }
+
+ [Test]
+ public void ResponseParsingError_UnaryResponse()
+ {
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ return Task.FromResult("UNPARSEABLE_VALUE");
+ });
+
+ var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST"));
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public void RequestSerializationError_BlockingUnary()
+ {
+ Assert.Throws<IOException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE"));
+ }
+
+ [Test]
+ public void SerializationResultIsNull_BlockingUnary()
+ {
+ Assert.Throws<NullReferenceException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "SERIALIZE_TO_NULL"));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
index 7d658576e5..f23c9e9757 100644
--- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -16,15 +16,7 @@
#endregion
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core;
using Grpc.Core.Internal;
-using Grpc.Core.Utils;
-using NUnit.Framework;
namespace Grpc.Core.Tests
{
@@ -42,7 +34,7 @@ namespace Grpc.Core.Tests
get { return composable; }
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return null;
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 9aab54d2d0..775849d89b 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -107,6 +107,42 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
+ public void AsyncUnary_RequestSerializationExceptionDoesntLeakResources()
+ {
+ string nullRequest = null; // will throw when serializing
+ Assert.Throws(typeof(ArgumentNullException), () => asyncCall.UnaryCallAsync(nullRequest));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
+ public void AsyncUnary_StartCallFailureDoesntLeakResources()
+ {
+ fakeCall.MakeStartCallFail();
+ Assert.Throws(typeof(InvalidOperationException), () => asyncCall.UnaryCallAsync("request1"));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
+ public void SyncUnary_RequestSerializationExceptionDoesntLeakResources()
+ {
+ string nullRequest = null; // will throw when serializing
+ Assert.Throws(typeof(ArgumentNullException), () => asyncCall.UnaryCall(nullRequest));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
+ public void SyncUnary_StartCallFailureDoesntLeakResources()
+ {
+ fakeCall.MakeStartCallFail();
+ Assert.Throws(typeof(InvalidOperationException), () => asyncCall.UnaryCall("request1"));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
public void ClientStreaming_StreamingReadNotAllowed()
{
asyncCall.ClientStreamingCallAsync();
@@ -328,6 +364,15 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
+ public void ClientStreaming_StartCallFailureDoesntLeakResources()
+ {
+ fakeCall.MakeStartCallFail();
+ Assert.Throws(typeof(InvalidOperationException), () => asyncCall.ClientStreamingCallAsync());
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
public void ServerStreaming_StreamingSendNotAllowed()
{
asyncCall.StartServerStreamingCall("request1");
@@ -402,6 +447,27 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
+ public void ServerStreaming_RequestSerializationExceptionDoesntLeakResources()
+ {
+ string nullRequest = null; // will throw when serializing
+ Assert.Throws(typeof(ArgumentNullException), () => asyncCall.StartServerStreamingCall(nullRequest));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+ var readTask = responseStream.MoveNext();
+ }
+
+ [Test]
+ public void ServerStreaming_StartCallFailureDoesntLeakResources()
+ {
+ fakeCall.MakeStartCallFail();
+ Assert.Throws(typeof(InvalidOperationException), () => asyncCall.StartServerStreamingCall("request1"));
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
+ [Test]
public void DuplexStreaming_NoRequestNoResponse_Success()
{
asyncCall.StartDuplexStreamingCall();
@@ -558,6 +624,15 @@ namespace Grpc.Core.Internal.Tests
AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
}
+ [Test]
+ public void DuplexStreaming_StartCallFailureDoesntLeakResources()
+ {
+ fakeCall.MakeStartCallFail();
+ Assert.Throws(typeof(InvalidOperationException), () => asyncCall.StartDuplexStreamingCall());
+ Assert.AreEqual(0, channel.GetCallReferenceCount());
+ Assert.IsTrue(fakeCall.IsDisposed);
+ }
+
ClientSideStatus CreateClientSideStatus(StatusCode statusCode)
{
return new ClientSideStatus(new Status(statusCode, ""), new Metadata());
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
index 581ac3384b..ef67918dab 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
@@ -31,6 +31,7 @@ namespace Grpc.Core.Internal.Tests
/// </summary>
internal class FakeNativeCall : INativeCall
{
+ private bool shouldStartCallFail;
public IUnaryResponseClientCallback UnaryResponseClientCallback
{
get;
@@ -102,26 +103,31 @@ namespace Grpc.Core.Internal.Tests
public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
+ StartCallMaybeFail();
UnaryResponseClientCallback = callback;
}
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
+ StartCallMaybeFail();
throw new NotImplementedException();
}
public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
+ StartCallMaybeFail();
UnaryResponseClientCallback = callback;
}
public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
+ StartCallMaybeFail();
ReceivedStatusOnClientCallback = callback;
}
public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
+ StartCallMaybeFail();
ReceivedStatusOnClientCallback = callback;
}
@@ -165,5 +171,22 @@ namespace Grpc.Core.Internal.Tests
{
IsDisposed = true;
}
+
+ /// <summary>
+ /// Emulate CallSafeHandle.CheckOk() failure for all future attempts
+ /// to start a call.
+ /// </summary>
+ public void MakeStartCallFail()
+ {
+ shouldStartCallFail = true;
+ }
+
+ private void StartCallMaybeFail()
+ {
+ if (shouldStartCallFail)
+ {
+ throw new InvalidOperationException("Start call has failed.");
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/MarshallerTest.cs b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs
new file mode 100644
index 0000000000..97f64a0575
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/MarshallerTest.cs
@@ -0,0 +1,105 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class MarshallerTest
+ {
+ [Test]
+ public void ContextualSerializerEmulation()
+ {
+ Func<string, byte[]> simpleSerializer = System.Text.Encoding.UTF8.GetBytes;
+ Func<byte[], string> simpleDeserializer = System.Text.Encoding.UTF8.GetString;
+ var marshaller = new Marshaller<string>(simpleSerializer,
+ simpleDeserializer);
+
+ Assert.AreSame(simpleSerializer, marshaller.Serializer);
+ Assert.AreSame(simpleDeserializer, marshaller.Deserializer);
+
+ // test that emulated contextual serializer and deserializer work
+ string origMsg = "abc";
+ var serializationContext = new FakeSerializationContext();
+ marshaller.ContextualSerializer(origMsg, serializationContext);
+
+ var deserializationContext = new FakeDeserializationContext(serializationContext.Payload);
+ Assert.AreEqual(origMsg, marshaller.ContextualDeserializer(deserializationContext));
+ }
+
+ [Test]
+ public void SimpleSerializerEmulation()
+ {
+ Action<string, SerializationContext> contextualSerializer = (str, context) =>
+ {
+ var bytes = System.Text.Encoding.UTF8.GetBytes(str);
+ context.Complete(bytes);
+ };
+ Func<DeserializationContext, string> contextualDeserializer = (context) =>
+ {
+ return System.Text.Encoding.UTF8.GetString(context.PayloadAsNewBuffer());
+ };
+ var marshaller = new Marshaller<string>(contextualSerializer, contextualDeserializer);
+
+ Assert.AreSame(contextualSerializer, marshaller.ContextualSerializer);
+ Assert.AreSame(contextualDeserializer, marshaller.ContextualDeserializer);
+
+ // test that emulated serializer and deserializer work
+ var origMsg = "abc";
+ var serialized = marshaller.Serializer(origMsg);
+ Assert.AreEqual(origMsg, marshaller.Deserializer(serialized));
+ }
+
+ class FakeSerializationContext : SerializationContext
+ {
+ public byte[] Payload;
+ public override void Complete(byte[] payload)
+ {
+ this.Payload = payload;
+ }
+ }
+
+ class FakeDeserializationContext : DeserializationContext
+ {
+ public byte[] payload;
+
+ public FakeDeserializationContext(byte[] payload)
+ {
+ this.payload = payload;
+ }
+
+ public override int PayloadLength => payload.Length;
+
+ public override byte[] PayloadAsNewBuffer()
+ {
+ return payload;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
index 8916731757..d85d7572a6 100644
--- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
@@ -66,11 +66,30 @@ namespace Grpc.Core.Tests
new Metadata.Entry("0123456789abc", "XYZ");
new Metadata.Entry("-abc", "XYZ");
new Metadata.Entry("a_bc_", "XYZ");
+ new Metadata.Entry("abc.xyz", "XYZ");
+ new Metadata.Entry("abc.xyz-bin", new byte[] {1, 2, 3});
Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz"));
Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz"));
}
[Test]
+ public void KeysAreNormalized_UppercaseKey()
+ {
+ var uppercaseKey = "ABC";
+ var entry = new Metadata.Entry(uppercaseKey, "XYZ");
+ Assert.AreEqual("abc", entry.Key);
+ }
+
+ [Test]
+ public void KeysAreNormalized_LowercaseKey()
+ {
+ var lowercaseKey = "abc";
+ var entry = new Metadata.Entry(lowercaseKey, "XYZ");
+ // no allocation if key already lowercase
+ Assert.AreSame(lowercaseKey, entry.Key);
+ }
+
+ [Test]
public void Entry_ConstructionPreconditions()
{
Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz"));
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index eaad409ec0..0904453b6e 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -102,6 +102,7 @@ namespace Grpc.Core.Tests
"Grpc.HealthCheck.Tests",
"Grpc.IntegrationTesting",
"Grpc.Reflection.Tests",
+ "Grpc.Tools.Tests",
};
foreach (var assemblyName in otherAssemblies)
{
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e9930b6fbc..7ce929dfa3 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -72,9 +72,9 @@ namespace Grpc.Core
this.environment = GrpcEnvironment.AddRef();
this.completionQueue = this.environment.PickCompletionQueue();
- using (var nativeCredentials = credentials.ToNativeCredentials())
using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options.Values))
{
+ var nativeCredentials = credentials.GetNativeCredentials();
if (nativeCredentials != null)
{
this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs);
@@ -136,7 +136,7 @@ namespace Grpc.Core
/// </summary>
public async Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{
- var result = await WaitForStateChangedInternalAsync(lastObservedState, deadline).ConfigureAwait(false);
+ var result = await TryWaitForStateChangedAsync(lastObservedState, deadline).ConfigureAwait(false);
if (!result)
{
throw new TaskCanceledException("Reached deadline.");
@@ -147,7 +147,7 @@ namespace Grpc.Core
/// Returned tasks completes once channel state has become different from
/// given lastObservedState (<c>true</c> is returned) or if the wait has timed out (<c>false</c> is returned).
/// </summary>
- internal Task<bool> WaitForStateChangedInternalAsync(ChannelState lastObservedState, DateTime? deadline = null)
+ public Task<bool> TryWaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{
GrpcPreconditions.CheckArgument(lastObservedState != ChannelState.Shutdown,
"Shutdown is a terminal state. No further state changes can occur.");
@@ -297,6 +297,12 @@ namespace Grpc.Core
activeCallCounter.Decrement();
}
+ // for testing only
+ internal long GetCallReferenceCount()
+ {
+ return activeCallCounter.Count;
+ }
+
private ChannelState GetConnectivityState(bool tryToConnect)
{
try
diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
index ba482897d7..3ce32f31b7 100644
--- a/src/csharp/Grpc.Core/ChannelCredentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -31,6 +31,19 @@ namespace Grpc.Core
public abstract class ChannelCredentials
{
static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
+ readonly Lazy<ChannelCredentialsSafeHandle> cachedNativeCredentials;
+
+ /// <summary>
+ /// Creates a new instance of channel credentials
+ /// </summary>
+ public ChannelCredentials()
+ {
+ // Native credentials object need to be kept alive once initialized for subchannel sharing to work correctly
+ // with secure connections. See https://github.com/grpc/grpc/issues/15207.
+ // We rely on finalizer to clean up the native portion of ChannelCredentialsSafeHandle after the ChannelCredentials
+ // instance becomes unused.
+ this.cachedNativeCredentials = new Lazy<ChannelCredentialsSafeHandle>(() => CreateNativeCredentials());
+ }
/// <summary>
/// Returns instance of credentials that provides no security and
@@ -57,11 +70,22 @@ namespace Grpc.Core
}
/// <summary>
- /// Creates native object for the credentials. May return null if insecure channel
- /// should be created.
+ /// Gets native object for the credentials, creating one if it already doesn't exist. May return null if insecure channel
+ /// should be created. Caller must not call <c>Dispose()</c> on the returned native credentials as their lifetime
+ /// is managed by this class (and instances of native credentials are cached).
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal ChannelCredentialsSafeHandle GetNativeCredentials()
+ {
+ return cachedNativeCredentials.Value;
+ }
+
+ /// <summary>
+ /// Creates a new native object for the credentials. May return null if insecure channel
+ /// should be created. For internal use only, use <see cref="GetNativeCredentials"/> instead.
/// </summary>
/// <returns>The native credentials.</returns>
- internal abstract ChannelCredentialsSafeHandle ToNativeCredentials();
+ internal abstract ChannelCredentialsSafeHandle CreateNativeCredentials();
/// <summary>
/// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
@@ -73,7 +97,7 @@ namespace Grpc.Core
private sealed class InsecureCredentialsImpl : ChannelCredentials
{
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return null;
}
@@ -145,7 +169,7 @@ namespace Grpc.Core
get { return true; }
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
@@ -173,12 +197,11 @@ namespace Grpc.Core
GrpcPreconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
- using (var channelCreds = channelCredentials.ToNativeCredentials())
using (var callCreds = callCredentials.ToNativeCredentials())
{
- var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCreds, callCreds);
+ var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCredentials.GetNativeCredentials(), callCreds);
if (nativeComposite.IsInvalid)
{
throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 6ad5d56cad..880f2bef5f 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -26,8 +26,10 @@ namespace Grpc.Core
/// <summary>
/// Channel option specified when creating a channel.
/// Corresponds to grpc_channel_args from grpc/grpc.h.
+ /// Commonly used channel option names are defined in <c>ChannelOptions</c>,
+ /// but any of the GRPC_ARG_* channel options names defined in grpc_types.h can be used.
/// </summary>
- public sealed class ChannelOption
+ public sealed class ChannelOption : IEquatable<ChannelOption>
{
/// <summary>
/// Type of <c>ChannelOption</c>.
@@ -119,10 +121,60 @@ namespace Grpc.Core
return stringValue;
}
}
+
+ /// <summary>
+ /// Determines whether the specified object is equal to the current object.
+ /// </summary>
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as ChannelOption);
+ }
+
+ /// <summary>
+ /// Determines whether the specified object is equal to the current object.
+ /// </summary>
+ public bool Equals(ChannelOption other)
+ {
+ return other != null &&
+ type == other.type &&
+ name == other.name &&
+ intValue == other.intValue &&
+ stringValue == other.stringValue;
+ }
+
+ /// <summary>
+ /// A hash code for the current object.
+ /// </summary>
+ public override int GetHashCode()
+ {
+ var hashCode = 1412678443;
+ hashCode = hashCode * -1521134295 + type.GetHashCode();
+ hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(name);
+ hashCode = hashCode * -1521134295 + intValue.GetHashCode();
+ hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(stringValue);
+ return hashCode;
+ }
+
+ /// <summary>
+ /// Equality operator.
+ /// </summary>
+ public static bool operator ==(ChannelOption option1, ChannelOption option2)
+ {
+ return EqualityComparer<ChannelOption>.Default.Equals(option1, option2);
+ }
+
+ /// <summary>
+ /// Inequality operator.
+ /// </summary>
+ public static bool operator !=(ChannelOption option1, ChannelOption option2)
+ {
+ return !(option1 == option2);
+ }
}
/// <summary>
- /// Defines names of supported channel options.
+ /// Defines names of most commonly used channel options.
+ /// Other supported options names can be found in grpc_types.h (GRPC_ARG_* definitions)
/// </summary>
public static class ChannelOptions
{
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index fac34071be..05edce7467 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -151,12 +151,12 @@ namespace Grpc.Core
{
private class ClientBaseConfigurationInterceptor : Interceptor
{
- readonly Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor;
+ readonly Func<IMethod, string, CallOptions, ClientBaseConfigurationInfo> interceptor;
/// <summary>
/// Creates a new instance of ClientBaseConfigurationInterceptor given the specified header and host interceptor function.
/// </summary>
- public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor)
+ public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, ClientBaseConfigurationInfo> interceptor)
{
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
}
@@ -166,7 +166,7 @@ namespace Grpc.Core
where TResponse : class
{
var newHostAndCallOptions = interceptor(context.Method, context.Host, context.Options);
- return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Item1, newHostAndCallOptions.Item2);
+ return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Host, newHostAndCallOptions.CallOptions);
}
public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
@@ -195,6 +195,18 @@ namespace Grpc.Core
}
}
+ internal struct ClientBaseConfigurationInfo
+ {
+ internal readonly string Host;
+ internal readonly CallOptions CallOptions;
+
+ internal ClientBaseConfigurationInfo(string host, CallOptions callOptions)
+ {
+ Host = host;
+ CallOptions = callOptions;
+ }
+ }
+
readonly CallInvoker undecoratedCallInvoker;
readonly string host;
@@ -206,7 +218,7 @@ namespace Grpc.Core
internal CallInvoker CreateDecoratedCallInvoker()
{
- return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => Tuple.Create(this.host, options)));
+ return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => new ClientBaseConfigurationInfo(this.host, options)));
}
internal ClientBaseConfiguration WithHost(string host)
diff --git a/src/csharp/Grpc.Core/DeserializationContext.cs b/src/csharp/Grpc.Core/DeserializationContext.cs
new file mode 100644
index 0000000000..5b6372ef85
--- /dev/null
+++ b/src/csharp/Grpc.Core/DeserializationContext.cs
@@ -0,0 +1,46 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Provides access to the payload being deserialized when deserializing messages.
+ /// </summary>
+ public abstract class DeserializationContext
+ {
+ /// <summary>
+ /// Get the total length of the payload in bytes.
+ /// </summary>
+ public abstract int PayloadLength { get; }
+
+ /// <summary>
+ /// Gets the entire payload as a newly allocated byte array.
+ /// Once the byte array is returned, the byte array becomes owned by the caller and won't be ever accessed or reused by gRPC again.
+ /// NOTE: Obtaining the buffer as a newly allocated byte array is the simplest way of accessing the payload,
+ /// but it can have important consequences in high-performance scenarios.
+ /// In particular, using this method usually requires copying of the entire buffer one extra time.
+ /// Also, allocating a new buffer each time can put excessive pressure on GC, especially if
+ /// the payload is more than 86700 bytes large (which means the newly allocated buffer will be placed in LOH,
+ /// and LOH object can only be garbage collected via a full ("stop the world") GC run).
+ /// NOTE: Deserializers are expected not to call this method more than once per received message
+ /// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so.
+ /// </summary>
+ /// <returns>byte array containing the entire payload.</returns>
+ public abstract byte[] PayloadAsNewBuffer();
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 3c9e090ba4..4cdf0ee6a7 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -17,6 +17,7 @@
#endregion
using System;
+using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Logging;
using Grpc.Core.Profiling;
@@ -34,6 +35,8 @@ namespace Grpc.Core.Internal
readonly CallInvocationDetails<TRequest, TResponse> details;
readonly INativeCall injectedNativeCall; // for testing
+ bool registeredWithChannel;
+
// Dispose of to de-register cancellation token registration
IDisposable cancellationTokenRegistration;
@@ -77,43 +80,59 @@ namespace Grpc.Core.Internal
using (profiler.NewScope("AsyncCall.UnaryCall"))
using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.CreateSync())
{
- byte[] payload = UnsafeSerialize(msg);
+ bool callStartedOk = false;
+ try
+ {
+ unaryResponseTcs = new TaskCompletionSource<TResponse>();
- unaryResponseTcs = new TaskCompletionSource<TResponse>();
+ lock (myLock)
+ {
+ GrpcPreconditions.CheckState(!started);
+ started = true;
+ Initialize(cq);
- lock (myLock)
- {
- GrpcPreconditions.CheckState(!started);
- started = true;
- Initialize(cq);
+ halfcloseRequested = true;
+ readingDone = true;
+ }
- halfcloseRequested = true;
- readingDone = true;
- }
+ byte[] payload = UnsafeSerialize(msg);
- using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
- {
- var ctx = details.Channel.Environment.BatchContextPool.Lease();
- try
+ using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
- call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
- var ev = cq.Pluck(ctx.Handle);
- bool success = (ev.success != 0);
+ var ctx = details.Channel.Environment.BatchContextPool.Lease();
try
{
- using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch"))
+ call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+ callStartedOk = true;
+
+ var ev = cq.Pluck(ctx.Handle);
+ bool success = (ev.success != 0);
+ try
{
- HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata());
+ using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch"))
+ {
+ HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata());
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.Error(e, "Exception occurred while invoking completion delegate.");
}
}
- catch (Exception e)
+ finally
{
- Logger.Error(e, "Exception occurred while invoking completion delegate.");
+ ctx.Recycle();
}
}
- finally
+ }
+ finally
+ {
+ if (!callStartedOk)
{
- ctx.Recycle();
+ lock (myLock)
+ {
+ OnFailedToStartCallLocked();
+ }
}
}
@@ -130,22 +149,35 @@ namespace Grpc.Core.Internal
{
lock (myLock)
{
- GrpcPreconditions.CheckState(!started);
- started = true;
+ bool callStartedOk = false;
+ try
+ {
+ GrpcPreconditions.CheckState(!started);
+ started = true;
- Initialize(details.Channel.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
- halfcloseRequested = true;
- readingDone = true;
+ halfcloseRequested = true;
+ readingDone = true;
- byte[] payload = UnsafeSerialize(msg);
+ byte[] payload = UnsafeSerialize(msg);
- unaryResponseTcs = new TaskCompletionSource<TResponse>();
- using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ unaryResponseTcs = new TaskCompletionSource<TResponse>();
+ using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ {
+ call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+ callStartedOk = true;
+ }
+
+ return unaryResponseTcs.Task;
+ }
+ finally
{
- call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+ if (!callStartedOk)
+ {
+ OnFailedToStartCallLocked();
+ }
}
- return unaryResponseTcs.Task;
}
}
@@ -157,20 +189,32 @@ namespace Grpc.Core.Internal
{
lock (myLock)
{
- GrpcPreconditions.CheckState(!started);
- started = true;
+ bool callStartedOk = false;
+ try
+ {
+ GrpcPreconditions.CheckState(!started);
+ started = true;
- Initialize(details.Channel.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
- readingDone = true;
+ readingDone = true;
+
+ unaryResponseTcs = new TaskCompletionSource<TResponse>();
+ using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ {
+ call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags);
+ callStartedOk = true;
+ }
- unaryResponseTcs = new TaskCompletionSource<TResponse>();
- using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ return unaryResponseTcs.Task;
+ }
+ finally
{
- call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags);
+ if (!callStartedOk)
+ {
+ OnFailedToStartCallLocked();
+ }
}
-
- return unaryResponseTcs.Task;
}
}
@@ -181,21 +225,33 @@ namespace Grpc.Core.Internal
{
lock (myLock)
{
- GrpcPreconditions.CheckState(!started);
- started = true;
+ bool callStartedOk = false;
+ try
+ {
+ GrpcPreconditions.CheckState(!started);
+ started = true;
- Initialize(details.Channel.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
- halfcloseRequested = true;
+ halfcloseRequested = true;
- byte[] payload = UnsafeSerialize(msg);
+ byte[] payload = UnsafeSerialize(msg);
- streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
- using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
+ using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ {
+ call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+ callStartedOk = true;
+ }
+ call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
+ }
+ finally
{
- call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+ if (!callStartedOk)
+ {
+ OnFailedToStartCallLocked();
+ }
}
- call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
}
}
@@ -207,17 +263,29 @@ namespace Grpc.Core.Internal
{
lock (myLock)
{
- GrpcPreconditions.CheckState(!started);
- started = true;
+ bool callStartedOk = false;
+ try
+ {
+ GrpcPreconditions.CheckState(!started);
+ started = true;
- Initialize(details.Channel.CompletionQueue);
+ Initialize(details.Channel.CompletionQueue);
- streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
- using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
+ using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
+ {
+ call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags);
+ callStartedOk = true;
+ }
+ call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
+ }
+ finally
{
- call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags);
+ if (!callStartedOk)
+ {
+ OnFailedToStartCallLocked();
+ }
}
- call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
}
}
@@ -325,9 +393,22 @@ namespace Grpc.Core.Internal
}
}
- protected override void OnAfterReleaseResources()
+ protected override void OnAfterReleaseResourcesLocked()
{
- details.Channel.RemoveCallReference(this);
+ if (registeredWithChannel)
+ {
+ details.Channel.RemoveCallReference(this);
+ registeredWithChannel = false;
+ }
+ }
+
+ protected override void OnAfterReleaseResourcesUnlocked()
+ {
+ // If cancellation callback is in progress, this can block
+ // so we need to do this outside of call's lock to prevent
+ // deadlock.
+ // See https://github.com/grpc/grpc/issues/14777
+ // See https://github.com/dotnet/corefx/issues/14903
cancellationTokenRegistration?.Dispose();
}
@@ -385,10 +466,27 @@ namespace Grpc.Core.Internal
var call = CreateNativeCall(cq);
details.Channel.AddCallReference(this);
+ registeredWithChannel = true;
InitializeInternal(call);
+
RegisterCancellationCallback();
}
+ private void OnFailedToStartCallLocked()
+ {
+ ReleaseResources();
+
+ // We need to execute the hook that disposes the cancellation token
+ // registration, but it cannot be done from under a lock.
+ // To make things simple, we just schedule the unregistering
+ // on a threadpool.
+ // - Once the native call is disposed, the Cancel() calls are ignored anyway
+ // - We don't care about the overhead as OnFailedToStartCallLocked() only happens
+ // when something goes very bad when initializing a call and that should
+ // never happen when gRPC is used correctly.
+ ThreadPool.QueueUserWorkItem((state) => OnAfterReleaseResourcesUnlocked());
+ }
+
private INativeCall CreateNativeCall(CompletionQueueSafeHandle cq)
{
if (injectedNativeCall != null)
@@ -448,6 +546,7 @@ namespace Grpc.Core.Internal
TResponse msg = default(TResponse);
var deserializeException = TryDeserialize(receivedMessage, out msg);
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -464,7 +563,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
responseHeadersTcs.SetResult(responseHeaders);
@@ -494,6 +598,7 @@ namespace Grpc.Core.Internal
TaskCompletionSource<object> delayedStreamingWriteTcs = null;
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -504,7 +609,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (delayedStreamingWriteTcs != null)
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 3273c26b88..a93dc34620 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -189,17 +189,21 @@ namespace Grpc.Core.Internal
/// </summary>
protected abstract Exception GetRpcExceptionClientOnly();
- private void ReleaseResources()
+ protected void ReleaseResources()
{
if (call != null)
{
call.Dispose();
}
disposed = true;
- OnAfterReleaseResources();
+ OnAfterReleaseResourcesLocked();
}
- protected virtual void OnAfterReleaseResources()
+ protected virtual void OnAfterReleaseResourcesLocked()
+ {
+ }
+
+ protected virtual void OnAfterReleaseResourcesUnlocked()
{
}
@@ -235,6 +239,7 @@ namespace Grpc.Core.Internal
{
bool delayCompletion = false;
TaskCompletionSource<object> origTcs = null;
+ bool releasedResources;
lock (myLock)
{
if (!success && !finished && IsClient) {
@@ -252,7 +257,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (!success)
@@ -282,9 +292,15 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleSendStatusFromServerFinished(bool success)
{
+ bool releasedResources;
lock (myLock)
{
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (!success)
@@ -310,6 +326,7 @@ namespace Grpc.Core.Internal
var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
TaskCompletionSource<TRead> origTcs = null;
+ bool releasedResources;
lock (myLock)
{
origTcs = streamingReadTcs;
@@ -332,7 +349,12 @@ namespace Grpc.Core.Internal
streamingReadTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (deserializeException != null && !IsClient)
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 11acb27533..0ceca4abb8 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -184,7 +184,7 @@ namespace Grpc.Core.Internal
throw new InvalidOperationException("Call be only called for client calls");
}
- protected override void OnAfterReleaseResources()
+ protected override void OnAfterReleaseResourcesLocked()
{
server.RemoveCallReference(this);
}
@@ -206,6 +206,7 @@ namespace Grpc.Core.Internal
{
// NOTE: because this event is a result of batch containing GRPC_OP_RECV_CLOSE_ON_SERVER,
// success will be always set to true.
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -217,7 +218,12 @@ namespace Grpc.Core.Internal
streamingReadTcs = new TaskCompletionSource<TRequest>();
streamingReadTcs.SetResult(default(TRequest));
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (cancelled)
diff --git a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs
index 3f9605bfdd..09ded1a036 100644
--- a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs
+++ b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs
@@ -35,6 +35,13 @@ namespace Grpc.Core.Internal
/// </summary>
public static string PtrToStringUTF8(IntPtr ptr, int len)
{
+ if (len == 0)
+ {
+ return "";
+ }
+
+ // TODO(jtattermusch): once Span dependency is added,
+ // use Span-based API to decode the string without copying the buffer.
var bytes = new byte[len];
Marshal.Copy(ptr, bytes, 0, len);
return EncodingUTF8.GetString(bytes);
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index 4d695e8850..faeb51e6f7 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -68,8 +68,8 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg);
- Logger.Error(e, GetMetadataExceptionLogMsg);
+ // eat the exception, we must not throw when inside callback from native code.
+ Logger.Error(e, "Exception occurred while invoking native metadata interceptor handler.");
}
}
@@ -87,7 +87,8 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg);
+ string detail = GetMetadataExceptionStatusMsg + " " + e.ToString();
+ Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, detail);
Logger.Error(e, GetMetadataExceptionLogMsg);
}
}
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
index 153a52f947..a45cbe4107 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
@@ -505,7 +505,7 @@ namespace Grpc.Core.Internal
public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback);
public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor);
public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
- public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+ public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args);
public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq);
@@ -752,7 +752,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
[DllImport(ImportName)]
- public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+ public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
[DllImport(ImportName)]
public static extern void grpcsharp_server_credentials_release(IntPtr credentials);
@@ -1045,7 +1045,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
[DllImport(ImportName)]
- public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+ public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
[DllImport(ImportName)]
public static extern void grpcsharp_server_credentials_release(IntPtr credentials);
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
index 545e581f94..5f8c95c4ea 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -32,13 +32,13 @@ namespace Grpc.Core.Internal
{
}
- public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth)
+ public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, SslClientCertificateRequestType clientCertificateRequest)
{
GrpcPreconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
return Native.grpcsharp_ssl_server_credentials_create(pemRootCerts,
keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
new UIntPtr((ulong)keyCertPairCertChainArray.Length),
- forceClientAuth ? 1 : 0);
+ clientCertificateRequest);
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
index 7185d68efe..1786fc2e3f 100644
--- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
+++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
@@ -51,11 +51,12 @@ namespace Grpc.Core.Internal
Logger.Debug("Attempting to load native library \"{0}\"", this.libraryPath);
- this.handle = PlatformSpecificLoadLibrary(this.libraryPath);
+ this.handle = PlatformSpecificLoadLibrary(this.libraryPath, out string loadLibraryErrorDetail);
if (this.handle == IntPtr.Zero)
{
- throw new IOException(string.Format("Error loading native library \"{0}\"", this.libraryPath));
+ throw new IOException(string.Format("Error loading native library \"{0}\". {1}",
+ this.libraryPath, loadLibraryErrorDetail));
}
}
@@ -129,31 +130,44 @@ namespace Grpc.Core.Internal
/// <summary>
/// Loads library in a platform specific way.
/// </summary>
- private static IntPtr PlatformSpecificLoadLibrary(string libraryPath)
+ private static IntPtr PlatformSpecificLoadLibrary(string libraryPath, out string errorMsg)
{
if (PlatformApis.IsWindows)
{
+ // TODO(jtattermusch): populate the error on Windows
+ errorMsg = null;
return Windows.LoadLibrary(libraryPath);
}
if (PlatformApis.IsLinux)
{
if (PlatformApis.IsMono)
{
- return Mono.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+ return LoadLibraryPosix(Mono.dlopen, Mono.dlerror, libraryPath, out errorMsg);
}
if (PlatformApis.IsNetCore)
{
- return CoreCLR.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+ return LoadLibraryPosix(CoreCLR.dlopen, CoreCLR.dlerror, libraryPath, out errorMsg);
}
- return Linux.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+ return LoadLibraryPosix(Linux.dlopen, Linux.dlerror, libraryPath, out errorMsg);
}
if (PlatformApis.IsMacOSX)
{
- return MacOSX.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+ return LoadLibraryPosix(MacOSX.dlopen, MacOSX.dlerror, libraryPath, out errorMsg);
}
throw new InvalidOperationException("Unsupported platform.");
}
+ private static IntPtr LoadLibraryPosix(Func<string, int, IntPtr> dlopenFunc, Func<IntPtr> dlerrorFunc, string libraryPath, out string errorMsg)
+ {
+ errorMsg = null;
+ IntPtr ret = dlopenFunc(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+ if (ret == IntPtr.Zero)
+ {
+ errorMsg = Marshal.PtrToStringAnsi(dlerrorFunc());
+ }
+ return ret;
+ }
+
private static string FirstValidLibraryPath(string[] libraryPathAlternatives)
{
GrpcPreconditions.CheckArgument(libraryPathAlternatives.Length > 0, "libraryPathAlternatives cannot be empty.");
@@ -184,6 +198,9 @@ namespace Grpc.Core.Internal
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
+ internal static extern IntPtr dlerror();
+
+ [DllImport("libdl.so")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
}
@@ -193,6 +210,9 @@ namespace Grpc.Core.Internal
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libSystem.dylib")]
+ internal static extern IntPtr dlerror();
+
+ [DllImport("libSystem.dylib")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
}
@@ -209,6 +229,9 @@ namespace Grpc.Core.Internal
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("__Internal")]
+ internal static extern IntPtr dlerror();
+
+ [DllImport("__Internal")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
}
@@ -223,6 +246,9 @@ namespace Grpc.Core.Internal
internal static extern IntPtr dlopen(string filename, int flags);
[DllImport("libcoreclr.so")]
+ internal static extern IntPtr dlerror();
+
+ [DllImport("libcoreclr.so")]
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
}
}
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 1d758ca935..0af9aa586b 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -29,36 +29,129 @@ namespace Grpc.Core
readonly Func<T, byte[]> serializer;
readonly Func<byte[], T> deserializer;
+ readonly Action<T, SerializationContext> contextualSerializer;
+ readonly Func<DeserializationContext, T> contextualDeserializer;
+
/// <summary>
- /// Initializes a new marshaller.
+ /// Initializes a new marshaller from simple serialize/deserialize functions.
/// </summary>
/// <param name="serializer">Function that will be used to serialize messages.</param>
/// <param name="deserializer">Function that will be used to deserialize messages.</param>
public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{
- this.serializer = GrpcPreconditions.CheckNotNull(serializer, "serializer");
- this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, "deserializer");
+ this.serializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
+ this.deserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
+ this.contextualSerializer = EmulateContextualSerializer;
+ this.contextualDeserializer = EmulateContextualDeserializer;
}
/// <summary>
- /// Gets the serializer function.
+ /// Initializes a new marshaller from serialize/deserialize fuctions that can access serialization and deserialization
+ /// context. Compared to the simple serializer/deserializer functions, using the contextual version provides more
+ /// flexibility and can lead to increased efficiency (and better performance).
+ /// Note: This constructor is part of an experimental API that can change or be removed without any prior notice.
/// </summary>
- public Func<T, byte[]> Serializer
+ /// <param name="serializer">Function that will be used to serialize messages.</param>
+ /// <param name="deserializer">Function that will be used to deserialize messages.</param>
+ public Marshaller(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)
{
- get
- {
- return this.serializer;
- }
+ this.contextualSerializer = GrpcPreconditions.CheckNotNull(serializer, nameof(serializer));
+ this.contextualDeserializer = GrpcPreconditions.CheckNotNull(deserializer, nameof(deserializer));
+ // TODO(jtattermusch): once gRPC C# library switches to using contextual (de)serializer,
+ // emulating the simple (de)serializer will become unnecessary.
+ this.serializer = EmulateSimpleSerializer;
+ this.deserializer = EmulateSimpleDeserializer;
}
/// <summary>
+ /// Gets the serializer function.
+ /// </summary>
+ public Func<T, byte[]> Serializer => this.serializer;
+
+ /// <summary>
/// Gets the deserializer function.
/// </summary>
- public Func<byte[], T> Deserializer
+ public Func<byte[], T> Deserializer => this.deserializer;
+
+ /// <summary>
+ /// Gets the serializer function.
+ /// Note: experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public Action<T, SerializationContext> ContextualSerializer => this.contextualSerializer;
+
+ /// <summary>
+ /// Gets the serializer function.
+ /// Note: experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public Func<DeserializationContext, T> ContextualDeserializer => this.contextualDeserializer;
+
+ // for backward compatibility, emulate the simple serializer using the contextual one
+ private byte[] EmulateSimpleSerializer(T msg)
{
- get
+ // TODO(jtattermusch): avoid the allocation by passing a thread-local instance
+ // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer.
+ var context = new EmulatedSerializationContext();
+ this.contextualSerializer(msg, context);
+ return context.GetPayload();
+ }
+
+ // for backward compatibility, emulate the simple deserializer using the contextual one
+ private T EmulateSimpleDeserializer(byte[] payload)
+ {
+ // TODO(jtattermusch): avoid the allocation by passing a thread-local instance
+ // This code will become unnecessary once gRPC C# library switches to using contextual (de)serializer.
+ var context = new EmulatedDeserializationContext(payload);
+ return this.contextualDeserializer(context);
+ }
+
+ // for backward compatibility, emulate the contextual serializer using the simple one
+ private void EmulateContextualSerializer(T message, SerializationContext context)
+ {
+ var payload = this.serializer(message);
+ context.Complete(payload);
+ }
+
+ // for backward compatibility, emulate the contextual deserializer using the simple one
+ private T EmulateContextualDeserializer(DeserializationContext context)
+ {
+ return this.deserializer(context.PayloadAsNewBuffer());
+ }
+
+ internal class EmulatedSerializationContext : SerializationContext
+ {
+ bool isComplete;
+ byte[] payload;
+
+ public override void Complete(byte[] payload)
+ {
+ GrpcPreconditions.CheckState(!isComplete);
+ this.isComplete = true;
+ this.payload = payload;
+ }
+
+ internal byte[] GetPayload()
+ {
+ return this.payload;
+ }
+ }
+
+ internal class EmulatedDeserializationContext : DeserializationContext
+ {
+ readonly byte[] payload;
+ bool alreadyCalledPayloadAsNewBuffer;
+
+ public EmulatedDeserializationContext(byte[] payload)
+ {
+ this.payload = GrpcPreconditions.CheckNotNull(payload);
+ }
+
+ public override int PayloadLength => payload.Length;
+
+ public override byte[] PayloadAsNewBuffer()
{
- return this.deserializer;
+ GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer);
+ alreadyCalledPayloadAsNewBuffer = true;
+ return payload;
}
}
}
@@ -77,6 +170,15 @@ namespace Grpc.Core
}
/// <summary>
+ /// Creates a marshaller from specified contextual serializer and deserializer.
+ /// Note: This method is part of an experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public static Marshaller<T> Create<T>(Action<T, SerializationContext> serializer, Func<DeserializationContext, T> deserializer)
+ {
+ return new Marshaller<T>(serializer, deserializer);
+ }
+
+ /// <summary>
/// Returns a marshaller for <c>string</c> type. This is useful for testing.
/// </summary>
public static Marshaller<string> StringMarshaller
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index 0e4456278c..bc263c3469 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -135,7 +135,7 @@ namespace Grpc.Core
}
/// <summary>
- /// <see cref="T:IList`1"/>
+ /// Adds a new ASCII-valued metadata entry. See <c>Metadata.Entry</c> constructor for params.
/// </summary>
public void Add(string key, string value)
{
@@ -143,7 +143,7 @@ namespace Grpc.Core
}
/// <summary>
- /// <see cref="T:IList`1"/>
+ /// Adds a new binary-valued metadata entry. See <c>Metadata.Entry</c> constructor for params.
/// </summary>
public void Add(string key, byte[] valueBytes)
{
@@ -225,8 +225,6 @@ namespace Grpc.Core
/// </summary>
public class Entry
{
- private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$");
-
readonly string key;
readonly string value;
readonly byte[] valueBytes;
@@ -241,7 +239,7 @@ namespace Grpc.Core
/// <summary>
/// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct with a binary value.
/// </summary>
- /// <param name="key">Metadata key, needs to have suffix indicating a binary valued metadata entry.</param>
+ /// <param name="key">Metadata key. Gets converted to lowercase. Needs to have suffix indicating a binary valued metadata entry. Can only contain lowercase alphanumeric characters, underscores, hyphens and dots.</param>
/// <param name="valueBytes">Value bytes.</param>
public Entry(string key, byte[] valueBytes)
{
@@ -255,9 +253,9 @@ namespace Grpc.Core
}
/// <summary>
- /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct holding an ASCII value.
+ /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct with an ASCII value.
/// </summary>
- /// <param name="key">Metadata key, must not use suffix indicating a binary valued metadata entry.</param>
+ /// <param name="key">Metadata key. Gets converted to lowercase. Must not use suffix indicating a binary valued metadata entry. Can only contain lowercase alphanumeric characters, underscores, hyphens and dots.</param>
/// <param name="value">Value string. Only ASCII characters are allowed.</param>
public Entry(string key, string value)
{
@@ -358,10 +356,42 @@ namespace Grpc.Core
private static string NormalizeKey(string key)
{
- var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant();
- GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized),
- "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
- return normalized;
+ GrpcPreconditions.CheckNotNull(key, "key");
+
+ GrpcPreconditions.CheckArgument(IsValidKey(key, out bool isLowercase),
+ "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores, hyphens and dots.");
+ if (isLowercase)
+ {
+ // save allocation of a new string if already lowercase
+ return key;
+ }
+
+ return key.ToLowerInvariant();
+ }
+
+ private static bool IsValidKey(string input, out bool isLowercase)
+ {
+ isLowercase = true;
+ for (int i = 0; i < input.Length; i++)
+ {
+ char c = input[i];
+ if ('a' <= c && c <= 'z' ||
+ '0' <= c && c <= '9' ||
+ c == '.' ||
+ c == '_' ||
+ c == '-' )
+ continue;
+
+ if ('A' <= c && c <= 'Z')
+ {
+ isLowercase = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
index e3bbeb071e..af660064a4 100644
--- a/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
+++ b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
@@ -1,6 +1,6 @@
<Project>
<ItemGroup>
- <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.so">
+ <Content Include="..\..\..\cmake\build\libgrpc_csharp_ext.so">
<Link>libgrpc_csharp_ext.x64.so</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>false</Pack>
diff --git a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
index 309e33d47e..570b0cd8b7 100644
--- a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
+++ b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
@@ -1,6 +1,6 @@
<Project>
<ItemGroup>
- <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
+ <Content Include="..\..\..\cmake\build\libgrpc_csharp_ext.dylib">
<Link>libgrpc_csharp_ext.x64.dylib</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Pack>false</Pack>
diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs
index 94429d74ce..ff89897565 100644
--- a/src/csharp/Grpc.Core/RpcException.cs
+++ b/src/csharp/Grpc.Core/RpcException.cs
@@ -33,10 +33,8 @@ namespace Grpc.Core
/// Creates a new <c>RpcException</c> associated with given status.
/// </summary>
/// <param name="status">Resulting status of a call.</param>
- public RpcException(Status status) : base(status.ToString())
+ public RpcException(Status status) : this(status, Metadata.Empty, status.ToString())
{
- this.status = status;
- this.trailers = Metadata.Empty;
}
/// <summary>
@@ -44,10 +42,8 @@ namespace Grpc.Core
/// </summary>
/// <param name="status">Resulting status of a call.</param>
/// <param name="message">The exception message.</param>
- public RpcException(Status status, string message) : base(message)
+ public RpcException(Status status, string message) : this(status, Metadata.Empty, message)
{
- this.status = status;
- this.trailers = Metadata.Empty;
}
/// <summary>
@@ -55,7 +51,17 @@ namespace Grpc.Core
/// </summary>
/// <param name="status">Resulting status of a call.</param>
/// <param name="trailers">Response trailing metadata.</param>
- public RpcException(Status status, Metadata trailers) : base(status.ToString())
+ public RpcException(Status status, Metadata trailers) : this(status, trailers, status.ToString())
+ {
+ }
+
+ /// <summary>
+ /// Creates a new <c>RpcException</c> associated with given status, message and trailing response metadata.
+ /// </summary>
+ /// <param name="status">Resulting status of a call.</param>
+ /// <param name="trailers">Response trailing metadata.</param>
+ /// <param name="message">The exception message.</param>
+ public RpcException(Status status, Metadata trailers, string message) : base(message)
{
this.status = status;
this.trailers = GrpcPreconditions.CheckNotNull(trailers);
diff --git a/src/csharp/Grpc.Core/SerializationContext.cs b/src/csharp/Grpc.Core/SerializationContext.cs
new file mode 100644
index 0000000000..cf4d1595da
--- /dev/null
+++ b/src/csharp/Grpc.Core/SerializationContext.cs
@@ -0,0 +1,34 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Provides storage for payload when serializing a message.
+ /// </summary>
+ public abstract class SerializationContext
+ {
+ /// <summary>
+ /// Use the byte array as serialized form of current message and mark serialization process as complete.
+ /// Complete() can only be called once. By calling this method the caller gives up the ownership of the
+ /// payload which must not be accessed afterwards.
+ /// </summary>
+ /// <param name="payload">the serialized form of current message</param>
+ public abstract void Complete(byte[] payload);
+ }
+}
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
index 703f9ff6b3..8e4e44ba50 100644
--- a/src/csharp/Grpc.Core/ServerCredentials.cs
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -58,41 +58,106 @@ namespace Grpc.Core
}
/// <summary>
+ /// Modes of requesting client's SSL certificate by the server.
+ /// Corresponds to <c>grpc_ssl_client_certificate_request_type</c>.
+ /// </summary>
+ public enum SslClientCertificateRequestType {
+ /// <summary>
+ /// Server does not request client certificate.
+ /// The certificate presented by the client is not checked by the server at
+ /// all. (A client may present a self signed or signed certificate or not
+ /// present a certificate at all and any of those option would be accepted)
+ /// </summary>
+ DontRequest = 0,
+ /// <summary>
+ /// Server requests client certificate but does not enforce that the client
+ /// presents a certificate.
+ /// If the client presents a certificate, the client authentication is left to
+ /// the application (the necessary metadata will be available to the
+ /// application via authentication context properties, see grpc_auth_context).
+ /// The client's key certificate pair must be valid for the SSL connection to
+ /// be established.
+ ///</summary>
+ RequestButDontVerify,
+ /// <summary>
+ /// Server requests client certificate but does not enforce that the client
+ /// presents a certificate.
+ /// If the client presents a certificate, the client authentication is done by
+ /// the gRPC framework. (For a successful connection the client needs to either
+ /// present a certificate that can be verified against the root certificate
+ /// configured by the server or not present a certificate at all)
+ /// The client's key certificate pair must be valid for the SSL connection to
+ /// be established.
+ /// </summary>
+ RequestAndVerify,
+ /// <summary>
+ /// Server requests client certificate and enforces that the client presents a
+ /// certificate.
+ /// If the client presents a certificate, the client authentication is left to
+ /// the application (the necessary metadata will be available to the
+ /// application via authentication context properties, see grpc_auth_context).
+ /// The client's key certificate pair must be valid for the SSL connection to
+ /// be established.
+ ///</summary>
+ RequestAndRequireButDontVerify,
+ /// <summary>
+ /// Server requests client certificate and enforces that the client presents a
+ /// certificate.
+ /// The cerificate presented by the client is verified by the gRPC framework.
+ /// (For a successful connection the client needs to present a certificate that
+ /// can be verified against the root certificate configured by the server)
+ /// The client's key certificate pair must be valid for the SSL connection to
+ /// be established.
+ /// </summary>
+ RequestAndRequireAndVerify,
+ }
+ /// <summary>
/// Server-side SSL credentials.
/// </summary>
public class SslServerCredentials : ServerCredentials
{
readonly IList<KeyCertificatePair> keyCertificatePairs;
readonly string rootCertificates;
- readonly bool forceClientAuth;
+ readonly SslClientCertificateRequestType clientCertificateRequest;
/// <summary>
/// Creates server-side SSL credentials.
/// </summary>
/// <param name="keyCertificatePairs">Key-certificates to use.</param>
/// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
- /// <param name="forceClientAuth">If true, client will be rejected unless it proves its unthenticity using against rootCertificates.</param>
+ /// <param name="forceClientAuth">Deprecated, use clientCertificateRequest overload instead.</param>
public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth)
+ : this(keyCertificatePairs, rootCertificates, forceClientAuth ? SslClientCertificateRequestType.RequestAndRequireAndVerify : SslClientCertificateRequestType.DontRequest)
+ {
+ }
+
+ /// <summary>
+ /// Creates server-side SSL credentials.
+ /// </summary>
+ /// <param name="keyCertificatePairs">Key-certificates to use.</param>
+ /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
+ /// <param name="clientCertificateRequest">Options for requesting and verifying client certificate.</param>
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, SslClientCertificateRequestType clientCertificateRequest)
{
this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
GrpcPreconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
"At least one KeyCertificatePair needs to be provided.");
- if (forceClientAuth)
+ if (clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireAndVerify)
{
GrpcPreconditions.CheckNotNull(rootCertificates,
- "Cannot force client authentication unless you provide rootCertificates.");
+ "Cannot require and verify client certificate unless you provide rootCertificates.");
}
this.rootCertificates = rootCertificates;
- this.forceClientAuth = forceClientAuth;
+ this.clientCertificateRequest = clientCertificateRequest;
}
/// <summary>
/// Creates server-side SSL credentials.
- /// This constructor should be use if you do not wish to autheticate client
- /// using client root certificates.
+ /// This constructor should be used if you do not wish to authenticate the client.
+ /// (client certificate won't be requested and checked by the server at all).
/// </summary>
/// <param name="keyCertificatePairs">Key-certificates to use.</param>
- public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, false)
+ public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, SslClientCertificateRequestType.DontRequest)
{
}
@@ -119,13 +184,24 @@ namespace Grpc.Core
}
/// <summary>
- /// If true, the authenticity of client check will be enforced.
+ /// Deprecated. If true, the authenticity of client check will be enforced.
/// </summary>
public bool ForceClientAuthentication
{
get
{
- return this.forceClientAuth;
+ return this.clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireAndVerify;
+ }
+ }
+
+ /// <summary>
+ /// Mode of requesting certificate from client by the server.
+ /// </summary>
+ public SslClientCertificateRequestType ClientCertificateRequest
+ {
+ get
+ {
+ return this.clientCertificateRequest;
}
}
@@ -139,7 +215,7 @@ namespace Grpc.Core
certChains[i] = keyCertificatePairs[i].CertificateChain;
keys[i] = keyCertificatePairs[i].PrivateKey;
}
- return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth);
+ return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, clientCertificateRequest);
}
}
}
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 45bd8ebd85..ed0d884365 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
- <GrpcCsharpVersion>1.15.0-dev</GrpcCsharpVersion>
+ <GrpcCsharpVersion>1.17.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 295e0f2577..14714c8c4a 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.15.0.0";
+ public const string CurrentAssemblyFileVersion = "1.17.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.15.0-dev";
+ public const string CurrentVersion = "1.17.0-dev";
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index ad7033b782..8daf3fa98b 100755
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -18,7 +18,7 @@
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
- <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
+ <PackageReference Include="CommandLineParser" Version="2.3.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index c83ccd2612..40447854f4 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -153,9 +153,10 @@ namespace Grpc.IntegrationTesting
[Test]
public void MetadataCredentials_InterceptorThrows()
{
+ var authInterceptorExceptionMessage = "Auth interceptor throws";
var callCredentials = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) =>
{
- throw new Exception("Auth interceptor throws");
+ throw new Exception(authInterceptorExceptionMessage);
}));
var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(), callCredentials);
channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
@@ -163,6 +164,7 @@ namespace Grpc.IntegrationTesting
var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { }));
Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode);
+ StringAssert.Contains(authInterceptorExceptionMessage, ex.Status.Detail);
}
private class FakeTestService : TestService.TestServiceBase
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
index 152d8feab9..b3c47c2d8d 100644
--- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -37,20 +37,24 @@ namespace Grpc.IntegrationTesting
public class SslCredentialsTest
{
const string Host = "localhost";
+ const string IsPeerAuthenticatedMetadataKey = "test_only_is_peer_authenticated";
Server server;
Channel channel;
TestService.TestServiceClient client;
- [OneTimeSetUp]
- public void Init()
+ string rootCert;
+ KeyCertificatePair keyCertPair;
+
+ public void InitClientAndServer(bool clientAddKeyCertPair,
+ SslClientCertificateRequestType clientCertRequestType)
{
- var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
- var keyCertPair = new KeyCertificatePair(
+ rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
+ keyCertPair = new KeyCertificatePair(
File.ReadAllText(TestCredentials.ServerCertChainPath),
File.ReadAllText(TestCredentials.ServerPrivateKeyPath));
- var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true);
- var clientCredentials = new SslCredentials(rootCert, keyCertPair);
+ var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, clientCertRequestType);
+ var clientCredentials = clientAddKeyCertPair ? new SslCredentials(rootCert, keyCertPair) : new SslCredentials(rootCert);
// Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
@@ -72,19 +76,133 @@ namespace Grpc.IntegrationTesting
[OneTimeTearDown]
public void Cleanup()
{
- channel.ShutdownAsync().Wait();
- server.ShutdownAsync().Wait();
+ if (channel != null)
+ {
+ channel.ShutdownAsync().Wait();
+ }
+ if (server != null)
+ {
+ server.ShutdownAsync().Wait();
+ }
}
[Test]
- public void AuthenticatedClientAndServer()
+ public async Task NoClientCert_DontRequestClientCertificate_Accepted()
{
- var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
- Assert.AreEqual(10, response.Payload.Body.Length);
+ InitClientAndServer(
+ clientAddKeyCertPair: false,
+ clientCertRequestType: SslClientCertificateRequestType.DontRequest);
+
+ await CheckAccepted(expectPeerAuthenticated: false);
}
[Test]
- public async Task AuthContextIsPopulated()
+ public async Task ClientWithCert_DontRequestClientCertificate_AcceptedButPeerNotAuthenticated()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: true,
+ clientCertRequestType: SslClientCertificateRequestType.DontRequest);
+
+ await CheckAccepted(expectPeerAuthenticated: false);
+ }
+
+ [Test]
+ public async Task NoClientCert_RequestClientCertificateButDontVerify_Accepted()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: false,
+ clientCertRequestType: SslClientCertificateRequestType.RequestButDontVerify);
+
+ await CheckAccepted(expectPeerAuthenticated: false);
+ }
+
+ [Test]
+ public async Task NoClientCert_RequestClientCertificateAndVerify_Accepted()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: false,
+ clientCertRequestType: SslClientCertificateRequestType.RequestAndVerify);
+
+ await CheckAccepted(expectPeerAuthenticated: false);
+ }
+
+ [Test]
+ public async Task ClientWithCert_RequestAndRequireClientCertificateButDontVerify_Accepted()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: true,
+ clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireButDontVerify);
+
+ await CheckAccepted(expectPeerAuthenticated: true);
+ await CheckAuthContextIsPopulated();
+ }
+
+ [Test]
+ public async Task ClientWithCert_RequestAndRequireClientCertificateAndVerify_Accepted()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: true,
+ clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireAndVerify);
+
+ await CheckAccepted(expectPeerAuthenticated: true);
+ await CheckAuthContextIsPopulated();
+ }
+
+ [Test]
+ public void NoClientCert_RequestAndRequireClientCertificateButDontVerify_Rejected()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: false,
+ clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireButDontVerify);
+
+ CheckRejected();
+ }
+
+ [Test]
+ public void NoClientCert_RequestAndRequireClientCertificateAndVerify_Rejected()
+ {
+ InitClientAndServer(
+ clientAddKeyCertPair: false,
+ clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireAndVerify);
+
+ CheckRejected();
+ }
+
+ [Test]
+ public void Constructor_LegacyForceClientAuth()
+ {
+ var creds = new SslServerCredentials(new[] { keyCertPair }, rootCert, true);
+ Assert.AreEqual(SslClientCertificateRequestType.RequestAndRequireAndVerify, creds.ClientCertificateRequest);
+
+ var creds2 = new SslServerCredentials(new[] { keyCertPair }, rootCert, false);
+ Assert.AreEqual(SslClientCertificateRequestType.DontRequest, creds2.ClientCertificateRequest);
+ }
+
+ [Test]
+ public void Constructor_NullRootCerts()
+ {
+ var keyCertPairs = new[] { keyCertPair };
+ Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.DontRequest));
+ Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndVerify));
+ Assert.DoesNotThrow(() => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireButDontVerify));
+ Assert.Throws(typeof(ArgumentNullException), () => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireAndVerify));
+ }
+
+ private async Task CheckAccepted(bool expectPeerAuthenticated)
+ {
+ var call = client.UnaryCallAsync(new SimpleRequest { ResponseSize = 10 });
+ var response = await call;
+ Assert.AreEqual(10, response.Payload.Body.Length);
+ Assert.AreEqual(expectPeerAuthenticated.ToString(), call.GetTrailers().First((entry) => entry.Key == IsPeerAuthenticatedMetadataKey).Value);
+ }
+
+ private void CheckRejected()
+ {
+ var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { ResponseSize = 10 }));
+ Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode);
+ }
+
+ private async Task CheckAuthContextIsPopulated()
{
var call = client.StreamingInputCall();
await call.RequestStream.CompleteAsync();
@@ -96,6 +214,7 @@ namespace Grpc.IntegrationTesting
{
public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
+ context.ResponseTrailers.Add(IsPeerAuthenticatedMetadataKey, context.AuthContext.IsPeerAuthenticated.ToString());
return Task.FromResult(new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) });
}
diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
index 8a629f9748..d39d46cf1b 100644
--- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
+++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
@@ -16,7 +16,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
+ <PackageReference Include="CommandLineParser" Version="2.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs
new file mode 100644
index 0000000000..e4c9b2fa84
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs
@@ -0,0 +1,85 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class CSharpGeneratorTest : GeneratorTest
+ {
+ GeneratorServices _generator;
+
+ [SetUp]
+ public new void SetUp()
+ {
+ _generator = GeneratorServices.GetForLanguage("CSharp", _log);
+ }
+
+ [TestCase("foo.proto", "Foo.cs", "FooGrpc.cs")]
+ [TestCase("sub/foo.proto", "Foo.cs", "FooGrpc.cs")]
+ [TestCase("one_two.proto", "OneTwo.cs", "OneTwoGrpc.cs")]
+ [TestCase("__one_two!.proto", "OneTwo!.cs", "OneTwo!Grpc.cs")]
+ [TestCase("one(two).proto", "One(two).cs", "One(two)Grpc.cs")]
+ [TestCase("one_(two).proto", "One(two).cs", "One(two)Grpc.cs")]
+ [TestCase("one two.proto", "One two.cs", "One twoGrpc.cs")]
+ [TestCase("one_ two.proto", "One two.cs", "One twoGrpc.cs")]
+ [TestCase("one .proto", "One .cs", "One Grpc.cs")]
+ public void NameMangling(string proto, string expectCs, string expectGrpcCs)
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "grpcservices", "both"));
+ Assert.AreEqual(2, poss.Length);
+ Assert.Contains(expectCs, poss);
+ Assert.Contains(expectGrpcCs, poss);
+ }
+
+ [Test]
+ public void NoGrpcOneOutput()
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto"));
+ Assert.AreEqual(1, poss.Length);
+ }
+
+ [TestCase("none")]
+ [TestCase("")]
+ public void GrpcNoneOneOutput(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(1, poss.Length);
+ }
+
+ [TestCase("client")]
+ [TestCase("server")]
+ [TestCase("both")]
+ public void GrpcEnabledTwoOutputs(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [Test]
+ public void OutputDirMetadataRecognized()
+ {
+ var item = Utils.MakeItem("foo.proto", "OutputDir", "out");
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(1, poss.Length);
+ Assert.That(poss[0], Is.EqualTo("out/Foo.cs") | Is.EqualTo("out\\Foo.cs"));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs
new file mode 100644
index 0000000000..bd0405a03a
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs
@@ -0,0 +1,88 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.IO;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class CppGeneratorTest : GeneratorTest
+ {
+ GeneratorServices _generator;
+
+ [SetUp]
+ public new void SetUp()
+ {
+ _generator = GeneratorServices.GetForLanguage("Cpp", _log);
+ }
+
+ [TestCase("foo.proto", "", "foo")]
+ [TestCase("foo.proto", ".", "foo")]
+ [TestCase("foo.proto", "./", "foo")]
+ [TestCase("sub/foo.proto", "", "sub/foo")]
+ [TestCase("root/sub/foo.proto", "root", "sub/foo")]
+ [TestCase("root/sub/foo.proto", "root", "sub/foo")]
+ [TestCase("/root/sub/foo.proto", "/root", "sub/foo")]
+ public void RelativeDirectoryCompute(string proto, string root, string expectStem)
+ {
+ if (Path.DirectorySeparatorChar == '\\')
+ expectStem = expectStem.Replace('/', '\\');
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "ProtoRoot", root));
+ Assert.AreEqual(2, poss.Length);
+ Assert.Contains(expectStem + ".pb.cc", poss);
+ Assert.Contains(expectStem + ".pb.h", poss);
+ }
+
+ [Test]
+ public void NoGrpcTwoOutputs()
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto"));
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [TestCase("false")]
+ [TestCase("")]
+ public void GrpcDisabledTwoOutput(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [TestCase("true")]
+ public void GrpcEnabledFourOutputs(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(4, poss.Length);
+ Assert.Contains("foo.pb.cc", poss);
+ Assert.Contains("foo.pb.h", poss);
+ Assert.Contains("foo_grpc.pb.cc", poss);
+ Assert.Contains("foo_grpc.pb.h", poss);
+ }
+
+ [Test]
+ public void OutputDirMetadataRecognized()
+ {
+ var item = Utils.MakeItem("foo.proto", "OutputDir", "out");
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ Assert.That(Path.GetDirectoryName(poss[0]), Is.EqualTo("out"));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs
new file mode 100644
index 0000000000..e89a8f4b5d
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs
@@ -0,0 +1,146 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.IO;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class DepFileUtilTest
+ {
+
+ [Test]
+ public void HashString64Hex_IsSane()
+ {
+ string hashFoo1 = DepFileUtil.HashString64Hex("foo");
+ string hashEmpty = DepFileUtil.HashString64Hex("");
+ string hashFoo2 = DepFileUtil.HashString64Hex("foo");
+
+ StringAssert.IsMatch("^[a-f0-9]{16}$", hashFoo1);
+ Assert.AreEqual(hashFoo1, hashFoo2);
+ Assert.AreNotEqual(hashFoo1, hashEmpty);
+ }
+
+ [Test]
+ public void GetDepFilenameForProto_IsSane()
+ {
+ StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}_foo.protodep$",
+ DepFileUtil.GetDepFilenameForProto("out", "foo.proto"));
+ StringAssert.IsMatch(@"^[a-f0-9]{16}_foo.protodep$",
+ DepFileUtil.GetDepFilenameForProto("", "foo.proto"));
+ }
+
+ [Test]
+ public void GetDepFilenameForProto_HashesDir()
+ {
+ string PickHash(string fname) =>
+ DepFileUtil.GetDepFilenameForProto("", fname).Substring(0, 16);
+
+ string same1 = PickHash("dir1/dir2/foo.proto");
+ string same2 = PickHash("dir1/dir2/proto.foo");
+ string same3 = PickHash("dir1/dir2/proto");
+ string same4 = PickHash("dir1/dir2/.proto");
+ string unsame1 = PickHash("dir2/foo.proto");
+ string unsame2 = PickHash("/dir2/foo.proto");
+
+ Assert.AreEqual(same1, same2);
+ Assert.AreEqual(same1, same3);
+ Assert.AreEqual(same1, same4);
+ Assert.AreNotEqual(same1, unsame1);
+ Assert.AreNotEqual(unsame1, unsame2);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Full file reading tests
+
+ // Generated by protoc on Windows. Slashes vary.
+ const string depFile1 =
+ @"C:\projects\foo\src\./foo.grpc.pb.cc \
+C:\projects\foo\src\./foo.grpc.pb.h \
+C:\projects\foo\src\./foo.pb.cc \
+ C:\projects\foo\src\./foo.pb.h: C:/usr/include/google/protobuf/wrappers.proto\
+ C:/usr/include/google/protobuf/any.proto\
+C:/usr/include/google/protobuf/source_context.proto\
+ C:/usr/include/google/protobuf/type.proto\
+ foo.proto";
+
+ // This has a nasty output directory with a space.
+ const string depFile2 =
+ @"obj\Release x64\net45\/Foo.cs \
+obj\Release x64\net45\/FooGrpc.cs: C:/usr/include/google/protobuf/wrappers.proto\
+ C:/projects/foo/src//foo.proto";
+
+ [Test]
+ public void ReadDependencyInput_FullFile1()
+ {
+ string[] deps = ReadDependencyInputFromFileData(depFile1, "foo.proto");
+
+ Assert.NotNull(deps);
+ Assert.That(deps, Has.Length.InRange(4, 5)); // foo.proto may or may not be listed.
+ Assert.That(deps, Has.One.EndsWith("wrappers.proto"));
+ Assert.That(deps, Has.One.EndsWith("type.proto"));
+ Assert.That(deps, Has.None.StartWith(" "));
+ }
+
+ [Test]
+ public void ReadDependencyInput_FullFile2()
+ {
+ string[] deps = ReadDependencyInputFromFileData(depFile2, "C:/projects/foo/src/foo.proto");
+
+ Assert.NotNull(deps);
+ Assert.That(deps, Has.Length.InRange(1, 2));
+ Assert.That(deps, Has.One.EndsWith("wrappers.proto"));
+ Assert.That(deps, Has.None.StartWith(" "));
+ }
+
+ [Test]
+ public void ReadDependencyInput_FullFileUnparsable()
+ {
+ string[] deps = ReadDependencyInputFromFileData("a:/foo.proto", "/foo.proto");
+ Assert.NotNull(deps);
+ Assert.Zero(deps.Length);
+ }
+
+ // NB in our tests files are put into the temp directory but all have
+ // different names. Avoid adding files with the same directory path and
+ // name, or add reasonable handling for it if required. Tests are run in
+ // parallel and will collide otherwise.
+ private string[] ReadDependencyInputFromFileData(string fileData, string protoName)
+ {
+ string tempPath = Path.GetTempPath();
+ string tempfile = DepFileUtil.GetDepFilenameForProto(tempPath, protoName);
+ try
+ {
+ File.WriteAllText(tempfile, fileData);
+ var mockEng = new Moq.Mock<IBuildEngine>();
+ var log = new TaskLoggingHelper(mockEng.Object, "x");
+ return DepFileUtil.ReadDependencyInputs(tempPath, protoName, log);
+ }
+ finally
+ {
+ try
+ {
+ File.Delete(tempfile);
+ }
+ catch { }
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs
new file mode 100644
index 0000000000..8a8fc81aba
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class GeneratorTest
+ {
+ protected Mock<IBuildEngine> _mockEngine;
+ protected TaskLoggingHelper _log;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _mockEngine = new Mock<IBuildEngine>();
+ _log = new TaskLoggingHelper(_mockEngine.Object, "dummy");
+ }
+
+ [TestCase("csharp")]
+ [TestCase("CSharp")]
+ [TestCase("cpp")]
+ public void ValidLanguages(string lang)
+ {
+ Assert.IsNotNull(GeneratorServices.GetForLanguage(lang, _log));
+ _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Never);
+ }
+
+ [TestCase("")]
+ [TestCase("COBOL")]
+ public void InvalidLanguages(string lang)
+ {
+ Assert.IsNull(GeneratorServices.GetForLanguage(lang, _log));
+ _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Once);
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
new file mode 100644
index 0000000000..a2d4874eec
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
@@ -0,0 +1,78 @@
+<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <Import Project="..\Grpc.Core\Version.csproj.include" />
+
+ <PropertyGroup>
+ <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+
+ <Import Project="..\Grpc.Core\SourceLink.csproj.include" />
+
+ <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings
+ in that file conflict with the intent of this build, as it cannot be signed,
+ and may not compile Grpc.Core/Version.cs, as that file references constants
+ in Grpc.Core.dll.
+ TODO(kkm): Refactor imports. -->
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' ">
+ <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 -->
+ <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Tools\Grpc.Tools.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Moq" Version="4.8.3" />
+ <PackageReference Include="NUnit; NUnitLite" Version="3.10.1" />
+ <PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+ <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" />
+ </ItemGroup>
+
+ <!-- Groups below is a hack to allow the test to run under Mono Framework build.
+ ========================================================================== -->
+
+ <!-- Mono unfortunately comes with broken Microsoft.Build.* assemblies installed in
+ the GAC, but fortunately searches for runtime assemblies in a different order
+ than Windows CLR host: the GAC assemblies have the lowest search priority, (see
+ https://www.mono-project.com/docs/advanced/assemblies-and-the-gac/), not the
+ highest as is in Windows (documented at
+ https://docs.microsoft.com/dotnet/framework/deployment/how-the-runtime-locates-assemblies).
+ To run the tests under Mono, we need correct assemblies in the same directory as
+ the test executable. Correct versions are in the MSBuild directory under Mono. -->
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' ">
+ <None Include="$(_MSBuildAssemblyPath)/Microsoft.Build.Framework.dll;
+ $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.v4.0.dll;
+ $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.Core.dll"
+ CopyToOutputDirectory="Always" Visible="false" />
+ </ItemGroup>
+ <PropertyGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' ">
+ <!-- The None items are included into assembly candidate resolution by default, and
+ we do not want that, as they are not valid as reference assemblies (the version of
+ Microsoft.Build.Utilities.v4.0 is a pure facade for Microsoft.Build.Utilities.Core,
+ and does not define any types at all). Exclude them from assembly resolution. See
+ https://github.com/Microsoft/msbuild/blob/50639058f/documentation/wiki/ResolveAssemblyReference.md -->
+ <AssemblySearchPaths>{HintPathFromItem};{TargetFrameworkDirectory};{RawFileName}</AssemblySearchPaths>
+ <!-- Mono knows better where its MSBuild is. -->
+ <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' != 'Core' "
+ >$(MSBuildToolsPath)</_MSBuildAssemblyPath>
+ <!-- Under dotnet, make the best guess we can. -->
+ <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' == 'Core' "
+ >$(FrameworkPathOverride)/../msbuild/$(MSBuildToolsVersion)/bin</_MSBuildAssemblyPath>
+ </PropertyGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Tools.Tests/NUnitMain.cs b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..418c33820e
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
@@ -0,0 +1,33 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Reflection;
+using NUnitLite;
+
+namespace Grpc.Tools.Tests
+{
+ static class NUnitMain
+ {
+ public static int Main(string[] args) =>
+#if NETCOREAPP1_0 || NETCOREAPP1_1
+ new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
+#else
+ new AutoRun().Execute(args);
+#endif
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs
new file mode 100644
index 0000000000..ea763f4e40
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs
@@ -0,0 +1,76 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Reflection; // UWYU: Object.GetType() extension.
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileBasicTest
+ {
+ // Mock task class that stops right before invoking protoc.
+ public class ProtoCompileTestable : ProtoCompile
+ {
+ public string LastPathToTool { get; private set; }
+ public string[] LastResponseFile { get; private set; }
+
+ protected override int ExecuteTool(string pathToTool,
+ string response,
+ string commandLine)
+ {
+ // We should never be using command line commands.
+ Assert.That(commandLine, Is.Null | Is.Empty);
+
+ // Must receive a path to tool
+ Assert.That(pathToTool, Is.Not.Null & Is.Not.Empty);
+ Assert.That(response, Is.Not.Null & Does.EndWith("\n"));
+
+ LastPathToTool = pathToTool;
+ LastResponseFile = response.Remove(response.Length - 1).Split('\n');
+
+ // Do not run the tool, but pretend it ran successfully.
+ return 0;
+ }
+ };
+
+ protected Mock<IBuildEngine> _mockEngine;
+ protected ProtoCompileTestable _task;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _mockEngine = new Mock<IBuildEngine>();
+ _task = new ProtoCompileTestable {
+ BuildEngine = _mockEngine.Object
+ };
+ }
+
+ [TestCase("ProtoBuf")]
+ [TestCase("Generator")]
+ [TestCase("OutputDir")]
+ [Description("We trust MSBuild to initialize these properties.")]
+ public void RequiredAttributePresentOnProperty(string prop)
+ {
+ var pinfo = _task.GetType()?.GetProperty(prop);
+ Assert.NotNull(pinfo);
+ Assert.That(pinfo, Has.Attribute<RequiredAttribute>());
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs
new file mode 100644
index 0000000000..cac7146634
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs
@@ -0,0 +1,179 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.IO;
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileCommandLineGeneratorTest : ProtoCompileBasicTest
+ {
+ [SetUp]
+ public new void SetUp()
+ {
+ _task.Generator = "csharp";
+ _task.OutputDir = "outdir";
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto");
+ }
+
+ void ExecuteExpectSuccess()
+ {
+ _mockEngine
+ .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
+ .Callback((BuildErrorEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"));
+ bool result = _task.Execute();
+ Assert.IsTrue(result);
+ }
+
+ [Test]
+ public void MinimalCompile()
+ {
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastPathToTool, Does.Match(@"protoc(.exe)?$"));
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "a.proto" }));
+ }
+
+ [Test]
+ public void CompileTwoFiles()
+ {
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto", "foo/b.proto");
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "a.proto", "foo/b.proto" }));
+ }
+
+ [Test]
+ public void CompileWithProtoPaths()
+ {
+ _task.ProtoPath = new[] { "/path1", "/path2" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "--proto_path=/path1",
+ "--proto_path=/path2", "a.proto" }));
+ }
+
+ [TestCase("Cpp")]
+ [TestCase("CSharp")]
+ [TestCase("Java")]
+ [TestCase("Javanano")]
+ [TestCase("Js")]
+ [TestCase("Objc")]
+ [TestCase("Php")]
+ [TestCase("Python")]
+ [TestCase("Ruby")]
+ public void CompileWithOptions(string gen)
+ {
+ _task.Generator = gen;
+ _task.OutputOptions = new[] { "foo", "bar" };
+ ExecuteExpectSuccess();
+ gen = gen.ToLowerInvariant();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ $"--{gen}_out=outdir", $"--{gen}_opt=foo,bar", "a.proto" }));
+ }
+
+ [Test]
+ public void OutputDependencyFile()
+ {
+ _task.DependencyOut = "foo/my.protodep";
+ // Task fails trying to read the non-generated file; we ignore that.
+ _task.Execute();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--dependency_out=foo/my.protodep"));
+ }
+
+ [Test]
+ public void OutputDependencyWithProtoDepDir()
+ {
+ _task.ProtoDepDir = "foo";
+ // Task fails trying to read the non-generated file; we ignore that.
+ _task.Execute();
+ Assert.That(_task.LastResponseFile,
+ Has.One.Match(@"^--dependency_out=foo[/\\].+_a.protodep$"));
+ }
+
+ [Test]
+ public void GenerateGrpc()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--csharp_out=outdir", "--grpc_out=outdir",
+ "--plugin=protoc-gen-grpc=/foo/grpcgen" }));
+ }
+
+ [Test]
+ public void GenerateGrpcWithOutDir()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputDir = "gen-out";
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--csharp_out=outdir", "--grpc_out=gen-out" }));
+ }
+
+ [Test]
+ public void GenerateGrpcWithOptions()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputOptions = new[] { "baz", "quux" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--grpc_opt=baz,quux"));
+ }
+
+ [Test]
+ public void DirectoryArgumentsSlashTrimmed()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputDir = "gen-out/";
+ _task.OutputDir = "outdir/";
+ _task.ProtoPath = new[] { "/path1/", "/path2/" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--proto_path=/path1", "--proto_path=/path2",
+ "--csharp_out=outdir", "--grpc_out=gen-out" }));
+ }
+
+ [TestCase(".", ".")]
+ [TestCase("/", "/")]
+ [TestCase("//", "/")]
+ [TestCase("/foo/", "/foo")]
+ [TestCase("/foo", "/foo")]
+ [TestCase("foo/", "foo")]
+ [TestCase("foo//", "foo")]
+ [TestCase("foo/\\", "foo")]
+ [TestCase("foo\\/", "foo")]
+ [TestCase("C:\\foo", "C:\\foo")]
+ [TestCase("C:", "C:")]
+ [TestCase("C:\\", "C:\\")]
+ [TestCase("C:\\\\", "C:\\")]
+ public void DirectorySlashTrimmingCases(string given, string expect)
+ {
+ if (Path.DirectorySeparatorChar == '/')
+ expect = expect.Replace('\\', '/');
+ _task.OutputDir = given;
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--csharp_out=" + expect));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs
new file mode 100644
index 0000000000..1773dcb875
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs
@@ -0,0 +1,51 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileCommandLinePrinterTest : ProtoCompileBasicTest
+ {
+ [SetUp]
+ public new void SetUp()
+ {
+ _task.Generator = "csharp";
+ _task.OutputDir = "outdir";
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto");
+
+ _mockEngine
+ .Setup(me => me.LogMessageEvent(It.IsAny<BuildMessageEventArgs>()))
+ .Callback((BuildMessageEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"))
+ .Verifiable("Command line was not output by the task.");
+ }
+
+ void ExecuteExpectSuccess()
+ {
+ _mockEngine
+ .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
+ .Callback((BuildErrorEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"));
+ bool result = _task.Execute();
+ Assert.IsTrue(result);
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs
new file mode 100644
index 0000000000..54723b74fc
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs
@@ -0,0 +1,139 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Runtime.InteropServices; // For NETCORE tests.
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoToolsPlatformTaskTest
+ {
+ ProtoToolsPlatform _task;
+ int _cpuMatched, _osMatched;
+
+ [OneTimeSetUp]
+ public void SetUp()
+ {
+ var mockEng = new Mock<IBuildEngine>();
+ _task = new ProtoToolsPlatform() { BuildEngine = mockEng.Object };
+ _task.Execute();
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+ Assert.AreEqual(1, _cpuMatched, "CPU type detection failed");
+ Assert.AreEqual(1, _osMatched, "OS detection failed");
+ }
+
+#if NETCORE
+ // PlatformAttribute not yet available in NUnit, coming soon:
+ // https://github.com/nunit/nunit/pull/3003.
+ // Use same test case names as under the full framework.
+ [Test]
+ public void CpuIsX86()
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X86)
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x86", _task.Cpu);
+ }
+ }
+
+ [Test]
+ public void CpuIsX64()
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X64)
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x64", _task.Cpu);
+ }
+ }
+
+ [Test]
+ public void OsIsWindows()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ _osMatched++;
+ Assert.AreEqual("windows", _task.Os);
+ }
+ }
+
+ [Test]
+ public void OsIsLinux()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ _osMatched++;
+ Assert.AreEqual("linux", _task.Os);
+ }
+ }
+
+ [Test]
+ public void OsIsMacOsX()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ _osMatched++;
+ Assert.AreEqual("macosx", _task.Os);
+ }
+ }
+
+#else // !NETCORE, i.e. full framework.
+
+ [Test, Platform("32-Bit")]
+ public void CpuIsX86()
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x86", _task.Cpu);
+ }
+
+ [Test, Platform("64-Bit")]
+ public void CpuIsX64()
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x64", _task.Cpu);
+ }
+
+ [Test, Platform("Win")]
+ public void OsIsWindows()
+ {
+ _osMatched++;
+ Assert.AreEqual("windows", _task.Os);
+ }
+
+ [Test, Platform("Linux")]
+ public void OsIsLinux()
+ {
+ _osMatched++;
+ Assert.AreEqual("linux", _task.Os);
+ }
+
+ [Test, Platform("MacOSX")]
+ public void OsIsMacOsX()
+ {
+ _osMatched++;
+ Assert.AreEqual("macosx", _task.Os);
+ }
+
+#endif // NETCORE
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/Utils.cs b/src/csharp/Grpc.Tools.Tests/Utils.cs
new file mode 100644
index 0000000000..6e0f1cffd5
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/Utils.cs
@@ -0,0 +1,46 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Linq;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools.Tests
+{
+ static class Utils
+ {
+ // Build an item with a name from args[0] and metadata key-value pairs
+ // from the rest of args, interleaved.
+ // This does not do any checking, and expects an odd number of args.
+ public static ITaskItem MakeItem(params string[] args)
+ {
+ var item = new TaskItem(args[0]);
+ for (int i = 1; i < args.Length; i += 2)
+ {
+ item.SetMetadata(args[i], args[i + 1]);
+ }
+ return item;
+ }
+
+ // Return an array of items from given itemspecs.
+ public static ITaskItem[] MakeSimpleItems(params string[] specs)
+ {
+ return specs.Select(s => new TaskItem(s)).ToArray();
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
deleted file mode 100644
index 0cae5572fd..0000000000
--- a/src/csharp/Grpc.Tools.nuspec
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package>
- <metadata>
- <id>Grpc.Tools</id>
- <title>gRPC C# Tools</title>
- <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
- <description>Precompiled protobuf compiler and gRPC protobuf compiler plugin for generating gRPC client/server C# code. Binaries are available for Windows, Linux and MacOS.</description>
- <version>$version$</version>
- <authors>Google Inc.</authors>
- <owners>grpc-packages</owners>
- <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
- <projectUrl>https://github.com/grpc/grpc</projectUrl>
- <requireLicenseAcceptance>false</requireLicenseAcceptance>
- <releaseNotes>Release $version$</releaseNotes>
- <copyright>Copyright 2015, Google Inc.</copyright>
- <tags>gRPC RPC Protocol HTTP/2</tags>
- </metadata>
- <files>
- <!-- forward slashes in src path enable building on Linux -->
- <file src="protoc_plugins/protoc_windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" />
- <file src="protoc_plugins/protoc_windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" />
- <file src="protoc_plugins/protoc_windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" />
- <file src="protoc_plugins/protoc_windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" />
- <file src="protoc_plugins/protoc_linux_x86/protoc" target="tools/linux_x86/protoc" />
- <file src="protoc_plugins/protoc_linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_linux_x64/protoc" target="tools/linux_x64/protoc" />
- <file src="protoc_plugins/protoc_linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_macos_x86/protoc" target="tools/macosx_x86/protoc" />
- <file src="protoc_plugins/protoc_macos_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_macos_x64/protoc" target="tools/macosx_x64/protoc" />
- <file src="protoc_plugins/protoc_macos_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" />
- </files>
-</package>
diff --git a/src/csharp/Grpc.Tools/Common.cs b/src/csharp/Grpc.Tools/Common.cs
new file mode 100644
index 0000000000..e6acdd6393
--- /dev/null
+++ b/src/csharp/Grpc.Tools/Common.cs
@@ -0,0 +1,114 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+[assembly: InternalsVisibleTo("Grpc.Tools.Tests")]
+
+namespace Grpc.Tools
+{
+ // Metadata names (MSBuild item attributes) that we refer to often.
+ static class Metadata
+ {
+ // On output dependency lists.
+ public static string Source = "Source";
+ // On ProtoBuf items.
+ public static string ProtoRoot = "ProtoRoot";
+ public static string OutputDir = "OutputDir";
+ public static string GrpcServices = "GrpcServices";
+ public static string GrpcOutputDir = "GrpcOutputDir";
+ };
+
+ // A few flags used to control the behavior under various platforms.
+ internal static class Platform
+ {
+ public enum OsKind { Unknown, Windows, Linux, MacOsX };
+ public static readonly OsKind Os;
+
+ public enum CpuKind { Unknown, X86, X64 };
+ public static readonly CpuKind Cpu;
+
+ // This is not necessarily true, but good enough. BCL lacks a per-FS
+ // API to determine file case sensitivity.
+ public static bool IsFsCaseInsensitive => Os == OsKind.Windows;
+ public static bool IsWindows => Os == OsKind.Windows;
+
+ static Platform()
+ {
+#if NETCORE
+ Os = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OsKind.Windows
+ : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OsKind.Linux
+ : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OsKind.MacOsX
+ : OsKind.Unknown;
+
+ switch (RuntimeInformation.OSArchitecture)
+ {
+ case Architecture.X86: Cpu = CpuKind.X86; break;
+ case Architecture.X64: Cpu = CpuKind.X64; break;
+ // We do not have build tools for other architectures.
+ default: Cpu = CpuKind.Unknown; break;
+ }
+#else
+ // Running under either Mono or full MS framework.
+ Os = OsKind.Windows;
+ if (Type.GetType("Mono.Runtime", throwOnError: false) != null)
+ {
+ // Congratulations. We are running under Mono.
+ var plat = Environment.OSVersion.Platform;
+ if (plat == PlatformID.MacOSX)
+ {
+ Os = OsKind.MacOsX;
+ }
+ else if (plat == PlatformID.Unix || (int)plat == 128)
+ {
+ // This is how Mono detects OSX internally.
+ Os = File.Exists("/usr/lib/libc.dylib") ? OsKind.MacOsX : OsKind.Linux;
+ }
+ }
+
+ // Hope we are not building on ARM under Xamarin!
+ Cpu = Environment.Is64BitOperatingSystem ? CpuKind.X64 : CpuKind.X86;
+#endif
+ }
+ };
+
+ // Exception handling helpers.
+ static class Exceptions
+ {
+ // Returns true iff the exception indicates an error from an I/O call. See
+ // https://github.com/Microsoft/msbuild/blob/v15.4.8.50001/src/Shared/ExceptionHandling.cs#L101
+ static public bool IsIoRelated(Exception ex) =>
+ ex is IOException ||
+ (ex is ArgumentException && !(ex is ArgumentNullException)) ||
+ ex is SecurityException ||
+ ex is UnauthorizedAccessException ||
+ ex is NotSupportedException;
+ };
+
+ // String helpers.
+ static class Strings
+ {
+ // Compare string to argument using OrdinalIgnoreCase comparison.
+ public static bool EqualNoCase(this string a, string b) =>
+ string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
+ }
+}
diff --git a/src/csharp/Grpc.Tools/DepFileUtil.cs b/src/csharp/Grpc.Tools/DepFileUtil.cs
new file mode 100644
index 0000000000..440d3d535c
--- /dev/null
+++ b/src/csharp/Grpc.Tools/DepFileUtil.cs
@@ -0,0 +1,273 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ internal static class DepFileUtil
+ {
+ /*
+ Sample dependency files. Notable features we have to deal with:
+ * Slash doubling, must normalize them.
+ * Spaces in file names. Cannot just "unwrap" the line on backslash at eof;
+ rather, treat every line as containing one file name except for one with
+ the ':' separator, as containing exactly two.
+ * Deal with ':' also being drive letter separator (second example).
+
+ obj\Release\net45\/Foo.cs \
+ obj\Release\net45\/FooGrpc.cs: C:/foo/include/google/protobuf/wrappers.proto\
+ C:/projects/foo/src//foo.proto
+
+ C:\projects\foo\src\./foo.grpc.pb.cc \
+ C:\projects\foo\src\./foo.grpc.pb.h \
+ C:\projects\foo\src\./foo.pb.cc \
+ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
+ C:/foo/include/google/protobuf/any.proto\
+ C:/foo/include/google/protobuf/source_context.proto\
+ C:/foo/include/google/protobuf/type.proto\
+ foo.proto
+ */
+
+ /// <summary>
+ /// Read file names from the dependency file to the right of ':'
+ /// </summary>
+ /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
+ /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
+ /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
+ /// <returns>
+ /// Array of the proto file <b>input</b> dependencies as written by protoc, or empty
+ /// array if the dependency file does not exist or cannot be parsed.
+ /// </returns>
+ public static string[] ReadDependencyInputs(string protoDepDir, string proto,
+ TaskLoggingHelper log)
+ {
+ string depFilename = GetDepFilenameForProto(protoDepDir, proto);
+ string[] lines = ReadDepFileLines(depFilename, false, log);
+ if (lines.Length == 0)
+ {
+ return lines;
+ }
+
+ var result = new List<string>();
+ bool skip = true;
+ foreach (string line in lines)
+ {
+ // Start at the only line separating dependency outputs from inputs.
+ int ix = skip ? FindLineSeparator(line) : -1;
+ skip = skip && ix < 0;
+ if (skip) { continue; }
+ string file = ExtractFilenameFromLine(line, ix + 1, line.Length);
+ if (file == "")
+ {
+ log.LogMessage(MessageImportance.Low,
+ $"Skipping unparsable dependency file {depFilename}.\nLine with error: '{line}'");
+ return new string[0];
+ }
+
+ // Do not bend over backwards trying not to include a proto into its
+ // own list of dependencies. Since a file is not older than self,
+ // it is safe to add; this is purely a memory optimization.
+ if (file != proto)
+ {
+ result.Add(file);
+ }
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Read file names from the dependency file to the left of ':'
+ /// </summary>
+ /// <param name="depFilename">Path to dependency file written by protoc</param>
+ /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
+ /// <returns>
+ /// Array of the protoc-generated outputs from the given dependency file
+ /// written by protoc, or empty array if the file does not exist or cannot
+ /// be parsed.
+ /// </returns>
+ /// <remarks>
+ /// Since this is called after a protoc invocation, an unparsable or missing
+ /// file causes an error-level message to be logged.
+ /// </remarks>
+ public static string[] ReadDependencyOutputs(string depFilename,
+ TaskLoggingHelper log)
+ {
+ string[] lines = ReadDepFileLines(depFilename, true, log);
+ if (lines.Length == 0)
+ {
+ return lines;
+ }
+
+ var result = new List<string>();
+ foreach (string line in lines)
+ {
+ int ix = FindLineSeparator(line);
+ string file = ExtractFilenameFromLine(line, 0, ix >= 0 ? ix : line.Length);
+ if (file == "")
+ {
+ log.LogError("Unable to parse generated dependency file {0}.\n" +
+ "Line with error: '{1}'", depFilename, line);
+ return new string[0];
+ }
+ result.Add(file);
+
+ // If this is the line with the separator, do not read further.
+ if (ix >= 0) { break; }
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Construct relative dependency file name from directory hash and file name
+ /// </summary>
+ /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
+ /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
+ /// <returns>
+ /// Full relative path to the dependency file, e. g.
+ /// "out/deadbeef12345678_file.protodep"
+ /// </returns>
+ /// <remarks>
+ /// Since a project may contain proto files with the same filename but in different
+ /// directories, a unique filename for the dependency file is constructed based on the
+ /// proto file name both name and directory. The directory path can be arbitrary,
+ /// for example, it can be outside of the project, or an absolute path including
+ /// a drive letter, or a UNC network path. A name constructed from such a path by,
+ /// for example, replacing disallowed name characters with an underscore, may well
+ /// be over filesystem's allowed path length, since it will be located under the
+ /// project and solution directories, which are also some level deep from the root.
+ /// Instead of creating long and unwieldy names for these proto sources, we cache
+ /// the full path of the name without the filename, and append the filename to it,
+ /// as in e. g. "foo/file.proto" will yield the name "deadbeef12345678_file", where
+ /// "deadbeef12345678" is a presumed hash value of the string "foo/". This allows
+ /// the file names be short, unique (up to a hash collision), and still allowing
+ /// the user to guess their provenance.
+ /// </remarks>
+ public static string GetDepFilenameForProto(string protoDepDir, string proto)
+ {
+ string dirname = Path.GetDirectoryName(proto);
+ if (Platform.IsFsCaseInsensitive)
+ {
+ dirname = dirname.ToLowerInvariant();
+ }
+ string dirhash = HashString64Hex(dirname);
+ string filename = Path.GetFileNameWithoutExtension(proto);
+ return Path.Combine(protoDepDir, $"{dirhash}_{filename}.protodep");
+ }
+
+ // Get a 64-bit hash for a directory string. We treat it as if it were
+ // unique, since there are not so many distinct proto paths in a project.
+ // We take the first 64 bit of the string SHA1.
+ // Internal for tests access only.
+ internal static string HashString64Hex(string str)
+ {
+ using (var sha1 = System.Security.Cryptography.SHA1.Create())
+ {
+ byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(str));
+ var hashstr = new StringBuilder(16);
+ for (int i = 0; i < 8; i++)
+ {
+ hashstr.Append(hash[i].ToString("x2"));
+ }
+ return hashstr.ToString();
+ }
+ }
+
+ // Extract filename between 'beg' (inclusive) and 'end' (exclusive) from
+ // line 'line', skipping over trailing and leading whitespace, and, when
+ // 'end' is immediately past end of line 'line', also final '\' (used
+ // as a line continuation token in the dep file).
+ // Returns an empty string if the filename cannot be extracted.
+ static string ExtractFilenameFromLine(string line, int beg, int end)
+ {
+ while (beg < end && char.IsWhiteSpace(line[beg])) beg++;
+ if (beg < end && end == line.Length && line[end - 1] == '\\') end--;
+ while (beg < end && char.IsWhiteSpace(line[end - 1])) end--;
+ if (beg == end) return "";
+
+ string filename = line.Substring(beg, end - beg);
+ try
+ {
+ // Normalize file name.
+ return Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename));
+ }
+ catch (Exception ex) when (Exceptions.IsIoRelated(ex))
+ {
+ return "";
+ }
+ }
+
+ // Finds the index of the ':' separating dependency clauses in the line,
+ // not taking Windows drive spec into account. Returns the index of the
+ // separating ':', or -1 if no separator found.
+ static int FindLineSeparator(string line)
+ {
+ // Mind this case where the first ':' is not separator:
+ // C:\foo\bar\.pb.h: C:/protobuf/wrappers.proto\
+ int ix = line.IndexOf(':');
+ if (ix <= 0 || ix == line.Length - 1
+ || (line[ix + 1] != '/' && line[ix + 1] != '\\')
+ || !char.IsLetter(line[ix - 1]))
+ {
+ return ix; // Not a windows drive: no letter before ':', or no '\' after.
+ }
+ for (int j = ix - 1; --j >= 0;)
+ {
+ if (!char.IsWhiteSpace(line[j]))
+ {
+ return ix; // Not space or BOL only before "X:/".
+ }
+ }
+ return line.IndexOf(':', ix + 1);
+ }
+
+ // Read entire dependency file. The 'required' parameter controls error
+ // logging behavior in case the file not found. We require this file when
+ // compiling, but reading it is optional when computing dependencies.
+ static string[] ReadDepFileLines(string filename, bool required,
+ TaskLoggingHelper log)
+ {
+ try
+ {
+ var result = File.ReadAllLines(filename);
+ if (!required)
+ {
+ log.LogMessage(MessageImportance.Low, $"Using dependency file {filename}");
+ }
+ return result;
+ }
+ catch (Exception ex) when (Exceptions.IsIoRelated(ex))
+ {
+ if (required)
+ {
+ log.LogError($"Unable to load {filename}: {ex.GetType().Name}: {ex.Message}");
+ }
+ else
+ {
+ log.LogMessage(MessageImportance.Low, $"Skipping {filename}: {ex.Message}");
+ }
+ return new string[0];
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/GeneratorServices.cs b/src/csharp/Grpc.Tools/GeneratorServices.cs
new file mode 100644
index 0000000000..536ec43c83
--- /dev/null
+++ b/src/csharp/Grpc.Tools/GeneratorServices.cs
@@ -0,0 +1,194 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.IO;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ // Abstract class for language-specific analysis behavior, such
+ // as guessing the generated files the same way protoc does.
+ internal abstract class GeneratorServices
+ {
+ protected readonly TaskLoggingHelper Log;
+ protected GeneratorServices(TaskLoggingHelper log) { Log = log; }
+
+ // Obtain a service for the given language (csharp, cpp).
+ public static GeneratorServices GetForLanguage(string lang, TaskLoggingHelper log)
+ {
+ if (lang.EqualNoCase("csharp")) { return new CSharpGeneratorServices(log); }
+ if (lang.EqualNoCase("cpp")) { return new CppGeneratorServices(log); }
+
+ log.LogError("Invalid value '{0}' for task property 'Generator'. " +
+ "Supported generator languages: CSharp, Cpp.", lang);
+ return null;
+ }
+
+ // Guess whether item's metadata suggests gRPC stub generation.
+ // When "gRPCServices" is not defined, assume gRPC is not used.
+ // When defined, C# uses "none" to skip gRPC, C++ uses "false", so
+ // recognize both. Since the value is tightly coupled to the scripts,
+ // we do not try to validate the value; scripts take care of that.
+ // It is safe to assume that gRPC is requested for any other value.
+ protected bool GrpcOutputPossible(ITaskItem proto)
+ {
+ string gsm = proto.GetMetadata(Metadata.GrpcServices);
+ return !gsm.EqualNoCase("") && !gsm.EqualNoCase("none")
+ && !gsm.EqualNoCase("false");
+ }
+
+ public abstract string[] GetPossibleOutputs(ITaskItem proto);
+ };
+
+ // C# generator services.
+ internal class CSharpGeneratorServices : GeneratorServices
+ {
+ public CSharpGeneratorServices(TaskLoggingHelper log) : base(log) { }
+
+ public override string[] GetPossibleOutputs(ITaskItem protoItem)
+ {
+ bool doGrpc = GrpcOutputPossible(protoItem);
+ string filename = LowerUnderscoreToUpperCamel(
+ Path.GetFileNameWithoutExtension(protoItem.ItemSpec));
+
+ var outputs = new string[doGrpc ? 2 : 1];
+ string outdir = protoItem.GetMetadata(Metadata.OutputDir);
+ string fileStem = Path.Combine(outdir, filename);
+ outputs[0] = fileStem + ".cs";
+ if (doGrpc)
+ {
+ // Override outdir if kGrpcOutputDir present, default to proto output.
+ outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
+ if (outdir != "")
+ {
+ fileStem = Path.Combine(outdir, filename);
+ }
+ outputs[1] = fileStem + "Grpc.cs";
+ }
+ return outputs;
+ }
+
+ string LowerUnderscoreToUpperCamel(string str)
+ {
+ // See src/compiler/generator_helpers.h:118
+ var result = new StringBuilder(str.Length, str.Length);
+ bool cap = true;
+ foreach (char c in str)
+ {
+ if (c == '_')
+ {
+ cap = true;
+ }
+ else if (cap)
+ {
+ result.Append(char.ToUpperInvariant(c));
+ cap = false;
+ }
+ else
+ {
+ result.Append(c);
+ }
+ }
+ return result.ToString();
+ }
+ };
+
+ // C++ generator services.
+ internal class CppGeneratorServices : GeneratorServices
+ {
+ public CppGeneratorServices(TaskLoggingHelper log) : base(log) { }
+
+ public override string[] GetPossibleOutputs(ITaskItem protoItem)
+ {
+ bool doGrpc = GrpcOutputPossible(protoItem);
+ string root = protoItem.GetMetadata(Metadata.ProtoRoot);
+ string proto = protoItem.ItemSpec;
+ string filename = Path.GetFileNameWithoutExtension(proto);
+ // E. g., ("foo/", "foo/bar/x.proto") => "bar"
+ string relative = GetRelativeDir(root, proto);
+
+ var outputs = new string[doGrpc ? 4 : 2];
+ string outdir = protoItem.GetMetadata(Metadata.OutputDir);
+ string fileStem = Path.Combine(outdir, relative, filename);
+ outputs[0] = fileStem + ".pb.cc";
+ outputs[1] = fileStem + ".pb.h";
+ if (doGrpc)
+ {
+ // Override outdir if kGrpcOutputDir present, default to proto output.
+ outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
+ if (outdir != "")
+ {
+ fileStem = Path.Combine(outdir, relative, filename);
+ }
+ outputs[2] = fileStem + "_grpc.pb.cc";
+ outputs[3] = fileStem + "_grpc.pb.h";
+ }
+ return outputs;
+ }
+
+ // Calculate part of proto path relative to root. Protoc is very picky
+ // about them matching exactly, so can be we. Expect root be exact prefix
+ // to proto, minus some slash normalization.
+ string GetRelativeDir(string root, string proto)
+ {
+ string protoDir = Path.GetDirectoryName(proto);
+ string rootDir = EndWithSlash(Path.GetDirectoryName(EndWithSlash(root)));
+ if (rootDir == s_dotSlash)
+ {
+ // Special case, otherwise we can return "./" instead of "" below!
+ return protoDir;
+ }
+ if (Platform.IsFsCaseInsensitive)
+ {
+ protoDir = protoDir.ToLowerInvariant();
+ rootDir = rootDir.ToLowerInvariant();
+ }
+ protoDir = EndWithSlash(protoDir);
+ if (!protoDir.StartsWith(rootDir))
+ {
+ Log.LogWarning("ProtoBuf item '{0}' has the ProtoRoot metadata '{1}' " +
+ "which is not prefix to its path. Cannot compute relative path.",
+ proto, root);
+ return "";
+ }
+ return protoDir.Substring(rootDir.Length);
+ }
+
+ // './' or '.\', normalized per system.
+ static string s_dotSlash = "." + Path.DirectorySeparatorChar;
+
+ static string EndWithSlash(string str)
+ {
+ if (str == "")
+ {
+ return s_dotSlash;
+ }
+ else if (str[str.Length - 1] != '\\' && str[str.Length - 1] != '/')
+ {
+ return str + Path.DirectorySeparatorChar;
+ }
+ else
+ {
+ return str;
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/Grpc.Tools.csproj b/src/csharp/Grpc.Tools/Grpc.Tools.csproj
new file mode 100644
index 0000000000..61fa75a4ec
--- /dev/null
+++ b/src/csharp/Grpc.Tools/Grpc.Tools.csproj
@@ -0,0 +1,101 @@
+<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <Import Project="..\Grpc.Core\Version.csproj.include" />
+
+ <PropertyGroup>
+ <AssemblyName>Protobuf.MSBuild</AssemblyName>
+ <Version>$(GrpcCsharpVersion)</Version>
+ <!-- If changing targets, change also paths in Google.Protobuf.Tools.targets. -->
+ <TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
+ </PropertyGroup>
+
+ <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings
+ in that file conflict with the intent of this build, as it cannot be signed,
+ and may not compile Grpc.Core/Version.cs, as that file references constants
+ in Grpc.Core.dll.
+ TODO(kkm): Refactor imports. -->
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' ">
+ <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 -->
+ <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
+ </PropertyGroup>
+
+ <PropertyGroup Label="Asset root folders. TODO(kkm): Change with package separation.">
+ <!-- TODO(kkm): Rework whole section when splitting packages. -->
+ <!-- GRPC: ../../third_party/protobuf/src/google/protobuf/ -->
+ <!-- GPB: ../src/google/protobuf/ -->
+ <Assets_ProtoInclude>../../../third_party/protobuf/src/google/protobuf/</Assets_ProtoInclude>
+
+ <!-- GPB: ../protoc/ -->
+ <!-- GRPC: ../protoc_plugins/protoc_ -->
+ <Assets_ProtoCompiler>../protoc_plugins/protoc_</Assets_ProtoCompiler>
+
+ <!-- GRPC: ../protoc_plugins/ -->
+ <Assets_GrpcPlugins>../protoc_plugins/</Assets_GrpcPlugins>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
+ </PropertyGroup>
+
+ <PropertyGroup Label="NuGet package definition" Condition=" '$(Configuration)' == 'Release' ">
+ <!-- TODO(kkm): Change to "build\" after splitting. -->
+ <BuildOutputTargetFolder>build\_protobuf\</BuildOutputTargetFolder>
+ <DevelopmentDependency>true</DevelopmentDependency>
+ <NoPackageAnalysis>true</NoPackageAnalysis>
+ <PackageId>Grpc.Tools</PackageId>
+ <Description>gRPC and Protocol Buffer compiler for managed C# and native C++ projects.
+
+Add this package to a project that contains .proto files to be compiled to code.
+It contains the compilers, include files and project system integration for gRPC
+and Protocol buffer service description files necessary to build them on Windows,
+Linux and MacOS. Managed runtime is supplied separately in the Grpc.Core package.</Description>
+ <Copyright>Copyright 2018 gRPC authors</Copyright>
+ <Authors>gRPC authors</Authors>
+ <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+ <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+ <PackageTags>gRPC RPC protocol HTTP/2</PackageTags>
+ </PropertyGroup>
+
+ <ItemGroup Label="NuGet package assets">
+ <None Pack="true" PackagePath="build\" Include="build\**\*.xml; build\**\*.props; build\**\*.targets;" />
+
+ <!-- Protobuf assets (for Google.Protobuf.Tools) -->
+ <_ProtoAssetName Include="any;api;descriptor;duration;empty;field_mask;
+ source_context;struct;timestamp;type;wrappers" />
+ <_Asset PackagePath="build/native/include/google/protobuf/" Include="@(_ProtoAssetName->'$(Assets_ProtoInclude)%(Identity).proto')" />
+
+ <!-- TODO(kkm): GPB builds assets into "macosx", GRPC into "macos". -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <_Asset PackagePath="tools/windows_x86/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x86/protoc.exe" />
+ <_Asset PackagePath="tools/windows_x64/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x64/protoc.exe" />
+ <_Asset PackagePath="tools/linux_x86/protoc" Include="$(Assets_ProtoCompiler)linux_x86/protoc" />
+ <_Asset PackagePath="tools/linux_x64/protoc" Include="$(Assets_ProtoCompiler)linux_x64/protoc" />
+ <_Asset PackagePath="tools/macosx_x86/protoc" Include="$(Assets_ProtoCompiler)macos_x86/protoc" /> <!-- GPB: macosx-->
+ <_Asset PackagePath="tools/macosx_x64/protoc" Include="$(Assets_ProtoCompiler)macos_x64/protoc" /> <!-- GPB: macosx-->
+
+ <!-- gRPC assets (for Grpc.Tools) -->
+ <_Asset PackagePath="tools/windows_x86/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x86/grpc_csharp_plugin.exe" />
+ <_Asset PackagePath="tools/windows_x64/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x64/grpc_csharp_plugin.exe" />
+ <_Asset PackagePath="tools/linux_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x86/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/linux_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x64/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/macosx_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x86/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/macosx_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x64/grpc_csharp_plugin" />
+
+ <None Include="@(_Asset)" Pack="true" Visible="false" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+ <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" Pack="false" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" />
+ <!-- Set PrivateAssets="All" on all items, even those implicitly added,
+ so that they do not become dependencies of this package. -->
+ <PackageReference Update="@(PackageReference)" PrivateAssets="All" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Tools/ProtoCompile.cs b/src/csharp/Grpc.Tools/ProtoCompile.cs
new file mode 100644
index 0000000000..93608e1ac0
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoCompile.cs
@@ -0,0 +1,441 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ /// <summary>
+ /// Run Google proto compiler (protoc).
+ ///
+ /// After a successful run, the task reads the dependency file if specified
+ /// to be saved by the compiler, and returns its output files.
+ ///
+ /// This task (unlike PrepareProtoCompile) does not attempt to guess anything
+ /// about language-specific behavior of protoc, and therefore can be used for
+ /// any language outputs.
+ /// </summary>
+ public class ProtoCompile : ToolTask
+ {
+ /*
+
+ Usage: /home/kkm/work/protobuf/src/.libs/lt-protoc [OPTION] PROTO_FILES
+ Parse PROTO_FILES and generate output based on the options given:
+ -IPATH, --proto_path=PATH Specify the directory in which to search for
+ imports. May be specified multiple times;
+ directories will be searched in order. If not
+ given, the current working directory is used.
+ --version Show version info and exit.
+ -h, --help Show this text and exit.
+ --encode=MESSAGE_TYPE Read a text-format message of the given type
+ from standard input and write it in binary
+ to standard output. The message type must
+ be defined in PROTO_FILES or their imports.
+ --decode=MESSAGE_TYPE Read a binary message of the given type from
+ standard input and write it in text format
+ to standard output. The message type must
+ be defined in PROTO_FILES or their imports.
+ --decode_raw Read an arbitrary protocol message from
+ standard input and write the raw tag/value
+ pairs in text format to standard output. No
+ PROTO_FILES should be given when using this
+ flag.
+ --descriptor_set_in=FILES Specifies a delimited list of FILES
+ each containing a FileDescriptorSet (a
+ protocol buffer defined in descriptor.proto).
+ The FileDescriptor for each of the PROTO_FILES
+ provided will be loaded from these
+ FileDescriptorSets. If a FileDescriptor
+ appears multiple times, the first occurrence
+ will be used.
+ -oFILE, Writes a FileDescriptorSet (a protocol buffer,
+ --descriptor_set_out=FILE defined in descriptor.proto) containing all of
+ the input files to FILE.
+ --include_imports When using --descriptor_set_out, also include
+ all dependencies of the input files in the
+ set, so that the set is self-contained.
+ --include_source_info When using --descriptor_set_out, do not strip
+ SourceCodeInfo from the FileDescriptorProto.
+ This results in vastly larger descriptors that
+ include information about the original
+ location of each decl in the source file as
+ well as surrounding comments.
+ --dependency_out=FILE Write a dependency output file in the format
+ expected by make. This writes the transitive
+ set of input file paths to FILE
+ --error_format=FORMAT Set the format in which to print errors.
+ FORMAT may be 'gcc' (the default) or 'msvs'
+ (Microsoft Visual Studio format).
+ --print_free_field_numbers Print the free field numbers of the messages
+ defined in the given proto files. Groups share
+ the same field number space with the parent
+ message. Extension ranges are counted as
+ occupied fields numbers.
+
+ --plugin=EXECUTABLE Specifies a plugin executable to use.
+ Normally, protoc searches the PATH for
+ plugins, but you may specify additional
+ executables not in the path using this flag.
+ Additionally, EXECUTABLE may be of the form
+ NAME=PATH, in which case the given plugin name
+ is mapped to the given executable even if
+ the executable's own name differs.
+ --cpp_out=OUT_DIR Generate C++ header and source.
+ --csharp_out=OUT_DIR Generate C# source file.
+ --java_out=OUT_DIR Generate Java source file.
+ --javanano_out=OUT_DIR Generate Java Nano source file.
+ --js_out=OUT_DIR Generate JavaScript source.
+ --objc_out=OUT_DIR Generate Objective C header and source.
+ --php_out=OUT_DIR Generate PHP source file.
+ --python_out=OUT_DIR Generate Python source file.
+ --ruby_out=OUT_DIR Generate Ruby source file.
+ @<filename> Read options and filenames from file. If a
+ relative file path is specified, the file
+ will be searched in the working directory.
+ The --proto_path option will not affect how
+ this argument file is searched. Content of
+ the file will be expanded in the position of
+ @<filename> as in the argument list. Note
+ that shell expansion is not applied to the
+ content of the file (i.e., you cannot use
+ quotes, wildcards, escapes, commands, etc.).
+ Each line corresponds to a single argument,
+ even if it contains spaces.
+ */
+ static string[] s_supportedGenerators = new[] { "cpp", "csharp", "java",
+ "javanano", "js", "objc",
+ "php", "python", "ruby" };
+
+ /// <summary>
+ /// Code generator.
+ /// </summary>
+ [Required]
+ public string Generator { get; set; }
+
+ /// <summary>
+ /// Protobuf files to compile.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Directory where protoc dependency files are cached. If provided, dependency
+ /// output filename is autogenerated from source directory hash and file name.
+ /// Mutually exclusive with DependencyOut.
+ /// Switch: --dependency_out (with autogenerated file name).
+ /// </summary>
+ public string ProtoDepDir { get; set; }
+
+ /// <summary>
+ /// Dependency file full name. Mutually exclusive with ProtoDepDir.
+ /// Autogenerated file name is available in this property after execution.
+ /// Switch: --dependency_out.
+ /// </summary>
+ [Output]
+ public string DependencyOut { get; set; }
+
+ /// <summary>
+ /// The directories to search for imports. Directories will be searched
+ /// in order. If not given, the current working directory is used.
+ /// Switch: --proto_path.
+ /// </summary>
+ public string[] ProtoPath { get; set; }
+
+ /// <summary>
+ /// Generated code directory. The generator property determines the language.
+ /// Switch: --GEN-out= (for different generators GEN).
+ /// </summary>
+ [Required]
+ public string OutputDir { get; set; }
+
+ /// <summary>
+ /// Codegen options. See also OptionsFromMetadata.
+ /// Switch: --GEN_out= (for different generators GEN).
+ /// </summary>
+ public string[] OutputOptions { get; set; }
+
+ /// <summary>
+ /// Full path to the gRPC plugin executable. If specified, gRPC generation
+ /// is enabled for the files.
+ /// Switch: --plugin=protoc-gen-grpc=
+ /// </summary>
+ public string GrpcPluginExe { get; set; }
+
+ /// <summary>
+ /// Generated gRPC directory. The generator property determines the
+ /// language. If gRPC is enabled but this is not given, OutputDir is used.
+ /// Switch: --grpc_out=
+ /// </summary>
+ public string GrpcOutputDir { get; set; }
+
+ /// <summary>
+ /// gRPC Codegen options. See also OptionsFromMetadata.
+ /// --grpc_opt=opt1,opt2=val (comma-separated).
+ /// </summary>
+ public string[] GrpcOutputOptions { get; set; }
+
+ /// <summary>
+ /// List of files written in addition to generated outputs. Includes a
+ /// single item for the dependency file if written.
+ /// </summary>
+ [Output]
+ public ITaskItem[] AdditionalFileWrites { get; private set; }
+
+ /// <summary>
+ /// List of language files generated by protoc. Empty unless DependencyOut
+ /// or ProtoDepDir is set, since the file writes are extracted from protoc
+ /// dependency output file.
+ /// </summary>
+ [Output]
+ public ITaskItem[] GeneratedFiles { get; private set; }
+
+ // Hide this property from MSBuild, we should never use a shell script.
+ private new bool UseCommandProcessor { get; set; }
+
+ protected override string ToolName => Platform.IsWindows ? "protoc.exe" : "protoc";
+
+ // Since we never try to really locate protoc.exe somehow, just try ToolExe
+ // as the full tool location. It will be either just protoc[.exe] from
+ // ToolName above if not set by the user, or a user-supplied full path. The
+ // base class will then resolve the former using system PATH.
+ protected override string GenerateFullPathToTool() => ToolExe;
+
+ // Log protoc errors with the High priority (bold white in MsBuild,
+ // printed with -v:n, and shown in the Output windows in VS).
+ protected override MessageImportance StandardErrorLoggingImportance => MessageImportance.High;
+
+ // Called by base class to validate arguments and make them consistent.
+ protected override bool ValidateParameters()
+ {
+ // Part of proto command line switches, must be lowercased.
+ Generator = Generator.ToLowerInvariant();
+ if (!System.Array.Exists(s_supportedGenerators, g => g == Generator))
+ {
+ Log.LogError("Invalid value for Generator='{0}'. Supported generators: {1}",
+ Generator, string.Join(", ", s_supportedGenerators));
+ }
+
+ if (ProtoDepDir != null && DependencyOut != null)
+ {
+ Log.LogError("Properties ProtoDepDir and DependencyOut may not be both specified");
+ }
+
+ if (ProtoBuf.Length > 1 && (ProtoDepDir != null || DependencyOut != null))
+ {
+ Log.LogError("Proto compiler currently allows only one input when " +
+ "--dependency_out is specified (via ProtoDepDir or DependencyOut). " +
+ "Tracking issue: https://github.com/google/protobuf/pull/3959");
+ }
+
+ // Use ProtoDepDir to autogenerate DependencyOut
+ if (ProtoDepDir != null)
+ {
+ DependencyOut = DepFileUtil.GetDepFilenameForProto(ProtoDepDir, ProtoBuf[0].ItemSpec);
+ }
+
+ if (GrpcPluginExe == null)
+ {
+ GrpcOutputOptions = null;
+ GrpcOutputDir = null;
+ }
+ else if (GrpcOutputDir == null)
+ {
+ // Use OutputDir for gRPC output if not specified otherwise by user.
+ GrpcOutputDir = OutputDir;
+ }
+
+ return !Log.HasLoggedErrors && base.ValidateParameters();
+ }
+
+ // Protoc chokes on BOM, naturally. I would!
+ static readonly Encoding s_utf8WithoutBom = new UTF8Encoding(false);
+ protected override Encoding ResponseFileEncoding => s_utf8WithoutBom;
+
+ // Protoc takes one argument per line from the response file, and does not
+ // require any quoting whatsoever. Otherwise, this is similar to the
+ // standard CommandLineBuilder
+ class ProtocResponseFileBuilder
+ {
+ StringBuilder _data = new StringBuilder(1000);
+ public override string ToString() => _data.ToString();
+
+ // If 'value' is not empty, append '--name=value\n'.
+ public void AddSwitchMaybe(string name, string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ _data.Append("--").Append(name).Append("=")
+ .Append(value).Append('\n');
+ }
+ }
+
+ // Add switch with the 'values' separated by commas, for options.
+ public void AddSwitchMaybe(string name, string[] values)
+ {
+ if (values?.Length > 0)
+ {
+ _data.Append("--").Append(name).Append("=")
+ .Append(string.Join(",", values)).Append('\n');
+ }
+ }
+
+ // Add a positional argument to the file data.
+ public void AddArg(string arg)
+ {
+ _data.Append(arg).Append('\n');
+ }
+ };
+
+ // Called by the base ToolTask to get response file contents.
+ protected override string GenerateResponseFileCommands()
+ {
+ var cmd = new ProtocResponseFileBuilder();
+ cmd.AddSwitchMaybe(Generator + "_out", TrimEndSlash(OutputDir));
+ cmd.AddSwitchMaybe(Generator + "_opt", OutputOptions);
+ cmd.AddSwitchMaybe("plugin=protoc-gen-grpc", GrpcPluginExe);
+ cmd.AddSwitchMaybe("grpc_out", TrimEndSlash(GrpcOutputDir));
+ cmd.AddSwitchMaybe("grpc_opt", GrpcOutputOptions);
+ if (ProtoPath != null)
+ {
+ foreach (string path in ProtoPath)
+ cmd.AddSwitchMaybe("proto_path", TrimEndSlash(path));
+ }
+ cmd.AddSwitchMaybe("dependency_out", DependencyOut);
+ foreach (var proto in ProtoBuf)
+ {
+ cmd.AddArg(proto.ItemSpec);
+ }
+ return cmd.ToString();
+ }
+
+ // Protoc cannot digest trailing slashes in directory names,
+ // curiously under Linux, but not in Windows.
+ static string TrimEndSlash(string dir)
+ {
+ if (dir == null || dir.Length <= 1)
+ {
+ return dir;
+ }
+ string trim = dir.TrimEnd('/', '\\');
+ // Do not trim the root slash, drive letter possible.
+ if (trim.Length == 0)
+ {
+ // Slashes all the way down.
+ return dir.Substring(0, 1);
+ }
+ if (trim.Length == 2 && dir.Length > 2 && trim[1] == ':')
+ {
+ // We have a drive letter and root, e. g. 'C:\'
+ return dir.Substring(0, 3);
+ }
+ return trim;
+ }
+
+ // Called by the base class to log tool's command line.
+ //
+ // Protoc command file is peculiar, with one argument per line, separated
+ // by newlines. Unwrap it for log readability into a single line, and also
+ // quote arguments, lest it look weird and so it may be copied and pasted
+ // into shell. Since this is for logging only, correct enough is correct.
+ protected override void LogToolCommand(string cmd)
+ {
+ var printer = new StringBuilder(1024);
+
+ // Print 'str' slice into 'printer', wrapping in quotes if contains some
+ // interesting characters in file names, or if empty string. The list of
+ // characters requiring quoting is not by any means exhaustive; we are
+ // just striving to be nice, not guaranteeing to be nice.
+ var quotable = new[] { ' ', '!', '$', '&', '\'', '^' };
+ void PrintQuoting(string str, int start, int count)
+ {
+ bool wrap = count == 0 || str.IndexOfAny(quotable, start, count) >= 0;
+ if (wrap) printer.Append('"');
+ printer.Append(str, start, count);
+ if (wrap) printer.Append('"');
+ }
+
+ for (int ib = 0, ie; (ie = cmd.IndexOf('\n', ib)) >= 0; ib = ie + 1)
+ {
+ // First line only contains both the program name and the first switch.
+ // We can rely on at least the '--out_dir' switch being always present.
+ if (ib == 0)
+ {
+ int iep = cmd.IndexOf(" --");
+ if (iep > 0)
+ {
+ PrintQuoting(cmd, 0, iep);
+ ib = iep + 1;
+ }
+ }
+ printer.Append(' ');
+ if (cmd[ib] == '-')
+ {
+ // Print switch unquoted, including '=' if any.
+ int iarg = cmd.IndexOf('=', ib, ie - ib);
+ if (iarg < 0)
+ {
+ // Bare switch without a '='.
+ printer.Append(cmd, ib, ie - ib);
+ continue;
+ }
+ printer.Append(cmd, ib, iarg + 1 - ib);
+ ib = iarg + 1;
+ }
+ // A positional argument or switch value.
+ PrintQuoting(cmd, ib, ie - ib);
+ }
+
+ base.LogToolCommand(printer.ToString());
+ }
+
+ // Main task entry point.
+ public override bool Execute()
+ {
+ base.UseCommandProcessor = false;
+
+ bool ok = base.Execute();
+ if (!ok)
+ {
+ return false;
+ }
+
+ // Read dependency output file from the compiler to retrieve the
+ // definitive list of created files. Report the dependency file
+ // itself as having been written to.
+ if (DependencyOut != null)
+ {
+ string[] outputs = DepFileUtil.ReadDependencyOutputs(DependencyOut, Log);
+ if (HasLoggedErrors)
+ {
+ return false;
+ }
+
+ GeneratedFiles = new ITaskItem[outputs.Length];
+ for (int i = 0; i < outputs.Length; i++)
+ {
+ GeneratedFiles[i] = new TaskItem(outputs[i]);
+ }
+ AdditionalFileWrites = new ITaskItem[] { new TaskItem(DependencyOut) };
+ }
+
+ return true;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs
new file mode 100644
index 0000000000..915be3421e
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs
@@ -0,0 +1,86 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Collections.Generic;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ public class ProtoCompilerOutputs : Task
+ {
+ /// <summary>
+ /// Code generator. Currently supported are "csharp", "cpp".
+ /// </summary>
+ [Required]
+ public string Generator { get; set; }
+
+ /// <summary>
+ /// All Proto files in the project. The task computes possible outputs
+ /// from these proto files, and returns them in the PossibleOutputs list.
+ /// Not all of these might be actually produced by protoc; this is dealt
+ /// with later in the ProtoCompile task which returns the list of
+ /// files actually produced by the compiler.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Output items per each potential output. We do not look at existing
+ /// cached dependency even if they exist, since file may be refactored,
+ /// affecting whether or not gRPC code file is generated from a given proto.
+ /// Instead, all potentially possible generated sources are collected.
+ /// It is a wise idea to generate empty files later for those potentials
+ /// that are not actually created by protoc, so the dependency checks
+ /// result in a minimal recompilation. The Protoc task can output the
+ /// list of files it actually produces, given right combination of its
+ /// properties.
+ /// Output items will have the Source metadata set on them:
+ /// <ItemName Include="MyProto.cs" Source="my_proto.proto" />
+ /// </summary>
+ [Output]
+ public ITaskItem[] PossibleOutputs { get; private set; }
+
+ public override bool Execute()
+ {
+ var generator = GeneratorServices.GetForLanguage(Generator, Log);
+ if (generator == null)
+ {
+ // Error already logged, just return.
+ return false;
+ }
+
+ // Get language-specific possible output. The generator expects certain
+ // metadata be set on the proto item.
+ var possible = new List<ITaskItem>();
+ foreach (var proto in ProtoBuf)
+ {
+ var outputs = generator.GetPossibleOutputs(proto);
+ foreach (string output in outputs)
+ {
+ var ti = new TaskItem(output);
+ ti.SetMetadata(Metadata.Source, proto.ItemSpec);
+ possible.Add(ti);
+ }
+ }
+ PossibleOutputs = possible.ToArray();
+
+ return !Log.HasLoggedErrors;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoReadDependencies.cs b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs
new file mode 100644
index 0000000000..963837e8b7
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs
@@ -0,0 +1,78 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System.Collections.Generic;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ public class ProtoReadDependencies : Task
+ {
+ /// <summary>
+ /// The collection is used to collect possible additional dependencies
+ /// of proto files cached under ProtoDepDir.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Directory where protoc dependency files are cached.
+ /// </summary>
+ [Required]
+ public string ProtoDepDir { get; set; }
+
+ /// <summary>
+ /// Additional items that a proto file depends on. This list may include
+ /// extra dependencies; we do our best to include as few extra positives
+ /// as reasonable to avoid missing any. The collection item is the
+ /// dependency, and its Source metadatum is the dependent proto file, like
+ /// <ItemName Include="/usr/include/proto/wrapper.proto"
+ /// Source="my_proto.proto" />
+ /// </summary>
+ [Output]
+ public ITaskItem[] Dependencies { get; private set; }
+
+ public override bool Execute()
+ {
+ // Read dependency files, where available. There might be none,
+ // just use a best effort.
+ if (ProtoDepDir != null)
+ {
+ var dependencies = new List<ITaskItem>();
+ foreach (var proto in ProtoBuf)
+ {
+ string[] deps = DepFileUtil.ReadDependencyInputs(ProtoDepDir, proto.ItemSpec, Log);
+ foreach (string dep in deps)
+ {
+ var ti = new TaskItem(dep);
+ ti.SetMetadata(Metadata.Source, proto.ItemSpec);
+ dependencies.Add(ti);
+ }
+ }
+ Dependencies = dependencies.ToArray();
+ }
+ else
+ {
+ Dependencies = new ITaskItem[0];
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs
new file mode 100644
index 0000000000..aed8a66339
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ /// <summary>
+ /// A helper task to resolve actual OS type and bitness.
+ /// </summary>
+ public class ProtoToolsPlatform : Task
+ {
+ /// <summary>
+ /// Return one of 'linux', 'macosx' or 'windows'.
+ /// If the OS is unknown, the property is not set.
+ /// </summary>
+ [Output]
+ public string Os { get; set; }
+
+ /// <summary>
+ /// Return one of 'x64' or 'x86'.
+ /// If the CPU is unknown, the property is not set.
+ /// </summary>
+ [Output]
+ public string Cpu { get; set; }
+
+
+ public override bool Execute()
+ {
+ switch (Platform.Os)
+ {
+ case Platform.OsKind.Linux: Os = "linux"; break;
+ case Platform.OsKind.MacOsX: Os = "macosx"; break;
+ case Platform.OsKind.Windows: Os = "windows"; break;
+ default: Os = ""; break;
+ }
+
+ switch (Platform.Cpu)
+ {
+ case Platform.CpuKind.X86: Cpu = "x86"; break;
+ case Platform.CpuKind.X64: Cpu = "x64"; break;
+ default: Cpu = ""; break;
+ }
+ return true;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/Grpc.Tools.props
new file mode 100644
index 0000000000..dbcd8bf494
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.props
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+
+ <!-- Name of this file must match package ID. -->
+ <!-- Packages will be split later. -->
+ <Import Project="_grpc/_Grpc.Tools.props"/>
+ <Import Project="_protobuf/Google.Protobuf.Tools.props"/>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets
new file mode 100644
index 0000000000..c0a5b1e2c5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+
+ <!-- Name of this file must match package ID. -->
+ <!-- Packages will be split later. -->
+ <Import Project="_grpc/_Grpc.Tools.targets"/>
+ <Import Project="_protobuf/Google.Protobuf.Tools.targets"/>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml
new file mode 100644
index 0000000000..54468eb5ef
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml
@@ -0,0 +1,30 @@
+<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
+ <Rule Name="ProtoBuf"
+ DisplayName="File Properties"
+ PageTemplate="generic"
+ Description="File Properties"
+ OverrideMode="Extend">
+ <Rule.DataSource>
+ <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf"
+ HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" />
+ </Rule.DataSource>
+
+ <Rule.Categories>
+ <Category Name="gRPC" DisplayName="gRPC" />
+ </Rule.Categories>
+
+ <EnumProperty Name="GrpcServices" DisplayName="gRPC Stub Classes"
+ Category="gRPC" Default="Both"
+ Description="Generate gRPC server and client stub classes.">
+ <EnumValue Name="Both" DisplayName="Client and Server" IsDefault="true" />
+ <EnumValue Name="Client" DisplayName="Client only" />
+ <EnumValue Name="Server" DisplayName="Server only" />
+ <EnumValue Name="None" DisplayName="Do not generate" />
+ <EnumProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </EnumProperty.DataSource>
+ </EnumProperty>
+
+ </Rule>
+</ProjectSchemaDefinitions>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/README b/src/csharp/Grpc.Tools/build/_grpc/README
new file mode 100644
index 0000000000..4a7204b9ff
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/README
@@ -0,0 +1,3 @@
+TODO(kkm): These file will go into Grpc.Tools/build after package split.
+ Remove leading underscores from file names; they are hiding the
+ files from some NuGet versions which pull them into project.
diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props
new file mode 100644
index 0000000000..8ce07c48ab
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets
new file mode 100644
index 0000000000..5f76c03ce5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <gRPC_PluginFileName Condition=" '$(gRPC_PluginFileName)' == '' and '$(Language)' == 'C#' ">grpc_csharp_plugin</gRPC_PluginFileName>
+ </PropertyGroup>
+
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <!-- Extend property pages with gRPC properties. -->
+ <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Grpc.CSharp.xml">
+ <Context>File;BrowseObject</Context>
+ </PropertyPageSchema>
+ </ItemGroup>
+
+ <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <ProtoBuf>
+ <GrpcServices Condition=" '%(ProtoBuf.GrpcServices)' == '' ">Both</GrpcServices>
+ </ProtoBuf>
+ </ItemDefinitionGroup>
+
+ <!-- This target is invoked in a C# project, or can be called in a customized project. -->
+ <Target Name="gRPC_ResolvePluginFullPath" AfterTargets="Protobuf_ResolvePlatform">
+ <PropertyGroup>
+ <!-- TODO(kkm): Do not use Protobuf_PackagedToolsPath, roll gRPC's own. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' "
+ >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\$(gRPC_PluginFileName).exe</gRPC_PluginFullPath>
+ <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' "
+ >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/$(gRPC_PluginFileName)</gRPC_PluginFullPath>
+ </PropertyGroup>
+ </Target>
+
+ <Target Name="_gRPC_PrepareCompileOptions" AfterTargets="Protobuf_PrepareCompileOptions">
+ <ItemGroup Condition=" '$(Language)' == 'C#' ">
+ <Protobuf_Compile Condition=" %(Protobuf_Compile.GrpcServices) != 'None' ">
+ <GrpcPluginExe Condition=" '%(Protobuf_Compile.GrpcPluginExe)' == '' ">$(gRPC_PluginFullPath)</GrpcPluginExe>
+ <GrpcOutputDir Condition=" '%(Protobuf_Compile.GrpcOutputDir)' == '' " >%(Protobuf_Compile.OutputDir)</GrpcOutputDir>
+ <_GrpcOutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._GrpcOutputOptions);internal_access</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Client' ">
+ <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_server</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Server' ">
+ <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_client</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props
new file mode 100644
index 0000000000..9f2d8bb4b5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+ <!-- Revision number of this package conventions (as if "API" version). -->
+ <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision>
+
+ <!-- TODO(kkm): Remove one "../" when separating packages. -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <Protobuf_PackagedToolsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../../tools) )</Protobuf_PackagedToolsPath>
+ <Protobuf_StandardImportsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../native/include) )</Protobuf_StandardImportsPath>
+ </PropertyGroup>
+
+ <!-- NET SDK projects only: include proto files by default. Other project
+ types are not setting or using $(EnableDefaultItems).
+ Note that MSBuild evaluates all ItemGroups and their conditions in the
+ final pass over the build script, so properties like EnableDefaultProtoBufItems
+ here can be changed later in the project. -->
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' ">
+ <ProtoBuf Include="**/*.proto"
+ Condition=" '$(EnableDefaultItems)' == 'true' and '$(EnableDefaultProtoBufItems)' == 'true' " />
+ </ItemGroup>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets
new file mode 100644
index 0000000000..1d233d23a8
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets
@@ -0,0 +1,384 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <!-- We allow a non-C# generator be set by the user, but skip adding outputs to Compile in this case. -->
+ <Protobuf_Generator Condition=" '$(Protobuf_Generator)' == '' and '$(Language)' == 'C#' ">CSharp</Protobuf_Generator>
+ <!-- Configuration is passing the smoke test. -->
+ <Protobuf_ProjectSupported Condition=" '$(Protobuf_Generator)' != '' ">true</Protobuf_ProjectSupported>
+ <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard1.3\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
+ <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net45\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
+ </PropertyGroup>
+
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoToolsPlatform" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompilerOutputs" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoReadDependencies" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompile" />
+
+ <PropertyGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' ">
+ <Protobuf_IntermediatePath Condition=" '$(Protobuf_IntermediatePath)' == '' ">$(IntermediateOutputPath)</Protobuf_IntermediatePath>
+ <Protobuf_OutputPath Condition=" '$(Protobuf_OutputPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_OutputPath>
+ <Protobuf_DepFilesPath Condition=" '$(Protobuf_DepFilesPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_DepFilesPath>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <ProtoBuf>
+ <Access Condition="'%(ProtoBuf.Access)' == '' ">Public</Access>
+ <ProtoCompile Condition="'%(ProtoBuf.ProtoCompile)' == '' ">True</ProtoCompile>
+ <ProtoRoot Condition="'%(ProtoBuf.ProtoRoot)' == '' " />
+ <CompileOutputs Condition="'%(ProtoBuf.CompileOutputs)' == ''">True</CompileOutputs>
+ <OutputDir Condition="'%(ProtoBuf.OutputDir)' == '' ">$(Protobuf_OutputPath)</OutputDir>
+ </ProtoBuf>
+ </ItemDefinitionGroup>
+
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Protobuf.CSharp.xml">
+ <Context>File;BrowseObject</Context>
+ </PropertyPageSchema>
+ <AvailableItemName Include="ProtoBuf" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <!-- NET SDK: by default, do not include proto files in the directory.
+ Current Microsoft's recommendation is against globbing:
+ https://docs.microsoft.com/en-us/dotnet/core/tools/csproj#recommendation -->
+ <EnableDefaultProtoBufItems Condition=" '$(EnableDefaultProtoBufItems)' == '' ">false</EnableDefaultProtoBufItems>
+ </PropertyGroup>
+
+ <!-- Check configuration sanity before build. -->
+ <Target Name="_Protobuf_SanityCheck" BeforeTargets="PrepareForBuild">
+ <Error
+ Condition=" '$(Protobuf_ProjectSupported)' != 'true' "
+ Text="Google.Protobuf.Tools proto compilation is only supported by default in a C# project (extension .csproj)" />
+ </Target>
+
+ <!--================================================================================
+ Tool path resolution
+ =================================================================================-->
+
+ <!-- Extension point for plugin packages: use Protobuf_ToolsOs and Protobuf_ToolsCpu
+ to resolve executable. Either or both may be blank, however, if resolution
+ fails; do check them before using. -->
+ <Target Name="Protobuf_ResolvePlatform">
+ <ProtoToolsPlatform>
+ <Output TaskParameter="Os" PropertyName="_Protobuf_ToolsOs"/>
+ <Output TaskParameter="Cpu" PropertyName="_Protobuf_ToolsCpu"/>
+ </ProtoToolsPlatform>
+
+ <PropertyGroup>
+ <!-- First try environment variable. -->
+ <Protobuf_ToolsOs>$(PROTOBUF_TOOLS_OS)</Protobuf_ToolsOs>
+ <Protobuf_ToolsCpu>$(PROTOBUF_TOOLS_CPU)</Protobuf_ToolsCpu>
+ <Protobuf_ProtocFullPath>$(PROTOBUF_PROTOC)</Protobuf_ProtocFullPath>
+
+ <!-- Next try OS and CPU resolved by ProtoToolsPlatform. -->
+ <Protobuf_ToolsOs Condition=" '$(Protobuf_ToolsOs)' == '' ">$(_Protobuf_ToolsOs)</Protobuf_ToolsOs>
+ <Protobuf_ToolsCpu Condition=" '$(Protobuf_ToolsCpu)' == '' ">$(_Protobuf_ToolsCpu)</Protobuf_ToolsCpu>
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' "
+ >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\protoc.exe</Protobuf_ProtocFullPath>
+ <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' "
+ >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/protoc</Protobuf_ProtocFullPath>
+ </PropertyGroup>
+
+ <Error Condition=" '$(DesignTimeBuild)' != 'true' and '$(PROTOBUF_PROTOC)' == ''
+ and ( '$(Protobuf_ToolsOs)' == '' or '$(Protobuf_ToolsCpu)' == '' ) "
+ Text="Google.Protobuf.Tools cannot determine host OS and CPU.&#10;Use environment variables PROTOBUF_TOOLS_OS={linux|macosx|windows} and PROTOBUF_TOOLS_CPU={x86|x64} to try the closest match to your system.&#10;You may also set PROTOBUF_PROTOC to specify full path to the host-provided compiler (v3.5+ is required)." />
+ </Target>
+
+ <!--================================================================================
+ Proto compilation
+ =================================================================================-->
+
+ <!-- Extension points. -->
+ <Target Name="Protobuf_BeforeCompile" />
+ <Target Name="Protobuf_AfterCompile" />
+
+ <!-- Main compile sequence. Certain steps are gated by the value $(DesignTimeBuild),
+ so the sequence is good for either design time or build time. -->
+ <Target Name="Protobuf_Compile"
+ Condition=" '@(ProtoBuf)' != '' "
+ DependsOnTargets=" Protobuf_BeforeCompile;
+ Protobuf_ResolvePlatform;
+ _Protobuf_SelectFiles;
+ Protobuf_PrepareCompile;
+ _Protobuf_AugmentLanguageCompile;
+ _Protobuf_CoreCompile;
+ Protobuf_ReconcileOutputs;
+ Protobuf_AfterCompile" />
+
+ <!-- Do proto compilation by default in a C# project. In other types, the user invoke
+ Protobuf_Compile directly where required. -->
+ <!-- TODO(kkm): Do shared compile in outer multitarget project? -->
+ <Target Name="_Protobuf_Compile_BeforeCsCompile"
+ BeforeTargets="BeforeCompile"
+ DependsOnTargets="Protobuf_Compile"
+ Condition=" '$(Language)' == 'C#' " />
+
+ <Target Name="_Protobuf_SelectFiles">
+ <!-- Guess .proto root for the files. Whenever the root is set for a file explicitly,
+ leave it as is. Otherwise, for files under the project directory, set the root
+ to "." for the project's directory, as it is the current when compiling; for the
+ files outside of project directory, use each .proto file's directory as the root. -->
+ <FindUnderPath Path="$(MSBuildProjectDirectory)"
+ Files="@(ProtoBuf->WithMetadataValue('ProtoRoot',''))">
+ <Output TaskParameter="InPath" ItemName="_Protobuf_NoRootInProject"/>
+ <Output TaskParameter="OutOfPath" ItemName="_Protobuf_NoRootElsewhere"/>
+ </FindUnderPath>
+ <ItemGroup>
+ <!-- Files with explicit metadata. -->
+ <Protobuf_Compile Include="@(ProtoBuf->HasMetadata('ProtoRoot'))" />
+ <!-- In-project files will have ProtoRoot='.'. -->
+ <Protobuf_Compile Include="@(_Protobuf_NoRootInProject)">
+ <ProtoRoot>.</ProtoRoot>
+ </Protobuf_Compile>
+ <!-- Out-of-project files will have respective ProtoRoot='%(RelativeDir)'. -->
+ <Protobuf_Compile Include="@(_Protobuf_NoRootElsewhere)">
+ <ProtoRoot>%(RelativeDir)</ProtoRoot>
+ </Protobuf_Compile>
+ <!-- Remove files not for compile. -->
+ <Protobuf_Compile Remove="@(Protobuf_Compile)" Condition=" !%(ProtoCompile) " />
+ <!-- Ensure invariant Source=%(Identity). -->
+ <Protobuf_Compile>
+ <Source>%(Identity)</Source>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+
+ <!-- Extension point for non-C# project. Protobuf_Generator should be supported
+ by the ProtoCompile task, but we skip inferring expected outputs. All proto
+ files will be always recompiled with a warning, unless you add expectations
+ to the Protobuf_ExpectedOutputs collection.
+
+ All inferred ExpectedOutputs will be added to code compile (C#) in a C# project
+ by default. This is controlled per-proto by the CompileOutputs metadata. -->
+ <Target Name="Protobuf_PrepareCompile" Condition=" '@(Protobuf_Compile)' != '' ">
+ <!-- Predict expected names. -->
+ <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' "
+ ProtoBuf="@(Protobuf_Compile)"
+ Generator="$(Protobuf_Generator)">
+ <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" />
+ </ProtoCompilerOutputs>
+ <!-- Read any dependency files from previous compiles. -->
+ <ProtoReadDependencies Condition=" '$(Protobuf_DepFilesPath)' != '' and '$(DesignTimeBuild)' != 'true' "
+ ProtoBuf="@(Protobuf_Compile)"
+ ProtoDepDir="$(Protobuf_DepFilesPath)" >
+ <Output TaskParameter="Dependencies" ItemName="Protobuf_Dependencies" />
+ </ProtoReadDependencies>
+ </Target>
+
+ <!-- Add all expected outputs, and only these, to language compile. -->
+ <Target Name="_Protobuf_AugmentLanguageCompile"
+ DependsOnTargets="_Protobuf_EnforceInvariants"
+ Condition=" '$(Language)' == 'C#' ">
+ <ItemGroup>
+ <_Protobuf_CodeCompile Include="@(Protobuf_ExpectedOutputs->Distinct())"
+ Condition=" '%(Source)' != '' and '@(Protobuf_Compile->WithMetadataValue('CompileOutputs', 'true'))' != '' " />
+ <Compile Include="@(_Protobuf_CodeCompile)" />
+ </ItemGroup>
+ </Target>
+
+ <!-- These invariants must be kept for compile up-to-date check to work. -->
+ <Target Name="_Protobuf_EnforceInvariants">
+ <!-- Enforce Source=Identity on proto files. The 'Source' metadata is used as a common
+ key to match dependencies/expected outputs in the lists for up-to-date checks. -->
+ <ItemGroup>
+ <Protobuf_Compile>
+ <Source>%(Identity)</Source>
+ </Protobuf_Compile>
+ </ItemGroup>
+
+ <!-- Remove possible output and dependency declarations that have no Source set, or those
+ not matching any proto marked for compilation. -->
+ <ItemGroup>
+ <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Protobuf_ExpectedOutputs.Source)' == '' " />
+ <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " />
+ <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Protobuf_Dependencies.Source)' == '' " />
+ <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " />
+ </ItemGroup>
+ </Target>
+
+ <!-- Gather files with and without known outputs, separately. -->
+ <Target Name="_Protobuf_GatherStaleFiles"
+ Condition=" '@(Protobuf_Compile)' != '' "
+ DependsOnTargets="_Protobuf_EnforceInvariants; _Protobuf_GatherStaleSimple; _Protobuf_GatherStaleBatched">
+ <ItemGroup>
+ <!-- Drop outputs from MSBuild inference (they won't have the '_Exec' metadata). -->
+ <_Protobuf_OutOfDateProto Remove="@(_Protobuf_OutOfDateProto->WithMetadataValue('_Exec',''))" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_Protobuf_GatherStaleSimple">
+ <!-- Simple selection: always compile files that have no declared outputs (but warn below). -->
+ <ItemGroup>
+ <_Protobuf_OutOfDateProto Include="@(Protobuf_Compile)"
+ Condition = " '%(Source)' != '' and '@(Protobuf_ExpectedOutputs)' == '' ">
+ <_Exec>true</_Exec>
+ </_Protobuf_OutOfDateProto>
+ </ItemGroup>
+
+ <!-- You are seeing this warning because there was no Protobuf_ExpectedOutputs items with
+ their Source attribute pointing to the proto files listed in the warning. Such files
+ will be recompiled on every build, as there is nothing to run up-to-date check against.
+ Set Protobuf_NoOrphanWarning to 'true' to suppress if this is what you want. -->
+ <Warning Condition=" '@(_Protobuf_OutOfDateProto)' != '' and '$(Protobuf_NoOrphanWarning)' != 'true' "
+ Text="The following files have no known outputs, and will be always recompiled as if out-of-date:&#10;@(_Protobuf_Orphans->'&#10; %(Identity)', '')" />
+ </Target>
+
+ <Target Name="_Protobuf_GatherStaleBatched"
+ Inputs="@(Protobuf_Compile);%(Source);@(Protobuf_Dependencies);$(MSBuildAllProjects)"
+ Outputs="@(Protobuf_ExpectedOutputs)" >
+ <!-- The '_Exec' metadatum is set to distinguish really executed items from those MSBuild so
+ "helpfully" infers in a bucketed task. For the same reason, cannot use the intrinsic
+ ItemGroup task here. -->
+ <CreateItem Include="@(Protobuf_Compile)" AdditionalMetadata="_Exec=true">
+ <Output TaskParameter="Include" ItemName="_Protobuf_OutOfDateProto"/>
+ </CreateItem>
+ </Target>
+
+ <!-- Extension point: Plugins massage metadata into recognized metadata
+ values passed to the ProtoCompile task. -->
+ <Target Name="Protobuf_PrepareCompileOptions" Condition=" '@(Protobuf_Compile)' != '' ">
+ <ItemGroup>
+ <Protobuf_Compile>
+ <_OutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._OutputOptions);internal_access</_OutputOptions>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_Protobuf_CoreCompile"
+ Condition=" '$(DesignTimeBuild)' != 'true' "
+ DependsOnTargets="Protobuf_PrepareCompileOptions;_Protobuf_GatherStaleFiles">
+ <!-- Ensure output directories. -->
+ <MakeDir Directories="%(_Protobuf_OutOfDateProto.OutputDir)" />
+ <MakeDir Directories="%(_Protobuf_OutOfDateProto.GrpcOutputDir)" />
+ <MakeDir Directories="$(Protobuf_DepFilesPath)" />
+
+ <!-- Force output to the current directory if the user has set it to empty. -->
+ <ItemGroup>
+ <_Protobuf_OutOfDateProto>
+ <OutputDir Condition=" '%(OutputDir)' == '' ">.</OutputDir>
+ </_Protobuf_OutOfDateProto>
+ </ItemGroup>
+
+ <ProtoCompile Condition=" '@(_Protobuf_OutOfDateProto)' != '' "
+ ToolExe="$(Protobuf_ProtocFullPath)"
+ Generator="$(Protobuf_Generator)"
+ ProtoBuf="%(_Protobuf_OutOfDateProto.Source)"
+ ProtoPath="%(_Protobuf_OutOfDateProto.AdditionalImportDirs);$(Protobuf_StandardImportsPath);%(_Protobuf_OutOfDateProto.ProtoRoot)"
+ ProtoDepDir="$(Protobuf_DepFilesPath)"
+ OutputDir="%(_Protobuf_OutOfDateProto.OutputDir)"
+ OutputOptions="%(_Protobuf_OutOfDateProto._OutputOptions)"
+ GrpcPluginExe="%(_Protobuf_OutOfDateProto.GrpcPluginExe)"
+ GrpcOutputDir="%(_Protobuf_OutOfDateProto.GrpcOutputDir)"
+ GrpcOutputOptions="%(_Protobuf_OutOfDateProto._GrpcOutputOptions)"
+ >
+ <Output TaskParameter="GeneratedFiles" ItemName="_Protobuf_GeneratedFiles"/>
+ </ProtoCompile>
+
+ <!-- Compute files expected but not in fact produced by protoc. -->
+ <ItemGroup Condition=" '@(_Protobuf_OutOfDateProto)' != '' ">
+ <Protobuf_ExpectedNotGenerated Include="@(Protobuf_ExpectedOutputs)"
+ Condition=" '%(Source)' != '' and '@(_Protobuf_OutOfDateProto)' != '' " />
+ <Protobuf_ExpectedNotGenerated Remove="@(_Protobuf_GeneratedFiles)" />
+ </ItemGroup>
+ </Target>
+
+ <!-- Extension point. Plugins and/or unsupported projects may take special care of the
+ Protobuf_ExpectedNotGenerated list in BeforeTargets. We just silently create the
+ missing outputs so that out-of-date checks work (we do not add them to language
+ compile though). You can empty this collection in your Before targets to do nothing.
+ The target is not executed if the proto compiler is not executed. -->
+ <Target Name="Protobuf_ReconcileOutputs"
+ Condition=" '$(DesignTimeBuild)' != 'true' ">
+ <!-- Warn about unexpected/missing files outside object file directory only.
+ This should have happened because build was incorrectly customized. -->
+ <FindUnderPath Path="$(BaseIntermediateOutputPath)" Files="@(Protobuf_ExpectedNotGenerated)">
+ <Output TaskParameter="InPath" ItemName="_Protobuf_ExpectedNotGeneratedInTemp"/>
+ <Output TaskParameter="OutOfPath" ItemName="_Protobuf_ExpectedNotGeneratedElsewhere"/>
+ </FindUnderPath>
+
+ <!-- Prevent unnecessary recompilation by silently creating empty files. This probably
+ has happened because a proto file with an rpc service was processed by the gRPC
+ plugin, and the user did not set GrpcOutput to None. When we treat outputs as
+ transient, we can do it permissively. -->
+ <Touch Files="@(_Protobuf_ExpectedNotGeneratedInTemp)" AlwaysCreate="true" />
+
+ <!-- Also create empty files outside of the intermediate directory, if the user wants so. -->
+ <Touch Files="@(_Protobuf_ExpectedNotGeneratedElsewhere)" AlwaysCreate="true"
+ Condition=" '$(Protobuf_TouchMissingExpected)' == 'true' "/>
+
+ <!-- You are seeing this warning because there were some Protobuf_ExpectedOutputs items
+ (outside of the transient directory under obj/) not in fact produced by protoc. -->
+ <Warning Condition=" '@(_Protobuf_ExpectedNotGeneratedElsewhere)' != '' and $(Protobuf_NoWarnMissingExpected) != 'true' "
+ Text="Some expected protoc outputs were not generated.&#10;@(_Protobuf_ExpectedNotGeneratedElsewhere->'&#10; %(Identity)', '')" />
+ </Target>
+
+ <!--================================================================================
+ Proto cleanup
+ =================================================================================-->
+
+ <!-- We fully support cleanup only in a C# project. If extending the build for other
+ generators/plugins, then mostly roll your own. -->
+
+ <!-- Extension points. -->
+ <Target Name="Protobuf_BeforeClean" />
+ <Target Name="Protobuf_AfterClean" />
+
+ <!-- Main cleanup sequence. -->
+ <Target Name="Protobuf_Clean"
+ Condition=" '@(ProtoBuf)' != '' "
+ DependsOnTargets=" Protobuf_BeforeClean;
+ Protobuf_PrepareClean;
+ _Protobuf_CoreClean;
+ Protobuf_AfterClean" />
+
+ <!-- Do proto cleanup by default in a C# project. In other types, the user should
+ invoke Protobuf_Clean directly if required. -->
+ <Target Name="_Protobuf_Clean_AfterCsClean"
+ AfterTargets="CoreClean"
+ DependsOnTargets="Protobuf_Clean"
+ Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' " />
+
+ <!-- Extension point for non-C# project. ProtoCompilerOutputs is not invoked for
+ non-C# projects, since inferring protoc outputs is required, so this is a
+ no-op in other project types. In your extension target populate the
+ Protobuf_ExpectedOutputs with all possible output. An option is to include
+ all existing outputs using Include with a wildcard, if you know where to look.
+
+ Note this is like Protobuf_PrepareCompile, but uses @(Protobuf) regardless
+ of the Compile metadata, to remove all possible outputs. Plugins should err
+ on the side of overextending the Protobuf_ExpectedOutputs here.
+
+ All ExpectedOutputs will be removed. -->
+ <Target Name="Protobuf_PrepareClean" Condition=" '@(Protobuf)' != '' ">
+ <!-- Predict expected names. -->
+ <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' "
+ ProtoBuf="@(Protobuf)"
+ Generator="$(Protobuf_Generator)">
+ <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" />
+ </ProtoCompilerOutputs>
+ </Target>
+
+ <Target Name="_Protobuf_CoreClean">
+ <ItemGroup>
+ <_Protobuf_Protodep Include="$(Protobuf_DepFilesPath)*.protodep" />
+ </ItemGroup>
+ <Delete Files="@(Protobuf_ExpectedOutputs);@(_Protobuf_Protodep)" TreatErrorsAsWarnings="true" />
+ </Target>
+
+ <!--================================================================================
+ Design-time support
+ =================================================================================-->
+
+ <!-- Add all .proto files to the SourceFilesProjectOutputGroupOutput, so that:
+ * Visual Studio triggers a build when any of them changed;
+ * The Pack target includes .proto files into the source package. -->
+ <Target Name="_Protobuf_SourceFilesProjectOutputGroup"
+ BeforeTargets="SourceFilesProjectOutputGroup"
+ Condition=" '@(ProtoBuf)' != '' " >
+ <ItemGroup>
+ <SourceFilesProjectOutputGroupOutput Include="@(ProtoBuf->'%(FullPath)')" />
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml
new file mode 100644
index 0000000000..2c41fbcbd0
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml
@@ -0,0 +1,99 @@
+<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
+ <FileExtension Name=".proto"
+ ContentType="ProtoFile" />
+
+ <ContentType Name="ProtoFile"
+ DisplayName="Protocol buffer definitions file"
+ ItemType="ProtoBuf" />
+
+ <ItemType Name="ProtoBuf"
+ DisplayName="Protobuf compiler" />
+
+ <Rule Name="ProtoBuf"
+ DisplayName="File Properties"
+ PageTemplate="generic"
+ Description="File Properties"
+ OverrideMode="Extend">
+ <Rule.DataSource>
+ <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf"
+ HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" />
+ </Rule.DataSource>
+
+ <Rule.Categories>
+ <Category Name="Advanced" DisplayName="Advanced" />
+ <Category Name="Protobuf" DisplayName="Protobuf" />
+ <Category Name="Misc" DisplayName="Misc" />
+ </Rule.Categories>
+
+ <DynamicEnumProperty Name="{}{ItemType}" DisplayName="Build Action" Category="Advanced"
+ Description="How the file relates to the build and deployment processes."
+ EnumProvider="ItemTypes" />
+
+ <StringProperty Name="Identity" Visible="false" ReadOnly="true">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="Identity" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <StringProperty Name="FullPath"
+ DisplayName="Full Path"
+ ReadOnly="true"
+ Category="Misc"
+ Description="Location of the file.">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="FullPath" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <StringProperty Name="FileNameAndExtension"
+ DisplayName="File Name"
+ ReadOnly="true"
+ Category="Misc"
+ Description="Name of the file or folder.">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="FileNameAndExtension" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <BoolProperty Name="Visible" Visible="false" Default="true" />
+
+ <StringProperty Name="DependentUpon" Visible="false">
+ <StringProperty.Metadata>
+ <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" />
+ </StringProperty.Metadata>
+ </StringProperty>
+
+ <StringProperty Name="Link" Visible="false">
+ <StringProperty.DataSource>
+ <DataSource SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ <StringProperty.Metadata>
+ <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" />
+ </StringProperty.Metadata>
+ </StringProperty>
+
+ <EnumProperty Name="Access" DisplayName="Class Access"
+ Category="Protobuf"
+ Description="Public or internal access modifier on generated classes.">
+ <EnumValue Name="Public" DisplayName="Public" IsDefault="true" />
+ <EnumValue Name="Internal" DisplayName="Internal" />
+ <EnumProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </EnumProperty.DataSource>
+ </EnumProperty>
+
+ <BoolProperty Name="ProtoCompile" DisplayName="Compile Protobuf"
+ Category="Protobuf" Default="true"
+ Description="Specifies if this file is compiled or only imported by other files.">
+ <BoolProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </BoolProperty.DataSource>
+ </BoolProperty>
+
+ </Rule>
+</ProjectSchemaDefinitions>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/README b/src/csharp/Grpc.Tools/build/_protobuf/README
new file mode 100644
index 0000000000..e6e358a218
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/README
@@ -0,0 +1 @@
+TODO(kkm): These file will go into Google.Protobuf.Tools/build after package split.
diff --git a/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props
new file mode 100644
index 0000000000..f83c4d135a
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+ <!-- Revision number of this package conventions (as if "API" version). -->
+ <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision>
+
+ <!-- For a Visual Studio C++ native project we currently only resolve tools and import paths. -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <Protobuf_ProtocFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\protoc.exe</Protobuf_ProtocFullPath>
+ <Protobuf_StandardImportsPath>$(MSBuildThisFileDirectory)include\</Protobuf_StandardImportsPath>
+ <gRPC_PluginFileName>grpc_cpp_plugin</gRPC_PluginFileName>
+ <gRPC_PluginFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\grpc_cpp_plugin.exe</gRPC_PluginFullPath>
+ </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index d9a7b8d556..6c1b2e9998 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -39,6 +39,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Gr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Microbenchmarks", "Grpc.Microbenchmarks\Grpc.Microbenchmarks.csproj", "{84C17746-4727-4290-8E8B-A380793DAE1E}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools", "Grpc.Tools\Grpc.Tools.csproj", "{8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools.Tests", "Grpc.Tools.Tests\Grpc.Tools.Tests.csproj", "{AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -117,6 +121,14 @@ Global
{84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
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/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 8f38f0aa20..27688360e9 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.15.0-dev
+set VERSION=1.17.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
@@ -39,10 +39,10 @@ xcopy /Y /I nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll ..\..\cmake\bu
%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Tools --output ..\..\..\artifacts || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Core.NativeDebug.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
-%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat
index 9c53114b84..dd74de0491 100644
--- a/src/csharp/build_unitypackage.bat
+++ b/src/csharp/build_unitypackage.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.15.0-dev
+set VERSION=1.17.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/doc/README.md b/src/csharp/doc/README.md
index 46cce013a1..427f457eb6 100644
--- a/src/csharp/doc/README.md
+++ b/src/csharp/doc/README.md
@@ -1,9 +1,28 @@
DocFX-generated C# API Reference
--------------------------------
+## Generating docs manually (on Windows)
+
Install docfx based on instructions here: https://github.com/dotnet/docfx
```
# generate docfx documentation into ./html directory
$ docfx
```
+
+## Release process: script for regenerating the docs automatically
+
+After each gRPC C# release, the docs need to be regenerated
+and updated on the grpc.io site. The automated script will
+re-generate the docs (using dockerized docfx installation)
+and make everything ready for creating a PR to update the docs.
+
+```
+# 1. Run the script on Linux with docker installed
+$ ./generate_reference_docs.sh
+
+# 2. Enter the git repo with updated "gh-pages" branch
+$ cd grpc-gh-pages
+
+# 3. Review the changes and create a pull request
+```
diff --git a/src/csharp/doc/generate_reference_docs.sh b/src/csharp/doc/generate_reference_docs.sh
new file mode 100755
index 0000000000..c20d6c30bd
--- /dev/null
+++ b/src/csharp/doc/generate_reference_docs.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# 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.
+
+# Generates C# API docs using docfx inside docker.
+set -ex
+cd $(dirname $0)
+
+# cleanup temporary files
+rm -rf html obj grpc-gh-pages
+
+# generate into src/csharp/doc/html directory
+cd ..
+docker run --rm -v "$(pwd)":/work -w /work/doc --user "$(id -u):$(id -g)" -it tsgkadot/docker-docfx:latest docfx
+cd doc
+
+# prepare a clone of "gh-pages" branch where the generated docs are stored
+GITHUB_USER="${USER}"
+git clone -b gh-pages -o upstream git@github.com:grpc/grpc.git grpc-gh-pages
+cd grpc-gh-pages
+git remote add origin "git@github.com:${GITHUB_USER}/grpc.git"
+
+# replace old generated docs by the ones we just generated
+rm -r csharp
+cp -r ../html csharp
+
+echo "Done. Go to src/csharp/doc/grpc-gh-pages git repository and create a pull request to update the generated docs."
diff --git a/src/csharp/doc/integration.md-fig.1-classic.png b/src/csharp/doc/integration.md-fig.1-classic.png
new file mode 100644
index 0000000000..80c57261ad
--- /dev/null
+++ b/src/csharp/doc/integration.md-fig.1-classic.png
Binary files differ
diff --git a/src/csharp/doc/integration.md-fig.2-sdk.png b/src/csharp/doc/integration.md-fig.2-sdk.png
new file mode 100644
index 0000000000..6d653e4a58
--- /dev/null
+++ b/src/csharp/doc/integration.md-fig.2-sdk.png
Binary files differ
diff --git a/src/csharp/experimental/README.md b/src/csharp/experimental/README.md
index bd53cbcd35..64515075ce 100644
--- a/src/csharp/experimental/README.md
+++ b/src/csharp/experimental/README.md
@@ -22,10 +22,14 @@ gRPC C# now has experimental support for Unity. Please try using gRPC with
Unity and provide feedback!
How to test gRPC in a Unity project
+
1. Create a Unity project that targets .NET 4.x (Edit -> Project Settings -> Editor -> Scripting Runtime Version). gRPC uses APIs that are only available in .NET4.5+ so this is a requirement.
+
2. Download the latest development build of `grpc_unity_package.VERSION.zip` from
[daily builds](https://packages.grpc.io/)
+
3. Extract the `.zip` file in the `Assets` directory in your Unity project
+
4. Unity IDE will pick up all the bundled files and add them to project automatically.
You should be able to use gRPC and Protobuf in your scripts from now on.
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 87a2516f8d..ed002ae1ff 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -964,7 +964,7 @@ GPR_EXPORT grpc_server_credentials* GPR_CALLTYPE
grpcsharp_ssl_server_credentials_create(
const char* pem_root_certs, const char** key_cert_pair_cert_chain_array,
const char** key_cert_pair_private_key_array, size_t num_key_cert_pairs,
- int force_client_auth) {
+ grpc_ssl_client_certificate_request_type client_request_type) {
size_t i;
grpc_server_credentials* creds;
grpc_ssl_pem_key_cert_pair* key_cert_pairs =
@@ -979,12 +979,9 @@ grpcsharp_ssl_server_credentials_create(
key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
}
}
- creds = grpc_ssl_server_credentials_create_ex(
- pem_root_certs, key_cert_pairs, num_key_cert_pairs,
- force_client_auth
- ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
- : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
- NULL);
+ creds = grpc_ssl_server_credentials_create_ex(pem_root_certs, key_cert_pairs,
+ num_key_cert_pairs,
+ client_request_type, NULL);
gpr_free(key_cert_pairs);
return creds;
}
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index c2f243fe0a..760776f9e7 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -23,8 +23,10 @@
"Grpc.Core.Tests.ClientServerTest",
"Grpc.Core.Tests.CompressionTest",
"Grpc.Core.Tests.ContextPropagationTest",
+ "Grpc.Core.Tests.ContextualMarshallerTest",
"Grpc.Core.Tests.GrpcEnvironmentTest",
"Grpc.Core.Tests.HalfcloseTest",
+ "Grpc.Core.Tests.MarshallerTest",
"Grpc.Core.Tests.MarshallingErrorsTest",
"Grpc.Core.Tests.MetadataTest",
"Grpc.Core.Tests.PerformanceTest",
@@ -62,5 +64,15 @@
"Grpc.Reflection.Tests": [
"Grpc.Reflection.Tests.ReflectionClientServerTest",
"Grpc.Reflection.Tests.SymbolRegistryTest"
+ ],
+ "Grpc.Tools.Tests": [
+ "Grpc.Tools.Tests.CppGeneratorTest",
+ "Grpc.Tools.Tests.CSharpGeneratorTest",
+ "Grpc.Tools.Tests.DepFileUtilTest",
+ "Grpc.Tools.Tests.GeneratorTest",
+ "Grpc.Tools.Tests.ProtoCompileBasicTest",
+ "Grpc.Tools.Tests.ProtoCompileCommandLineGeneratorTest",
+ "Grpc.Tools.Tests.ProtoCompileCommandLinePrinterTest",
+ "Grpc.Tools.Tests.ProtoToolsPlatformTaskTest"
]
}
diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
index 5e9a9a4513..a95a120d21 100644
--- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
+++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
- v = '1.15.0-dev'
+ v = '1.17.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC
diff --git a/src/objective-c/BoringSSL-GRPC.podspec b/src/objective-c/BoringSSL-GRPC.podspec
index 704b35a29e..04e4d5768f 100644
--- a/src/objective-c/BoringSSL-GRPC.podspec
+++ b/src/objective-c/BoringSSL-GRPC.podspec
@@ -38,7 +38,7 @@
Pod::Spec.new do |s|
s.name = 'BoringSSL-GRPC'
- version = '0.0.1'
+ version = '0.0.2'
s.version = version
s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
# Adapted from the homepage:
@@ -81,7 +81,7 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '5.0'
s.osx.deployment_target = '10.7'
- name = 'openssl'
+ name = 'openssl_grpc'
# When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework.
# This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include
@@ -1546,6 +1546,7 @@ Pod::Spec.new do |s|
sed -i'.back' '/^#define \\([A-Za-z0-9_]*\\) \\1/d' include/openssl/ssl.h
sed -i'.back' 'N;/^#define \\([A-Za-z0-9_]*\\) *\\\\\\n *\\1/d' include/openssl/ssl.h
sed -i'.back' 's/#ifndef md5_block_data_order/#ifndef GRPC_SHADOW_md5_block_data_order/g' crypto/fipsmodule/md5/md5.c
+ find . -type f \\( -path '*.h' -or -path '*.cc' -or -path '*.c' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
# Redefine symbols to avoid conflict when the same app also depends on OpenSSL. The list of
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 862909f238..85b95dee91 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -69,7 +69,7 @@ static NSMutableDictionary *kHostCache;
// gRPC library.
// TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched.
NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]];
- if (hostURL.host && !hostURL.port) {
+ if (hostURL.host && hostURL.port == nil) {
address = [hostURL.host stringByAppendingString:@":443"];
}
@@ -193,6 +193,7 @@ static NSMutableDictionary *kHostCache;
if (pemPrivateKey == nil && pemCertChain == nil) {
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL);
} else {
+ assert(pemPrivateKey != nil && pemCertChain != nil);
grpc_ssl_pem_key_cert_pair key_cert_pair;
NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey];
NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain];
@@ -226,7 +227,7 @@ static NSMutableDictionary *kHostCache;
args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
}
- if (_responseSizeLimitOverride) {
+ if (_responseSizeLimitOverride != nil) {
args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = _responseSizeLimitOverride;
}
diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h
index a63e76ee4d..fb05638b78 100644
--- a/src/objective-c/GRPCClient/private/NSError+GRPC.h
+++ b/src/objective-c/GRPCClient/private/NSError+GRPC.h
@@ -25,6 +25,6 @@
* and whose domain is |kGRPCErrorDomain|.
*/
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode
- details:(char *)details
+ details:(const char *)details
errorString:(const char *)errorString;
@end
diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.m b/src/objective-c/GRPCClient/private/NSError+GRPC.m
index 199b2ebb6c..3eefed88d6 100644
--- a/src/objective-c/GRPCClient/private/NSError+GRPC.m
+++ b/src/objective-c/GRPCClient/private/NSError+GRPC.m
@@ -24,18 +24,20 @@ NSString *const kGRPCErrorDomain = @"io.grpc";
@implementation NSError (GRPC)
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode
- details:(char *)details
+ details:(const char *)details
errorString:(const char *)errorString {
if (statusCode == GRPC_STATUS_OK) {
return nil;
}
- NSString *message = [NSString stringWithCString:details encoding:NSUTF8StringEncoding];
- NSString *debugMessage = [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding];
- return [NSError errorWithDomain:kGRPCErrorDomain
- code:statusCode
- userInfo:@{
- NSLocalizedDescriptionKey : message,
- NSDebugDescriptionErrorKey : debugMessage
- }];
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+ if (details) {
+ userInfo[NSLocalizedDescriptionKey] =
+ [NSString stringWithCString:details encoding:NSUTF8StringEncoding];
+ }
+ if (errorString) {
+ userInfo[NSDebugDescriptionErrorKey] =
+ [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding];
+ }
+ return [NSError errorWithDomain:kGRPCErrorDomain code:statusCode userInfo:userInfo];
}
@end
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index 52fe0dd050..d5463c0b4c 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -22,4 +22,4 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev"
diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
index 75a669da4d..84893b92c1 100644
--- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
+++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
@@ -39,7 +39,7 @@
#import "src/core/tsi/grpc_shadow_boringssl.h"
-#import <openssl/ssl.h>
+#import <openssl_grpc/ssl.h>
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 5750dccd89..9d79606881 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -545,7 +545,7 @@ BOOL isRemoteInteropTest(NSString *host) {
} else {
// Keepalive should kick after 1s elapsed and fails the call.
XCTAssertNotNil(error);
- XCTAssertEqual(error.code, GRPC_STATUS_INTERNAL);
+ XCTAssertEqual(error.code, GRPC_STATUS_UNAVAILABLE);
XCTAssertEqualObjects(
error.localizedDescription, @"keepalive watchdog timeout",
@"Unexpected failure that is not keepalive watchdog timeout.");
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 507d251b48..5d2f1340da 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -14,6 +14,7 @@ GRPC_LOCAL_SRC = '../../..'
InteropTestsLocalSSL
InteropTestsLocalCleartext
InteropTestsRemoteWithCronet
+ UnitTests
).each do |target_name|
target target_name do
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 0e0e8babc0..f0d8123263 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -13,6 +13,8 @@
16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; };
20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
+ 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* UnitTests.m */; };
+ 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */; };
5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; };
@@ -54,10 +56,18 @@
91D4B3C85B6D8562F409CB48 /* libPods-InteropTestsLocalSSLCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */; };
BC111C80CBF7068B62869352 /* libPods-InteropTestsRemoteCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */; };
C3D6F4270A2FFF634D8849ED /* libPods-InteropTestsLocalCleartextCFStream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */; };
+ CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */; };
F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 635697C61B14FC11007A7283;
+ remoteInfo = Tests;
+ };
5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
@@ -138,6 +148,7 @@
1588C85DEAF7FC0ACDEA4C02 /* Pods-InteropTestsLocalCleartext.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.test.xcconfig"; sourceTree = "<group>"; };
17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = "<group>"; };
20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2B89F3037963E6EDDD48D8C3 /* Pods-InteropTestsRemoteWithCronet.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.test.xcconfig"; sourceTree = "<group>"; };
303F4A17EB1650FC44603D17 /* Pods-InteropTestsRemoteCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.release.xcconfig"; sourceTree = "<group>"; };
32748C4078AEB05F8F954361 /* Pods-InteropTestsRemoteCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream.debug.xcconfig"; sourceTree = "<group>"; };
@@ -155,6 +166,9 @@
55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig"; sourceTree = "<group>"; };
573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = "<group>"; };
5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
+ 5E0282E6215AA697007AC99D /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5E0282E8215AA697007AC99D /* UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnitTests.m; sourceTree = "<group>"; };
+ 5E0282EA215AA697007AC99D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = "<group>"; };
5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; sourceTree = "<group>"; };
@@ -192,7 +206,9 @@
7BA53C6D224288D5870FE6F3 /* Pods-InteropTestsLocalCleartextCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.release.xcconfig"; sourceTree = "<group>"; };
8B498B05C6DA0818B2FA91D4 /* Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.cronet.xcconfig"; sourceTree = "<group>"; };
943138072A9605B5B8DC1FC0 /* Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.debug.xcconfig"; sourceTree = "<group>"; };
+ 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.test.xcconfig"; sourceTree = "<group>"; };
9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteWithCronet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = "<group>"; };
A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RxLibraryUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
A6F832FCEFA6F6881E620F12 /* Pods-InteropTestsRemote.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.test.xcconfig"; sourceTree = "<group>"; };
AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.cronet.xcconfig"; sourceTree = "<group>"; };
@@ -208,9 +224,11 @@
DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSL.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.debug.xcconfig"; sourceTree = "<group>"; };
E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.debug.xcconfig"; sourceTree = "<group>"; };
+ E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.cronet.xcconfig"; sourceTree = "<group>"; };
E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = "<group>"; };
E4FD4606D4AB8D5A314D72F0 /* Pods-InteropTestsLocalCleartextCFStream.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartextCFStream/Pods-InteropTestsLocalCleartextCFStream.test.xcconfig"; sourceTree = "<group>"; };
E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.cronet.xcconfig"; sourceTree = "<group>"; };
+ EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = "<group>"; };
F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSLCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; };
F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteCFStream.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -219,6 +237,15 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 5E0282E3215AA697007AC99D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E0282EB215AA697007AC99D /* libTests.a in Frameworks */,
+ CCF5C0719EF608276AE16374 /* libPods-UnitTests.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -341,6 +368,7 @@
F44AC3F44E3491A8C0D890FE /* libPods-InteropTestsRemoteCFStream.a */,
0BDA4BA011779D5D25B5618C /* libPods-InteropTestsLocalCleartextCFStream.a */,
F3AB031E0E26AC8EF30A2A2A /* libPods-InteropTestsLocalSSLCFStream.a */,
+ 22A3EBB488699C8CEA19707B /* libPods-UnitTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -394,10 +422,23 @@
41AA59529240A6BBBD3DB904 /* Pods-InteropTestsLocalSSLCFStream.test.xcconfig */,
55B630C1FF8C36D1EFC4E0A4 /* Pods-InteropTestsLocalSSLCFStream.cronet.xcconfig */,
5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */,
+ A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */,
+ 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */,
+ E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */,
+ EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
+ 5E0282E7215AA697007AC99D /* UnitTests */ = {
+ isa = PBXGroup;
+ children = (
+ 5E0282E8215AA697007AC99D /* UnitTests.m */,
+ 5E0282EA215AA697007AC99D /* Info.plist */,
+ );
+ path = UnitTests;
+ sourceTree = "<group>";
+ };
5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
isa = PBXGroup;
children = (
@@ -432,6 +473,7 @@
5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
5EAD6D251E27047400002378 /* CronetUnitTests */,
+ 5E0282E7215AA697007AC99D /* UnitTests */,
635697C81B14FC11007A7283 /* Products */,
51E4650F34F854F41FF053B3 /* Pods */,
136D535E19727099B941D7B1 /* Frameworks */,
@@ -453,6 +495,7 @@
5EC5E421208177CC000EF4AD /* InteropTestsRemoteCFStream.xctest */,
5EC5E4312081856B000EF4AD /* InteropTestsLocalCleartextCFStream.xctest */,
5EC5E442208185CE000EF4AD /* InteropTestsLocalSSLCFStream.xctest */,
+ 5E0282E6215AA697007AC99D /* UnitTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -485,6 +528,26 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
+ 5E0282E5215AA697007AC99D /* UnitTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5E0282F2215AA697007AC99D /* Build configuration list for PBXNativeTarget "UnitTests" */;
+ buildPhases = (
+ F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */,
+ 5E0282E2215AA697007AC99D /* Sources */,
+ 5E0282E3215AA697007AC99D /* Frameworks */,
+ 5E0282E4215AA697007AC99D /* Resources */,
+ 9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 5E0282ED215AA697007AC99D /* PBXTargetDependency */,
+ );
+ name = UnitTests;
+ productName = UnitTests;
+ productReference = 5E0282E6215AA697007AC99D /* UnitTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */;
@@ -729,6 +792,10 @@
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
+ 5E0282E5215AA697007AC99D = {
+ CreatedOnToolsVersion = 9.2;
+ ProvisioningStyle = Automatic;
+ };
5E8A5DA31D3840B4000F8BC4 = {
CreatedOnToolsVersion = 7.3.1;
};
@@ -794,11 +861,19 @@
5EC5E420208177CC000EF4AD /* InteropTestsRemoteCFStream */,
5EC5E4302081856B000EF4AD /* InteropTestsLocalCleartextCFStream */,
5EC5E441208185CE000EF4AD /* InteropTestsLocalSSLCFStream */,
+ 5E0282E5215AA697007AC99D /* UnitTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 5E0282E4215AA697007AC99D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5E8A5DA21D3840B4000F8BC4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1098,6 +1173,24 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteCFStream/Pods-InteropTestsRemoteCFStream-resources.sh\"\n";
showEnvVarsInLog = 0;
};
+ 9AD0B5E94F2AA5962EA6AA36 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
A023FB55205A7EA37D413549 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1260,6 +1353,24 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
+ F07941C0BAF6A7C67AA60C48 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
F3D5B2CDA172580341682830 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1299,6 +1410,14 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 5E0282E2215AA697007AC99D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E0282E9215AA697007AC99D /* UnitTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5E8A5DA01D3840B4000F8BC4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1412,6 +1531,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 5E0282ED215AA697007AC99D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 635697C61B14FC11007A7283 /* Tests */;
+ targetProxy = 5E0282EC215AA697007AC99D /* PBXContainerItemProxy */;
+ };
5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 635697C61B14FC11007A7283 /* Tests */;
@@ -1455,6 +1579,128 @@
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
+ 5E0282EE215AA697007AC99D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A2DCF2570BE515B62CB924CA /* Pods-UnitTests.debug.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = UnitTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
+ };
+ name = Debug;
+ };
+ 5E0282EF215AA697007AC99D /* Test */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 94D7A5FAA13480E9A5166D7A /* Pods-UnitTests.test.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = UnitTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
+ };
+ name = Test;
+ };
+ 5E0282F0215AA697007AC99D /* Cronet */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E1E7660656D902104F728892 /* Pods-UnitTests.cronet.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = UnitTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
+ };
+ name = Cronet;
+ };
+ 5E0282F1215AA697007AC99D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = EBFFEC04B514CB0D4922DC40 /* Pods-UnitTests.release.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ INFOPLIST_FILE = UnitTests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = io.grpc.UnitTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ USER_HEADER_SEARCH_PATHS = "\"$(PODS_ROOT)/../../../..\"";
+ };
+ name = Release;
+ };
5E1228981E4D400F00E8504F /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -2602,6 +2848,17 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 5E0282F2215AA697007AC99D /* Build configuration list for PBXNativeTarget "UnitTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E0282EE215AA697007AC99D /* Debug */,
+ 5E0282EF215AA697007AC99D /* Test */,
+ 5E0282F0215AA697007AC99D /* Cronet */,
+ 5E0282F1215AA697007AC99D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme
new file mode 100644
index 0000000000..3af3555f48
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0920"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "NO"
+ buildForArchiving = "NO"
+ buildForAnalyzing = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "5E0282E5215AA697007AC99D"
+ BuildableName = "UnitTests.xctest"
+ BlueprintName = "UnitTests"
+ ReferencedContainer = "container:Tests.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "5E0282E5215AA697007AC99D"
+ BuildableName = "UnitTests.xctest"
+ BlueprintName = "UnitTests"
+ ReferencedContainer = "container:Tests.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = ""
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "5E0282E5215AA697007AC99D"
+ BuildableName = "UnitTests.xctest"
+ BlueprintName = "UnitTests"
+ ReferencedContainer = "container:Tests.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "5E0282E5215AA697007AC99D"
+ BuildableName = "UnitTests.xctest"
+ BlueprintName = "UnitTests"
+ ReferencedContainer = "container:Tests.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/src/objective-c/tests/UnitTests/Info.plist b/src/objective-c/tests/UnitTests/Info.plist
new file mode 100644
index 0000000000..6c40a6cd0c
--- /dev/null
+++ b/src/objective-c/tests/UnitTests/Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/src/objective-c/tests/UnitTests/UnitTests.m b/src/objective-c/tests/UnitTests/UnitTests.m
new file mode 100644
index 0000000000..57e686d1b6
--- /dev/null
+++ b/src/objective-c/tests/UnitTests/UnitTests.m
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#import <XCTest/XCTest.h>
+
+#import <GRPCClient/GRPCCall.h>
+
+#import "src/objective-c/GRPCClient/private/NSError+GRPC.h"
+
+@interface UnitTests : XCTestCase
+
+@end
+
+@implementation UnitTests
+
+- (void)testNSError {
+ const char *kDetails = "test details";
+ const char *kErrorString = "test errorString";
+ NSError *error1 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_OK details:nil errorString:nil];
+ NSError *error2 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_CANCELLED
+ details:kDetails
+ errorString:kErrorString];
+ NSError *error3 = [NSError grpc_errorFromStatusCode:GRPC_STATUS_UNAUTHENTICATED
+ details:kDetails
+ errorString:nil];
+ NSError *error4 =
+ [NSError grpc_errorFromStatusCode:GRPC_STATUS_UNAVAILABLE details:nil errorString:nil];
+
+ XCTAssertNil(error1);
+ XCTAssertEqual(error2.code, 1);
+ XCTAssertEqualObjects(error2.domain, @"io.grpc");
+ XCTAssertEqualObjects(error2.userInfo[NSLocalizedDescriptionKey],
+ [NSString stringWithUTF8String:kDetails]);
+ XCTAssertEqualObjects(error2.userInfo[NSDebugDescriptionErrorKey],
+ [NSString stringWithUTF8String:kErrorString]);
+ XCTAssertEqual(error3.code, 16);
+ XCTAssertEqualObjects(error3.domain, @"io.grpc");
+ XCTAssertEqualObjects(error3.userInfo[NSLocalizedDescriptionKey],
+ [NSString stringWithUTF8String:kDetails]);
+ XCTAssertNil(error3.userInfo[NSDebugDescriptionErrorKey]);
+ XCTAssertEqual(error4.code, 14);
+ XCTAssertEqualObjects(error4.domain, @"io.grpc");
+ XCTAssertNil(error4.userInfo[NSLocalizedDescriptionKey]);
+ XCTAssertNil(error4.userInfo[NSDebugDescriptionErrorKey]);
+}
+
+@end
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index 9dde07d55c..f37c6cf9f6 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -163,4 +163,14 @@ xcodebuild \
| egrep -v '^$' \
| egrep -v "(GPBDictionary|GPBArray)" -
+echo "TIME: $(date)"
+xcodebuild \
+ -workspace Tests.xcworkspace \
+ -scheme UnitTests \
+ -destination name="iPhone 8" \
+ test \
+ | egrep -v "$XCODEBUILD_FILTER" \
+ | egrep -v '^$' \
+ | egrep -v "(GPBDictionary|GPBArray)" -
+
exit 0
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index d532eed245..ca27c03b3c 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -22,5 +22,5 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev"
-#define GRPC_C_VERSION_STRING @"6.0.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.17.0-dev"
+#define GRPC_C_VERSION_STRING @"7.0.0-dev"
diff --git a/src/php/composer.json b/src/php/composer.json
index 91913d73d2..d54db91b5f 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Developement use only",
"license": "Apache-2.0",
- "version": "1.15.0",
+ "version": "1.17.0",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index 99dd9d68f0..70f8bbbf40 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define PHP_GRPC_VERSION "1.15.0dev"
+#define PHP_GRPC_VERSION "1.17.0dev"
#endif /* VERSION_H */
diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php
index 49b0e350f7..583c618d32 100644
--- a/src/php/tests/unit_tests/ChannelTest.php
+++ b/src/php/tests/unit_tests/ChannelTest.php
@@ -599,10 +599,10 @@ class ChannelTest extends PHPUnit_Framework_TestCase
public function testPersistentChannelForceNewOldChannelIdle2()
{
- $this->channel1 = new Grpc\Channel('localhost:50029', [
+ $this->channel1 = new Grpc\Channel('localhost:50032', [
"grpc_target_persist_bound" => 2,
]);
- $this->channel2 = new Grpc\Channel('localhost:50029', []);
+ $this->channel2 = new Grpc\Channel('localhost:50032', []);
// try to connect on channel2
$state = $this->channel1->getConnectivityState(true);
diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto
index d930dfcfb4..6202e5e817 100644
--- a/src/proto/grpc/channelz/channelz.proto
+++ b/src/proto/grpc/channelz/channelz.proto
@@ -424,6 +424,8 @@ service Channelz {
rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
// Gets all servers that exist in the process.
rpc GetServers(GetServersRequest) returns (GetServersResponse);
+ // Returns a single Server, or else a NOT_FOUND code.
+ rpc GetServer(GetServerRequest) returns (GetServerResponse);
// Gets all server sockets that exist in the process.
rpc GetServerSockets(GetServerSocketsRequest) returns (GetServerSocketsResponse);
// Returns a single Channel, or else a NOT_FOUND code.
@@ -466,6 +468,17 @@ message GetServersResponse {
bool end = 2;
}
+message GetServerRequest {
+ // server_id is the identifier of the specific server to get.
+ int64 server_id = 1;
+}
+
+message GetServerResponse {
+ // The Server that corresponds to the requested server_id. This field
+ // should be set.
+ Server server = 1;
+}
+
message GetServerSocketsRequest {
int64 server_id = 1;
// start_socket_id indicates that only sockets at or above this id should be
diff --git a/src/proto/grpc/health/v1/BUILD b/src/proto/grpc/health/v1/BUILD
index d234842883..97642985c9 100644
--- a/src/proto/grpc/health/v1/BUILD
+++ b/src/proto/grpc/health/v1/BUILD
@@ -22,3 +22,11 @@ grpc_proto_library(
name = "health_proto",
srcs = ["health.proto"],
)
+
+filegroup(
+ name = "health_proto_file",
+ srcs = [
+ "health.proto",
+ ],
+)
+
diff --git a/src/proto/grpc/health/v1/health.proto b/src/proto/grpc/health/v1/health.proto
index 4b4677b8a4..38843ff1e7 100644
--- a/src/proto/grpc/health/v1/health.proto
+++ b/src/proto/grpc/health/v1/health.proto
@@ -34,10 +34,30 @@ message HealthCheckResponse {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
+ SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
service Health {
+ // If the requested service is unknown, the call will fail with status
+ // NOT_FOUND.
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+
+ // Performs a watch for the serving status of the requested service.
+ // The server will immediately send back a message indicating the current
+ // serving status. It will then subsequently send a new message whenever
+ // the service's serving status changes.
+ //
+ // If the requested service is unknown when the call is received, the
+ // server will send a message setting the serving status to
+ // SERVICE_UNKNOWN but will *not* terminate the call. If at some
+ // future point, the serving status of the service becomes known, the
+ // server will send a new message with the service's serving status.
+ //
+ // If the call terminates with status UNIMPLEMENTED, then clients
+ // should assume this method is not supported and should not retry the
+ // call. If the call terminates with any other status (including OK),
+ // clients should retry the call with appropriate exponential backoff.
+ rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
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/control.proto b/src/proto/grpc/testing/control.proto
index 57592662c4..564d8234b7 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -25,6 +25,7 @@ enum ClientType {
SYNC_CLIENT = 0;
ASYNC_CLIENT = 1;
OTHER_CLIENT = 2; // used for some language-specific variants
+ CALLBACK_CLIENT = 3;
}
enum ServerType {
@@ -32,6 +33,7 @@ enum ServerType {
ASYNC_SERVER = 1;
ASYNC_GENERIC_SERVER = 2;
OTHER_SERVER = 3; // used for some language-specific variants
+ CALLBACK_SERVER = 4;
}
enum RpcType {
@@ -111,6 +113,10 @@ message ClientConfig {
// Use coalescing API when possible.
bool use_coalesce_api = 19;
+
+ // If 0, disabled. Else, specifies the period between gathering latency
+ // medians in milliseconds.
+ int32 median_latency_collection_interval_millis = 20;
}
message ClientStatus { ClientStats stats = 1; }
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..b805f4277b 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -39,36 +39,6 @@ PROTO_STEM = os.path.join(GRPC_STEM, 'src', 'proto')
PROTO_GEN_STEM = os.path.join(GRPC_STEM, 'src', 'python', 'gens')
CYTHON_STEM = os.path.join(PYTHON_STEM, 'grpc', '_cython')
-CONF_PY_ADDENDUM = """
-extensions.append('sphinx.ext.napoleon')
-napoleon_google_docstring = True
-napoleon_numpy_docstring = True
-napoleon_include_special_with_doc = True
-
-html_theme = 'sphinx_rtd_theme'
-copyright = "2016, The gRPC Authors"
-"""
-
-API_GLOSSARY = """
-
-Glossary
-================
-
-.. glossary::
-
- metadatum
- A key-value pair included in the HTTP header. It is a
- 2-tuple where the first entry is the key and the
- second is the value, i.e. (key, value). The metadata key is an ASCII str,
- and must be a valid HTTP header name. The metadata value can be
- either a valid HTTP ASCII str, or bytes. If bytes are provided,
- the key must end with '-bin', i.e.
- ``('binary-metadata-bin', b'\\x00\\xFF')``
-
- metadata
- A sequence of metadatum.
-"""
-
class CommandError(Exception):
"""Simple exception class for GRPC custom commands."""
@@ -124,25 +94,14 @@ class SphinxDocumentation(setuptools.Command):
def run(self):
# We import here to ensure that setup.py has had a chance to install the
# relevant package eggs first.
- import sphinx
- import sphinx.apidoc
- metadata = self.distribution.metadata
- src_dir = os.path.join(PYTHON_STEM, 'grpc')
- sys.path.append(src_dir)
- sphinx.apidoc.main([
- '', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
- '-V', metadata.version, '-R', metadata.version, '-o',
- os.path.join('doc', 'src'), src_dir
- ])
- conf_filepath = os.path.join('doc', 'src', 'conf.py')
- with open(conf_filepath, 'a') as conf_file:
- conf_file.write(CONF_PY_ADDENDUM)
- glossary_filepath = os.path.join('doc', 'src', 'grpc.rst')
- with open(glossary_filepath, 'a') as glossary_filepath:
- glossary_filepath.write(API_GLOSSARY)
- sphinx.main(
- ['', os.path.join('doc', 'src'),
- os.path.join('doc', 'build')])
+ import sphinx.cmd.build
+ source_dir = os.path.join(GRPC_STEM, 'doc', 'python', 'sphinx')
+ target_dir = os.path.join(GRPC_STEM, 'doc', 'build')
+ exit_code = sphinx.cmd.build.build_main(
+ ['-b', 'html', '-W', '--keep-going', source_dir, target_dir])
+ if exit_code is not 0:
+ raise CommandError(
+ "Documentation generation has warnings or errors")
class BuildProjectMetadata(setuptools.Command):
@@ -253,6 +212,12 @@ class BuildExt(build_ext.build_ext):
LINK_OPTIONS = {}
def build_extensions(self):
+ # This special conditioning is here due to difference of compiler
+ # behavior in gcc and clang. The clang doesn't take --stdc++11
+ # flags but gcc does. Since the setuptools of Python only support
+ # all C or all C++ compilation, the mix of C and C++ will crash.
+ # *By default*, the macOS use clang and Linux use gcc, that's why
+ # the special condition here is checking platform.
if "darwin" in sys.platform:
config = os.environ.get('CONFIG', 'opt')
target_path = os.path.abspath(
@@ -274,8 +239,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/BUILD.bazel b/src/python/grpcio/grpc/BUILD.bazel
index 3f214bf3b0..2e6839ef2d 100644
--- a/src/python/grpcio/grpc/BUILD.bazel
+++ b/src/python/grpcio/grpc/BUILD.bazel
@@ -2,7 +2,7 @@ load("@grpc_python_dependencies//:requirements.bzl", "requirement")
package(default_visibility = ["//visibility:public"])
-py_binary(
+py_library(
name = "grpcio",
srcs = ["__init__.py"],
deps = [
@@ -22,7 +22,6 @@ py_binary(
data = [
"//:grpc",
],
- main = "__init__.py",
imports = ["../",],
)
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 863696d236..88c5b6d5be 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -15,12 +15,14 @@
import abc
import enum
+import logging
import sys
-
import six
from grpc._cython import cygrpc as _cygrpc
+logging.getLogger(__name__).addHandler(logging.NullHandler())
+
############################## Future Interface ###############################
@@ -48,11 +50,13 @@ class Future(six.with_metaclass(abc.ABCMeta)):
Returns:
bool:
Returns True if the computation was canceled.
+
Returns False under all other circumstances, for example:
+
1. computation has begun and could not be canceled.
2. computation has finished
3. computation is scheduled for execution and it is impossible
- to determine its state without blocking.
+ to determine its state without blocking.
"""
raise NotImplementedError()
@@ -66,7 +70,9 @@ class Future(six.with_metaclass(abc.ABCMeta)):
bool:
Returns True if the computation was cancelled before its result became
available.
- False under all other circumstances, for example:
+
+ Returns False under all other circumstances, for example:
+
1. computation was not cancelled.
2. computation's result is available.
"""
@@ -79,9 +85,9 @@ class Future(six.with_metaclass(abc.ABCMeta)):
This method does not block.
Returns:
- bool:
Returns True if the computation is scheduled for execution or
currently executing.
+
Returns False if the computation already executed or was cancelled.
"""
raise NotImplementedError()
@@ -210,7 +216,33 @@ class ChannelConnectivity(enum.Enum):
@enum.unique
class StatusCode(enum.Enum):
- """Mirrors grpc_status_code in the gRPC Core."""
+ """Mirrors grpc_status_code in the gRPC Core.
+
+ Attributes:
+ OK: Not an error; returned on success
+ CANCELLED: The operation was cancelled (typically by the caller).
+ UNKNOWN: Unknown error.
+ INVALID_ARGUMENT: Client specified an invalid argument.
+ DEADLINE_EXCEEDED: Deadline expired before operation could complete.
+ NOT_FOUND: Some requested entity (e.g., file or directory) was not found.
+ ALREADY_EXISTS: Some entity that we attempted to create (e.g., file or directory)
+ already exists.
+ PERMISSION_DENIED: The caller does not have permission to execute the specified
+ operation.
+ UNAUTHENTICATED: The request does not have valid authentication credentials for the
+ operation.
+ RESOURCE_EXHAUSTED: Some resource has been exhausted, perhaps a per-user quota, or
+ perhaps the entire file system is out of space.
+ FAILED_PRECONDITION: Operation was rejected because the system is not in a state
+ required for the operation's execution.
+ ABORTED: The operation was aborted, typically due to a concurrency issue
+ like sequencer check failures, transaction aborts, etc.
+ UNIMPLEMENTED: Operation is not implemented or not supported/enabled in this service.
+ INTERNAL: Internal errors. Means some invariants expected by underlying
+ system has been broken.
+ UNAVAILABLE: The service is currently unavailable.
+ DATA_LOSS: Unrecoverable data loss or corruption.
+ """
OK = (_cygrpc.StatusCode.ok, 'ok')
CANCELLED = (_cygrpc.StatusCode.cancelled, 'cancelled')
UNKNOWN = (_cygrpc.StatusCode.unknown, 'unknown')
@@ -357,6 +389,8 @@ class ClientCallDetails(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to
the service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional flag t
+ enable wait for ready mechanism.
"""
@@ -450,8 +484,7 @@ class StreamUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
actual RPC on the underlying Channel. It is the interceptor's
responsibility to call it if it decides to move the RPC forward.
The interceptor can use
- `response_future = continuation(client_call_details,
- request_iterator)`
+ `response_future = continuation(client_call_details, request_iterator)`
to continue with the RPC. `continuation` returns an object that is
both a Call for the RPC and a Future. In the event of RPC completion,
the return Call-Future's result value will be the response message
@@ -462,11 +495,11 @@ class StreamUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator: An iterator that yields request values for the RPC.
Returns:
- An object that is both a Call for the RPC and a Future.
- In the event of RPC completion, the return Call-Future's
- result value will be the response message of the RPC.
- Should the event terminate with non-OK status, the returned
- Call-Future's exception value will be an RpcError.
+ An object that is both a Call for the RPC and a Future.
+ In the event of RPC completion, the return Call-Future's
+ result value will be the response message of the RPC.
+ Should the event terminate with non-OK status, the returned
+ Call-Future's exception value will be an RpcError.
"""
raise NotImplementedError()
@@ -482,13 +515,13 @@ class StreamStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator):
"""Intercepts a stream-stream invocation.
+ Args:
continuation: A function that proceeds with the invocation by
executing the next interceptor in chain or invoking the
actual RPC on the underlying Channel. It is the interceptor's
responsibility to call it if it decides to move the RPC forward.
The interceptor can use
- `response_iterator = continuation(client_call_details,
- request_iterator)`
+ `response_iterator = continuation(client_call_details, request_iterator)`
to continue with the RPC. `continuation` returns an object that is
both a Call for the RPC and an iterator for response values.
Drawing response values from the returned Call-iterator may
@@ -499,10 +532,10 @@ class StreamStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
request_iterator: An iterator that yields request values for the RPC.
Returns:
- An object that is both a Call for the RPC and an iterator of
- response values. Drawing response values from the returned
- Call-iterator may raise RpcError indicating termination of
- the RPC with non-OK status.
+ An object that is both a Call for the RPC and an iterator of
+ response values. Drawing response values from the returned
+ Call-iterator may raise RpcError indicating termination of
+ the RPC with non-OK status.
"""
raise NotImplementedError()
@@ -609,7 +642,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-unary RPC from client-side."""
@abc.abstractmethod
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -619,6 +657,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC.
@@ -631,7 +671,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -641,6 +686,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC and a Call value for the RPC.
@@ -653,7 +700,12 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
- def future(self, request, timeout=None, metadata=None, credentials=None):
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -663,6 +715,8 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and a Future.
@@ -678,7 +732,12 @@ class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-stream RPC from client-side."""
@abc.abstractmethod
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
"""Invokes the underlying RPC.
Args:
@@ -688,6 +747,8 @@ class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: An optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and an iterator of
@@ -706,7 +767,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -717,6 +779,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC.
@@ -733,7 +797,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Synchronously invokes the underlying RPC on the client.
Args:
@@ -744,6 +809,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
The response value for the RPC and a Call object for the RPC.
@@ -760,7 +827,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Asynchronously invokes the underlying RPC on the client.
Args:
@@ -770,6 +838,8 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and a Future.
@@ -789,7 +859,8 @@ class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
"""Invokes the underlying RPC on the client.
Args:
@@ -799,6 +870,8 @@ class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: Optional :term:`metadata` to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
+ wait_for_ready: This is an EXPERIMENTAL argument. An optional
+ flag to enable wait for ready mechanism
Returns:
An object that is both a Call for the RPC and an iterator of
@@ -972,8 +1045,7 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
"""Gets one or more peer identity(s).
Equivalent to
- servicer_context.auth_context().get(
- servicer_context.peer_identity_key())
+ servicer_context.auth_context().get(servicer_context.peer_identity_key())
Returns:
An iterable of the identities, or None if the call is not
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index 6876601785..ab154d8512 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -466,10 +466,11 @@ def _end_unary_response_blocking(state, call, with_call, deadline):
raise _Rendezvous(state, None, None, deadline)
-def _stream_unary_invocation_operationses(metadata):
+def _stream_unary_invocation_operationses(metadata, initial_metadata_flags):
return (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
),
@@ -477,15 +478,19 @@ def _stream_unary_invocation_operationses(metadata):
)
-def _stream_unary_invocation_operationses_and_tags(metadata):
+def _stream_unary_invocation_operationses_and_tags(metadata,
+ initial_metadata_flags):
return tuple((
operations,
None,
- ) for operations in _stream_unary_invocation_operationses(metadata))
+ )
+ for operations in _stream_unary_invocation_operationses(
+ metadata, initial_metadata_flags))
class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -494,15 +499,18 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def _prepare(self, request, timeout, metadata):
+ def _prepare(self, request, timeout, metadata, wait_for_ready):
deadline, serialized_request, rendezvous = _start_unary_request(
request, timeout, self._request_serializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
if serialized_request is None:
return None, None, None, rendezvous
else:
state = _RPCState(_UNARY_UNARY_INITIAL_DUE, None, None, None, None)
operations = (
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.SendMessageOperation(serialized_request, _EMPTY_FLAGS),
cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
@@ -511,9 +519,10 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
)
return state, operations, deadline, None
- def _blocking(self, request, timeout, metadata, credentials):
+ def _blocking(self, request, timeout, metadata, credentials,
+ wait_for_ready):
state, operations, deadline, rendezvous = self._prepare(
- request, timeout, metadata)
+ request, timeout, metadata, wait_for_ready)
if state is None:
raise rendezvous
else:
@@ -527,17 +536,34 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
_handle_event(event, state, self._response_deserializer)
return state, call,
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
- state, call, = self._blocking(request, timeout, metadata, credentials)
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ state, call, = self._blocking(request, timeout, metadata, credentials,
+ wait_for_ready)
return _end_unary_response_blocking(state, call, False, None)
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
- state, call, = self._blocking(request, timeout, metadata, credentials)
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ state, call, = self._blocking(request, timeout, metadata, credentials,
+ wait_for_ready)
return _end_unary_response_blocking(state, call, True, None)
- def future(self, request, timeout=None, metadata=None, credentials=None):
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
state, operations, deadline, rendezvous = self._prepare(
- request, timeout, metadata)
+ request, timeout, metadata, wait_for_ready)
if state is None:
raise rendezvous
else:
@@ -552,6 +578,7 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -560,16 +587,24 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
deadline, serialized_request, rendezvous = _start_unary_request(
request, timeout, self._request_serializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
if serialized_request is None:
raise rendezvous
else:
state = _RPCState(_UNARY_STREAM_INITIAL_DUE, None, None, None, None)
operationses = (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.SendMessageOperation(serialized_request,
_EMPTY_FLAGS),
cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
@@ -588,6 +623,7 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -596,13 +632,17 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def _blocking(self, request_iterator, timeout, metadata, credentials):
+ def _blocking(self, request_iterator, timeout, metadata, credentials,
+ wait_for_ready):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
call = self._channel.segregated_call(
0, self._method, None, deadline, metadata, None
if credentials is None else credentials._credentials,
- _stream_unary_invocation_operationses_and_tags(metadata))
+ _stream_unary_invocation_operationses_and_tags(
+ metadata, initial_metadata_flags))
_consume_request_iterator(request_iterator, state, call,
self._request_serializer, None)
while True:
@@ -618,32 +658,38 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
state, call, = self._blocking(request_iterator, timeout, metadata,
- credentials)
+ credentials, wait_for_ready)
return _end_unary_response_blocking(state, call, False, None)
def with_call(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
state, call, = self._blocking(request_iterator, timeout, metadata,
- credentials)
+ credentials, wait_for_ready)
return _end_unary_response_blocking(state, call, True, None)
def future(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
event_handler = _event_handler(state, self._response_deserializer)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
call = self._managed_call(
0, self._method, None, deadline, metadata, None
if credentials is None else credentials._credentials,
- _stream_unary_invocation_operationses(metadata), event_handler)
+ _stream_unary_invocation_operationses(
+ metadata, initial_metadata_flags), event_handler)
_consume_request_iterator(request_iterator, state, call,
self._request_serializer, event_handler)
return _Rendezvous(state, call, self._response_deserializer, deadline)
@@ -651,6 +697,7 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
+ # pylint: disable=too-many-arguments
def __init__(self, channel, managed_call, method, request_serializer,
response_deserializer):
self._channel = channel
@@ -663,12 +710,16 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
deadline = _deadline(timeout)
state = _RPCState(_STREAM_STREAM_INITIAL_DUE, None, None, None, None)
+ initial_metadata_flags = _InitialMetadataFlags().with_wait_for_ready(
+ wait_for_ready)
operationses = (
(
- cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+ cygrpc.SendInitialMetadataOperation(metadata,
+ initial_metadata_flags),
cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
),
(cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),),
@@ -683,6 +734,24 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
return _Rendezvous(state, call, self._response_deserializer, deadline)
+class _InitialMetadataFlags(int):
+ """Stores immutable initial metadata flags"""
+
+ def __new__(cls, value=_EMPTY_FLAGS):
+ value &= cygrpc.InitialMetadataFlags.used_mask
+ return super(_InitialMetadataFlags, cls).__new__(cls, value)
+
+ def with_wait_for_ready(self, wait_for_ready):
+ if wait_for_ready is not None:
+ if wait_for_ready:
+ self = self.__class__(self | cygrpc.InitialMetadataFlags.wait_for_ready | \
+ cygrpc.InitialMetadataFlags.wait_for_ready_explicitly_set)
+ elif not wait_for_ready:
+ self = self.__class__(self & ~cygrpc.InitialMetadataFlags.wait_for_ready | \
+ cygrpc.InitialMetadataFlags.wait_for_ready_explicitly_set)
+ return self
+
+
class _ChannelCallState(object):
def __init__(self, channel):
@@ -979,5 +1048,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)
- _moot(self._connectivity_state)
+ 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 _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 8358cbec5b..f69127e38e 100644
--- a/src/python/grpcio/grpc/_common.py
+++ b/src/python/grpcio/grpc/_common.py
@@ -65,18 +65,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/BUILD.bazel b/src/python/grpcio/grpc/_cython/BUILD.bazel
index 7124e83dee..cfd3a51d9b 100644
--- a/src/python/grpcio/grpc/_cython/BUILD.bazel
+++ b/src/python/grpcio/grpc/_cython/BUILD.bazel
@@ -8,6 +8,7 @@ pyx_library(
"__init__.py",
"cygrpc.pxd",
"cygrpc.pyx",
+ "_cygrpc/_hooks.pyx.pxi",
"_cygrpc/grpc_string.pyx.pxi",
"_cygrpc/arguments.pyx.pxi",
"_cygrpc/call.pyx.pxi",
@@ -15,6 +16,7 @@ pyx_library(
"_cygrpc/credentials.pyx.pxi",
"_cygrpc/completion_queue.pyx.pxi",
"_cygrpc/event.pyx.pxi",
+ "_cygrpc/fork_posix.pyx.pxi",
"_cygrpc/metadata.pyx.pxi",
"_cygrpc/operation.pyx.pxi",
"_cygrpc/records.pyx.pxi",
@@ -24,12 +26,14 @@ pyx_library(
"_cygrpc/time.pyx.pxi",
"_cygrpc/grpc_gevent.pyx.pxi",
"_cygrpc/grpc.pxi",
+ "_cygrpc/_hooks.pxd.pxi",
"_cygrpc/arguments.pxd.pxi",
"_cygrpc/call.pxd.pxi",
"_cygrpc/channel.pxd.pxi",
"_cygrpc/credentials.pxd.pxi",
"_cygrpc/completion_queue.pxd.pxi",
"_cygrpc/event.pxd.pxi",
+ "_cygrpc/fork_posix.pxd.pxi",
"_cygrpc/metadata.pxd.pxi",
"_cygrpc/operation.pxd.pxi",
"_cygrpc/records.pxd.pxi",
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi
index 6cb1bc0c05..e0e068e452 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pxd.pxi
@@ -32,7 +32,7 @@ cdef class _ArgumentProcessor:
cdef grpc_arg c_argument
- cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references)
+ cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references) except *
cdef class _ArgumentsProcessor:
@@ -42,5 +42,5 @@ cdef class _ArgumentsProcessor:
cdef readonly list _references
cdef grpc_channel_args _c_arguments
- cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable)
+ cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable) except *
cdef un_c(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi
index 2239e26b32..b7a4277ff6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/arguments.pyx.pxi
@@ -52,7 +52,7 @@ cdef grpc_arg _unwrap_grpc_arg(tuple wrapped_arg):
cdef class _ArgumentProcessor:
- cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references):
+ cdef void c(self, argument, grpc_arg_pointer_vtable *vtable, references) except *:
key, value = argument
cdef bytes encoded_key = _encode(key)
if encoded_key is not key:
@@ -89,7 +89,7 @@ cdef class _ArgumentsProcessor:
self._argument_processors = []
self._references = []
- cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable):
+ cdef grpc_channel_args *c(self, grpc_arg_pointer_vtable *vtable) except *:
self._c_arguments.arguments_length = len(self._arguments)
if self._c_arguments.arguments_length == 0:
return NULL
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 38fd9e78b2..63048e8da0 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -144,8 +144,14 @@ cdef class SSLChannelCredentials(ChannelCredentials):
return grpc_ssl_credentials_create(
c_pem_root_certificates, NULL, NULL, NULL)
else:
- c_pem_key_certificate_pair.private_key = self._private_key
- c_pem_key_certificate_pair.certificate_chain = self._certificate_chain
+ if self._private_key:
+ c_pem_key_certificate_pair.private_key = self._private_key
+ else:
+ c_pem_key_certificate_pair.private_key = NULL
+ if self._certificate_chain:
+ c_pem_key_certificate_pair.certificate_chain = self._certificate_chain
+ else:
+ c_pem_key_certificate_pair.certificate_chain = NULL
return grpc_ssl_credentials_create(
c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 4781219319..23428f0b0c 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -140,6 +140,10 @@ cdef extern from "grpc/grpc.h":
const int GRPC_WRITE_NO_COMPRESS
const int GRPC_WRITE_USED_MASK
+ const int GRPC_INITIAL_METADATA_WAIT_FOR_READY
+ const int GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+ const int GRPC_INITIAL_METADATA_USED_MASK
+
const int GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
ctypedef struct grpc_completion_queue:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
index c39fef08fa..53f0c7f0bb 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/metadata.pyx.pxi
@@ -15,6 +15,12 @@
import collections
+class InitialMetadataFlags:
+ used_mask = GRPC_INITIAL_METADATA_USED_MASK
+ wait_for_ready = GRPC_INITIAL_METADATA_WAIT_FOR_READY
+ wait_for_ready_explicitly_set = GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+
+
_Metadatum = collections.namedtuple('_Metadatum', ('key', 'value',))
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.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/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index c33911ebc1..42b3a1ad49 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
-__version__ = """1.15.0.dev0"""
+__version__ = """1.17.0.dev0"""
diff --git a/src/python/grpcio/grpc/_interceptor.py b/src/python/grpcio/grpc/_interceptor.py
index 1d2d374ad1..4345114026 100644
--- a/src/python/grpcio/grpc/_interceptor.py
+++ b/src/python/grpcio/grpc/_interceptor.py
@@ -46,7 +46,7 @@ def service_pipeline(interceptors):
class _ClientCallDetails(
collections.namedtuple(
'_ClientCallDetails',
- ('method', 'timeout', 'metadata', 'credentials')),
+ ('method', 'timeout', 'metadata', 'credentials', 'wait_for_ready')),
grpc.ClientCallDetails):
pass
@@ -72,7 +72,12 @@ def _unwrap_client_call_details(call_details, default_details):
except AttributeError:
credentials = default_details.credentials
- return method, timeout, metadata, credentials
+ try:
+ wait_for_ready = call_details.wait_for_ready
+ except AttributeError:
+ wait_for_ready = default_details.wait_for_ready
+
+ return method, timeout, metadata, credentials, wait_for_ready
class _FailureOutcome(grpc.RpcError, grpc.Future, grpc.Call):
@@ -193,28 +198,39 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
self._method = method
self._interceptor = interceptor
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
response, ignored_call = self._with_call(
request,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
return response
- def _with_call(self, request, timeout=None, metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def _with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
try:
response, call = self._thunk(new_method).with_call(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
return _UnaryOutcome(response, call)
except grpc.RpcError:
raise
@@ -225,25 +241,37 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
continuation, client_call_details, request)
return call.result(), call
- def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ def with_call(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
return self._with_call(
request,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
- def future(self, request, timeout=None, metadata=None, credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def future(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method).future(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_unary_unary(
@@ -259,18 +287,24 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
self._method = method
self._interceptor = interceptor
- def __call__(self, request, timeout=None, metadata=None, credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ def __call__(self,
+ request,
+ timeout=None,
+ metadata=None,
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method)(
request,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_unary_stream(
@@ -290,31 +324,35 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
response, ignored_call = self._with_call(
request_iterator,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
return response
def _with_call(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
try:
response, call = self._thunk(new_method).with_call(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
return _UnaryOutcome(response, call)
except grpc.RpcError:
raise
@@ -329,29 +367,33 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
+ credentials=None,
+ wait_for_ready=None):
return self._with_call(
request_iterator,
timeout=timeout,
metadata=metadata,
- credentials=credentials)
+ credentials=credentials,
+ wait_for_ready=wait_for_ready)
def future(self,
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method).future(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_stream_unary(
@@ -371,18 +413,20 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
request_iterator,
timeout=None,
metadata=None,
- credentials=None):
- client_call_details = _ClientCallDetails(self._method, timeout,
- metadata, credentials)
+ credentials=None,
+ wait_for_ready=None):
+ client_call_details = _ClientCallDetails(
+ self._method, timeout, metadata, credentials, wait_for_ready)
def continuation(new_details, request_iterator):
- new_method, new_timeout, new_metadata, new_credentials = (
+ new_method, new_timeout, new_metadata, new_credentials, new_wait_for_ready = (
_unwrap_client_call_details(new_details, client_call_details))
return self._thunk(new_method)(
request_iterator,
timeout=new_timeout,
metadata=new_metadata,
- credentials=new_credentials)
+ credentials=new_credentials,
+ wait_for_ready=new_wait_for_ready)
try:
return self._interceptor.intercept_stream_stream(
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 38f6b4d24c..2c929102cc 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -92,7 +92,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -209,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',
@@ -256,11 +256,14 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
- 'src/core/lib/security/security_connector/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/alts/alts_security_connector.cc',
+ 'src/core/lib/security/security_connector/fake/fake_security_connector.cc',
'src/core/lib/security/security_connector/load_system_roots_fallback.cc',
'src/core/lib/security/security_connector/load_system_roots_linux.cc',
- 'src/core/lib/security/security_connector/local_security_connector.cc',
+ 'src/core/lib/security/security_connector/local/local_security_connector.cc',
'src/core/lib/security/security_connector/security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl/ssl_security_connector.cc',
+ 'src/core/lib/security/security_connector/ssl_utils.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
@@ -279,7 +282,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',
@@ -315,6 +318,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/connector.cc',
+ 'src/core/ext/filters/client_channel/health/health_check_client.cc',
'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
'src/core/ext/filters/client_channel/http_proxy.cc',
'src/core/ext/filters/client_channel/lb_policy.cc',
@@ -329,9 +333,8 @@ 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/tsi/alts_transport_security.cc',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
'src/core/tsi/fake_transport_security.cc',
'src/core/tsi/local_transport_security.cc',
'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
@@ -350,10 +353,14 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 9337800a33..71113e68d9 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel
new file mode 100644
index 0000000000..ce3121fa90
--- /dev/null
+++ b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel
@@ -0,0 +1,33 @@
+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_health_proto",
+ srcs = [
+ "//src/proto/grpc/health/v1:health_proto_file",
+ ],
+ outs = ["health.proto",],
+ cmd = "cp $< $@",
+)
+
+py_proto_library(
+ name = "py_health_proto",
+ protos = [":mv_health_proto",],
+ with_grpc = True,
+ deps = [
+ requirement('protobuf'),
+ ],
+)
+
+py_library(
+ name = "grpc_health",
+ srcs = ["health.py",],
+ deps = [
+ ":py_health_proto",
+ "//src/python/grpcio/grpc:grpcio",
+ ],
+ imports=["../../",],
+)
+
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 3b84f7a4c5..a30aac2e0b 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
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_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 7b0e48ea23..aafea9fe76 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
diff --git a/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py b/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py
index 191b1c1726..d7205ca579 100644
--- a/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py
+++ b/src/python/grpcio_testing/grpc_testing/_channel/_invocation.py
@@ -18,6 +18,7 @@ import threading
import grpc
_NOT_YET_OBSERVED = object()
+logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio_testing/grpc_testing/_server/_rpc.py b/src/python/grpcio_testing/grpc_testing/_server/_rpc.py
index b856da100f..736b714dc6 100644
--- a/src/python/grpcio_testing/grpc_testing/_server/_rpc.py
+++ b/src/python/grpcio_testing/grpc_testing/_server/_rpc.py
@@ -18,6 +18,7 @@ import threading
import grpc
from grpc_testing import _common
+logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio_testing/grpc_testing/_time.py b/src/python/grpcio_testing/grpc_testing/_time.py
index 75e6db3458..9692c34e6f 100644
--- a/src/python/grpcio_testing/grpc_testing/_time.py
+++ b/src/python/grpcio_testing/grpc_testing/_time.py
@@ -21,6 +21,7 @@ import time as _time
import grpc
import grpc_testing
+logging.basicConfig()
_LOGGER = logging.getLogger(__name__)
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index df9953fa25..876acd3142 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
diff --git a/src/python/grpcio_tests/commands.py b/src/python/grpcio_tests/commands.py
index 0dfbf3180b..d163f6fb68 100644
--- a/src/python/grpcio_tests/commands.py
+++ b/src/python/grpcio_tests/commands.py
@@ -116,6 +116,8 @@ class TestGevent(setuptools.Command):
# eventually succeed, but need to dig into performance issues.
'unit._cython._no_messages_server_completion_queue_per_call_test.Test.test_rpcs',
'unit._cython._no_messages_single_server_completion_queue_test.Test.test_rpcs',
+ # TODO(https://github.com/grpc/grpc/issues/16890) enable this test
+ 'unit._cython._channel_test.ChannelTest.test_multiple_channels_lonely_connectivity',
# I have no idea why this doesn't work in gevent, but it shouldn't even be
# using the c-core
'testing._client_test.ClientTest.test_infinite_request_stream_real_time',
@@ -128,7 +130,9 @@ class TestGevent(setuptools.Command):
# Beta API is unsupported for gevent
'protoc_plugin.beta_python_plugin_test',
'unit.beta._beta_features_test',
- )
+ # TODO(https://github.com/grpc/grpc/issues/15411) unpin gevent version
+ # This test will stuck while running higher version of gevent
+ 'unit._auth_context_test.AuthContextTest.testSessionResumption')
description = 'run tests with gevent. Assumes grpc/gevent are installed'
user_options = []
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index b2cf129e4f..cc9b41587c 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
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/health_check/BUILD.bazel b/src/python/grpcio_tests/tests/health_check/BUILD.bazel
new file mode 100644
index 0000000000..19e1e1b2e1
--- /dev/null
+++ b/src/python/grpcio_tests/tests/health_check/BUILD.bazel
@@ -0,0 +1,15 @@
+package(default_visibility = ["//visibility:public"])
+
+py_test(
+ name = "health_servicer_test",
+ srcs = ["_health_servicer_test.py"],
+ main = "_health_servicer_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_health_checking/grpc_health/v1:grpc_health",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ ],
+ imports = ["../../",],
+)
+
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..aebdbf67eb
--- /dev/null
+++ b/src/python/grpcio_tests/tests/interop/BUILD.bazel
@@ -0,0 +1,101 @@
+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'),
+ requirement('urllib3'),
+ requirement('chardet'),
+ requirement('certifi'),
+ requirement('idna'),
+ ],
+ 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 fd28d498a1..72f88a1c98 100644
--- a/src/python/grpcio_tests/tests/interop/server.py
+++ b/src/python/grpcio_tests/tests/interop/server.py
@@ -26,6 +26,7 @@ from tests.interop import resources
from tests.unit import test_common
_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/testing/BUILD.bazel b/src/python/grpcio_tests/tests/testing/BUILD.bazel
new file mode 100644
index 0000000000..9bdd616c56
--- /dev/null
+++ b/src/python/grpcio_tests/tests/testing/BUILD.bazel
@@ -0,0 +1,30 @@
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+ name = "testing",
+ srcs = ["__init__.py",],
+ deps = [
+ # ":_application_common",
+ ":_server_application",
+ ],
+)
+
+# TODO(ghostwriternr): To be added later.
+# py_library(
+# name = "_application_common",
+# srcs = ["_application_common.py",],
+# deps = [
+# "//src/python/grpcio_tests/tests/testing/proto:requests",
+# "//src/python/grpcio_tests/tests/testing/proto:services",
+# ],
+# imports = ["../../",],
+# )
+
+py_library(
+ name = "_server_application",
+ srcs = ["_server_application.py",],
+ imports = ["../../",],
+)
+
+
+
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 76d5d22d57..a3006d9afc 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -42,11 +42,14 @@
"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_flags_test.MetadataFlagsTest",
"unit._metadata_test.MetadataTest",
"unit._reconnect_test.ReconnectTest",
"unit._resource_exhausted_test.ResourceExhaustedTest",
diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel
new file mode 100644
index 0000000000..de33b81e32
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel
@@ -0,0 +1,84 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+package(default_visibility = ["//visibility:public"])
+
+GRPCIO_TESTS_UNIT = [
+ "_api_test.py",
+ "_auth_context_test.py",
+ "_auth_test.py",
+ "_channel_args_test.py",
+ "_channel_close_test.py",
+ "_channel_connectivity_test.py",
+ "_channel_ready_future_test.py",
+ "_compression_test.py",
+ "_credentials_test.py",
+ "_empty_message_test.py",
+ "_exit_test.py",
+ "_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
+ # "_reconnect_test.py",
+ "_resource_exhausted_test.py",
+ "_rpc_test.py",
+ # TODO(ghostwriternr): To be added later.
+ # "_server_ssl_cert_config_test.py",
+ "_server_test.py",
+ "_session_cache_test.py",
+]
+
+py_library(
+ name = "resources",
+ srcs = ["resources.py"],
+ data=[
+ "//src/python/grpcio_tests/tests/unit/credentials",
+ ],
+)
+
+py_library(
+ name = "test_common",
+ srcs = ["test_common.py"],
+)
+
+py_library(
+ name = "_exit_scenarios",
+ srcs = ["_exit_scenarios.py"],
+)
+
+py_library(
+ name = "_thread_pool",
+ srcs = ["_thread_pool.py"],
+)
+
+py_library(
+ name = "_from_grpc_import_star",
+ srcs = ["_from_grpc_import_star.py"],
+)
+
+[
+ py_test(
+ name=test_file_name[:-3],
+ size="small",
+ srcs=[test_file_name],
+ main=test_file_name,
+ deps=[
+ "//src/python/grpcio/grpc:grpcio",
+ ":resources",
+ ":test_common",
+ ":_exit_scenarios",
+ ":_thread_pool",
+ ":_from_grpc_import_star",
+ "//src/python/grpcio_tests/tests/unit/framework/common",
+ "//src/python/grpcio_tests/tests/testing",
+ requirement('six'),
+ ],
+ imports=["../../",],
+ data=[
+ "//src/python/grpcio_tests/tests/unit/credentials",
+ ],
+ ) for test_file_name in GRPCIO_TESTS_UNIT
+]
+
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 869c2f4d2f..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
@@ -33,6 +34,14 @@ TEST_CHANNEL_ARGS = (
('arg6', TestPointerWrapper()),
)
+INVALID_TEST_CHANNEL_ARGS = [
+ {
+ 'foo': 'bar'
+ },
+ (('key',),),
+ 'str',
+]
+
class ChannelArgsTest(unittest.TestCase):
@@ -44,6 +53,15 @@ class ChannelArgsTest(unittest.TestCase):
futures.ThreadPoolExecutor(max_workers=1),
options=TEST_CHANNEL_ARGS)
+ def test_invalid_client_args(self):
+ for invalid_arg in INVALID_TEST_CHANNEL_ARGS:
+ self.assertRaises(
+ ValueError,
+ grpc.insecure_channel,
+ 'localhost:8080',
+ options=invalid_arg)
+
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/_cython/BUILD.bazel b/src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel
new file mode 100644
index 0000000000..458a6b1fb8
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_cython/BUILD.bazel
@@ -0,0 +1,46 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+package(default_visibility = ["//visibility:public"])
+
+GRPCIO_TESTS_UNIT_CYTHON = [
+ "_cancel_many_calls_test.py",
+ "_channel_test.py",
+ "_no_messages_server_completion_queue_per_call_test.py",
+ "_no_messages_single_server_completion_queue_test.py",
+ "_read_some_but_not_all_responses_test.py",
+ "_server_test.py",
+ "cygrpc_test.py",
+]
+
+py_library(
+ name = "common",
+ srcs = ["_common.py"],
+)
+
+py_library(
+ name = "test_utilities",
+ srcs = ["test_utilities.py"],
+)
+
+[
+ py_test(
+ name=test_file_name[:-3],
+ size="small",
+ srcs=[test_file_name],
+ main=test_file_name,
+ deps=[
+ "//src/python/grpcio/grpc:grpcio",
+ ":common",
+ ":test_utilities",
+ "//src/python/grpcio_tests/tests/unit/framework/common",
+ "//src/python/grpcio_tests/tests/unit:test_common",
+ "//src/python/grpcio_tests/tests/unit:resources",
+ ],
+ imports=["../../../",],
+ data=[
+ "//src/python/grpcio_tests/tests/unit/credentials",
+ ],
+ ) for test_file_name in GRPCIO_TESTS_UNIT_CYTHON
+]
+
+
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..631b9de9db
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_logging_test.py
@@ -0,0 +1,80 @@
+# 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)
+
+ @isolated_logging
+ def test_grpc_logger(self):
+ self.assertIn("grpc", logging.Logger.manager.loggerDict)
+ root_logger = logging.getLogger("grpc")
+ self.assertEqual(1, len(root_logger.handlers))
+ self.assertIsInstance(root_logger.handlers[0], logging.NullHandler)
+
+
+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_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py
new file mode 100644
index 0000000000..2d352e99d4
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py
@@ -0,0 +1,251 @@
+# 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 metadata flags feature by testing wait-for-ready semantics"""
+
+import time
+import weakref
+import unittest
+import threading
+import socket
+from six.moves import queue
+
+import grpc
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+_REQUEST = b'\x00\x00\x00'
+_RESPONSE = b'\x00\x00\x00'
+
+
+def handle_unary_unary(test, request, servicer_context):
+ return _RESPONSE
+
+
+def handle_unary_stream(test, request, servicer_context):
+ for _ in range(test_constants.STREAM_LENGTH):
+ yield _RESPONSE
+
+
+def handle_stream_unary(test, request_iterator, servicer_context):
+ for _ in request_iterator:
+ pass
+ return _RESPONSE
+
+
+def handle_stream_stream(test, request_iterator, servicer_context):
+ for _ in request_iterator:
+ yield _RESPONSE
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+ def __init__(self, test, request_streaming, response_streaming):
+ self.request_streaming = request_streaming
+ self.response_streaming = response_streaming
+ self.request_deserializer = None
+ self.response_serializer = None
+ self.unary_unary = None
+ self.unary_stream = None
+ self.stream_unary = None
+ self.stream_stream = None
+ if self.request_streaming and self.response_streaming:
+ self.stream_stream = lambda req, ctx: handle_stream_stream(test, req, ctx)
+ elif self.request_streaming:
+ self.stream_unary = lambda req, ctx: handle_stream_unary(test, req, ctx)
+ elif self.response_streaming:
+ self.unary_stream = lambda req, ctx: handle_unary_stream(test, req, ctx)
+ else:
+ self.unary_unary = lambda req, ctx: handle_unary_unary(test, req, ctx)
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def __init__(self, test):
+ self._test = test
+
+ def service(self, handler_call_details):
+ if handler_call_details.method == _UNARY_UNARY:
+ return _MethodHandler(self._test, False, False)
+ elif handler_call_details.method == _UNARY_STREAM:
+ return _MethodHandler(self._test, False, True)
+ elif handler_call_details.method == _STREAM_UNARY:
+ return _MethodHandler(self._test, True, False)
+ elif handler_call_details.method == _STREAM_STREAM:
+ return _MethodHandler(self._test, True, True)
+ else:
+ return None
+
+
+def get_free_loopback_tcp_port():
+ tcp = socket.socket(socket.AF_INET6)
+ tcp.bind(('', 0))
+ address_tuple = tcp.getsockname()
+ return tcp, "[::1]:%s" % (address_tuple[1])
+
+
+def create_dummy_channel():
+ """Creating dummy channels is a workaround for retries"""
+ _, addr = get_free_loopback_tcp_port()
+ return grpc.insecure_channel(addr)
+
+
+def perform_unary_unary_call(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).__call__(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_unary_unary_with_call(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).with_call(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_unary_unary_future(channel, wait_for_ready=None):
+ channel.unary_unary(_UNARY_UNARY).future(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready).result(
+ timeout=test_constants.LONG_TIMEOUT)
+
+
+def perform_unary_stream_call(channel, wait_for_ready=None):
+ response_iterator = channel.unary_stream(_UNARY_STREAM).__call__(
+ _REQUEST,
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+ for _ in response_iterator:
+ pass
+
+
+def perform_stream_unary_call(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).__call__(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_stream_unary_with_call(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).with_call(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+
+
+def perform_stream_unary_future(channel, wait_for_ready=None):
+ channel.stream_unary(_STREAM_UNARY).future(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready).result(
+ timeout=test_constants.LONG_TIMEOUT)
+
+
+def perform_stream_stream_call(channel, wait_for_ready=None):
+ response_iterator = channel.stream_stream(_STREAM_STREAM).__call__(
+ iter([_REQUEST] * test_constants.STREAM_LENGTH),
+ timeout=test_constants.LONG_TIMEOUT,
+ wait_for_ready=wait_for_ready)
+ for _ in response_iterator:
+ pass
+
+
+_ALL_CALL_CASES = [
+ perform_unary_unary_call, perform_unary_unary_with_call,
+ perform_unary_unary_future, perform_unary_stream_call,
+ perform_stream_unary_call, perform_stream_unary_with_call,
+ perform_stream_unary_future, perform_stream_stream_call
+]
+
+
+class MetadataFlagsTest(unittest.TestCase):
+
+ def check_connection_does_failfast(self, fn, channel, wait_for_ready=None):
+ try:
+ fn(channel, wait_for_ready)
+ self.fail("The Call should fail")
+ except BaseException as e: # pylint: disable=broad-except
+ self.assertIn('StatusCode.UNAVAILABLE', str(e))
+
+ def test_call_wait_for_ready_default(self):
+ for perform_call in _ALL_CALL_CASES:
+ self.check_connection_does_failfast(perform_call,
+ create_dummy_channel())
+
+ def test_call_wait_for_ready_disabled(self):
+ for perform_call in _ALL_CALL_CASES:
+ self.check_connection_does_failfast(
+ perform_call, create_dummy_channel(), wait_for_ready=False)
+
+ def test_call_wait_for_ready_enabled(self):
+ # To test the wait mechanism, Python thread is required to make
+ # client set up first without handling them case by case.
+ # Also, Python thread don't pass the unhandled exceptions to
+ # main thread. So, it need another method to store the
+ # exceptions and raise them again in main thread.
+ unhandled_exceptions = queue.Queue()
+ tcp, addr = get_free_loopback_tcp_port()
+ wg = test_common.WaitGroup(len(_ALL_CALL_CASES))
+
+ def wait_for_transient_failure(channel_connectivity):
+ if channel_connectivity == grpc.ChannelConnectivity.TRANSIENT_FAILURE:
+ wg.done()
+
+ def test_call(perform_call):
+ try:
+ channel = grpc.insecure_channel(addr)
+ channel.subscribe(wait_for_transient_failure)
+ perform_call(channel, wait_for_ready=True)
+ except BaseException as e: # pylint: disable=broad-except
+ # If the call failed, the thread would be destroyed. The channel
+ # object can be collected before calling the callback, which
+ # will result in a deadlock.
+ wg.done()
+ unhandled_exceptions.put(e, True)
+
+ test_threads = []
+ for perform_call in _ALL_CALL_CASES:
+ test_thread = threading.Thread(
+ target=test_call, args=(perform_call,))
+ test_thread.exception = None
+ test_thread.start()
+ test_threads.append(test_thread)
+
+ # Start the server after the connections are waiting
+ wg.wait()
+ tcp.close()
+ server = test_common.test_server()
+ server.add_generic_rpc_handlers((_GenericHandler(weakref.proxy(self)),))
+ server.add_insecure_port(addr)
+ server.start()
+
+ for test_thread in test_threads:
+ test_thread.join()
+
+ # Stop the server to make test end properly
+ server.stop(0)
+
+ if not unhandled_exceptions.empty():
+ raise unhandled_exceptions.get(True)
+
+
+if __name__ == '__main__':
+ 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/beta/BUILD.bazel b/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel
new file mode 100644
index 0000000000..d3e0fe20eb
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/beta/BUILD.bazel
@@ -0,0 +1,75 @@
+load("@grpc_python_dependencies//:requirements.bzl", "requirement")
+
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+ name = "test_utilities",
+ srcs = ["test_utilities.py"],
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ ],
+)
+
+py_test(
+ name = "_beta_features_test",
+ srcs = ["_beta_features_test.py"],
+ main = "_beta_features_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_tests/tests/unit:resources",
+ "//src/python/grpcio_tests/tests/unit/framework/common",
+ ":test_utilities",
+ ],
+ imports=["../../../",],
+)
+
+py_test(
+ name = "_connectivity_channel_test",
+ srcs = ["_connectivity_channel_test.py"],
+ main = "_connectivity_channel_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ ],
+)
+
+# TODO(ghostwriternr): To be added later.
+#py_test(
+# name = "_implementations_test",
+# srcs = ["_implementations_test.py"],
+# main = "_implementations_test.py",
+# size = "small",
+# deps = [
+# "//src/python/grpcio/grpc:grpcio",
+# "//src/python/grpcio_tests/tests/unit:resources",
+# requirement('oauth2client'),
+# ],
+# imports=["../../../",],
+#)
+
+py_test(
+ name = "_not_found_test",
+ srcs = ["_not_found_test.py"],
+ main = "_not_found_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_tests/tests/unit/framework/common",
+ ],
+ imports=["../../../",],
+)
+
+py_test(
+ name = "_utilities_test",
+ srcs = ["_utilities_test.py"],
+ main = "_utilities_test.py",
+ size = "small",
+ deps = [
+ "//src/python/grpcio/grpc:grpcio",
+ "//src/python/grpcio_tests/tests/unit/framework/common",
+ ],
+ imports=["../../../",],
+)
+
+
diff --git a/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel b/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel
new file mode 100644
index 0000000000..358216db58
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/BUILD.bazel
@@ -0,0 +1,10 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name="credentials",
+ srcs=glob([
+ "**",
+ ]),
+)
+
+
diff --git a/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel b/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel
new file mode 100644
index 0000000000..c206a04fad
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/framework/common/BUILD.bazel
@@ -0,0 +1,11 @@
+package(default_visibility = ["//visibility:public"])
+
+py_library(
+ name = "common",
+ srcs = [
+ "test_constants.py",
+ "test_control.py",
+ "test_coverage.py",
+ ],
+)
+
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/src/python/grpcio_tests/tests/unit/test_common.py b/src/python/grpcio_tests/tests/unit/test_common.py
index 61717ae135..bc3b24862d 100644
--- a/src/python/grpcio_tests/tests/unit/test_common.py
+++ b/src/python/grpcio_tests/tests/unit/test_common.py
@@ -14,6 +14,7 @@
"""Common code used throughout tests of gRPC."""
import collections
+import threading
from concurrent import futures
import grpc
@@ -107,3 +108,28 @@ def test_server(max_workers=10):
return grpc.server(
futures.ThreadPoolExecutor(max_workers=max_workers),
options=(('grpc.so_reuseport', 0),))
+
+
+class WaitGroup(object):
+
+ def __init__(self, n=0):
+ self.count = n
+ self.cv = threading.Condition()
+
+ def add(self, n):
+ self.cv.acquire()
+ self.count += n
+ self.cv.release()
+
+ def done(self):
+ self.cv.acquire()
+ self.count -= 1
+ if self.count == 0:
+ self.cv.notify_all()
+ self.cv.release()
+
+ def wait(self):
+ self.cv.acquire()
+ while self.count > 0:
+ self.cv.wait()
+ self.cv.release()
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index b6c0791469..fc641dae80 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -819,6 +819,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
unsigned write_flag = 0;
void* tag = (void*)&st;
+ grpc_ruby_fork_guard();
if (RTYPEDDATA_DATA(self) == NULL) {
rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
return Qnil;
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 3f0dc530cf..6d4b2293a2 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -217,6 +217,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE* argv, VALUE self) {
MEMZERO(&args, grpc_channel_args, 1);
grpc_ruby_once_init();
+ grpc_ruby_fork_guard();
rb_thread_call_without_gvl(
wait_until_channel_polling_thread_started_no_gil,
&stop_waiting_for_thread_start,
@@ -374,6 +375,7 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
watch_state_stack stack;
void* op_success = 0;
+ grpc_ruby_fork_guard();
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
if (wrapper->bg_wrapped == NULL) {
@@ -415,6 +417,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask,
grpc_slice* host_slice_ptr = NULL;
char* tmp_str = NULL;
+ grpc_ruby_fork_guard();
if (host != Qnil) {
host_slice =
grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host));
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index f065a857db..872aed0cfc 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -23,9 +23,13 @@
#include <math.h>
#include <ruby/vm.h>
+#include <stdbool.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <grpc/grpc.h>
+#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "rb_call.h"
#include "rb_call_credentials.h"
@@ -255,7 +259,26 @@ static void Init_grpc_time_consts() {
id_tv_nsec = rb_intern("tv_nsec");
}
-static void grpc_rb_shutdown(void) { grpc_shutdown(); }
+#if GPR_WINDOWS
+static void grpc_ruby_set_init_pid(void) {}
+static bool grpc_ruby_forked_after_init(void) { return false; }
+#else
+static pid_t grpc_init_pid;
+
+static void grpc_ruby_set_init_pid(void) {
+ GPR_ASSERT(grpc_init_pid == 0);
+ grpc_init_pid = getpid();
+}
+
+static bool grpc_ruby_forked_after_init(void) {
+ GPR_ASSERT(grpc_init_pid != 0);
+ return grpc_init_pid != getpid();
+}
+#endif
+
+static void grpc_rb_shutdown(void) {
+ if (!grpc_ruby_forked_after_init()) grpc_shutdown();
+}
/* Initialize the GRPC module structs */
@@ -276,10 +299,17 @@ VALUE sym_metadata = Qundef;
static gpr_once g_once_init = GPR_ONCE_INIT;
static void grpc_ruby_once_init_internal() {
+ grpc_ruby_set_init_pid();
grpc_init();
atexit(grpc_rb_shutdown);
}
+void grpc_ruby_fork_guard() {
+ if (grpc_ruby_forked_after_init()) {
+ rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking");
+ }
+}
+
static VALUE bg_thread_init_rb_mu = Qundef;
static int bg_thread_init_done = 0;
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index 577902319e..4118435ecf 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -69,4 +69,6 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval);
void grpc_ruby_once_init();
+void grpc_ruby_fork_guard();
+
#endif /* GRPC_RB_H_ */
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index f44f89dfa0..18245e9107 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -97,10 +97,14 @@ grpc_resource_quota_resize_type grpc_resource_quota_resize_import;
grpc_resource_quota_set_max_threads_type grpc_resource_quota_set_max_threads_import;
grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import;
grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import;
+grpc_channelz_get_servers_type grpc_channelz_get_servers_import;
+grpc_channelz_get_server_type grpc_channelz_get_server_import;
+grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import;
grpc_channelz_get_channel_type grpc_channelz_get_channel_import;
+grpc_channelz_get_subchannel_type grpc_channelz_get_subchannel_import;
+grpc_channelz_get_socket_type grpc_channelz_get_socket_import;
grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
-grpc_use_signal_type grpc_use_signal_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -351,10 +355,14 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_resource_quota_set_max_threads_import = (grpc_resource_quota_set_max_threads_type) GetProcAddress(library, "grpc_resource_quota_set_max_threads");
grpc_resource_quota_arg_vtable_import = (grpc_resource_quota_arg_vtable_type) GetProcAddress(library, "grpc_resource_quota_arg_vtable");
grpc_channelz_get_top_channels_import = (grpc_channelz_get_top_channels_type) GetProcAddress(library, "grpc_channelz_get_top_channels");
+ grpc_channelz_get_servers_import = (grpc_channelz_get_servers_type) GetProcAddress(library, "grpc_channelz_get_servers");
+ grpc_channelz_get_server_import = (grpc_channelz_get_server_type) GetProcAddress(library, "grpc_channelz_get_server");
+ grpc_channelz_get_server_sockets_import = (grpc_channelz_get_server_sockets_type) GetProcAddress(library, "grpc_channelz_get_server_sockets");
grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel");
+ grpc_channelz_get_subchannel_import = (grpc_channelz_get_subchannel_type) GetProcAddress(library, "grpc_channelz_get_subchannel");
+ grpc_channelz_get_socket_import = (grpc_channelz_get_socket_type) GetProcAddress(library, "grpc_channelz_get_socket");
grpc_insecure_channel_create_from_fd_import = (grpc_insecure_channel_create_from_fd_type) GetProcAddress(library, "grpc_insecure_channel_create_from_fd");
grpc_server_add_insecure_channel_from_fd_import = (grpc_server_add_insecure_channel_from_fd_type) GetProcAddress(library, "grpc_server_add_insecure_channel_from_fd");
- grpc_use_signal_import = (grpc_use_signal_type) GetProcAddress(library, "grpc_use_signal");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 99433f0e40..56d222c7ec 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -107,7 +107,7 @@ extern grpc_completion_queue_create_for_next_type grpc_completion_queue_create_f
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_pluck_type)(void* reserved);
extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
#define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import
-typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(void* shutdown_callback, void* reserved);
+typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(grpc_experimental_completion_queue_functor* shutdown_callback, void* reserved);
extern grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import;
#define grpc_completion_queue_create_for_callback grpc_completion_queue_create_for_callback_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attributes, void* reserved);
@@ -266,18 +266,30 @@ extern grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import
typedef char*(*grpc_channelz_get_top_channels_type)(intptr_t start_channel_id);
extern grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import;
#define grpc_channelz_get_top_channels grpc_channelz_get_top_channels_import
+typedef char*(*grpc_channelz_get_servers_type)(intptr_t start_server_id);
+extern grpc_channelz_get_servers_type grpc_channelz_get_servers_import;
+#define grpc_channelz_get_servers grpc_channelz_get_servers_import
+typedef char*(*grpc_channelz_get_server_type)(intptr_t server_id);
+extern grpc_channelz_get_server_type grpc_channelz_get_server_import;
+#define grpc_channelz_get_server grpc_channelz_get_server_import
+typedef char*(*grpc_channelz_get_server_sockets_type)(intptr_t server_id, intptr_t start_socket_id);
+extern grpc_channelz_get_server_sockets_type grpc_channelz_get_server_sockets_import;
+#define grpc_channelz_get_server_sockets grpc_channelz_get_server_sockets_import
typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id);
extern grpc_channelz_get_channel_type grpc_channelz_get_channel_import;
#define grpc_channelz_get_channel grpc_channelz_get_channel_import
+typedef char*(*grpc_channelz_get_subchannel_type)(intptr_t subchannel_id);
+extern grpc_channelz_get_subchannel_type grpc_channelz_get_subchannel_import;
+#define grpc_channelz_get_subchannel grpc_channelz_get_subchannel_import
+typedef char*(*grpc_channelz_get_socket_type)(intptr_t socket_id);
+extern grpc_channelz_get_socket_type grpc_channelz_get_socket_import;
+#define grpc_channelz_get_socket grpc_channelz_get_socket_import
typedef grpc_channel*(*grpc_insecure_channel_create_from_fd_type)(const char* target, int fd, const grpc_channel_args* args);
extern grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
#define grpc_insecure_channel_create_from_fd grpc_insecure_channel_create_from_fd_import
typedef void(*grpc_server_add_insecure_channel_from_fd_type)(grpc_server* server, void* reserved, int fd);
extern grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
#define grpc_server_add_insecure_channel_from_fd grpc_server_add_insecure_channel_from_fd_import
-typedef void(*grpc_use_signal_type)(int signum);
-extern grpc_use_signal_type grpc_use_signal_import;
-#define grpc_use_signal grpc_use_signal_import
typedef const grpc_auth_property*(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator* it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
@@ -401,10 +413,10 @@ extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials* creds, grpc_auth_metadata_processor processor);
extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
-typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)();
+typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)(void);
extern grpc_alts_credentials_client_options_create_type grpc_alts_credentials_client_options_create_import;
#define grpc_alts_credentials_client_options_create grpc_alts_credentials_client_options_create_import
-typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)();
+typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)(void);
extern grpc_alts_credentials_server_options_create_type grpc_alts_credentials_server_options_create_import;
#define grpc_alts_credentials_server_options_create grpc_alts_credentials_server_options_create_import
typedef void(*grpc_alts_credentials_client_options_add_target_service_account_type)(grpc_alts_credentials_options* options, const char* service_account);
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 88e6a0cfd5..2931f34409 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -243,6 +243,8 @@ static VALUE grpc_rb_server_request_call(VALUE self) {
static VALUE grpc_rb_server_start(VALUE self) {
grpc_rb_server* s = NULL;
TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
+
+ grpc_ruby_fork_guard();
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "destroyed!");
} else {
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 8f6aea30ad..0c15c2f3ba 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -68,7 +68,6 @@ module GRPC
codes[OUT_OF_RANGE] = OutOfRange
codes[UNIMPLEMENTED] = Unimplemented
codes[INTERNAL] = Internal
- codes[UNIMPLEMENTED] = Unimplemented
codes[UNAVAILABLE] = Unavailable
codes[DATA_LOSS] = DataLoss
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 5fd1805aab..efb0e4233d 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -32,7 +32,7 @@ module GRPC
# @return [Proc] { |instance| marshalled(instance) }
def marshal_proc
- proc { |o| o.class.method(marshal_method).call(o).to_s }
+ proc { |o| o.class.send(marshal_method, o).to_s }
end
# @param [:input, :output] target determines whether to produce the an
@@ -42,9 +42,9 @@ module GRPC
# @return [Proc] An unmarshal proc { |marshalled(instance)| instance }
def unmarshal_proc(target)
fail ArgumentError unless [:input, :output].include?(target)
- unmarshal_class = method(target).call
+ unmarshal_class = send(target)
unmarshal_class = unmarshal_class.type if unmarshal_class.is_a? Stream
- proc { |o| unmarshal_class.method(unmarshal_method).call(o) }
+ proc { |o| unmarshal_class.send(unmarshal_method, o) }
end
def handle_request_response(active_call, mth, inter_ctx)
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 838ac45927..3b5a0ce27f 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -136,7 +136,7 @@ module GRPC
begin
blk, args = worker_queue.pop
blk.call(*args)
- rescue StandardError => e
+ rescue StandardError, GRPC::Core::CallError => e
GRPC.logger.warn('Error in worker thread')
GRPC.logger.warn(e)
end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 5c21a5b168..243d566645 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '1.15.0.dev'
+ VERSION = '1.17.0.dev'
end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index cfed7ca12a..b2303c6e14 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -95,7 +95,7 @@ end
# creates a test stub that accesses host:port securely.
def create_stub(opts)
- address = "#{opts.host}:#{opts.port}"
+ address = "#{opts.server_host}:#{opts.server_port}"
# Provide channel args that request compression by default
# for compression interop tests
@@ -112,7 +112,7 @@ def create_stub(opts)
creds = ssl_creds(opts.use_test_ca)
stub_opts = {
channel_args: {
- GRPC::Core::Channel::SSL_TARGET => opts.host_override
+ GRPC::Core::Channel::SSL_TARGET => opts.server_host_override
}
}
@@ -703,19 +703,19 @@ class NamedTests
end
# Args is used to hold the command line info.
-Args = Struct.new(:default_service_account, :host, :host_override,
- :oauth_scope, :port, :secure, :test_case,
+Args = Struct.new(:default_service_account, :server_host, :server_host_override,
+ :oauth_scope, :server_port, :secure, :test_case,
:use_test_ca)
# validates the command line options, returning them as a Hash.
def parse_args
args = Args.new
- args.host_override = 'foo.test.google.fr'
+ args.server_host_override = 'foo.test.google.fr'
OptionParser.new do |opts|
opts.on('--oauth_scope scope',
'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
- args['host'] = v
+ args['server_host'] = v
end
opts.on('--default_service_account email_address',
'email address of the default service account') do |v|
@@ -723,9 +723,11 @@ def parse_args
end
opts.on('--server_host_override HOST_OVERRIDE',
'override host via a HTTP header') do |v|
- args['host_override'] = v
+ args['server_host_override'] = v
+ end
+ opts.on('--server_port SERVER_PORT', 'server port') do |v|
+ args['server_port'] = v
end
- opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v }
# instance_methods(false) gives only the methods defined in that class
test_cases = NamedTests.instance_methods(false).map(&:to_s)
test_case_list = test_cases.join(',')
@@ -744,7 +746,7 @@ def parse_args
end
def _check_args(args)
- %w(host port test_case).each do |a|
+ %w(server_host server_port test_case).each do |a|
if args[a].nil?
fail(OptionParser::MissingArgument, "please specify --#{a}")
end
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index 3c9eca47ec..adba6db99c 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -13,6 +13,7 @@
# limitations under the License.
require 'spec_helper'
+require 'English'
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
@@ -27,6 +28,28 @@ describe GRPC::Core::Channel do
GRPC::Core::ChannelCredentials.new(load_test_certs[0])
end
+ def fork_with_propagated_error_message
+ pipe_read, pipe_write = IO.pipe
+ pid = fork do
+ pipe_read.close
+ begin
+ yield
+ rescue => exc
+ pipe_write.syswrite(exc.message)
+ end
+ pipe_write.close
+ end
+ pipe_write.close
+
+ exc_message = pipe_read.read
+ Process.wait(pid)
+
+ unless $CHILD_STATUS.success?
+ raise "forked process failed with #{$CHILD_STATUS}"
+ end
+ raise exc_message unless exc_message.empty?
+ end
+
shared_examples '#new' do
it 'take a host name without channel args' do
blk = proc do
@@ -79,6 +102,14 @@ describe GRPC::Core::Channel do
blk = construct_with_args(args)
expect(&blk).to_not raise_error
end
+
+ it 'raises if grpc was initialized in another process' do
+ blk = construct_with_args({})
+ expect(&blk).not_to raise_error
+ expect do
+ fork_with_propagated_error_message(&blk)
+ end.to raise_error(RuntimeError, 'grpc cannot be used before and after forking')
+ end
end
describe '#new for secure channels' do
@@ -121,6 +152,19 @@ describe GRPC::Core::Channel do
end
expect(&blk).to raise_error(RuntimeError)
end
+
+ it 'raises if grpc was initialized in another process' do
+ ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure)
+
+ deadline = Time.now + 5
+
+ blk = proc do
+ fork_with_propagated_error_message do
+ ch.create_call(nil, nil, 'dummy_method', nil, deadline)
+ end
+ end
+ expect(&blk).to raise_error(RuntimeError, 'grpc cannot be used before and after forking')
+ end
end
describe '#destroy' do
diff --git a/src/ruby/spec/client_auth_spec.rb b/src/ruby/spec/client_auth_spec.rb
index c563ed3227..5d2e6d24ec 100644
--- a/src/ruby/spec/client_auth_spec.rb
+++ b/src/ruby/spec/client_auth_spec.rb
@@ -30,7 +30,7 @@ end
def create_server_creds
test_root = File.join(File.dirname(__FILE__), 'testdata')
- p "test root: #{test_root}"
+ GRPC.logger.info("test root: #{test_root}")
files = ['ca.pem', 'server1.key', 'server1.pem']
creds = files.map { |f| File.open(File.join(test_root, f)).read }
GRPC::Core::ServerCredentials.new(
@@ -59,7 +59,7 @@ class SslTestService
def a_client_streaming_rpc(call)
check_peer_cert(call)
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@@ -70,7 +70,7 @@ class SslTestService
def a_bidi_rpc(requests, call)
check_peer_cert(call)
- requests.each { |r| p r }
+ requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@@ -116,11 +116,11 @@ describe 'client-server auth' do
it 'client-server auth with server streaming RPCs' do
responses = @stub.a_server_streaming_rpc(EchoMsg.new)
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
it 'client-server auth with bidi RPCs' do
responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new])
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index fc50362ca5..200139d849 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -293,7 +293,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
describe 'without a call operation' do
def get_response(stub, credentials: nil)
- puts credentials.inspect
+ GRPC.logger.info(credentials.inspect)
stub.request_response(@method, @sent_msg, noop, noop,
metadata: @metadata,
credentials: credentials)
@@ -342,13 +342,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
end
end
@@ -435,13 +437,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
end
end
@@ -578,7 +582,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -586,7 +590,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -895,7 +899,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -903,7 +907,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index e072d0c45f..44a6134086 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -125,7 +125,7 @@ class CheckCallAfterFinishedService
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
# iterate through requests so call can complete
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@@ -138,7 +138,7 @@ class CheckCallAfterFinishedService
def a_bidi_rpc(requests, call)
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
- requests.each { |r| p r }
+ requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@@ -560,7 +560,7 @@ describe GRPC::RpcServer do
'connect_k1' => 'connect_v1'
}
wanted_md.each do |key, value|
- puts "key: #{key}"
+ GRPC.logger.info("key: #{key}")
expect(op.metadata[key]).to eq(value)
end
@srv.stop
diff --git a/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto b/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto
new file mode 100644
index 0000000000..e7ecf8c196
--- /dev/null
+++ b/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto
@@ -0,0 +1,28 @@
+// 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.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// For sanity checking package definitions
+option ruby_package = "Grpc.Testing.Package.Options";
+
+message TestRequest { }
+
+message TestResponse { }
+
+service TestService {
+ rpc GetTest(TestRequest) returns (TestResponse) { }
+}
diff --git a/src/ruby/spec/pb/codegen/package_option_spec.rb b/src/ruby/spec/pb/codegen/package_option_spec.rb
new file mode 100644
index 0000000000..0ebd503d79
--- /dev/null
+++ b/src/ruby/spec/pb/codegen/package_option_spec.rb
@@ -0,0 +1,52 @@
+# 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.
+
+require 'spec_helper'
+require 'open3'
+require 'tmpdir'
+
+describe 'Code Generation Options' do
+ it 'should generate and respect package options' do
+ fail 'CONFIG env variable unexpectedly unset' unless ENV['CONFIG']
+ bins_sub_dir = ENV['CONFIG']
+
+ pb_dir = File.dirname(__FILE__)
+ bins_dir = File.join('..', '..', '..', '..', '..', 'bins', bins_sub_dir)
+
+ plugin = File.join(bins_dir, 'grpc_ruby_plugin')
+ protoc = File.join(bins_dir, 'protobuf', 'protoc')
+
+ # Generate the service from the proto
+ Dir.mktmpdir(nil, File.dirname(__FILE__)) do |tmp_dir|
+ gen_file = system(protoc,
+ '-I.',
+ 'grpc/testing/package_options.proto',
+ "--grpc_out=#{tmp_dir}", # generate the service
+ "--ruby_out=#{tmp_dir}", # generate the definitions
+ "--plugin=protoc-gen-grpc=#{plugin}",
+ chdir: pb_dir,
+ out: File::NULL)
+
+ expect(gen_file).to be_truthy
+ begin
+ $LOAD_PATH.push(tmp_dir)
+ expect { Grpc::Testing::Package::Options::TestService::Service }.to raise_error(NameError)
+ expect(require('grpc/testing/package_options_services_pb')).to be_truthy
+ expect { Grpc::Testing::Package::Options::TestService::Service }.to_not raise_error
+ ensure
+ $LOAD_PATH.delete(tmp_dir)
+ end
+ end
+ end
+end
diff --git a/src/ruby/spec/support/services.rb b/src/ruby/spec/support/services.rb
index 27239cd66c..6e693f1cde 100644
--- a/src/ruby/spec/support/services.rb
+++ b/src/ruby/spec/support/services.rb
@@ -50,7 +50,9 @@ class EchoService
def a_client_streaming_rpc(call)
# iterate through requests so call can complete
call.output_metadata.update(@trailing_metadata)
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each do |r|
+ GRPC.logger.info(r)
+ end
EchoMsg.new
end
@@ -61,7 +63,9 @@ class EchoService
def a_bidi_rpc(requests, call)
call.output_metadata.update(@trailing_metadata)
- requests.each { |r| p r }
+ requests.each do |r|
+ GRPC.logger.info(r)
+ end
[EchoMsg.new, EchoMsg.new]
end
end
@@ -71,35 +75,37 @@ EchoStub = EchoService.rpc_stub_class
# For testing server interceptors
class TestServerInterceptor < GRPC::ServerInterceptor
def request_response(request:, call:, method:)
- p "Received request/response call at method #{method}" \
- " with request #{request} for call #{call}"
+ GRPC.logger.info("Received request/response call at method #{method}" \
+ " with request #{request} for call #{call}")
call.output_metadata[:interc] = 'from_request_response'
- p "[GRPC::Ok] (#{method.owner.name}.#{method.name})"
+ GRPC.logger.info("[GRPC::Ok] (#{method.owner.name}.#{method.name})")
yield
end
def client_streamer(call:, method:)
call.output_metadata[:interc] = 'from_client_streamer'
call.each_remote_read.each do |r|
- p "In interceptor: #{r}"
+ GRPC.logger.info("In interceptor: #{r}")
end
- p "Received client streamer call at method #{method} for call #{call}"
+ GRPC.logger.info(
+ "Received client streamer call at method #{method} for call #{call}"
+ )
yield
end
def server_streamer(request:, call:, method:)
- p "Received server streamer call at method #{method} with request" \
- " #{request} for call #{call}"
+ GRPC.logger.info("Received server streamer call at method #{method} with request" \
+ " #{request} for call #{call}")
call.output_metadata[:interc] = 'from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:)
requests.each do |r|
- p "Bidi request: #{r}"
+ GRPC.logger.info("Bidi request: #{r}")
end
- p "Received bidi streamer call at method #{method} with requests" \
- " #{requests} for call #{call}"
+ GRPC.logger.info("Received bidi streamer call at method #{method} with requests" \
+ " #{requests} for call #{call}")
call.output_metadata[:interc] = 'from_bidi_streamer'
yield
end
@@ -108,38 +114,38 @@ end
# For testing client interceptors
class TestClientInterceptor < GRPC::ClientInterceptor
def request_response(request:, call:, method:, metadata: {})
- p "Intercepted request/response call at method #{method}" \
+ GRPC.logger.info("Intercepted request/response call at method #{method}" \
" with request #{request} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
metadata['foo'] = 'bar_from_request_response'
yield
end
def client_streamer(requests:, call:, method:, metadata: {})
- p "Received client streamer call at method #{method}" \
+ GRPC.logger.info("Received client streamer call at method #{method}" \
" with requests #{requests} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
requests.each do |r|
- p "In client interceptor: #{r}"
+ GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_client_streamer'
yield
end
def server_streamer(request:, call:, method:, metadata: {})
- p "Received server streamer call at method #{method}" \
+ GRPC.logger.info("Received server streamer call at method #{method}" \
" with request #{request} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
metadata['foo'] = 'bar_from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:, metadata: {})
- p "Received bidi streamer call at method #{method}" \
+ GRPC.logger.info("Received bidi streamer call at method #{method}" \
"with requests #{requests} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
requests.each do |r|
- p "In client interceptor: #{r}"
+ GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_bidi_streamer'
yield
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 1b5e2c362b..92e85eb882 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
module GRPC
module Tools
- VERSION = '1.15.0.dev'
+ VERSION = '1.17.0.dev'
end
end
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index 2a514ed7b6..1628493d00 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -88,6 +88,7 @@
option(gRPC_BUILD_TESTS "Build tests" OFF)
option(gRPC_BUILD_CODEGEN "Build codegen" ON)
option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON)
+ option(gRPC_BACKWARDS_COMPATIBILITY_MODE "Build libraries that are binary compatible across a larger number of OS and libc versions" OFF)
set(gRPC_INSTALL_default ON)
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -164,6 +165,25 @@
set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf")
endif()
+ if(gRPC_BACKWARDS_COMPATIBILITY_MODE)
+ add_definitions(-DGPR_BACKWARDS_COMPATIBILITY_MODE)
+ if (_gRPC_PLATFORM_MAC)
+ # some C++11 constructs not supported before OS X 10.9
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
+ endif()
+ endif()
+
+ if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
+ # C core has C++ source code, but should not depend on libstc++ (for better portability).
+ # We need to use a few tricks to convince cmake to do that.
+ # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc
+ set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
+ # Exceptions and RTTI must be off to avoid dependency on libstdc++
+ set(_gRPC_CORE_NOSTDCXX_FLAGS -fno-exceptions -fno-rtti)
+ else()
+ set(_gRPC_CORE_NOSTDCXX_FLAGS "")
+ endif()
+
include(cmake/zlib.cmake)
include(cmake/cares.cmake)
include(cmake/protobuf.cmake)
@@ -403,7 +423,14 @@
PRIVATE <%text>${_gRPC_PROTO_GENS_DIR}</%text>
% endif
)
-
+ % if lib.language in ['c', 'csharp']:
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(${lib.name} PROPERTIES LINKER_LANGUAGE C)
+ # only use the flags for C++ source files
+ target_compile_options(${lib.name} PRIVATE <%text>$<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}></%text>)
+ endif()
+ % endif
% if len(get_deps(lib)) > 0:
target_link_libraries(${lib.name}
% for dep in get_deps(lib):
@@ -492,6 +519,14 @@
${dep}
% endfor
)
+
+ % if tgt.language in ['c', 'csharp']:
+ # avoid dependency on libstdc++
+ if (_gRPC_CORE_NOSTDCXX_FLAGS)
+ set_target_properties(${tgt.name} PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(${tgt.name} PRIVATE <%text>$<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}></%text>)
+ endif()
+ % endif
% endif
</%def>
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 2e3d75d819..0b67416d3e 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -692,7 +692,7 @@
PC_CFLAGS =
PC_REQUIRES_PRIVATE = gpr $(PC_REQUIRES_GRPC)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPC)
- PC_LIB = -lgrpc
+ PC_LIB = -lgrpc_unsecure
GRPC_UNSECURE_PC_FILE := $(CORE_PC_TEMPLATE)
PROTOBUF_PKG_CONFIG = false
@@ -769,7 +769,7 @@
PC_CFLAGS =
PC_REQUIRES_PRIVATE = grpc_unsecure $(PC_REQUIRES_GRPCXX)
PC_LIBS_PRIVATE = $(PC_LIBS_GRPCXX)
- PC_LIB = -lgrpc++
+ PC_LIB = -lgrpc++_unsecure
GRPCXX_UNSECURE_PC_FILE := $(CPP_PC_TEMPLATE)
ifeq ($(MAKECMDGOALS),clean)
diff --git a/templates/README.md b/templates/README.md
index c837b5b260..a7aeec26c7 100644
--- a/templates/README.md
+++ b/templates/README.md
@@ -1,9 +1,13 @@
# Regenerating project files
-Prerequisites: `python`, `pip install mako`, `go`
+Prerequisites
+- `python`
+- `pip install mako` (the template processor)
+- `pip install pyyaml` (to read the yaml files)
+- `go` (required by boringssl dependency)
```
-# Regenerate the projects files using templates
+# Regenerate the projects files (and other generated files) using templates
tools/buildgen/generate_projects.sh
```
@@ -19,25 +23,13 @@ So instead we decided to work the following way:
targets and files needed to build grpc and its tests, as well as a basic system
for dependency description.
-* Each project file (Makefile, Visual Studio project files, Bazel's BUILD) is
-a [YAML](http://yaml.org) file used by the `build.yaml` file to generate the
-final output file.
+* Most of the build systems supported by gRPC (e.g. Makefile, cmake, XCode) have a template defined in this directory. The templates use the information from the `build.yaml` file to generate the project files specific to a given build system.
This way we can maintain as many project system as we see fit, without having
to manually maintain them when we add or remove new code to the repository.
Only the structure of the project file is relevant to the template. The actual
list of source code and targets isn't.
-We currently have template files for GNU Make, Visual Studio 2013,
-[Bazel](http://bazel.io) and [gyp](https://gyp.gsrc.io/) (albeit only for
-Node.js). In the future, we
-would like to expand to also generate [cmake](https://cmake.org)
-project files, XCode project files, and an Android.mk file allowing to compile
-gRPC using Android's NDK.
-
-We'll gladly accept contribution that'd create additional project files
-using that system.
-
# Structure of `build.yaml`
The `build.yaml` file has the following structure:
@@ -87,7 +79,6 @@ src: # list of files to compile
secure: boolean, # see below
baselib: boolean, # this is a low level library that has system
# dependencies
-vs_project_guid: '{...}', # Visual Studio's unique guid for that project
filegroups: # list of filegroups to merge to that project
# note that this will be expanded automatically
deps: # list of libraries this target depends on
@@ -95,12 +86,6 @@ deps_linkage: "..." # "static" or "dynamic". Used by the Makefile only to
# determine the way dependencies are linkned. Defaults
# to "dynamic".
dll: "..." # see below.
-dll_def: "..." # Visual Studio's dll definition file.
-vs_props: # List of property sheets to attach to that project.
-vs_config_type: "..." # DynamicLibrary/StaticLibrary. Used only when
- # creating a library. Specifies if we're building a
- # static library or a dll. Use in conjunction with `dll_def`.
-vs_packages: # List of nuget packages this project depends on.
```
## The `"build"` tag
@@ -137,23 +122,17 @@ protobuf is for `"c++"` ones.
## The `"dll"` tag
-Used only by Visual Studio's project files. "true" means the project will be
+Currently only used by cmake. "true" means the project will be
built with both static and dynamic runtimes. "false" means it'll only be built
with static runtime. "only" means it'll only be built with the dll runtime.
-## The `"dll_def"` tag
-
-Specifies the visual studio's dll definition file. When creating a DLL, you
-sometimes (not always) need a def file (see grpc.def).
-
# The template system
We're currently using the [mako templates](http://www.makotemplates.org/)
renderer. That choice enables us to simply render text files without dragging
with us a lot of other features. Feel free to explore the current templates
-in that directory. The simplest one is probably [BUILD.template](BUILD.template)
-which is used to create the [Bazel](http://bazel.io/) project file.
+in that directory.
## The renderer engine
diff --git a/templates/gRPC-C++.podspec.template b/templates/gRPC-C++.podspec.template
index cff252b3a9..ed69a1ed4c 100644
--- a/templates/gRPC-C++.podspec.template
+++ b/templates/gRPC-C++.podspec.template
@@ -177,6 +177,9 @@
s.default_subspecs = 'Interface', 'Implementation'
+ # Certificates, to be able to establish TLS connections:
+ s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
+
s.header_mappings_dir = 'include/grpcpp'
s.subspec 'Interface' do |ss|
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index f912154301..98b6344a4b 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -174,7 +174,7 @@
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
- ss.dependency 'BoringSSL-GRPC', '0.0.1'
+ ss.dependency 'BoringSSL-GRPC', '0.0.2'
ss.dependency 'nanopb', '~> 0.3'
ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS'
@@ -223,5 +223,6 @@
s.prepare_command = <<-END_OF_COMMAND
find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
+ find src/core/ -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
end
diff --git a/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template
index 8ce2a57323..774fc2c56f 100644
--- a/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template
+++ b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template
@@ -73,7 +73,7 @@
'void grpcsharp_redirect_log(GprLogDelegate callback)',
'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)',
'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)',
- 'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth)',
+ 'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest)',
'void grpcsharp_server_credentials_release(IntPtr credentials)',
'ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args)',
'void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq)',
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 2ae909f53a..877899c7bd 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -41,10 +41,10 @@
%%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release Grpc.Tools --output ..\..\..\artifacts || goto :error
%%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Core.NativeDebug.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
- %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
diff --git a/templates/src/objective-c/BoringSSL-GRPC.podspec.template b/templates/src/objective-c/BoringSSL-GRPC.podspec.template
index 986216fdbf..2b3bb8d97a 100644
--- a/templates/src/objective-c/BoringSSL-GRPC.podspec.template
+++ b/templates/src/objective-c/BoringSSL-GRPC.podspec.template
@@ -43,7 +43,7 @@
Pod::Spec.new do |s|
s.name = 'BoringSSL-GRPC'
- version = '0.0.1'
+ version = '0.0.2'
s.version = version
s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
# Adapted from the homepage:
@@ -86,7 +86,7 @@
s.ios.deployment_target = '5.0'
s.osx.deployment_target = '10.7'
- name = 'openssl'
+ name = 'openssl_grpc'
# When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework.
# This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include
@@ -1551,6 +1551,7 @@
sed -i'.back' '/^#define \\([A-Za-z0-9_]*\\) \\1/d' include/openssl/ssl.h
sed -i'.back' 'N;/^#define \\([A-Za-z0-9_]*\\) *\\\\\\n *\\1/d' include/openssl/ssl.h
sed -i'.back' 's/#ifndef md5_block_data_order/#ifndef GRPC_SHADOW_md5_block_data_order/g' crypto/fipsmodule/md5/md5.c
+ find . -type f \\( -path '*.h' -or -path '*.cc' -or -path '*.c' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
# Redefine symbols to avoid conflict when the same app also depends on OpenSSL. The list of
diff --git a/templates/tools/dockerfile/apt_get_python_27.include b/templates/tools/dockerfile/apt_get_python_27.include
new file mode 100644
index 0000000000..4ee37ef11f
--- /dev/null
+++ b/templates/tools/dockerfile/apt_get_python_27.include
@@ -0,0 +1,3 @@
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
diff --git a/templates/tools/dockerfile/bazel.include b/templates/tools/dockerfile/bazel.include
index ee4f9556af..c7714f5663 100644
--- a/templates/tools/dockerfile/bazel.include
+++ b/templates/tools/dockerfile/bazel.include
@@ -1,5 +1,6 @@
#========================
# Bazel installation
-RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
-RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
-RUN apt-get -y update && apt-get -y install bazel=0.15.0 && apt-get clean
+
+RUN apt-get update && apt-get install -y wget && apt-get clean
+RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
+RUN chmod 755 /usr/local/bin/bazel
diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include
index 3a40711e37..7ed0074867 100644
--- a/templates/tools/dockerfile/csharp_deps.include
+++ b/templates/tools/dockerfile/csharp_deps.include
@@ -15,3 +15,10 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y ${'\\'}
&& apt-get clean
RUN nuget update -self
+
+#=================
+# Use cmake 3.6 from jessie-backports
+# needed to build grpc_csharp_ext with cmake
+
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
diff --git a/templates/tools/dockerfile/debian_testing_repo.include b/templates/tools/dockerfile/debian_testing_repo.include
new file mode 100644
index 0000000000..1a5248e226
--- /dev/null
+++ b/templates/tools/dockerfile/debian_testing_repo.include
@@ -0,0 +1,3 @@
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
diff --git a/templates/tools/dockerfile/gcp_api_libraries.include b/templates/tools/dockerfile/gcp_api_libraries.include
index adecb92c15..5a263649d2 100644
--- a/templates/tools/dockerfile/gcp_api_libraries.include
+++ b/templates/tools/dockerfile/gcp_api_libraries.include
@@ -1,3 +1,3 @@
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template
index 4fb7b4642d..34ea645cfa 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM google/dart:latest
+ FROM google/dart:2.0
# Upgrade Dart to version 2.
RUN apt-get update && apt-get upgrade -y dart
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
index 79c55d5e56..c908a638ed 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM golang:latest
+ FROM golang:1.11
<%include file="../../go_path.include"/>
<%include file="../../python_deps.include"/>
diff --git a/templates/tools/dockerfile/java_build_interop.sh.include b/templates/tools/dockerfile/java_build_interop.sh.include
index 895b86ace0..16d5fb65cf 100755
--- a/templates/tools/dockerfile/java_build_interop.sh.include
+++ b/templates/tools/dockerfile/java_build_interop.sh.include
@@ -25,3 +25,11 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc-java
./gradlew :grpc-interop-testing:installDist -PskipCodegen=true
+
+# enable extra java logging
+mkdir -p /var/local/grpc_java_logging
+echo "handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = ALL
+.level = FINE
+io.grpc.netty.NettyClientHandler = ALL
+io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
diff --git a/templates/tools/dockerfile/python_stretch.include b/templates/tools/dockerfile/python_stretch.include
new file mode 100644
index 0000000000..45bafe5184
--- /dev/null
+++ b/templates/tools/dockerfile/python_stretch.include
@@ -0,0 +1,9 @@
+FROM debian:stretch
+
+<%include file="./apt_get_basic.include"/>
+<%include file="./gcp_api_libraries.include"/>
+<%include file="./apt_get_python_27.include"/>
+<%include file="./debian_testing_repo.include"/>
+<%include file="./run_tests_addons.include"/>
+# Define the default command.
+CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile.template
new file mode 100644
index 0000000000..a1c9d9f84d
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile.template
@@ -0,0 +1,17 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ <%include file="../../python_stretch.include"/>
diff --git a/templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile.template
index 1e013b742c..93b655ea0d 100644
--- a/templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile.template
@@ -1,6 +1,6 @@
%YAML 1.2
--- |
- # Copyright 2016 gRPC authors.
+ # 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.
@@ -13,17 +13,8 @@
# 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.
-
- FROM debian:stretch
-
- <%include file="../../apt_get_basic.include"/>
- <%include file="../../gcp_api_libraries.include"/>
- <%include file="../../python_deps.include"/>
- <%include file="../../apt_get_pyenv.include"/>
- # Install pip and virtualenv for Python 3.5
- RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
- RUN python3.5 -m pip install virtualenv
- <%include file="../../run_tests_addons.include"/>
- # Define the default command.
- CMD ["bash"]
+ <%include file="../../python_stretch.include"/>
+
+ RUN apt-get update && apt-get install -y python3.5 python3-all-dev
+ RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
diff --git a/templates/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile.template
new file mode 100644
index 0000000000..a5dcf196f2
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile.template
@@ -0,0 +1,20 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ <%include file="../../python_stretch.include"/>
+
+ RUN apt-get update && apt-get -t testing install -y python3.6 python3-all-dev
+ RUN curl https://bootstrap.pypa.io/get-pip.py | python3.6
diff --git a/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template
new file mode 100644
index 0000000000..ff342db493
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile.template
@@ -0,0 +1,20 @@
+%YAML 1.2
+--- |
+ # 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.
+
+ <%include file="../../python_stretch.include"/>
+
+ RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
+ RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
diff --git a/templates/tools/run_tests/generated/lb_interop_test_scenarios.json.template b/templates/tools/run_tests/generated/lb_interop_test_scenarios.json.template
new file mode 100644
index 0000000000..18d71a7c84
--- /dev/null
+++ b/templates/tools/run_tests/generated/lb_interop_test_scenarios.json.template
@@ -0,0 +1,6 @@
+%YAML 1.2
+--- |
+ <%!
+ import json
+ %>
+ ${json.dumps(lb_interop_test_scenarios, indent=4, sort_keys=True)}
diff --git a/test/cpp/util/.clang-tidy b/test/.clang-tidy
index f951ee5fea..f951ee5fea 100644
--- a/test/cpp/util/.clang-tidy
+++ b/test/.clang-tidy
diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc
index ade23133c5..4f5d2a2862 100644
--- a/test/core/bad_client/bad_client.cc
+++ b/test/core/bad_client/bad_client.cc
@@ -66,7 +66,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
thd_args* a = static_cast<thd_args*>(ts);
grpc_core::ExecCtx exec_ctx;
grpc_server_setup_transport(a->server, transport, nullptr,
- grpc_server_get_channel_args(a->server));
+ grpc_server_get_channel_args(a->server), 0);
}
/* Sets the read_done event */
diff --git a/test/core/channel/channel_stack_test.cc b/test/core/channel/channel_stack_test.cc
index 2f5329a96d..6f0bfa06d2 100644
--- a/test/core/channel/channel_stack_test.cc
+++ b/test/core/channel/channel_stack_test.cc
@@ -124,7 +124,7 @@ static void test_create_channel_stack(void) {
gpr_now(GPR_CLOCK_MONOTONIC), /* start_time */
GRPC_MILLIS_INF_FUTURE, /* deadline */
nullptr, /* arena */
- nullptr /* call_combiner */
+ nullptr, /* call_combiner */
};
grpc_error* error =
grpc_call_stack_init(channel_stack, 1, free_call, call_stack, &args);
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc
index f224457a55..3d8de79e37 100644
--- a/test/core/channel/channel_trace_test.cc
+++ b/test/core/channel/channel_trace_test.cc
@@ -30,6 +30,7 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
+#include "src/core/lib/surface/channel.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/channel_trace_proto_helper.h"
@@ -40,6 +41,19 @@
namespace grpc_core {
namespace channelz {
namespace testing {
+
+// testing peer to access channel internals
+class ChannelNodePeer {
+ public:
+ explicit ChannelNodePeer(ChannelNode* node) : node_(node) {}
+ ChannelTrace* trace() const { return &node_->trace_; }
+
+ private:
+ ChannelNode* node_;
+};
+
+size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); }
+
namespace {
grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
@@ -54,6 +68,11 @@ grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
void ValidateJsonArraySize(grpc_json* json, const char* key,
size_t expected_size) {
grpc_json* arr = GetJsonChild(json, key);
+ // the events array should not be present if there are no events.
+ if (expected_size == 0) {
+ EXPECT_EQ(arr, nullptr);
+ return;
+ }
ASSERT_NE(arr, nullptr);
ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
size_t count = 0;
@@ -83,29 +102,29 @@ void AddSimpleTrace(ChannelTrace* tracer) {
}
// checks for the existence of all the required members of the tracer.
-void ValidateChannelTrace(ChannelTrace* tracer,
- size_t expected_num_event_logged, size_t max_nodes) {
- if (!max_nodes) return;
+void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged,
+ size_t num_events_expected) {
grpc_json* json = tracer->RenderJson();
EXPECT_NE(json, nullptr);
char* json_str = grpc_json_dump_to_string(json, 0);
grpc_json_destroy(json);
grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str);
grpc_json* parsed_json = grpc_json_parse_string(json_str);
- ValidateChannelTraceData(parsed_json, expected_num_event_logged,
- GPR_MIN(expected_num_event_logged, max_nodes));
+ ValidateChannelTraceData(parsed_json, num_events_logged, num_events_expected);
grpc_json_destroy(parsed_json);
gpr_free(json_str);
}
+void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) {
+ ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged);
+}
+
class ChannelFixture {
public:
- ChannelFixture(int max_trace_nodes) {
- grpc_arg client_a;
- client_a.type = GRPC_ARG_INTEGER;
- client_a.key =
- const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
- client_a.value.integer = max_trace_nodes;
+ ChannelFixture(int max_tracer_event_memory) {
+ grpc_arg client_a = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ max_tracer_event_memory);
grpc_channel_args client_args = {1, &client_a};
channel_ =
grpc_insecure_channel_create("fake_target", &client_args, nullptr);
@@ -121,66 +140,67 @@ class ChannelFixture {
} // anonymous namespace
-class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
+const int kEventListMemoryLimit = 1024 * 1024;
// Tests basic ChannelTrace functionality like construction, adding trace, and
// lookups by uuid.
-TEST_P(ChannelTracerTest, BasicTest) {
+TEST(ChannelTracerTest, BasicTest) {
grpc_core::ExecCtx exec_ctx;
- ChannelTrace tracer(GetParam());
+ ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
tracer.AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("trace three"));
tracer.AddTraceEvent(ChannelTrace::Severity::Error,
grpc_slice_from_static_string("trace four error"));
- ValidateChannelTrace(&tracer, 4, GetParam());
+ ValidateChannelTrace(&tracer, 4);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 6, GetParam());
+ ValidateChannelTrace(&tracer, 6);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 10, GetParam());
+ ValidateChannelTrace(&tracer, 10);
}
// Tests more complex functionality, like a parent channel tracking
// subchannles. This exercises the ref/unref patterns since the parent tracer
// and this function will both hold refs to the subchannel.
-TEST_P(ChannelTracerTest, ComplexTest) {
+TEST(ChannelTracerTest, ComplexTest) {
grpc_core::ExecCtx exec_ctx;
- ChannelTrace tracer(GetParam());
+ ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ChannelFixture channel1(GetParam());
- RefCountedPtr<ChannelNode> sc1 =
- MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
- tracer.AddTraceEventReferencingSubchannel(
+ ChannelFixture channel1(kEventListMemoryLimit);
+ RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
+ channel1.channel(), kEventListMemoryLimit, true);
+ ChannelNodePeer sc1_peer(sc1.get());
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
- ValidateChannelTrace(&tracer, 3, GetParam());
- AddSimpleTrace(sc1->trace());
- AddSimpleTrace(sc1->trace());
- AddSimpleTrace(sc1->trace());
- ValidateChannelTrace(sc1->trace(), 3, GetParam());
- AddSimpleTrace(sc1->trace());
- AddSimpleTrace(sc1->trace());
- AddSimpleTrace(sc1->trace());
- ValidateChannelTrace(sc1->trace(), 6, GetParam());
+ ValidateChannelTrace(&tracer, 3);
+ AddSimpleTrace(sc1_peer.trace());
+ AddSimpleTrace(sc1_peer.trace());
+ AddSimpleTrace(sc1_peer.trace());
+ ValidateChannelTrace(sc1_peer.trace(), 3);
+ AddSimpleTrace(sc1_peer.trace());
+ AddSimpleTrace(sc1_peer.trace());
+ AddSimpleTrace(sc1_peer.trace());
+ ValidateChannelTrace(sc1_peer.trace(), 6);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 5, GetParam());
- ChannelFixture channel2(GetParam());
- RefCountedPtr<ChannelNode> sc2 =
- MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
- tracer.AddTraceEventReferencingChannel(
+ ValidateChannelTrace(&tracer, 5);
+ ChannelFixture channel2(kEventListMemoryLimit);
+ RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
+ channel2.channel(), kEventListMemoryLimit, true);
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2);
- tracer.AddTraceEventReferencingSubchannel(
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
- ValidateChannelTrace(&tracer, 7, GetParam());
+ ValidateChannelTrace(&tracer, 7);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
@@ -194,53 +214,128 @@ TEST_P(ChannelTracerTest, ComplexTest) {
// Test a case in which the parent channel has subchannels and the subchannels
// have connections. Ensures that everything lives as long as it should then
// gets deleted.
-TEST_P(ChannelTracerTest, TestNesting) {
+TEST(ChannelTracerTest, TestNesting) {
grpc_core::ExecCtx exec_ctx;
- ChannelTrace tracer(GetParam());
+ ChannelTrace tracer(kEventListMemoryLimit);
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 2, GetParam());
- ChannelFixture channel1(GetParam());
- RefCountedPtr<ChannelNode> sc1 =
- MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
- tracer.AddTraceEventReferencingChannel(
+ ValidateChannelTrace(&tracer, 2);
+ ChannelFixture channel1(kEventListMemoryLimit);
+ RefCountedPtr<ChannelNode> sc1 = MakeRefCounted<ChannelNode>(
+ channel1.channel(), kEventListMemoryLimit, true);
+ ChannelNodePeer sc1_peer(sc1.get());
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
- ValidateChannelTrace(&tracer, 3, GetParam());
- AddSimpleTrace(sc1->trace());
- ChannelFixture channel2(GetParam());
- RefCountedPtr<ChannelNode> conn1 =
- MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
+ ValidateChannelTrace(&tracer, 3);
+ AddSimpleTrace(sc1_peer.trace());
+ ChannelFixture channel2(kEventListMemoryLimit);
+ RefCountedPtr<ChannelNode> conn1 = MakeRefCounted<ChannelNode>(
+ channel2.channel(), kEventListMemoryLimit, true);
+ ChannelNodePeer conn1_peer(conn1.get());
// nesting one level deeper.
- sc1->trace()->AddTraceEventReferencingSubchannel(
+ sc1_peer.trace()->AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("connection one created"), conn1);
- ValidateChannelTrace(&tracer, 3, GetParam());
- AddSimpleTrace(conn1->trace());
+ ValidateChannelTrace(&tracer, 3);
+ AddSimpleTrace(conn1_peer.trace());
AddSimpleTrace(&tracer);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 5, GetParam());
- ValidateChannelTrace(conn1->trace(), 1, GetParam());
- ChannelFixture channel3(GetParam());
- RefCountedPtr<ChannelNode> sc2 =
- MakeRefCounted<ChannelNode>(channel3.channel(), GetParam(), true);
- tracer.AddTraceEventReferencingSubchannel(
+ ValidateChannelTrace(&tracer, 5);
+ ValidateChannelTrace(conn1_peer.trace(), 1);
+ ChannelFixture channel3(kEventListMemoryLimit);
+ RefCountedPtr<ChannelNode> sc2 = MakeRefCounted<ChannelNode>(
+ channel3.channel(), kEventListMemoryLimit, true);
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2);
// this trace should not get added to the parents children since it is already
// present in the tracer.
- tracer.AddTraceEventReferencingChannel(
+ tracer.AddTraceEventWithReference(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
AddSimpleTrace(&tracer);
- ValidateChannelTrace(&tracer, 8, GetParam());
+ ValidateChannelTrace(&tracer, 8);
sc1.reset();
sc2.reset();
conn1.reset();
}
-INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
- ::testing::Values(0, 1, 2, 6, 10, 15));
+TEST(ChannelTracerTest, TestSmallMemoryLimit) {
+ grpc_core::ExecCtx exec_ctx;
+ // doesn't make sense, but serves a testing purpose for the channel tracing
+ // bookkeeping. All tracing events added should will get immediately garbage
+ // collected.
+ const int kSmallMemoryLimit = 1;
+ ChannelTrace tracer(kSmallMemoryLimit);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ tracer.AddTraceEvent(ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("trace three"));
+ tracer.AddTraceEvent(ChannelTrace::Severity::Error,
+ grpc_slice_from_static_string("trace four error"));
+ ValidateChannelTraceCustom(&tracer, 4, 0);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTraceCustom(&tracer, 6, 0);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTraceCustom(&tracer, 10, 0);
+}
+
+TEST(ChannelTracerTest, TestEviction) {
+ grpc_core::ExecCtx exec_ctx;
+ const int kTraceEventSize = GetSizeofTraceEvent();
+ const int kNumEvents = 5;
+ ChannelTrace tracer(kTraceEventSize * kNumEvents);
+ for (int i = 1; i <= kNumEvents; ++i) {
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, i);
+ }
+ // at this point the list is full, and each subsequent enntry will cause an
+ // eviction.
+ for (int i = 1; i <= kNumEvents; ++i) {
+ AddSimpleTrace(&tracer);
+ ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents);
+ }
+}
+
+TEST(ChannelTracerTest, TestMultipleEviction) {
+ grpc_core::ExecCtx exec_ctx;
+ const int kTraceEventSize = GetSizeofTraceEvent();
+ const int kNumEvents = 5;
+ ChannelTrace tracer(kTraceEventSize * kNumEvents);
+ for (int i = 1; i <= kNumEvents; ++i) {
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, i);
+ }
+ // at this point the list is full, and each subsequent enntry will cause an
+ // eviction. We will now add in a trace event that has a copied string. This
+ // uses more memory, so it will cause a double eviciction
+ tracer.AddTraceEvent(
+ ChannelTrace::Severity::Info,
+ grpc_slice_from_copied_string(
+ "long enough string to trigger a multiple eviction"));
+ ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1);
+}
+
+TEST(ChannelTracerTest, TestTotalEviction) {
+ grpc_core::ExecCtx exec_ctx;
+ const int kTraceEventSize = GetSizeofTraceEvent();
+ const int kNumEvents = 5;
+ ChannelTrace tracer(kTraceEventSize * kNumEvents);
+ for (int i = 1; i <= kNumEvents; ++i) {
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, i);
+ }
+ // at this point the list is full. Now we add such a big slice that
+ // everything gets evicted.
+ grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1));
+ tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice);
+ ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0);
+}
} // namespace testing
} // namespace channelz
diff --git a/test/core/channel/channelz_registry_test.cc b/test/core/channel/channelz_registry_test.cc
index 581e867584..fdfc8eec94 100644
--- a/test/core/channel/channelz_registry_test.cc
+++ b/test/core/channel/channelz_registry_test.cc
@@ -43,56 +43,151 @@ namespace grpc_core {
namespace channelz {
namespace testing {
-TEST(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
- ChannelNode* channelz_channel = nullptr;
- intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
+class ChannelzRegistryPeer {
+ public:
+ const InlinedVector<BaseNode*, 20>* entities() {
+ return &ChannelzRegistry::Default()->entities_;
+ }
+ int num_empty_slots() {
+ return ChannelzRegistry::Default()->num_empty_slots_;
+ }
+};
+
+class ChannelzRegistryTest : public ::testing::Test {
+ protected:
+ // ensure we always have a fresh registry for tests.
+ void SetUp() override { ChannelzRegistry::Init(); }
+
+ void TearDown() override { ChannelzRegistry::Shutdown(); }
+};
+
+TEST_F(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
+ UniquePtr<BaseNode> channelz_channel =
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
+ intptr_t uuid = channelz_channel->uuid();
EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if "
"reserved according to "
"https://github.com/grpc/proposal/blob/master/"
"A14-channelz.md";
- ChannelzRegistry::UnregisterChannelNode(uuid);
}
-TEST(ChannelzRegistryTest, UuidsAreIncreasing) {
- ChannelNode* channelz_channel = nullptr;
- std::vector<intptr_t> uuids;
- uuids.reserve(10);
+TEST_F(ChannelzRegistryTest, UuidsAreIncreasing) {
+ std::vector<UniquePtr<BaseNode>> channelz_channels;
+ channelz_channels.reserve(10);
for (int i = 0; i < 10; ++i) {
- // reregister the same object. It's ok since we are just testing uuids
- uuids.push_back(ChannelzRegistry::RegisterChannelNode(channelz_channel));
+ channelz_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
}
- for (size_t i = 1; i < uuids.size(); ++i) {
- EXPECT_LT(uuids[i - 1], uuids[i]) << "Uuids must always be increasing";
+ for (size_t i = 1; i < channelz_channels.size(); ++i) {
+ EXPECT_LT(channelz_channels[i - 1]->uuid(), channelz_channels[i]->uuid())
+ << "Uuids must always be increasing";
}
}
-TEST(ChannelzRegistryTest, RegisterGetTest) {
- // we hackily jam an intptr_t into this pointer to check for equality later
- ChannelNode* channelz_channel = (ChannelNode*)42;
- intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
- ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
- EXPECT_EQ(channelz_channel, retrieved);
+TEST_F(ChannelzRegistryTest, RegisterGetTest) {
+ UniquePtr<BaseNode> channelz_channel =
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
+ BaseNode* retrieved = ChannelzRegistry::Get(channelz_channel->uuid());
+ EXPECT_EQ(channelz_channel.get(), retrieved);
}
-TEST(ChannelzRegistryTest, RegisterManyItems) {
- // we hackily jam an intptr_t into this pointer to check for equality later
- ChannelNode* channelz_channel = (ChannelNode*)42;
+TEST_F(ChannelzRegistryTest, RegisterManyItems) {
+ std::vector<UniquePtr<BaseNode>> channelz_channels;
for (int i = 0; i < 100; i++) {
- intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
- ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
- EXPECT_EQ(channelz_channel, retrieved);
+ channelz_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ BaseNode* retrieved = ChannelzRegistry::Get(channelz_channels[i]->uuid());
+ EXPECT_EQ(channelz_channels[i].get(), retrieved);
}
}
-TEST(ChannelzRegistryTest, NullIfNotPresentTest) {
- // we hackily jam an intptr_t into this pointer to check for equality later
- ChannelNode* channelz_channel = (ChannelNode*)42;
- intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
+TEST_F(ChannelzRegistryTest, NullIfNotPresentTest) {
+ UniquePtr<BaseNode> channelz_channel =
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel);
// try to pull out a uuid that does not exist.
- ChannelNode* nonexistant = ChannelzRegistry::GetChannelNode(uuid + 1);
+ BaseNode* nonexistant = ChannelzRegistry::Get(channelz_channel->uuid() + 1);
EXPECT_EQ(nonexistant, nullptr);
- ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
- EXPECT_EQ(channelz_channel, retrieved);
+ BaseNode* retrieved = ChannelzRegistry::Get(channelz_channel->uuid());
+ EXPECT_EQ(channelz_channel.get(), retrieved);
+}
+
+TEST_F(ChannelzRegistryTest, TestCompaction) {
+ const int kLoopIterations = 100;
+ // These channels that will stay in the registry for the duration of the test.
+ std::vector<UniquePtr<BaseNode>> even_channels;
+ even_channels.reserve(kLoopIterations);
+ {
+ // The channels will unregister themselves at the end of the for block.
+ std::vector<UniquePtr<BaseNode>> odd_channels;
+ odd_channels.reserve(kLoopIterations);
+ for (int i = 0; i < kLoopIterations; i++) {
+ even_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ odd_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ }
+ }
+ // without compaction, there would be exactly kLoopIterations empty slots at
+ // this point. However, one of the unregisters should have triggered
+ // compaction.
+ ChannelzRegistryPeer peer;
+ EXPECT_LT(peer.num_empty_slots(), kLoopIterations);
+}
+
+TEST_F(ChannelzRegistryTest, TestGetAfterCompaction) {
+ const int kLoopIterations = 100;
+ // These channels that will stay in the registry for the duration of the test.
+ std::vector<UniquePtr<BaseNode>> even_channels;
+ even_channels.reserve(kLoopIterations);
+ std::vector<intptr_t> odd_uuids;
+ odd_uuids.reserve(kLoopIterations);
+ {
+ // The channels will unregister themselves at the end of the for block.
+ std::vector<UniquePtr<BaseNode>> odd_channels;
+ odd_channels.reserve(kLoopIterations);
+ for (int i = 0; i < kLoopIterations; i++) {
+ even_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ odd_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ odd_uuids.push_back(odd_channels[i]->uuid());
+ }
+ }
+ for (int i = 0; i < kLoopIterations; i++) {
+ BaseNode* retrieved = ChannelzRegistry::Get(even_channels[i]->uuid());
+ EXPECT_EQ(even_channels[i].get(), retrieved);
+ retrieved = ChannelzRegistry::Get(odd_uuids[i]);
+ EXPECT_EQ(retrieved, nullptr);
+ }
+}
+
+TEST_F(ChannelzRegistryTest, TestAddAfterCompaction) {
+ const int kLoopIterations = 100;
+ // These channels that will stay in the registry for the duration of the test.
+ std::vector<UniquePtr<BaseNode>> even_channels;
+ even_channels.reserve(kLoopIterations);
+ std::vector<intptr_t> odd_uuids;
+ odd_uuids.reserve(kLoopIterations);
+ {
+ // The channels will unregister themselves at the end of the for block.
+ std::vector<UniquePtr<BaseNode>> odd_channels;
+ odd_channels.reserve(kLoopIterations);
+ for (int i = 0; i < kLoopIterations; i++) {
+ even_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ odd_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ odd_uuids.push_back(odd_channels[i]->uuid());
+ }
+ }
+ std::vector<UniquePtr<BaseNode>> more_channels;
+ more_channels.reserve(kLoopIterations);
+ for (int i = 0; i < kLoopIterations; i++) {
+ more_channels.push_back(
+ MakeUnique<BaseNode>(BaseNode::EntityType::kTopLevelChannel));
+ BaseNode* retrieved = ChannelzRegistry::Get(more_channels[i]->uuid());
+ EXPECT_EQ(more_channels[i].get(), retrieved);
+ }
}
} // namespace testing
@@ -101,9 +196,7 @@ TEST(ChannelzRegistryTest, NullIfNotPresentTest) {
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
- grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
- grpc_shutdown();
return ret;
}
diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc
index ad5f86d934..4d4b077002 100644
--- a/test/core/channel/channelz_test.cc
+++ b/test/core/channel/channelz_test.cc
@@ -31,6 +31,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/channel_trace_proto_helper.h"
@@ -44,16 +45,17 @@ namespace channelz {
namespace testing {
// testing peer to access channel internals
-class ChannelNodePeer {
+class CallCountingHelperPeer {
public:
- ChannelNodePeer(ChannelNode* channel) : channel_(channel) {}
- grpc_millis last_call_started_millis() {
- return (grpc_millis)gpr_atm_no_barrier_load(
- &channel_->last_call_started_millis_);
+ explicit CallCountingHelperPeer(CallCountingHelper* node) : node_(node) {}
+ grpc_millis last_call_started_millis() const {
+ CallCountingHelper::CounterData data;
+ node_->CollectData(&data);
+ return (grpc_millis)gpr_atm_no_barrier_load(&data.last_call_started_millis);
}
private:
- ChannelNode* channel_;
+ CallCountingHelper* node_;
};
namespace {
@@ -83,6 +85,19 @@ void ValidateJsonArraySize(grpc_json* json, const char* key,
EXPECT_EQ(count, expected_size);
}
+std::vector<intptr_t> GetUuidListFromArray(grpc_json* arr) {
+ EXPECT_EQ(arr->type, GRPC_JSON_ARRAY);
+ std::vector<intptr_t> uuids;
+ for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
+ grpc_json* it = GetJsonChild(child, "ref");
+ EXPECT_NE(it, nullptr);
+ it = GetJsonChild(it, "channelId");
+ EXPECT_NE(it, nullptr);
+ uuids.push_back(atoi(it->value));
+ }
+ return uuids;
+}
+
void ValidateGetTopChannels(size_t expected_channels) {
char* json_str = ChannelzRegistry::GetTopChannels(0);
grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
@@ -102,15 +117,34 @@ void ValidateGetTopChannels(size_t expected_channels) {
gpr_free(core_api_json_str);
}
+void ValidateGetServers(size_t expected_servers) {
+ char* json_str = ChannelzRegistry::GetServers(0);
+ grpc::testing::ValidateGetServersResponseProtoJsonTranslation(json_str);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ // This check will naturally have to change when we support pagination.
+ // tracked: https://github.com/grpc/grpc/issues/16019.
+ ValidateJsonArraySize(parsed_json, "server", expected_servers);
+ grpc_json* end = GetJsonChild(parsed_json, "end");
+ ASSERT_NE(end, nullptr);
+ EXPECT_EQ(end->type, GRPC_JSON_TRUE);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+ // also check that the core API formats this correctly
+ char* core_api_json_str = grpc_channelz_get_servers(0);
+ grpc::testing::ValidateGetServersResponseProtoJsonTranslation(
+ core_api_json_str);
+ gpr_free(core_api_json_str);
+}
+
class ChannelFixture {
public:
- ChannelFixture(int max_trace_nodes = 0) {
- grpc_arg client_a[2];
- client_a[0] = grpc_channel_arg_integer_create(
- const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE),
- max_trace_nodes);
- client_a[1] = grpc_channel_arg_integer_create(
- const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
+ ChannelFixture(int max_tracer_event_memory = 0) {
+ grpc_arg client_a[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ max_tracer_event_memory),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true)};
grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
channel_ =
grpc_insecure_channel_create("fake_target", &client_args, nullptr);
@@ -124,6 +158,28 @@ class ChannelFixture {
grpc_channel* channel_;
};
+class ServerFixture {
+ public:
+ explicit ServerFixture(int max_tracer_event_memory = 0) {
+ grpc_arg server_a[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ max_tracer_event_memory),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true),
+ };
+ grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
+ server_ = grpc_server_create(&server_args, nullptr);
+ }
+
+ ~ServerFixture() { grpc_server_destroy(server_); }
+
+ grpc_server* server() const { return server_; }
+
+ private:
+ grpc_server* server_;
+};
+
struct validate_channel_data_args {
int64_t calls_started;
int64_t calls_failed;
@@ -157,14 +213,26 @@ void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
ValidateCounters(json_str, args);
gpr_free(json_str);
// also check that the core API formats this the correct way
- char* core_api_json_str = grpc_channelz_get_channel(channel->channel_uuid());
+ char* core_api_json_str = grpc_channelz_get_channel(channel->uuid());
grpc::testing::ValidateGetChannelResponseProtoJsonTranslation(
core_api_json_str);
gpr_free(core_api_json_str);
}
-grpc_millis GetLastCallStartedMillis(ChannelNode* channel) {
- ChannelNodePeer peer(channel);
+void ValidateServer(ServerNode* server, validate_channel_data_args args) {
+ char* json_str = server->RenderJsonString();
+ grpc::testing::ValidateServerProtoJsonTranslation(json_str);
+ ValidateCounters(json_str, args);
+ gpr_free(json_str);
+ // also check that the core API formats this the correct way
+ char* core_api_json_str = grpc_channelz_get_server(server->uuid());
+ grpc::testing::ValidateGetServerResponseProtoJsonTranslation(
+ core_api_json_str);
+ gpr_free(core_api_json_str);
+}
+
+grpc_millis GetLastCallStartedMillis(CallCountingHelper* channel) {
+ CallCountingHelperPeer peer(channel);
return peer.last_call_started_millis();
}
@@ -188,8 +256,16 @@ TEST_P(ChannelzChannelTest, BasicChannel) {
TEST(ChannelzChannelTest, ChannelzDisabled) {
grpc_core::ExecCtx exec_ctx;
+ // explicitly disable channelz
+ grpc_arg arg[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ 0),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), false)};
+ grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg};
grpc_channel* channel =
- grpc_insecure_channel_create("fake_target", nullptr, nullptr);
+ grpc_insecure_channel_create("fake_target", &args, nullptr);
ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel);
ASSERT_EQ(channelz_channel, nullptr);
grpc_channel_destroy(channel);
@@ -215,49 +291,196 @@ TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
grpc_core::ExecCtx exec_ctx;
- ChannelFixture channel(GetParam());
- ChannelNode* channelz_channel =
- grpc_channel_get_channelz_node(channel.channel());
+ CallCountingHelper counter;
// start a call to set the last call started timestamp
- channelz_channel->RecordCallStarted();
- grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel);
+ counter.RecordCallStarted();
+ grpc_millis millis1 = GetLastCallStartedMillis(&counter);
// time gone by should not affect the timestamp
ChannelzSleep(100);
- grpc_millis millis2 = GetLastCallStartedMillis(channelz_channel);
+ grpc_millis millis2 = GetLastCallStartedMillis(&counter);
EXPECT_EQ(millis1, millis2);
// calls succeeded or failed should not affect the timestamp
ChannelzSleep(100);
- channelz_channel->RecordCallFailed();
- channelz_channel->RecordCallSucceeded();
- grpc_millis millis3 = GetLastCallStartedMillis(channelz_channel);
+ counter.RecordCallFailed();
+ counter.RecordCallSucceeded();
+ grpc_millis millis3 = GetLastCallStartedMillis(&counter);
EXPECT_EQ(millis1, millis3);
// another call started should affect the timestamp
// sleep for extra long to avoid flakes (since we cache Now())
ChannelzSleep(5000);
- channelz_channel->RecordCallStarted();
- grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel);
+ counter.RecordCallStarted();
+ grpc_millis millis4 = GetLastCallStartedMillis(&counter);
EXPECT_NE(millis1, millis4);
}
-TEST(ChannelzGetTopChannelsTest, BasicTest) {
+class ChannelzRegistryBasedTest : public ::testing::TestWithParam<size_t> {
+ protected:
+ // ensure we always have a fresh registry for tests.
+ void SetUp() override {
+ ChannelzRegistry::Shutdown();
+ ChannelzRegistry::Init();
+ }
+
+ void TearDown() override {
+ ChannelzRegistry::Shutdown();
+ ChannelzRegistry::Init();
+ }
+};
+
+TEST_F(ChannelzRegistryBasedTest, BasicGetTopChannelsTest) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel;
ValidateGetTopChannels(1);
}
-TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
+TEST_F(ChannelzRegistryBasedTest, NoChannelsTest) {
grpc_core::ExecCtx exec_ctx;
ValidateGetTopChannels(0);
}
-TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) {
+TEST_F(ChannelzRegistryBasedTest, ManyChannelsTest) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channels[10];
(void)channels; // suppress unused variable error
ValidateGetTopChannels(10);
}
-TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsPagination) {
+ grpc_core::ExecCtx exec_ctx;
+ // this is over the pagination limit.
+ ChannelFixture channels[150];
+ (void)channels; // suppress unused variable error
+ char* json_str = ChannelzRegistry::GetTopChannels(0);
+ grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ // 100 is the pagination limit.
+ ValidateJsonArraySize(parsed_json, "channel", 100);
+ grpc_json* end = GetJsonChild(parsed_json, "end");
+ EXPECT_EQ(end, nullptr);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+ // Now we get the rest
+ json_str = ChannelzRegistry::GetTopChannels(101);
+ grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
+ parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", 50);
+ end = GetJsonChild(parsed_json, "end");
+ ASSERT_NE(end, nullptr);
+ EXPECT_EQ(end->type, GRPC_JSON_TRUE);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidCheck) {
+ const intptr_t kNumChannels = 50;
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channels[kNumChannels];
+ (void)channels; // suppress unused variable error
+ char* json_str = ChannelzRegistry::GetTopChannels(0);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", kNumChannels);
+ grpc_json* json_channels = GetJsonChild(parsed_json, "channel");
+ std::vector<intptr_t> uuids = GetUuidListFromArray(json_channels);
+ for (int i = 0; i < kNumChannels; ++i) {
+ EXPECT_EQ(i + 1, uuids[i]);
+ }
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMiddleUuidCheck) {
+ const intptr_t kNumChannels = 50;
+ const intptr_t kMidQuery = 40;
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channels[kNumChannels];
+ (void)channels; // suppress unused variable error
+ // only query for the end of the channels
+ char* json_str = ChannelzRegistry::GetTopChannels(kMidQuery);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", kNumChannels - kMidQuery + 1);
+ grpc_json* json_channels = GetJsonChild(parsed_json, "channel");
+ std::vector<intptr_t> uuids = GetUuidListFromArray(json_channels);
+ for (size_t i = 0; i < uuids.size(); ++i) {
+ EXPECT_EQ(static_cast<intptr_t>(kMidQuery + i), uuids[i]);
+ }
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsNoHitUuid) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture pre_channels[40]; // will take uuid[1, 40]
+ (void)pre_channels; // suppress unused variable error
+ ServerFixture servers[10]; // will take uuid[41, 50]
+ (void)servers; // suppress unused variable error
+ ChannelFixture channels[10]; // will take uuid[51, 60]
+ (void)channels; // suppress unused variable error
+ // query in the middle of the server channels
+ char* json_str = ChannelzRegistry::GetTopChannels(45);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", 10);
+ grpc_json* json_channels = GetJsonChild(parsed_json, "channel");
+ std::vector<intptr_t> uuids = GetUuidListFromArray(json_channels);
+ for (size_t i = 0; i < uuids.size(); ++i) {
+ EXPECT_EQ(static_cast<intptr_t>(51 + i), uuids[i]);
+ }
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channel_with_uuid1;
+ { ServerFixture channel_with_uuid2; }
+ ChannelFixture channel_with_uuid3;
+ { ServerFixture server_with_uuid4; }
+ ChannelFixture channel_with_uuid5;
+ // Current state of list: [1, NULL, 3, NULL, 5]
+ char* json_str = ChannelzRegistry::GetTopChannels(2);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", 2);
+ grpc_json* json_channels = GetJsonChild(parsed_json, "channel");
+ std::vector<intptr_t> uuids = GetUuidListFromArray(json_channels);
+ EXPECT_EQ(static_cast<intptr_t>(3), uuids[0]);
+ EXPECT_EQ(static_cast<intptr_t>(5), uuids[1]);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+ json_str = ChannelzRegistry::GetTopChannels(4);
+ parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", 1);
+ json_channels = GetJsonChild(parsed_json, "channel");
+ uuids = GetUuidListFromArray(json_channels);
+ EXPECT_EQ(static_cast<intptr_t>(5), uuids[0]);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidAfterCompaction) {
+ const intptr_t kLoopIterations = 50;
+ grpc_core::ExecCtx exec_ctx;
+ std::vector<UniquePtr<ChannelFixture>> even_channels;
+ {
+ // these will delete and unregister themselves after this block.
+ std::vector<UniquePtr<ChannelFixture>> odd_channels;
+ for (int i = 0; i < kLoopIterations; i++) {
+ odd_channels.push_back(MakeUnique<ChannelFixture>());
+ even_channels.push_back(MakeUnique<ChannelFixture>());
+ }
+ }
+ char* json_str = ChannelzRegistry::GetTopChannels(0);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateJsonArraySize(parsed_json, "channel", kLoopIterations);
+ grpc_json* json_channels = GetJsonChild(parsed_json, "channel");
+ std::vector<intptr_t> uuids = GetUuidListFromArray(json_channels);
+ for (int i = 0; i < kLoopIterations; ++i) {
+ // only the even uuids will still be present.
+ EXPECT_EQ((i + 1) * 2, uuids[i]);
+ }
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
+TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channels[10];
(void)channels; // suppress unused variable error
@@ -275,8 +498,43 @@ TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
grpc_channel_destroy(internal_channel);
}
+TEST(ChannelzServerTest, BasicServerAPIFunctionality) {
+ grpc_core::ExecCtx exec_ctx;
+ ServerFixture server(10);
+ ServerNode* channelz_server = grpc_server_get_channelz_node(server.server());
+ channelz_server->RecordCallStarted();
+ channelz_server->RecordCallFailed();
+ channelz_server->RecordCallSucceeded();
+ ValidateServer(channelz_server, {1, 1, 1});
+ channelz_server->RecordCallStarted();
+ channelz_server->RecordCallFailed();
+ channelz_server->RecordCallSucceeded();
+ channelz_server->RecordCallStarted();
+ channelz_server->RecordCallFailed();
+ channelz_server->RecordCallSucceeded();
+ ValidateServer(channelz_server, {3, 3, 3});
+}
+
+TEST_F(ChannelzRegistryBasedTest, BasicGetServersTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ServerFixture server;
+ ValidateGetServers(1);
+}
+
+TEST_F(ChannelzRegistryBasedTest, NoServersTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ValidateGetServers(0);
+}
+
+TEST_F(ChannelzRegistryBasedTest, ManyServersTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ServerFixture servers[10];
+ (void)servers; // suppress unused variable error
+ ValidateGetServers(10);
+}
+
INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
- ::testing::Values(0, 1, 2, 6, 10, 15));
+ ::testing::Values(0, 8, 64, 1024, 1024 * 1024));
} // namespace testing
} // namespace channelz
diff --git a/test/core/client_channel/parse_address_test.cc b/test/core/client_channel/parse_address_test.cc
index ae157fbb8b..004549fa62 100644
--- a/test/core/client_channel/parse_address_test.cc
+++ b/test/core/client_channel/parse_address_test.cc
@@ -91,6 +91,15 @@ static void test_grpc_parse_ipv6(const char* uri_text, const char* host,
grpc_uri_destroy(uri);
}
+/* Test parsing invalid ipv6 addresses (valid uri_text but invalid ipv6 addr) */
+static void test_grpc_parse_ipv6_invalid(const char* uri_text) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_uri* uri = grpc_uri_parse(uri_text, 0);
+ grpc_resolved_address addr;
+ GPR_ASSERT(!grpc_parse_ipv6(uri, &addr));
+ grpc_uri_destroy(uri);
+}
+
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
grpc_init();
@@ -100,5 +109,10 @@ int main(int argc, char** argv) {
test_grpc_parse_ipv6("ipv6:[2001:db8::1]:12345", "2001:db8::1", 12345, 0);
test_grpc_parse_ipv6("ipv6:[2001:db8::1%252]:12345", "2001:db8::1", 12345, 2);
+ /* Address length greater than GRPC_INET6_ADDRSTRLEN */
+ test_grpc_parse_ipv6_invalid(
+ "ipv6:WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW45%"
+ "v6:45%x$1*");
+
grpc_shutdown();
}
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
index 1c8d0775ab..eb5a911748 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
@@ -82,6 +82,10 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
return nullptr;
}
+static void my_cancel_ares_request_locked(grpc_ares_request* request) {
+ GPR_ASSERT(request == nullptr);
+}
+
static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver(
const char* name) {
grpc_core::ResolverFactory* factory =
@@ -148,6 +152,7 @@ int main(int argc, char** argv) {
g_combiner = grpc_combiner_create();
grpc_set_resolver_impl(&test_resolver);
grpc_dns_lookup_ares_locked = my_dns_lookup_ares_locked;
+ grpc_cancel_ares_request_locked = my_cancel_ares_request_locked;
grpc_channel_args* result = (grpc_channel_args*)1;
{
diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
index b1f3a1c08a..1a7db40f59 100644
--- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
@@ -28,12 +28,16 @@
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "test/core/util/test_config.h"
+constexpr int kMinResolutionPeriodMs = 1000;
+// Provide some slack when checking intervals, to allow for test timing issues.
+constexpr int kMinResolutionPeriodForCheckMs = 900;
+
extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
static grpc_address_resolver_vtable* default_resolve_address;
static grpc_combiner* g_combiner;
-grpc_ares_request* (*g_default_dns_lookup_ares_locked)(
+static grpc_ares_request* (*g_default_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
@@ -43,7 +47,7 @@ grpc_ares_request* (*g_default_dns_lookup_ares_locked)(
// times a system-level resolution has happened.
static int g_resolution_count;
-struct iomgr_args {
+static struct iomgr_args {
gpr_event ev;
gpr_atm done_atm;
gpr_mu* mu;
@@ -61,6 +65,16 @@ static void test_resolve_address_impl(const char* name,
default_resolve_address->resolve_address(
name, default_port, g_iomgr_args.pollset_set, on_done, addrs);
++g_resolution_count;
+ static grpc_millis last_resolution_time = 0;
+ if (last_resolution_time == 0) {
+ last_resolution_time =
+ grpc_timespec_to_millis_round_up(gpr_now(GPR_CLOCK_MONOTONIC));
+ } else {
+ grpc_millis now =
+ grpc_timespec_to_millis_round_up(gpr_now(GPR_CLOCK_MONOTONIC));
+ GPR_ASSERT(now - last_resolution_time >= kMinResolutionPeriodForCheckMs);
+ last_resolution_time = now;
+ }
}
static grpc_error* test_blocking_resolve_address_impl(
@@ -73,7 +87,7 @@ static grpc_error* test_blocking_resolve_address_impl(
static grpc_address_resolver_vtable test_resolver = {
test_resolve_address_impl, test_blocking_resolve_address_impl};
-grpc_ares_request* test_dns_lookup_ares_locked(
+static grpc_ares_request* test_dns_lookup_ares_locked(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
@@ -82,6 +96,16 @@ grpc_ares_request* test_dns_lookup_ares_locked(
dns_server, name, default_port, g_iomgr_args.pollset_set, on_done, addrs,
check_grpclb, service_config_json, combiner);
++g_resolution_count;
+ static grpc_millis last_resolution_time = 0;
+ if (last_resolution_time == 0) {
+ last_resolution_time =
+ grpc_timespec_to_millis_round_up(gpr_now(GPR_CLOCK_MONOTONIC));
+ } else {
+ grpc_millis now =
+ grpc_timespec_to_millis_round_up(gpr_now(GPR_CLOCK_MONOTONIC));
+ GPR_ASSERT(now - last_resolution_time >= kMinResolutionPeriodForCheckMs);
+ last_resolution_time = now;
+ }
return result;
}
@@ -91,7 +115,7 @@ static gpr_timespec test_deadline(void) {
static void do_nothing(void* arg, grpc_error* error) {}
-void iomgr_args_init(iomgr_args* args) {
+static void iomgr_args_init(iomgr_args* args) {
gpr_event_init(&args->ev);
args->pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
grpc_pollset_init(args->pollset, &args->mu);
@@ -100,7 +124,7 @@ void iomgr_args_init(iomgr_args* args) {
gpr_atm_rel_store(&args->done_atm, 0);
}
-void iomgr_args_finish(iomgr_args* args) {
+static void iomgr_args_finish(iomgr_args* args) {
GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
grpc_pollset_set_del_pollset(args->pollset_set, args->pollset);
grpc_pollset_set_destroy(args->pollset_set);
@@ -146,29 +170,19 @@ struct OnResolutionCallbackArg {
const char* uri_str = nullptr;
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
grpc_channel_args* result = nullptr;
- grpc_millis delay_before_second_resolution = 0;
};
-// Counter for the number of times a resolution notification callback has been
-// invoked.
-static int g_on_resolution_invocations_count;
-
// Set to true by the last callback in the resolution chain.
-bool g_all_callbacks_invoked;
+static bool g_all_callbacks_invoked;
-void on_fourth_resolution(void* arg, grpc_error* error) {
+static void on_second_resolution(void* arg, grpc_error* error) {
OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
grpc_channel_args_destroy(cb_arg->result);
GPR_ASSERT(error == GRPC_ERROR_NONE);
- ++g_on_resolution_invocations_count;
- gpr_log(GPR_INFO,
- "4th: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
- g_on_resolution_invocations_count, g_resolution_count);
- // In this case we expect to have incurred in another system-level resolution
- // because on_third_resolution slept for longer than the min resolution
- // period.
- GPR_ASSERT(g_on_resolution_invocations_count == 4);
- GPR_ASSERT(g_resolution_count == 3);
+ gpr_log(GPR_INFO, "2nd: g_resolution_count: %d", g_resolution_count);
+ // The resolution callback was not invoked until new data was
+ // available, which was delayed until after the cooldown period.
+ GPR_ASSERT(g_resolution_count == 2);
cb_arg->resolver.reset();
gpr_atm_rel_store(&g_iomgr_args.done_atm, 1);
gpr_mu_lock(g_iomgr_args.mu);
@@ -179,67 +193,13 @@ void on_fourth_resolution(void* arg, grpc_error* error) {
g_all_callbacks_invoked = true;
}
-void on_third_resolution(void* arg, grpc_error* error) {
- OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
- grpc_channel_args_destroy(cb_arg->result);
- GPR_ASSERT(error == GRPC_ERROR_NONE);
- ++g_on_resolution_invocations_count;
- gpr_log(GPR_INFO,
- "3rd: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
- g_on_resolution_invocations_count, g_resolution_count);
- // The timer set because of the previous re-resolution request fires, so a new
- // system-level resolution happened.
- GPR_ASSERT(g_on_resolution_invocations_count == 3);
- GPR_ASSERT(g_resolution_count == 2);
- grpc_core::ExecCtx::Get()->TestOnlySetNow(
- cb_arg->delay_before_second_resolution * 2);
- cb_arg->resolver->NextLocked(
- &cb_arg->result,
- GRPC_CLOSURE_CREATE(on_fourth_resolution, arg,
- grpc_combiner_scheduler(g_combiner)));
- cb_arg->resolver->RequestReresolutionLocked();
- gpr_mu_lock(g_iomgr_args.mu);
- GRPC_LOG_IF_ERROR("pollset_kick",
- grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
- gpr_mu_unlock(g_iomgr_args.mu);
-}
-
-void on_second_resolution(void* arg, grpc_error* error) {
- OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
- grpc_channel_args_destroy(cb_arg->result);
- GPR_ASSERT(error == GRPC_ERROR_NONE);
- ++g_on_resolution_invocations_count;
- gpr_log(GPR_INFO,
- "2nd: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
- g_on_resolution_invocations_count, g_resolution_count);
- // The resolution request for which this function is the callback happened
- // before the min resolution period. Therefore, no new system-level
- // resolutions happened, as indicated by g_resolution_count. But a resolution
- // timer was set to fire when the cooldown finishes.
- GPR_ASSERT(g_on_resolution_invocations_count == 2);
- GPR_ASSERT(g_resolution_count == 1);
- // Register a new callback to capture the timer firing.
- cb_arg->resolver->NextLocked(
- &cb_arg->result,
- GRPC_CLOSURE_CREATE(on_third_resolution, arg,
- grpc_combiner_scheduler(g_combiner)));
- gpr_mu_lock(g_iomgr_args.mu);
- GRPC_LOG_IF_ERROR("pollset_kick",
- grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
- gpr_mu_unlock(g_iomgr_args.mu);
-}
-
-void on_first_resolution(void* arg, grpc_error* error) {
+static void on_first_resolution(void* arg, grpc_error* error) {
OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
grpc_channel_args_destroy(cb_arg->result);
GPR_ASSERT(error == GRPC_ERROR_NONE);
- ++g_on_resolution_invocations_count;
- gpr_log(GPR_INFO,
- "1st: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
- g_on_resolution_invocations_count, g_resolution_count);
+ gpr_log(GPR_INFO, "1st: g_resolution_count: %d", g_resolution_count);
// There's one initial system-level resolution and one invocation of a
// notification callback (the current function).
- GPR_ASSERT(g_on_resolution_invocations_count == 1);
GPR_ASSERT(g_resolution_count == 1);
cb_arg->resolver->NextLocked(
&cb_arg->result,
@@ -265,9 +225,7 @@ static void start_test_under_combiner(void* arg, grpc_error* error) {
grpc_core::ResolverArgs args;
args.uri = uri;
args.combiner = g_combiner;
- g_on_resolution_invocations_count = 0;
g_resolution_count = 0;
- constexpr int kMinResolutionPeriodMs = 1000;
grpc_arg cooldown_arg;
cooldown_arg.key =
@@ -280,7 +238,6 @@ static void start_test_under_combiner(void* arg, grpc_error* error) {
res_cb_arg->resolver = factory->CreateResolver(args);
grpc_channel_args_destroy(cooldown_channel_args);
GPR_ASSERT(res_cb_arg->resolver != nullptr);
- res_cb_arg->delay_before_second_resolution = kMinResolutionPeriodMs;
// First resolution, would incur in system-level resolution.
res_cb_arg->resolver->NextLocked(
&res_cb_arg->result,
diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc
index 14caa3ea5d..f6696bf127 100644
--- a/test/core/client_channel/resolvers/fake_resolver_test.cc
+++ b/test/core/client_channel/resolvers/fake_resolver_test.cc
@@ -124,8 +124,8 @@ static void test_fake_resolver() {
build_fake_resolver(combiner, response_generator.get());
GPR_ASSERT(resolver.get() != nullptr);
// Test 1: normal resolution.
- // next_results != NULL, reresolution_results == NULL, last_used_results ==
- // NULL. Expected response is next_results.
+ // next_results != NULL, reresolution_results == NULL.
+ // Expected response is next_results.
grpc_channel_args* results = create_new_resolver_result();
on_resolution_arg on_res_arg = create_on_resolution_arg(results);
grpc_closure* on_resolution = GRPC_CLOSURE_CREATE(
@@ -137,10 +137,9 @@ static void test_fake_resolver() {
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
// Test 2: update resolution.
- // next_results != NULL, reresolution_results == NULL, last_used_results !=
- // NULL. Expected response is next_results.
+ // next_results != NULL, reresolution_results == NULL.
+ // Expected response is next_results.
results = create_new_resolver_result();
- grpc_channel_args* last_used_results = grpc_channel_args_copy(results);
on_res_arg = create_on_resolution_arg(results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
@@ -150,21 +149,9 @@ static void test_fake_resolver() {
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 3: fallback re-resolution.
- // next_results == NULL, reresolution_results == NULL, last_used_results !=
- // NULL. Expected response is last_used_results.
- on_res_arg = create_on_resolution_arg(last_used_results);
- on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
- grpc_combiner_scheduler(combiner));
- resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
- // Trigger a re-resolution.
- resolver->RequestReresolutionLocked();
- grpc_core::ExecCtx::Get()->Flush();
- GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
- grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 4: normal re-resolution.
- // next_results == NULL, reresolution_results != NULL, last_used_results !=
- // NULL. Expected response is reresolution_results.
+ // Test 3: normal re-resolution.
+ // next_results == NULL, reresolution_results != NULL.
+ // Expected response is reresolution_results.
grpc_channel_args* reresolution_results = create_new_resolver_result();
on_res_arg =
create_on_resolution_arg(grpc_channel_args_copy(reresolution_results));
@@ -180,9 +167,9 @@ static void test_fake_resolver() {
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 5: repeat re-resolution.
- // next_results == NULL, reresolution_results != NULL, last_used_results !=
- // NULL. Expected response is reresolution_results.
+ // Test 4: repeat re-resolution.
+ // next_results == NULL, reresolution_results != NULL.
+ // Expected response is reresolution_results.
on_res_arg = create_on_resolution_arg(reresolution_results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
@@ -192,11 +179,10 @@ static void test_fake_resolver() {
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 6: normal resolution.
- // next_results != NULL, reresolution_results != NULL, last_used_results !=
- // NULL. Expected response is next_results.
+ // Test 5: normal resolution.
+ // next_results != NULL, reresolution_results != NULL.
+ // Expected response is next_results.
results = create_new_resolver_result();
- last_used_results = grpc_channel_args_copy(results);
on_res_arg = create_on_resolution_arg(results);
on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
grpc_combiner_scheduler(combiner));
@@ -206,23 +192,7 @@ static void test_fake_resolver() {
grpc_core::ExecCtx::Get()->Flush();
GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 7: fallback re-resolution.
- // next_results == NULL, reresolution_results == NULL, last_used_results !=
- // NULL. Expected response is last_used_results.
- on_res_arg = create_on_resolution_arg(last_used_results);
- on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
- grpc_combiner_scheduler(combiner));
- resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
- // Reset reresolution_results.
- response_generator->SetReresolutionResponse(nullptr);
- // Flush here to guarantee that reresolution_results has been reset.
- grpc_core::ExecCtx::Get()->Flush();
- // Trigger a re-resolution.
- resolver->RequestReresolutionLocked();
- grpc_core::ExecCtx::Get()->Flush();
- GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
- grpc_timeout_seconds_to_deadline(5)) != nullptr);
- // Test 8: no-op.
+ // Test 6: no-op.
// Requesting a new resolution without setting the response shouldn't trigger
// the resolution callback.
memset(&on_res_arg, 0, sizeof(on_res_arg));
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/compression/BUILD b/test/core/compression/BUILD
index b60390dbfe..532972c784 100644
--- a/test/core/compression/BUILD
+++ b/test/core/compression/BUILD
@@ -55,7 +55,7 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "stream_compress_test",
+ name = "stream_compression_test",
srcs = ["stream_compression_test.cc"],
language = "C++",
deps = [
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/BUILD b/test/core/end2end/BUILD
index 37999a98d1..398e8a2d9a 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -18,7 +18,7 @@ licenses(["notice"]) # Apache v2
grpc_package(name = "test/core/end2end")
-load(":generate_tests.bzl", "grpc_end2end_tests")
+load(":generate_tests.bzl", "grpc_end2end_tests", "grpc_end2end_nosec_tests")
grpc_cc_library(
name = "cq_verifier",
@@ -46,7 +46,6 @@ grpc_cc_library(
visibility = ["//test:__subpackages__"],
)
-
grpc_cc_library(
name = "http_proxy",
srcs = ["fixtures/http_proxy_fixture.cc"],
@@ -128,7 +127,7 @@ grpc_cc_test(
srcs = ["inproc_callback_test.cc"],
language = "C++",
deps = [
- ':end2end_tests',
+ ":end2end_tests",
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
@@ -177,6 +176,8 @@ grpc_cc_test(
grpc_end2end_tests()
+grpc_end2end_nosec_tests()
+
grpc_cc_test(
name = "h2_ssl_session_reuse_test",
srcs = ["h2_ssl_session_reuse_test.cc"],
@@ -185,11 +186,11 @@ grpc_cc_test(
],
language = "C++",
deps = [
- ':end2end_tests',
- '//:gpr',
- '//:grpc',
- '//:tsi',
- '//test/core/util:gpr_test_util',
- '//test/core/util:grpc_test_util',
+ ":end2end_tests",
+ "//:gpr",
+ "//:grpc",
+ "//:tsi",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
],
)
diff --git a/test/core/end2end/end2end_test.sh b/test/core/end2end/end2end_test.sh
index 5bfb253090..6b23d848be 100755
--- a/test/core/end2end/end2end_test.sh
+++ b/test/core/end2end/end2end_test.sh
@@ -15,7 +15,7 @@
# 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.
-if [ -z "$3" ]
+if [ -n "$3" ]
then
export GRPC_POLL_STRATEGY=$3
fi
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc
index cdefcf4546..eb71e24c77 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.cc
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc
@@ -53,7 +53,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server));
+ grpc_server_get_channel_args(f->server), 0);
}
typedef struct {
diff --git a/test/core/end2end/fixtures/h2_sockpair.cc b/test/core/end2end/fixtures/h2_sockpair.cc
index 8966cb38d4..904bda5458 100644
--- a/test/core/end2end/fixtures/h2_sockpair.cc
+++ b/test/core/end2end/fixtures/h2_sockpair.cc
@@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server));
+ grpc_server_get_channel_args(f->server), 0);
}
typedef struct {
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.cc b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
index ebf4162217..45f7f254ac 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.cc
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
@@ -47,7 +47,7 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_endpoint_pair* sfd = static_cast<grpc_endpoint_pair*>(f->fixture_data);
grpc_endpoint_add_to_pollset(sfd->server, grpc_cq_pollset(f->cq));
grpc_server_setup_transport(f->server, transport, nullptr,
- grpc_server_get_channel_args(f->server));
+ grpc_server_get_channel_args(f->server), 0);
}
typedef struct {
diff --git a/test/core/end2end/fixtures/http_proxy_fixture.cc b/test/core/end2end/fixtures/http_proxy_fixture.cc
index ea9c000efb..b235c10165 100644
--- a/test/core/end2end/fixtures/http_proxy_fixture.cc
+++ b/test/core/end2end/fixtures/http_proxy_fixture.cc
@@ -52,6 +52,16 @@
#include "test/core/util/port.h"
struct grpc_end2end_http_proxy {
+ grpc_end2end_http_proxy()
+ : proxy_name(nullptr),
+ server(nullptr),
+ channel_args(nullptr),
+ mu(nullptr),
+ pollset(nullptr),
+ combiner(nullptr) {
+ gpr_ref_init(&users, 1);
+ combiner = grpc_combiner_create();
+ }
char* proxy_name;
grpc_core::Thread thd;
grpc_tcp_server* server;
@@ -519,11 +529,7 @@ static void thread_main(void* arg) {
grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(
grpc_channel_args* args) {
grpc_core::ExecCtx exec_ctx;
- grpc_end2end_http_proxy* proxy =
- static_cast<grpc_end2end_http_proxy*>(gpr_malloc(sizeof(*proxy)));
- memset(proxy, 0, sizeof(*proxy));
- proxy->combiner = grpc_combiner_create();
- gpr_ref_init(&proxy->users, 1);
+ grpc_end2end_http_proxy* proxy = grpc_core::New<grpc_end2end_http_proxy>();
// Construct proxy address.
const int proxy_port = grpc_pick_unused_port_or_die();
gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
@@ -573,7 +579,7 @@ void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
GRPC_CLOSURE_CREATE(destroy_pollset, proxy->pollset,
grpc_schedule_on_exec_ctx));
GRPC_COMBINER_UNREF(proxy->combiner, "test");
- gpr_free(proxy);
+ grpc_core::Delete(proxy);
}
const char* grpc_end2end_http_proxy_get_proxy_name(
diff --git a/test/core/end2end/fixtures/proxy.cc b/test/core/end2end/fixtures/proxy.cc
index 042c858b4c..869b6e846d 100644
--- a/test/core/end2end/fixtures/proxy.cc
+++ b/test/core/end2end/fixtures/proxy.cc
@@ -30,6 +30,17 @@
#include "test/core/util/port.h"
struct grpc_end2end_proxy {
+ grpc_end2end_proxy()
+ : proxy_port(nullptr),
+ server_port(nullptr),
+ cq(nullptr),
+ server(nullptr),
+ client(nullptr),
+ shutdown(false),
+ new_call(nullptr) {
+ memset(&new_call_details, 0, sizeof(new_call_details));
+ memset(&new_call_metadata, 0, sizeof(new_call_metadata));
+ }
grpc_core::Thread thd;
char* proxy_port;
char* server_port;
@@ -79,9 +90,7 @@ grpc_end2end_proxy* grpc_end2end_proxy_create(const grpc_end2end_proxy_def* def,
int proxy_port = grpc_pick_unused_port_or_die();
int server_port = grpc_pick_unused_port_or_die();
- grpc_end2end_proxy* proxy =
- static_cast<grpc_end2end_proxy*>(gpr_malloc(sizeof(*proxy)));
- memset(proxy, 0, sizeof(*proxy));
+ grpc_end2end_proxy* proxy = grpc_core::New<grpc_end2end_proxy>();
gpr_join_host_port(&proxy->proxy_port, "localhost", proxy_port);
gpr_join_host_port(&proxy->server_port, "localhost", server_port);
@@ -128,7 +137,7 @@ void grpc_end2end_proxy_destroy(grpc_end2end_proxy* proxy) {
grpc_channel_destroy(proxy->client);
grpc_completion_queue_destroy(proxy->cq);
grpc_call_details_destroy(&proxy->new_call_details);
- gpr_free(proxy);
+ grpc_core::Delete(proxy);
}
static void unrefpc(proxy_call* pc, const char* reason) {
diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc
index eacfd4a8c3..e97a544e12 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.cc
+++ b/test/core/end2end/fuzzers/api_fuzzer.cc
@@ -390,6 +390,10 @@ grpc_ares_request* my_dns_lookup_ares_locked(
return nullptr;
}
+static void my_cancel_ares_request_locked(grpc_ares_request* request) {
+ GPR_ASSERT(request == nullptr);
+}
+
////////////////////////////////////////////////////////////////////////////////
// client connection
@@ -416,7 +420,7 @@ static void do_connect(void* arg, grpc_error* error) {
grpc_transport* transport =
grpc_create_chttp2_transport(nullptr, server, false);
- grpc_server_setup_transport(g_server, transport, nullptr, nullptr);
+ grpc_server_setup_transport(g_server, transport, nullptr, nullptr, 0);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
GRPC_CLOSURE_SCHED(fc->closure, GRPC_ERROR_NONE);
@@ -705,6 +709,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
}
grpc_set_resolver_impl(&fuzzer_resolver);
grpc_dns_lookup_ares_locked = my_dns_lookup_ares_locked;
+ grpc_cancel_ares_request_locked = my_cancel_ares_request_locked;
GPR_ASSERT(g_channel == nullptr);
GPR_ASSERT(g_server == nullptr);
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index c719d0fa84..a79fe5ad95 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -34,27 +34,22 @@
"\x1Egrpc.max_request_message_bytes"
"\x1Fgrpc.max_response_message_bytes"
"$/grpc.lb.v1.LoadBalancer/BalanceLoad"
+"\x1C/grpc.health.v1.Health/Watch"
"\x07deflate"
"\x04gzip"
"\x0Bstream/gzip"
-"\x010"
-"\x08identity"
-"\x08trailers"
-"\x10application/grpc"
-"\x04POST"
-"\x03200"
-"\x03404"
-"\x04http"
-"\x05https"
-"\x04grpc"
"\x03GET"
-"\x03PUT"
+"\x04POST"
"\x01/"
"\x0B/index.html"
+"\x04http"
+"\x05https"
+"\x03200"
"\x03204"
"\x03206"
"\x03304"
"\x03400"
+"\x03404"
"\x03500"
"\x0Eaccept-charset"
"\x0Dgzip, deflate"
@@ -83,7 +78,6 @@
"\x08if-range"
"\x13if-unmodified-since"
"\x0Dlast-modified"
-"\x0Blb-cost-bin"
"\x04link"
"\x08location"
"\x0Cmax-forwards"
@@ -100,36 +94,32 @@
"\x04vary"
"\x03via"
"\x10www-authenticate"
+"\x010"
+"\x08identity"
+"\x08trailers"
+"\x10application/grpc"
+"\x04grpc"
+"\x03PUT"
+"\x0Blb-cost-bin"
"\x10identity,deflate"
"\x0Didentity,gzip"
"\x0Cdeflate,gzip"
"\x15identity,deflate,gzip"
-"\x00\x0Bgrpc-status\x010"
-"\x00\x0Bgrpc-status\x011"
-"\x00\x0Bgrpc-status\x012"
-"\x00\x0Dgrpc-encoding\x08identity"
-"\x00\x0Dgrpc-encoding\x04gzip"
-"\x00\x0Dgrpc-encoding\x07deflate"
-"\x00\x02te\x08trailers"
-"\x00\x0Ccontent-type\x10application/grpc"
-"\x00\x07:method\x04POST"
-"\x00\x07:status\x03200"
-"\x00\x07:status\x03404"
-"\x00\x07:scheme\x04http"
-"\x00\x07:scheme\x05https"
-"\x00\x07:scheme\x04grpc"
"\x00\x0A:authority\x00"
"\x00\x07:method\x03GET"
-"\x00\x07:method\x03PUT"
+"\x00\x07:method\x04POST"
"\x00\x05:path\x01/"
"\x00\x05:path\x0B/index.html"
+"\x00\x07:scheme\x04http"
+"\x00\x07:scheme\x05https"
+"\x00\x07:status\x03200"
"\x00\x07:status\x03204"
"\x00\x07:status\x03206"
"\x00\x07:status\x03304"
"\x00\x07:status\x03400"
+"\x00\x07:status\x03404"
"\x00\x07:status\x03500"
"\x00\x0Eaccept-charset\x00"
-"\x00\x0Faccept-encoding\x00"
"\x00\x0Faccept-encoding\x0Dgzip, deflate"
"\x00\x0Faccept-language\x00"
"\x00\x0Daccept-ranges\x00"
@@ -140,8 +130,6 @@
"\x00\x0Dauthorization\x00"
"\x00\x0Dcache-control\x00"
"\x00\x13content-disposition\x00"
-"\x00\x10content-encoding\x08identity"
-"\x00\x10content-encoding\x04gzip"
"\x00\x10content-encoding\x00"
"\x00\x10content-language\x00"
"\x00\x0Econtent-length\x00"
@@ -161,8 +149,6 @@
"\x00\x08if-range\x00"
"\x00\x13if-unmodified-since\x00"
"\x00\x0Dlast-modified\x00"
-"\x00\x08lb-token\x00"
-"\x00\x0Blb-cost-bin\x00"
"\x00\x04link\x00"
"\x00\x08location\x00"
"\x00\x0Cmax-forwards\x00"
@@ -180,6 +166,21 @@
"\x00\x04vary\x00"
"\x00\x03via\x00"
"\x00\x10www-authenticate\x00"
+"\x00\x0Bgrpc-status\x010"
+"\x00\x0Bgrpc-status\x011"
+"\x00\x0Bgrpc-status\x012"
+"\x00\x0Dgrpc-encoding\x08identity"
+"\x00\x0Dgrpc-encoding\x04gzip"
+"\x00\x0Dgrpc-encoding\x07deflate"
+"\x00\x02te\x08trailers"
+"\x00\x0Ccontent-type\x10application/grpc"
+"\x00\x07:scheme\x04grpc"
+"\x00\x07:method\x03PUT"
+"\x00\x0Faccept-encoding\x00"
+"\x00\x10content-encoding\x08identity"
+"\x00\x10content-encoding\x04gzip"
+"\x00\x08lb-token\x00"
+"\x00\x0Blb-cost-bin\x00"
"\x00\x14grpc-accept-encoding\x08identity"
"\x00\x14grpc-accept-encoding\x07deflate"
"\x00\x14grpc-accept-encoding\x10identity,deflate"
diff --git a/test/core/end2end/fuzzers/server_fuzzer.cc b/test/core/end2end/fuzzers/server_fuzzer.cc
index 248c34cbc1..bd686215dd 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.cc
+++ b/test/core/end2end/fuzzers/server_fuzzer.cc
@@ -62,7 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
grpc_server_start(server);
grpc_transport* transport =
grpc_create_chttp2_transport(nullptr, mock_endpoint, false);
- grpc_server_setup_transport(server, transport, nullptr, nullptr);
+ grpc_server_setup_transport(server, transport, nullptr, nullptr, 0);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
grpc_call* call1 = nullptr;
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 39b9ba4a19..601d3bac38 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -41,7 +41,7 @@ local_fixture_options = default_secure_fixture_options._replace(
fd_unsecure_fixture_options = default_unsecure_fixture_options._replace(
dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'],
exclude_iomgrs=['uv'], client_channel=False)
-inproc_fixture_options = default_unsecure_fixture_options._replace(
+inproc_fixture_options = default_secure_fixture_options._replace(
dns_resolver=False, fullstack=False, name_resolution=False,
supports_compression=False, is_inproc=True, is_http2=False,
supports_write_buffering=False, client_channel=False)
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index db2886d8e3..81956db841 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -13,277 +13,451 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
-
-load("//bazel:grpc_build_system.bzl", "grpc_sh_test", "grpc_cc_binary", "grpc_cc_library")
-
"""Generates the appropriate build.json data for all the end2end tests."""
+load("//bazel:grpc_build_system.bzl", "grpc_cc_binary", "grpc_cc_library")
-def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
- name_resolution=True, secure=True, tracing=False,
- platforms=['windows', 'linux', 'mac', 'posix'],
- is_inproc=False, is_http2=True, supports_proxy_auth=False,
- supports_write_buffering=True, client_channel=True):
- return struct(
- fullstack=fullstack,
- includes_proxy=includes_proxy,
- dns_resolver=dns_resolver,
- name_resolution=name_resolution,
- secure=secure,
- tracing=tracing,
- is_inproc=is_inproc,
- is_http2=is_http2,
- supports_proxy_auth=supports_proxy_auth,
- supports_write_buffering=supports_write_buffering,
- client_channel=client_channel,
- #platforms=platforms,
- )
+POLLERS = ["epollex", "epoll1", "poll", "poll-cv"]
+def _fixture_options(
+ fullstack = True,
+ includes_proxy = False,
+ dns_resolver = True,
+ name_resolution = True,
+ secure = True,
+ tracing = False,
+ _platforms = ["windows", "linux", "mac", "posix"],
+ is_inproc = False,
+ is_http2 = True,
+ supports_proxy_auth = False,
+ supports_write_buffering = True,
+ client_channel = True):
+ return struct(
+ fullstack = fullstack,
+ includes_proxy = includes_proxy,
+ dns_resolver = dns_resolver,
+ name_resolution = name_resolution,
+ secure = secure,
+ tracing = tracing,
+ is_inproc = is_inproc,
+ is_http2 = is_http2,
+ supports_proxy_auth = supports_proxy_auth,
+ supports_write_buffering = supports_write_buffering,
+ client_channel = client_channel,
+ #_platforms=_platforms,
+ )
# maps fixture name to whether it requires the security library
END2END_FIXTURES = {
- 'h2_compress': fixture_options(),
- 'h2_census': fixture_options(),
+ "h2_compress": _fixture_options(),
+ "h2_census": _fixture_options(),
# TODO(juanlishen): This is disabled for now, but should be considered to re-enable once we have
# decided how the load reporting service should be enabled.
- #'h2_load_reporting': fixture_options(),
- 'h2_fakesec': fixture_options(),
- 'h2_fd': fixture_options(dns_resolver=False, fullstack=False,
- client_channel=False,
- platforms=['linux', 'mac', 'posix']),
- 'h2_full': fixture_options(),
- 'h2_full+pipe': fixture_options(platforms=['linux']),
- 'h2_full+trace': fixture_options(tracing=True),
- 'h2_full+workarounds': fixture_options(),
- 'h2_http_proxy': fixture_options(supports_proxy_auth=True),
- 'h2_oauth2': fixture_options(),
- 'h2_proxy': fixture_options(includes_proxy=True),
- 'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False,
- client_channel=False),
- 'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False,
- client_channel=False),
- 'h2_sockpair+trace': fixture_options(fullstack=False, dns_resolver=False,
- tracing=True, client_channel=False),
- 'h2_ssl': fixture_options(secure=True),
- 'h2_local': fixture_options(secure=True, dns_resolver=False, platforms=['linux', 'mac', 'posix']),
- 'h2_ssl_proxy': fixture_options(includes_proxy=True, secure=True),
- 'h2_uds': fixture_options(dns_resolver=False,
- platforms=['linux', 'mac', 'posix']),
- 'inproc': fixture_options(fullstack=False, dns_resolver=False,
- name_resolution=False, is_inproc=True,
- is_http2=False, supports_write_buffering=False,
- client_channel=False),
+ #'h2_load_reporting': _fixture_options(),
+ "h2_fakesec": _fixture_options(),
+ "h2_fd": _fixture_options(
+ dns_resolver = False,
+ fullstack = False,
+ client_channel = False,
+ _platforms = ["linux", "mac", "posix"],
+ ),
+ "h2_full": _fixture_options(),
+ "h2_full+pipe": _fixture_options(_platforms = ["linux"]),
+ "h2_full+trace": _fixture_options(tracing = True),
+ "h2_full+workarounds": _fixture_options(),
+ "h2_http_proxy": _fixture_options(supports_proxy_auth = True),
+ "h2_oauth2": _fixture_options(),
+ "h2_proxy": _fixture_options(includes_proxy = True),
+ "h2_sockpair_1byte": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ ),
+ "h2_sockpair": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ ),
+ "h2_sockpair+trace": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ tracing = True,
+ client_channel = False,
+ ),
+ "h2_ssl": _fixture_options(secure = True),
+ "h2_local": _fixture_options(secure = True, dns_resolver = False, _platforms = ["linux", "mac", "posix"]),
+ "h2_ssl_proxy": _fixture_options(includes_proxy = True, secure = True),
+ "h2_uds": _fixture_options(
+ dns_resolver = False,
+ _platforms = ["linux", "mac", "posix"],
+ ),
+ "inproc": _fixture_options(
+ secure = True,
+ fullstack = False,
+ dns_resolver = False,
+ name_resolution = False,
+ is_inproc = True,
+ is_http2 = False,
+ supports_write_buffering = False,
+ client_channel = False,
+ ),
}
+# maps fixture name to whether it requires the security library
+END2END_NOSEC_FIXTURES = {
+ "h2_compress": _fixture_options(secure = False),
+ "h2_census": _fixture_options(secure = False),
+ # TODO(juanlishen): This is disabled for now, but should be considered to re-enable once we have
+ # decided how the load reporting service should be enabled.
+ #'h2_load_reporting': _fixture_options(),
+ "h2_fakesec": _fixture_options(),
+ "h2_fd": _fixture_options(
+ dns_resolver = False,
+ fullstack = False,
+ client_channel = False,
+ secure = False,
+ _platforms = ["linux", "mac", "posix"],
+ ),
+ "h2_full": _fixture_options(secure = False),
+ "h2_full+pipe": _fixture_options(secure = False, _platforms = ["linux"]),
+ "h2_full+trace": _fixture_options(secure = False, tracing = True),
+ "h2_full+workarounds": _fixture_options(secure = False),
+ "h2_http_proxy": _fixture_options(secure = False, supports_proxy_auth = True),
+ "h2_proxy": _fixture_options(secure = False, includes_proxy = True),
+ "h2_sockpair_1byte": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ secure = False,
+ ),
+ "h2_sockpair": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ secure = False,
+ ),
+ "h2_sockpair+trace": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ tracing = True,
+ secure = False,
+ client_channel = False,
+ ),
+ "h2_ssl": _fixture_options(secure = False),
+ "h2_ssl_proxy": _fixture_options(includes_proxy = True, secure = False),
+ "h2_uds": _fixture_options(
+ dns_resolver = False,
+ _platforms = ["linux", "mac", "posix"],
+ secure = False,
+ ),
+}
-def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
- proxyable=True, secure=False, traceable=False,
- exclude_inproc=False, needs_http2=False,
- needs_proxy_auth=False, needs_write_buffering=False,
- needs_client_channel=False):
- return struct(
- needs_fullstack=needs_fullstack,
- needs_dns=needs_dns,
- needs_names=needs_names,
- proxyable=proxyable,
- secure=secure,
- traceable=traceable,
- exclude_inproc=exclude_inproc,
- needs_http2=needs_http2,
- needs_proxy_auth=needs_proxy_auth,
- needs_write_buffering=needs_write_buffering,
- needs_client_channel=needs_client_channel,
- )
-
+def _test_options(
+ needs_fullstack = False,
+ needs_dns = False,
+ needs_names = False,
+ proxyable = True,
+ secure = False,
+ traceable = False,
+ exclude_inproc = False,
+ needs_http2 = False,
+ needs_proxy_auth = False,
+ needs_write_buffering = False,
+ needs_client_channel = False):
+ return struct(
+ needs_fullstack = needs_fullstack,
+ needs_dns = needs_dns,
+ needs_names = needs_names,
+ proxyable = proxyable,
+ secure = secure,
+ traceable = traceable,
+ exclude_inproc = exclude_inproc,
+ needs_http2 = needs_http2,
+ needs_proxy_auth = needs_proxy_auth,
+ needs_write_buffering = needs_write_buffering,
+ needs_client_channel = needs_client_channel,
+ )
# maps test names to options
END2END_TESTS = {
- 'bad_hostname': test_options(needs_names=True),
- 'bad_ping': test_options(needs_fullstack=True,proxyable=False),
- 'binary_metadata': test_options(),
- 'resource_quota_server': test_options(proxyable=False),
- 'call_creds': test_options(secure=True),
- 'call_host_override': test_options(needs_fullstack=True, needs_dns=True,
- needs_names=True),
- 'cancel_after_accept': test_options(),
- 'cancel_after_client_done': test_options(),
- 'cancel_after_invoke': test_options(),
- 'cancel_after_round_trip': test_options(),
- 'cancel_before_invoke': test_options(),
- 'cancel_in_a_vacuum': test_options(),
- 'cancel_with_status': test_options(),
- 'compressed_payload': test_options(proxyable=False, exclude_inproc=True),
- 'connectivity': test_options(needs_fullstack=True, needs_names=True,
- proxyable=False),
- 'channelz': test_options(),
- 'default_host': test_options(needs_fullstack=True, needs_dns=True,
- needs_names=True),
- 'disappearing_server': test_options(needs_fullstack=True,needs_names=True),
- 'empty_batch': test_options(),
- 'filter_causes_close': test_options(),
- 'filter_call_init_fails': test_options(),
- 'graceful_server_shutdown': test_options(exclude_inproc=True),
- 'hpack_size': test_options(proxyable=False, traceable=False,
- exclude_inproc=True),
- 'high_initial_seqno': test_options(),
- 'idempotent_request': test_options(),
- 'invoke_large_request': test_options(),
- 'keepalive_timeout': test_options(proxyable=False, needs_http2=True),
- 'large_metadata': test_options(),
- 'max_concurrent_streams': test_options(proxyable=False,
- exclude_inproc=True),
- 'max_connection_age': test_options(exclude_inproc=True),
- 'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
- 'max_message_length': test_options(),
- 'negative_deadline': test_options(),
- 'network_status_change': test_options(),
- 'no_error_on_hotpath': test_options(proxyable=False),
- 'no_logging': test_options(traceable=False),
- 'no_op': test_options(),
- 'payload': test_options(),
+ "bad_hostname": _test_options(needs_names = True),
+ "bad_ping": _test_options(needs_fullstack = True, proxyable = False),
+ "binary_metadata": _test_options(),
+ "resource_quota_server": _test_options(proxyable = False),
+ "call_creds": _test_options(secure = True),
+ "call_host_override": _test_options(
+ needs_fullstack = True,
+ needs_dns = True,
+ needs_names = True,
+ ),
+ "cancel_after_accept": _test_options(),
+ "cancel_after_client_done": _test_options(),
+ "cancel_after_invoke": _test_options(),
+ "cancel_after_round_trip": _test_options(),
+ "cancel_before_invoke": _test_options(),
+ "cancel_in_a_vacuum": _test_options(),
+ "cancel_with_status": _test_options(),
+ "compressed_payload": _test_options(proxyable = False, exclude_inproc = True),
+ "connectivity": _test_options(
+ needs_fullstack = True,
+ needs_names = True,
+ proxyable = False,
+ ),
+ "channelz": _test_options(),
+ "default_host": _test_options(
+ needs_fullstack = True,
+ needs_dns = True,
+ needs_names = True,
+ ),
+ "disappearing_server": _test_options(needs_fullstack = True, needs_names = True),
+ "empty_batch": _test_options(),
+ "filter_causes_close": _test_options(),
+ "filter_call_init_fails": _test_options(),
+ "graceful_server_shutdown": _test_options(exclude_inproc = True),
+ "hpack_size": _test_options(
+ proxyable = False,
+ traceable = False,
+ exclude_inproc = True,
+ ),
+ "high_initial_seqno": _test_options(),
+ "idempotent_request": _test_options(),
+ "invoke_large_request": _test_options(),
+ "keepalive_timeout": _test_options(proxyable = False, needs_http2 = True),
+ "large_metadata": _test_options(),
+ "max_concurrent_streams": _test_options(
+ proxyable = False,
+ exclude_inproc = True,
+ ),
+ "max_connection_age": _test_options(exclude_inproc = True),
+ "max_connection_idle": _test_options(needs_fullstack = True, proxyable = False),
+ "max_message_length": _test_options(),
+ "negative_deadline": _test_options(),
+ "network_status_change": _test_options(),
+ "no_error_on_hotpath": _test_options(proxyable = False),
+ "no_logging": _test_options(traceable = False),
+ "no_op": _test_options(),
+ "payload": _test_options(),
# TODO(juanlishen): This is disabled for now because it depends on some generated functions in
# end2end_tests.cc, which are not generated because they would depend on OpenCensus while
# OpenCensus can only be built via Bazel so far.
- # 'load_reporting_hook': test_options(),
- 'ping_pong_streaming': test_options(),
- 'ping': test_options(needs_fullstack=True, proxyable=False),
- 'proxy_auth': test_options(needs_proxy_auth=True),
- 'registered_call': test_options(),
- 'request_with_flags': test_options(proxyable=False),
- 'request_with_payload': test_options(),
+ # 'load_reporting_hook': _test_options(),
+ "ping_pong_streaming": _test_options(),
+ "ping": _test_options(needs_fullstack = True, proxyable = False),
+ "proxy_auth": _test_options(needs_proxy_auth = True),
+ "registered_call": _test_options(),
+ "request_with_flags": _test_options(proxyable = False),
+ "request_with_payload": _test_options(),
# TODO(roth): Remove proxyable=False for all retry tests once we
# have a way for the proxy to propagate the fact that trailing
# metadata is available when initial metadata is returned.
# See https://github.com/grpc/grpc/issues/14467 for context.
- 'retry': test_options(needs_client_channel=True, proxyable=False),
- 'retry_cancellation': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_disabled': test_options(needs_client_channel=True, proxyable=False),
- 'retry_exceeds_buffer_size_in_initial_batch': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_exceeds_buffer_size_in_subsequent_batch': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_non_retriable_status': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_non_retriable_status_before_recv_trailing_metadata_started':
- test_options(needs_client_channel=True, proxyable=False),
- 'retry_recv_initial_metadata': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_recv_message': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_server_pushback_delay': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_server_pushback_disabled': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_streaming': test_options(needs_client_channel=True, proxyable=False),
- 'retry_streaming_after_commit': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_streaming_succeeds_before_replay_finished': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_throttled': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_too_many_attempts': test_options(needs_client_channel=True,
- proxyable=False),
- 'server_finishes_request': test_options(),
- 'shutdown_finishes_calls': test_options(),
- 'shutdown_finishes_tags': test_options(),
- 'simple_cacheable_request': test_options(),
- 'simple_delayed_request': test_options(needs_fullstack=True),
- 'simple_metadata': test_options(),
- 'simple_request': test_options(),
- 'streaming_error_response': test_options(),
- 'stream_compression_compressed_payload': test_options(proxyable=False,
- exclude_inproc=True),
- 'stream_compression_payload': test_options(exclude_inproc=True),
- 'stream_compression_ping_pong_streaming': test_options(exclude_inproc=True),
- 'trailing_metadata': test_options(),
- 'authority_not_supported': test_options(),
- 'filter_latency': test_options(),
- 'filter_status_code': test_options(),
- 'workaround_cronet_compression': test_options(),
- 'write_buffering': test_options(needs_write_buffering=True),
- 'write_buffering_at_end': test_options(needs_write_buffering=True),
+ "retry": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_cancellation": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_disabled": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_exceeds_buffer_size_in_initial_batch": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_exceeds_buffer_size_in_subsequent_batch": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_non_retriable_status": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_non_retriable_status_before_recv_trailing_metadata_started": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_recv_initial_metadata": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_recv_message": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_server_pushback_delay": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_server_pushback_disabled": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_streaming": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_streaming_after_commit": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_streaming_succeeds_before_replay_finished": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_throttled": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_too_many_attempts": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "server_finishes_request": _test_options(),
+ "shutdown_finishes_calls": _test_options(),
+ "shutdown_finishes_tags": _test_options(),
+ "simple_cacheable_request": _test_options(),
+ "simple_delayed_request": _test_options(needs_fullstack = True),
+ "simple_metadata": _test_options(),
+ "simple_request": _test_options(),
+ "streaming_error_response": _test_options(),
+ "stream_compression_compressed_payload": _test_options(
+ proxyable = False,
+ exclude_inproc = True,
+ ),
+ "stream_compression_payload": _test_options(exclude_inproc = True),
+ "stream_compression_ping_pong_streaming": _test_options(exclude_inproc = True),
+ "trailing_metadata": _test_options(),
+ "authority_not_supported": _test_options(),
+ "filter_latency": _test_options(),
+ "filter_status_code": _test_options(),
+ "workaround_cronet_compression": _test_options(),
+ "write_buffering": _test_options(needs_write_buffering = True),
+ "write_buffering_at_end": _test_options(needs_write_buffering = True),
}
-
-def compatible(fopt, topt):
- if topt.needs_fullstack:
- if not fopt.fullstack:
- return False
- if topt.needs_dns:
- if not fopt.dns_resolver:
- return False
- if topt.needs_names:
- if not fopt.name_resolution:
- return False
- if not topt.proxyable:
- if fopt.includes_proxy:
- return False
- if not topt.traceable:
- if fopt.tracing:
- return False
- if topt.exclude_inproc:
- if fopt.is_inproc:
- return False
- if topt.needs_http2:
- if not fopt.is_http2:
- return False
- if topt.needs_proxy_auth:
- if not fopt.supports_proxy_auth:
- return False
- if topt.needs_write_buffering:
- if not fopt.supports_write_buffering:
- return False
- if topt.needs_client_channel:
- if not fopt.client_channel:
- return False
- return True
-
+def _compatible(fopt, topt):
+ if topt.needs_fullstack:
+ if not fopt.fullstack:
+ return False
+ if topt.needs_dns:
+ if not fopt.dns_resolver:
+ return False
+ if topt.needs_names:
+ if not fopt.name_resolution:
+ return False
+ if not topt.proxyable:
+ if fopt.includes_proxy:
+ return False
+ if not topt.traceable:
+ if fopt.tracing:
+ return False
+ if topt.exclude_inproc:
+ if fopt.is_inproc:
+ return False
+ if topt.needs_http2:
+ if not fopt.is_http2:
+ return False
+ if topt.needs_proxy_auth:
+ if not fopt.supports_proxy_auth:
+ return False
+ if topt.needs_write_buffering:
+ if not fopt.supports_write_buffering:
+ return False
+ if topt.needs_client_channel:
+ if not fopt.client_channel:
+ return False
+ return True
def grpc_end2end_tests():
- grpc_cc_library(
- name = 'end2end_tests',
- srcs = ['end2end_tests.cc', 'end2end_test_utils.cc'] + [
- 'tests/%s.cc' % t
- for t in sorted(END2END_TESTS.keys())],
- hdrs = [
- 'tests/cancel_test_helpers.h',
- 'end2end_tests.h'
- ],
- language = "C++",
- deps = [
- ':cq_verifier',
- ':ssl_test_data',
- ':http_proxy',
- ':proxy',
- ]
- )
+ grpc_cc_library(
+ name = "end2end_tests",
+ srcs = ["end2end_tests.cc", "end2end_test_utils.cc"] + [
+ "tests/%s.cc" % t
+ for t in sorted(END2END_TESTS.keys())
+ ],
+ hdrs = [
+ "tests/cancel_test_helpers.h",
+ "end2end_tests.h",
+ ],
+ language = "C++",
+ deps = [
+ ":cq_verifier",
+ ":ssl_test_data",
+ ":http_proxy",
+ ":proxy",
+ ],
+ )
- for f, fopt in END2END_FIXTURES.items():
- grpc_cc_binary(
- name = '%s_test' % f,
- srcs = ['fixtures/%s.cc' % f],
- language = "C++",
- deps = [
- ':end2end_tests',
- '//test/core/util:grpc_test_util',
- '//:grpc',
- '//test/core/util:gpr_test_util',
- '//:gpr',
- ],
+ for f, fopt in END2END_FIXTURES.items():
+ grpc_cc_binary(
+ name = "%s_test" % f,
+ srcs = ["fixtures/%s.cc" % f],
+ language = "C++",
+ deps = [
+ ":end2end_tests",
+ "//test/core/util:grpc_test_util",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//:gpr",
+ ],
+ )
+ for t, topt in END2END_TESTS.items():
+ #print(_compatible(fopt, topt), f, t, fopt, topt)
+ if not _compatible(fopt, topt):
+ continue
+ for poller in POLLERS:
+ native.sh_test(
+ name = "%s_test@%s@poller=%s" % (f, t, poller),
+ data = [":%s_test" % f],
+ srcs = ["end2end_test.sh"],
+ args = [
+ "$(location %s_test)" % f,
+ t,
+ poller,
+ ],
+ )
+
+def grpc_end2end_nosec_tests():
+ grpc_cc_library(
+ name = "end2end_nosec_tests",
+ srcs = ["end2end_nosec_tests.cc", "end2end_test_utils.cc"] + [
+ "tests/%s.cc" % t
+ for t in sorted(END2END_TESTS.keys())
+ if not END2END_TESTS[t].secure
+ ],
+ hdrs = [
+ "tests/cancel_test_helpers.h",
+ "end2end_tests.h",
+ ],
+ language = "C++",
+ deps = [
+ ":cq_verifier",
+ ":ssl_test_data",
+ ":http_proxy",
+ ":proxy",
+ ],
)
- for t, topt in END2END_TESTS.items():
- #print(compatible(fopt, topt), f, t, fopt, topt)
- if not compatible(fopt, topt): continue
- for poller in POLLERS:
- native.sh_test(
- name = '%s_test@%s@poller=%s' % (f, t, poller),
- data = [':%s_test' % f],
- srcs = ['end2end_test.sh'],
- args = [
- '$(location %s_test)' % f,
- t,
- poller,
- ],
+
+ for f, fopt in END2END_NOSEC_FIXTURES.items():
+ if fopt.secure:
+ continue
+ grpc_cc_binary(
+ name = "%s_nosec_test" % f,
+ srcs = ["fixtures/%s.cc" % f],
+ language = "C++",
+ deps = [
+ ":end2end_nosec_tests",
+ "//test/core/util:grpc_test_util_unsecure",
+ "//:grpc_unsecure",
+ "//test/core/util:gpr_test_util",
+ "//:gpr",
+ ],
)
+ for t, topt in END2END_TESTS.items():
+ #print(_compatible(fopt, topt), f, t, fopt, topt)
+ if not _compatible(fopt, topt):
+ continue
+ if topt.secure:
+ continue
+ for poller in POLLERS:
+ native.sh_test(
+ name = "%s_nosec_test@%s@poller=%s" % (f, t, poller),
+ data = [":%s_nosec_test" % f],
+ srcs = ["end2end_test.sh"],
+ args = [
+ "$(location %s_nosec_test)" % f,
+ t,
+ poller,
+ ],
+ )
diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc
index 8904c3d325..3f1c5596ad 100644
--- a/test/core/end2end/goaway_server_test.cc
+++ b/test/core/end2end/goaway_server_test.cc
@@ -50,6 +50,8 @@ static grpc_ares_request* (*iomgr_dns_lookup_ares_locked)(
grpc_lb_addresses** addresses, bool check_grpclb,
char** service_config_json, grpc_combiner* combiner);
+static void (*iomgr_cancel_ares_request_locked)(grpc_ares_request* request);
+
static void set_resolve_port(int port) {
gpr_mu_lock(&g_mu);
g_resolve_port = port;
@@ -130,6 +132,12 @@ static grpc_ares_request* my_dns_lookup_ares_locked(
return nullptr;
}
+static void my_cancel_ares_request_locked(grpc_ares_request* request) {
+ if (request != nullptr) {
+ iomgr_cancel_ares_request_locked(request);
+ }
+}
+
int main(int argc, char** argv) {
grpc_completion_queue* cq;
cq_verifier* cqv;
@@ -143,7 +151,9 @@ int main(int argc, char** argv) {
default_resolver = grpc_resolve_address_impl;
grpc_set_resolver_impl(&test_resolver);
iomgr_dns_lookup_ares_locked = grpc_dns_lookup_ares_locked;
+ iomgr_cancel_ares_request_locked = grpc_cancel_ares_request_locked;
grpc_dns_lookup_ares_locked = my_dns_lookup_ares_locked;
+ grpc_cancel_ares_request_locked = my_cancel_ares_request_locked;
int was_cancelled1;
int was_cancelled2;
diff --git a/test/core/end2end/inproc_callback_test.cc b/test/core/end2end/inproc_callback_test.cc
index 0d6c7c75a8..310030046a 100644
--- a/test/core/end2end/inproc_callback_test.cc
+++ b/test/core/end2end/inproc_callback_test.cc
@@ -37,13 +37,16 @@ typedef struct inproc_fixture_data {
namespace {
template <typename F>
-class CQDeletingCallback : public grpc_core::CQCallbackInterface {
+class CQDeletingCallback : public grpc_experimental_completion_queue_functor {
public:
- explicit CQDeletingCallback(F f) : func_(f) {}
- ~CQDeletingCallback() override {}
- void Run(bool ok) override {
- func_(ok);
- grpc_core::Delete(this);
+ explicit CQDeletingCallback(F f) : func_(f) {
+ functor_run = &CQDeletingCallback::Run;
+ }
+ ~CQDeletingCallback() {}
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ auto* callback = static_cast<CQDeletingCallback*>(cb);
+ callback->func_(static_cast<bool>(ok));
+ grpc_core::Delete(callback);
}
private:
@@ -51,18 +54,24 @@ class CQDeletingCallback : public grpc_core::CQCallbackInterface {
};
template <typename F>
-grpc_core::CQCallbackInterface* NewDeletingCallback(F f) {
+grpc_experimental_completion_queue_functor* NewDeletingCallback(F f) {
return grpc_core::New<CQDeletingCallback<F>>(f);
}
-class ShutdownCallback : public grpc_core::CQCallbackInterface {
+class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
ShutdownCallback() : done_(false) {
+ functor_run = &ShutdownCallback::StaticRun;
gpr_mu_init(&mu_);
gpr_cv_init(&cv_);
}
- ~ShutdownCallback() override {}
- void Run(bool ok) override {
+ ~ShutdownCallback() {}
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ auto* callback = static_cast<ShutdownCallback*>(cb);
+ callback->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
gpr_log(GPR_DEBUG, "CQ shutdown notification invoked");
gpr_mu_lock(&mu_);
done_ = true;
@@ -170,7 +179,7 @@ static void verify_tags(gpr_timespec deadline) {
// This function creates a callback functor that emits the
// desired tag into the global tag set
-static grpc_core::CQCallbackInterface* tag(intptr_t t) {
+static grpc_experimental_completion_queue_functor* tag(intptr_t t) {
auto func = [t](bool ok) {
gpr_mu_lock(&tags_mu);
gpr_log(GPR_DEBUG, "Completing operation %" PRIdPTR, t);
diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc
index 533703a2be..922783aa0d 100644
--- a/test/core/end2end/tests/channelz.cc
+++ b/test/core/end2end/tests/channelz.cc
@@ -22,12 +22,14 @@
#include <string.h>
#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#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"
@@ -198,17 +200,23 @@ static void run_one_request(grpc_end2end_test_config config,
static void test_channelz(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f;
- grpc_arg client_a;
- client_a.type = GRPC_ARG_INTEGER;
- client_a.key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
- client_a.value.integer = true;
- grpc_channel_args client_args = {1, &client_a};
+ grpc_arg arg[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ 0),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true)};
+ grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg};
- f = begin_test(config, "test_channelz", &client_args, nullptr);
+ f = begin_test(config, "test_channelz", &args, &args);
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(f.client);
-
GPR_ASSERT(channelz_channel != nullptr);
+
+ grpc_core::channelz::ServerNode* channelz_server =
+ grpc_server_get_channelz_node(f.server);
+ GPR_ASSERT(channelz_server != nullptr);
+
char* json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
// nothing is present yet
@@ -231,16 +239,30 @@ 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\""));
- // channel tracing is not enables, so these should not be preset.
+ // channel tracing is not enabled, so these should not be preset.
GPR_ASSERT(nullptr == strstr(json, "\"trace\""));
GPR_ASSERT(nullptr == strstr(json, "\"description\":\"Channel created\""));
GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\""));
gpr_free(json);
+ json = channelz_server->RenderJsonString();
+ GPR_ASSERT(json != nullptr);
+ GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
+ // channel tracing is not enabled, so these should not be preset.
+ GPR_ASSERT(nullptr == strstr(json, "\"trace\""));
+ GPR_ASSERT(nullptr == strstr(json, "\"description\":\"Channel created\""));
+ GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\""));
+ gpr_free(json);
+
+ json = channelz_server->RenderServerSockets(0);
+ GPR_ASSERT(nullptr != strstr(json, "\"socketRef\":"));
+ gpr_free(json);
+
end_test(&f);
config.tear_down_data(&f);
}
@@ -248,30 +270,39 @@ static void test_channelz(grpc_end2end_test_config config) {
static void test_channelz_with_channel_trace(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f;
- grpc_arg client_a[2];
- client_a[0].type = GRPC_ARG_INTEGER;
- client_a[0].key =
- const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
- client_a[0].value.integer = 5;
- client_a[1].type = GRPC_ARG_INTEGER;
- client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
- client_a[1].value.integer = true;
- grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
-
- f = begin_test(config, "test_channelz_with_channel_trace", &client_args,
- nullptr);
+ grpc_arg arg[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ 1024 * 1024),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true)};
+ grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg};
+
+ f = begin_test(config, "test_channelz_with_channel_trace", &args, &args);
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(f.client);
-
GPR_ASSERT(channelz_channel != nullptr);
+
+ grpc_core::channelz::ServerNode* channelz_server =
+ grpc_server_get_channelz_node(f.server);
+ GPR_ASSERT(channelz_server != nullptr);
+
+ run_one_request(config, f, true);
+
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\""));
gpr_free(json);
+ json = channelz_server->RenderJsonString();
+ GPR_ASSERT(json != nullptr);
+ GPR_ASSERT(nullptr != strstr(json, "\"trace\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Server created\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\""));
+ gpr_free(json);
+
end_test(&f);
config.tear_down_data(&f);
}
@@ -279,7 +310,15 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) {
static void test_channelz_disabled(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f;
- f = begin_test(config, "test_channelz_disabled", nullptr, nullptr);
+ grpc_arg arg[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ 0),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), false)};
+ grpc_channel_args args = {GPR_ARRAY_SIZE(arg), arg};
+
+ f = begin_test(config, "test_channelz_disabled", &args, &args);
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(f.client);
GPR_ASSERT(channelz_channel == nullptr);
diff --git a/test/core/end2end/tests/filter_status_code.cc b/test/core/end2end/tests/filter_status_code.cc
index ba3cbfa6d1..5ffc3d00a3 100644
--- a/test/core/end2end/tests/filter_status_code.cc
+++ b/test/core/end2end/tests/filter_status_code.cc
@@ -16,6 +16,14 @@
*
*/
+/* This test verifies -
+ * 1) grpc_call_final_info passed to the filters on destroying a call contains
+ * the proper status.
+ * 2) If the response has both an HTTP status code and a gRPC status code, then
+ * we should prefer the gRPC status code as mentioned in
+ * https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md
+ */
+
#include "test/core/end2end/end2end_tests.h"
#include <limits.h>
@@ -249,6 +257,22 @@ typedef struct final_status_data {
grpc_call_stack* call;
} final_status_data;
+static void server_start_transport_stream_op_batch(
+ grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
+ auto* data = static_cast<final_status_data*>(elem->call_data);
+ if (data->call == g_server_call_stack) {
+ if (op->send_initial_metadata) {
+ auto* batch = op->payload->send_initial_metadata.send_initial_metadata;
+ if (batch->idx.named.status != nullptr) {
+ /* Replace the HTTP status with 404 */
+ grpc_metadata_batch_substitute(batch, batch->idx.named.status,
+ GRPC_MDELEM_STATUS_404);
+ }
+ }
+ }
+ grpc_call_next_op(elem, op);
+}
+
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
final_status_data* data = static_cast<final_status_data*>(elem->call_data);
@@ -307,7 +331,7 @@ static const grpc_channel_filter test_client_filter = {
"client_filter_status_code"};
static const grpc_channel_filter test_server_filter = {
- grpc_call_next_op,
+ server_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(final_status_data),
init_call_elem,
diff --git a/test/core/end2end/tests/keepalive_timeout.cc b/test/core/end2end/tests/keepalive_timeout.cc
index 1ee5285027..5f6a36dac4 100644
--- a/test/core/end2end/tests/keepalive_timeout.cc
+++ b/test/core/end2end/tests/keepalive_timeout.cc
@@ -195,7 +195,7 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) {
char* details_str = grpc_slice_to_c_string(details);
char* method_str = grpc_slice_to_c_string(call_details.method);
- GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
+ GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "keepalive watchdog timeout"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
diff --git a/test/core/end2end/tests/retry_streaming.cc b/test/core/end2end/tests/retry_streaming.cc
index d06d124ca4..94a27faf7b 100644
--- a/test/core/end2end/tests/retry_streaming.cc
+++ b/test/core/end2end/tests/retry_streaming.cc
@@ -28,6 +28,9 @@
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
@@ -133,25 +136,30 @@ static void test_retry_streaming(grpc_end2end_test_config config) {
int was_cancelled = 2;
char* peer;
- grpc_arg arg;
- arg.type = GRPC_ARG_STRING;
- arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
- arg.value.string = const_cast<char*>(
- "{\n"
- " \"methodConfig\": [ {\n"
- " \"name\": [\n"
- " { \"service\": \"service\", \"method\": \"method\" }\n"
- " ],\n"
- " \"retryPolicy\": {\n"
- " \"maxAttempts\": 3,\n"
- " \"initialBackoff\": \"1s\",\n"
- " \"maxBackoff\": \"120s\",\n"
- " \"backoffMultiplier\": 1.6,\n"
- " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
- " }\n"
- " } ]\n"
- "}");
- grpc_channel_args client_args = {1, &arg};
+ grpc_arg args[] = {
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
+ 1024 * 8),
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true),
+ grpc_channel_arg_string_create(
+ const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
+ const_cast<char*>(
+ "{\n"
+ " \"methodConfig\": [ {\n"
+ " \"name\": [\n"
+ " { \"service\": \"service\", \"method\": \"method\" }\n"
+ " ],\n"
+ " \"retryPolicy\": {\n"
+ " \"maxAttempts\": 3,\n"
+ " \"initialBackoff\": \"1s\",\n"
+ " \"maxBackoff\": \"120s\",\n"
+ " \"backoffMultiplier\": 1.6,\n"
+ " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+ " }\n"
+ " } ]\n"
+ "}"))};
+ grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f =
begin_test(config, "retry_streaming", &client_args, nullptr);
@@ -161,6 +169,9 @@ static void test_retry_streaming(grpc_end2end_test_config config) {
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
nullptr, deadline, nullptr);
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(f.client);
+
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
@@ -384,6 +395,20 @@ static void test_retry_streaming(grpc_end2end_test_config config) {
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
+ GPR_ASSERT(channelz_channel != nullptr);
+ 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\""));
+ GPR_ASSERT(nullptr != strstr(json, "Resolution event"));
+ GPR_ASSERT(nullptr != strstr(json, "Created new LB policy"));
+ GPR_ASSERT(nullptr != strstr(json, "Service config changed"));
+ GPR_ASSERT(nullptr != strstr(json, "Address list became non-empty"));
+ GPR_ASSERT(nullptr != strstr(json, "Channel state change to CONNECTING"));
+ gpr_free(json);
+
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
@@ -414,6 +439,7 @@ static void test_retry_streaming(grpc_end2end_test_config config) {
void retry_streaming(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+
test_retry_streaming(config);
}
diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc
index 941d9ae319..9c018962f8 100644
--- a/test/core/end2end/tests/simple_request.cc
+++ b/test/core/end2end/tests/simple_request.cc
@@ -108,7 +108,9 @@ static void simple_request_body(grpc_end2end_test_config config,
grpc_stats_data* after =
static_cast<grpc_stats_data*>(gpr_malloc(sizeof(grpc_stats_data)));
+#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
grpc_stats_collect(before);
+#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
@@ -225,17 +227,18 @@ static void simple_request_body(grpc_end2end_test_config config,
cq_verifier_destroy(cqv);
+ int expected_calls = 1;
+ if (config.feature_mask & FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) {
+ expected_calls *= 2;
+ }
+#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
+
grpc_stats_collect(after);
char* stats = grpc_stats_data_as_json(after);
gpr_log(GPR_DEBUG, "%s", stats);
gpr_free(stats);
- int expected_calls = 1;
- if (config.feature_mask & FEATURE_MASK_SUPPORTS_REQUEST_PROXYING) {
- expected_calls *= 2;
- }
-#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
GPR_ASSERT(after->counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] -
before->counters[GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED] ==
expected_calls);
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/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc
index e9d1eb2c76..73e0773b31 100644
--- a/test/core/gprpp/inlined_vector_test.cc
+++ b/test/core/gprpp/inlined_vector_test.cc
@@ -264,6 +264,32 @@ TEST(InlinedVectorTest, MoveAssignmentAllocatedAllocated) {
EXPECT_EQ(move_assigned.data(), old_data);
}
+TEST(InlinedVectorTest, PopBackInlined) {
+ InlinedVector<UniquePtr<int>, 2> v;
+ // Add two elements, pop one out
+ v.push_back(MakeUnique<int>(3));
+ EXPECT_EQ(1UL, v.size());
+ EXPECT_EQ(3, *v[0]);
+ v.push_back(MakeUnique<int>(5));
+ EXPECT_EQ(2UL, v.size());
+ EXPECT_EQ(5, *v[1]);
+ v.pop_back();
+ EXPECT_EQ(1UL, v.size());
+}
+
+TEST(InlinedVectorTest, PopBackAllocated) {
+ const int kInlinedSize = 2;
+ InlinedVector<UniquePtr<int>, kInlinedSize> v;
+ // Add elements to ensure allocated backing.
+ for (size_t i = 0; i < kInlinedSize + 1; ++i) {
+ v.push_back(MakeUnique<int>(3));
+ EXPECT_EQ(i + 1, v.size());
+ }
+ size_t sz = v.size();
+ v.pop_back();
+ EXPECT_EQ(sz - 1, v.size());
+}
+
} // namespace testing
} // namespace grpc_core
diff --git a/test/core/gprpp/ref_counted_test.cc b/test/core/gprpp/ref_counted_test.cc
index f85a2e4675..62a3ea4d53 100644
--- a/test/core/gprpp/ref_counted_test.cc
+++ b/test/core/gprpp/ref_counted_test.cc
@@ -29,7 +29,10 @@ namespace {
class Foo : public RefCounted<Foo> {
public:
- Foo() {}
+ Foo() {
+ static_assert(std::has_virtual_destructor<Foo>::value,
+ "PolymorphicRefCount doesn't have a virtual dtor");
+ }
};
TEST(RefCounted, Basic) {
@@ -45,6 +48,28 @@ TEST(RefCounted, ExtraRef) {
foo->Unref();
}
+class FooNonPolymorphic
+ : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
+ public:
+ FooNonPolymorphic() {
+ static_assert(!std::has_virtual_destructor<FooNonPolymorphic>::value,
+ "NonPolymorphicRefCount has a virtual dtor");
+ }
+};
+
+TEST(RefCountedNonPolymorphic, Basic) {
+ FooNonPolymorphic* foo = New<FooNonPolymorphic>();
+ foo->Unref();
+}
+
+TEST(RefCountedNonPolymorphic, ExtraRef) {
+ FooNonPolymorphic* foo = New<FooNonPolymorphic>();
+ RefCountedPtr<FooNonPolymorphic> foop = foo->Ref();
+ foop.release();
+ foo->Unref();
+ foo->Unref();
+}
+
// Note: We use DebugOnlyTraceFlag instead of TraceFlag to ensure that
// things build properly in both debug and non-debug cases.
DebugOnlyTraceFlag foo_tracer(true, "foo");
@@ -66,6 +91,26 @@ TEST(RefCountedWithTracing, Basic) {
foo->Unref(DEBUG_LOCATION, "original_ref");
}
+class FooNonPolymorphicWithTracing
+ : public RefCountedWithTracing<FooNonPolymorphicWithTracing,
+ NonPolymorphicRefCount> {
+ public:
+ FooNonPolymorphicWithTracing() : RefCountedWithTracing(&foo_tracer) {}
+};
+
+TEST(RefCountedNonPolymorphicWithTracing, Basic) {
+ FooNonPolymorphicWithTracing* foo = New<FooNonPolymorphicWithTracing>();
+ RefCountedPtr<FooNonPolymorphicWithTracing> foop =
+ foo->Ref(DEBUG_LOCATION, "extra_ref");
+ foop.release();
+ foo->Unref(DEBUG_LOCATION, "extra_ref");
+ // Can use the no-argument methods, too.
+ foop = foo->Ref();
+ foop.release();
+ foo->Unref();
+ foo->Unref(DEBUG_LOCATION, "original_ref");
+}
+
} // namespace
} // namespace testing
} // namespace grpc_core
diff --git a/test/core/handshake/readahead_handshaker_server_ssl.cc b/test/core/handshake/readahead_handshaker_server_ssl.cc
index 97e9c20ee4..14d96b5d89 100644
--- a/test/core/handshake/readahead_handshaker_server_ssl.cc
+++ b/test/core/handshake/readahead_handshaker_server_ssl.cc
@@ -75,6 +75,7 @@ static grpc_handshaker* readahead_handshaker_create() {
static void readahead_handshaker_factory_add_handshakers(
grpc_handshaker_factory* hf, const grpc_channel_args* args,
+ grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_handshake_manager_add(handshake_mgr, readahead_handshaker_create());
}
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 675d9e6278..70ee83acd2 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -40,6 +40,7 @@ grpc_cc_library(
grpc_cc_test(
name = "combiner_test",
srcs = ["combiner_test.cc"],
+ data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
language = "C++",
deps = [
"//:gpr",
@@ -47,7 +48,6 @@ grpc_cc_test(
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
)
grpc_cc_test(
@@ -89,18 +89,6 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "ev_epollsig_linux_test",
- srcs = ["ev_epollsig_linux_test.cc"],
- language = "C++",
- deps = [
- "//:gpr",
- "//:grpc",
- "//test/core/util:gpr_test_util",
- "//test/core/util:grpc_test_util",
- ],
-)
-
-grpc_cc_test(
name = "fd_conservation_posix_test",
srcs = ["fd_conservation_posix_test.cc"],
language = "C++",
@@ -136,7 +124,6 @@ grpc_cc_test(
],
)
-
grpc_cc_test(
name = "load_file_test",
srcs = ["load_file_test.cc"],
@@ -150,8 +137,8 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "pollset_set_test",
- srcs = ["pollset_set_test.cc"],
+ name = "resolve_address_posix_test",
+ srcs = ["resolve_address_posix_test.cc"],
language = "C++",
deps = [
"//:gpr",
@@ -162,8 +149,11 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "resolve_address_posix_test",
- srcs = ["resolve_address_posix_test.cc"],
+ name = "resolve_address_using_ares_resolver_test",
+ srcs = ["resolve_address_test.cc"],
+ args = [
+ "--resolver=ares",
+ ],
language = "C++",
deps = [
"//:gpr",
@@ -174,8 +164,11 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "resolve_address_test",
+ name = "resolve_address_using_native_resolver_test",
srcs = ["resolve_address_test.cc"],
+ args = [
+ "--resolver=native",
+ ],
language = "C++",
deps = [
"//:gpr",
@@ -258,7 +251,6 @@ grpc_cc_test(
],
)
-
grpc_cc_test(
name = "tcp_server_posix_test",
srcs = ["tcp_server_posix_test.cc"],
diff --git a/test/core/iomgr/buffer_list_test.cc b/test/core/iomgr/buffer_list_test.cc
index 1086e42fcc..e104e8e91a 100644
--- a/test/core/iomgr/buffer_list_test.cc
+++ b/test/core/iomgr/buffer_list_test.cc
@@ -75,8 +75,8 @@ static void TestVerifierCalledOnAckVerifier(void* arg,
static void TestVerifierCalledOnAck() {
struct sock_extended_err serr;
serr.ee_data = 213;
- serr.ee_info = SCM_TSTAMP_ACK;
- struct scm_timestamping tss;
+ serr.ee_info = grpc_core::SCM_TSTAMP_ACK;
+ struct grpc_core::scm_timestamping tss;
tss.ts[0].tv_sec = 123;
tss.ts[0].tv_nsec = 456;
grpc_core::grpc_tcp_set_write_timestamps_callback(
diff --git a/test/core/iomgr/error_test.cc b/test/core/iomgr/error_test.cc
index a1628a1f71..d78a8c2af3 100644
--- a/test/core/iomgr/error_test.cc
+++ b/test/core/iomgr/error_test.cc
@@ -187,16 +187,6 @@ static void test_os_error() {
GRPC_ERROR_UNREF(error);
}
-static void test_special() {
- grpc_error* error = GRPC_ERROR_NONE;
- error = grpc_error_add_child(
- error, GRPC_ERROR_CREATE_FROM_STATIC_STRING("test child"));
- intptr_t i;
- GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &i));
- GPR_ASSERT(i == GRPC_STATUS_OK);
- GRPC_ERROR_UNREF(error);
-}
-
static void test_overflow() {
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Overflow");
@@ -235,7 +225,6 @@ int main(int argc, char** argv) {
test_os_error();
test_create_referencing();
test_create_referencing_many();
- test_special();
test_overflow();
grpc_shutdown();
diff --git a/test/core/iomgr/ev_epollsig_linux_test.cc b/test/core/iomgr/ev_epollsig_linux_test.cc
deleted file mode 100644
index 28c9dd408c..0000000000
--- a/test/core/iomgr/ev_epollsig_linux_test.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- *
- * Copyright 2015 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 "src/core/lib/iomgr/port.h"
-
-/* This test only relevant on linux systems where epoll() is available */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/gprpp/thd.h"
-#include "src/core/lib/iomgr/iomgr.h"
-#include "test/core/util/test_config.h"
-
-typedef struct test_pollset {
- grpc_pollset* pollset;
- gpr_mu* mu;
-} test_pollset;
-
-typedef struct test_fd {
- int inner_fd;
- grpc_fd* fd;
-} test_fd;
-
-/* num_fds should be an even number */
-static void test_fd_init(test_fd* tfds, int* fds, int num_fds) {
- int i;
- int r;
-
- /* Create some dummy file descriptors. Currently using pipe file descriptors
- * for this test but we could use any other type of file descriptors. Also,
- * since pipe() used in this test creates two fds in each call, num_fds should
- * be an even number */
- GPR_ASSERT((num_fds % 2) == 0);
- for (i = 0; i < num_fds; i = i + 2) {
- r = pipe(fds + i);
- if (r != 0) {
- gpr_log(GPR_ERROR, "Error in creating pipe. %d (%s)", errno,
- strerror(errno));
- return;
- }
- }
-
- for (i = 0; i < num_fds; i++) {
- tfds[i].inner_fd = fds[i];
- tfds[i].fd = grpc_fd_create(fds[i], "test_fd", false);
- }
-}
-
-static void test_fd_cleanup(test_fd* tfds, int num_fds) {
- int release_fd;
- int i;
-
- for (i = 0; i < num_fds; i++) {
- grpc_fd_shutdown(tfds[i].fd,
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup"));
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
- grpc_core::ExecCtx::Get()->Flush();
-
- GPR_ASSERT(release_fd == tfds[i].inner_fd);
- close(tfds[i].inner_fd);
- }
-}
-
-static void test_pollset_init(test_pollset* pollsets, int num_pollsets) {
- int i;
- for (i = 0; i < num_pollsets; i++) {
- pollsets[i].pollset =
- static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(pollsets[i].pollset, &pollsets[i].mu);
- }
-}
-
-static void destroy_pollset(void* p, grpc_error* error) {
- grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
-}
-
-static void test_pollset_cleanup(test_pollset* pollsets, int num_pollsets) {
- grpc_closure destroyed;
- int i;
-
- for (i = 0; i < num_pollsets; i++) {
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].pollset,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(pollsets[i].pollset, &destroyed);
-
- grpc_core::ExecCtx::Get()->Flush();
- gpr_free(pollsets[i].pollset);
- }
-}
-
- /*
- * Cases to test:
- * case 1) Polling islands of both fd and pollset are NULL
- * case 2) Polling island of fd is NULL but that of pollset is not-NULL
- * case 3) Polling island of fd is not-NULL but that of pollset is NULL
- * case 4) Polling islands of both fd and pollset are not-NULL and:
- * case 4.1) Polling islands of fd and pollset are equal
- * case 4.2) Polling islands of fd and pollset are NOT-equal (This results
- * in a merge)
- * */
-
-#define NUM_FDS 8
-#define NUM_POLLSETS 4
-
-static void test_add_fd_to_pollset() {
- grpc_core::ExecCtx exec_ctx;
- test_fd tfds[NUM_FDS];
- int fds[NUM_FDS];
- test_pollset pollsets[NUM_POLLSETS];
- void* expected_pi = nullptr;
- int i;
-
- test_fd_init(tfds, fds, NUM_FDS);
- test_pollset_init(pollsets, NUM_POLLSETS);
-
- /*Step 1.
- * Create three polling islands (This will exercise test case 1 and 2) with
- * the following configuration:
- * polling island 0 = { fds:0,1,2, pollsets:0}
- * polling island 1 = { fds:3,4, pollsets:1}
- * polling island 2 = { fds:5,6,7 pollsets:2}
- *
- *Step 2.
- * Add pollset 3 to polling island 0 (by adding fds 0 and 1 to pollset 3)
- * (This will exercise test cases 3 and 4.1). The configuration becomes:
- * polling island 0 = { fds:0,1,2, pollsets:0,3} <<< pollset 3 added here
- * polling island 1 = { fds:3,4, pollsets:1}
- * polling island 2 = { fds:5,6,7 pollsets:2}
- *
- *Step 3.
- * Merge polling islands 0 and 1 by adding fd 0 to pollset 1 (This will
- * exercise test case 4.2). The configuration becomes:
- * polling island (merged) = {fds: 0,1,2,3,4, pollsets: 0,1,3}
- * polling island 2 = {fds: 5,6,7 pollsets: 2}
- *
- *Step 4.
- * Finally do one more merge by adding fd 3 to pollset 2.
- * polling island (merged) = {fds: 0,1,2,3,4,5,6,7, pollsets: 0,1,2,3}
- */
-
- /* == Step 1 == */
- for (i = 0; i <= 2; i++) {
- grpc_pollset_add_fd(pollsets[0].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- for (i = 3; i <= 4; i++) {
- grpc_pollset_add_fd(pollsets[1].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- for (i = 5; i <= 7; i++) {
- grpc_pollset_add_fd(pollsets[2].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* == Step 2 == */
- for (i = 0; i <= 1; i++) {
- grpc_pollset_add_fd(pollsets[3].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* == Step 3 == */
- grpc_pollset_add_fd(pollsets[1].pollset, tfds[0].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* == Step 4 == */
- grpc_pollset_add_fd(pollsets[2].pollset, tfds[3].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* All polling islands are merged at this point */
-
- /* Compare Fd:0's polling island with that of all other Fds */
- expected_pi = grpc_fd_get_polling_island(tfds[0].fd);
- for (i = 1; i < NUM_FDS; i++) {
- GPR_ASSERT(grpc_are_polling_islands_equal(
- expected_pi, grpc_fd_get_polling_island(tfds[i].fd)));
- }
-
- /* Compare Fd:0's polling island with that of all other pollsets */
- for (i = 0; i < NUM_POLLSETS; i++) {
- GPR_ASSERT(grpc_are_polling_islands_equal(
- expected_pi, grpc_pollset_get_polling_island(pollsets[i].pollset)));
- }
-
- test_fd_cleanup(tfds, NUM_FDS);
- test_pollset_cleanup(pollsets, NUM_POLLSETS);
-}
-
-#undef NUM_FDS
-#undef NUM_POLLSETS
-
-typedef struct threading_shared {
- gpr_mu* mu;
- grpc_pollset* pollset;
- grpc_wakeup_fd* wakeup_fd;
- grpc_fd* wakeup_desc;
- grpc_closure on_wakeup;
- int wakeups;
-} threading_shared;
-
-static __thread int thread_wakeups = 0;
-
-static void test_threading_loop(void* arg) {
- threading_shared* shared = static_cast<threading_shared*>(arg);
- while (thread_wakeups < 1000000) {
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- gpr_mu_lock(shared->mu);
- GPR_ASSERT(GRPC_LOG_IF_ERROR(
- "pollset_work",
- grpc_pollset_work(shared->pollset, &worker, GRPC_MILLIS_INF_FUTURE)));
- gpr_mu_unlock(shared->mu);
- }
-}
-
-static void test_threading_wakeup(void* arg, grpc_error* error) {
- threading_shared* shared = static_cast<threading_shared*>(arg);
- ++shared->wakeups;
- ++thread_wakeups;
- if (error == GRPC_ERROR_NONE) {
- GPR_ASSERT(GRPC_LOG_IF_ERROR(
- "consume_wakeup", grpc_wakeup_fd_consume_wakeup(shared->wakeup_fd)));
- grpc_fd_notify_on_read(shared->wakeup_desc, &shared->on_wakeup);
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_next",
- grpc_wakeup_fd_wakeup(shared->wakeup_fd)));
- }
-}
-
-static void test_threading(void) {
- threading_shared shared;
- shared.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(shared.pollset, &shared.mu);
-
- grpc_core::Thread thds[10];
- for (auto& th : thds) {
- th = grpc_core::Thread("test_thread", test_threading_loop, &shared);
- th.Start();
- }
- grpc_wakeup_fd fd;
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
- shared.wakeup_fd = &fd;
- shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup", false);
- shared.wakeups = 0;
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_add_fd(shared.pollset, shared.wakeup_desc);
- grpc_fd_notify_on_read(
- shared.wakeup_desc,
- GRPC_CLOSURE_INIT(&shared.on_wakeup, test_threading_wakeup, &shared,
- grpc_schedule_on_exec_ctx));
- }
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_first",
- grpc_wakeup_fd_wakeup(shared.wakeup_fd)));
- for (auto& th : thds) {
- th.Join();
- }
- fd.read_fd = 0;
- grpc_wakeup_fd_destroy(&fd);
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED);
- grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr, "done");
- grpc_pollset_shutdown(shared.pollset,
- GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset,
- grpc_schedule_on_exec_ctx));
- }
- gpr_free(shared.pollset);
-}
-
-int main(int argc, char** argv) {
- const char* poll_strategy = nullptr;
- grpc_test_init(argc, argv);
- grpc_init();
- {
- grpc_core::ExecCtx exec_ctx;
-
- poll_strategy = grpc_get_poll_strategy_name();
- if (poll_strategy != nullptr && strcmp(poll_strategy, "epollsig") == 0) {
- test_add_fd_to_pollset();
- test_threading();
- } else {
- gpr_log(GPR_INFO,
- "Skipping the test. The test is only relevant for 'epollsig' "
- "strategy. and the current strategy is: '%s'",
- poll_strategy);
- }
- }
-
- grpc_shutdown();
- return 0;
-}
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-int main(int argc, char** argv) { return 0; }
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/test/core/iomgr/pollset_set_test.cc b/test/core/iomgr/pollset_set_test.cc
deleted file mode 100644
index 1aae1daa02..0000000000
--- a/test/core/iomgr/pollset_set_test.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- *
- * Copyright 2016 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 "src/core/lib/iomgr/port.h"
-
-/* This test only relevant on linux systems where epoll is available */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/iomgr.h"
-#include "test/core/util/test_config.h"
-
-/*******************************************************************************
- * test_pollset_set
- */
-
-typedef struct test_pollset_set {
- grpc_pollset_set* pss;
-} test_pollset_set;
-
-void init_test_pollset_sets(test_pollset_set* pollset_sets, const int num_pss) {
- for (int i = 0; i < num_pss; i++) {
- pollset_sets[i].pss = grpc_pollset_set_create();
- }
-}
-
-void cleanup_test_pollset_sets(test_pollset_set* pollset_sets,
- const int num_pss) {
- for (int i = 0; i < num_pss; i++) {
- grpc_pollset_set_destroy(pollset_sets[i].pss);
- pollset_sets[i].pss = nullptr;
- }
-}
-
-/*******************************************************************************
- * test_pollset
- */
-
-typedef struct test_pollset {
- grpc_pollset* ps;
- gpr_mu* mu;
-} test_pollset;
-
-static void init_test_pollsets(test_pollset* pollsets, const int num_pollsets) {
- for (int i = 0; i < num_pollsets; i++) {
- pollsets[i].ps =
- static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(pollsets[i].ps, &pollsets[i].mu);
- }
-}
-
-static void destroy_pollset(void* p, grpc_error* error) {
- grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
-}
-
-static void cleanup_test_pollsets(test_pollset* pollsets,
- const int num_pollsets) {
- grpc_closure destroyed;
- for (int i = 0; i < num_pollsets; i++) {
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].ps,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(pollsets[i].ps, &destroyed);
-
- grpc_core::ExecCtx::Get()->Flush();
- gpr_free(pollsets[i].ps);
- pollsets[i].ps = nullptr;
- }
-}
-
-/*******************************************************************************
- * test_fd
- */
-
-typedef struct test_fd {
- grpc_fd* fd;
- grpc_wakeup_fd wakeup_fd;
-
- bool is_on_readable_called; /* Is on_readable closure is called ? */
- grpc_closure on_readable; /* Closure to call when this fd is readable */
-} test_fd;
-
-void on_readable(void* tfd, grpc_error* error) {
- (static_cast<test_fd*>(tfd))->is_on_readable_called = true;
-}
-
-static void reset_test_fd(test_fd* tfd) {
- tfd->is_on_readable_called = false;
-
- GRPC_CLOSURE_INIT(&tfd->on_readable, on_readable, tfd,
- grpc_schedule_on_exec_ctx);
- grpc_fd_notify_on_read(tfd->fd, &tfd->on_readable);
-}
-
-static void init_test_fds(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd));
- tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd),
- "test_fd", false);
- reset_test_fd(&tfds[i]);
- }
-}
-
-static void cleanup_test_fds(test_fd* tfds, const int num_fds) {
- int release_fd;
-
- for (int i = 0; i < num_fds; i++) {
- grpc_fd_shutdown(tfds[i].fd,
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("fd cleanup"));
- grpc_core::ExecCtx::Get()->Flush();
-
- /* grpc_fd_orphan frees the memory allocated for grpc_fd. Normally it also
- * calls close() on the underlying fd. In our case, we are using
- * grpc_wakeup_fd and we would like to destroy it ourselves (by calling
- * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the
- * underlying fd, call it with a non-NULL 'release_fd' parameter */
- grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd);
- }
-}
-
-static void make_test_fds_readable(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_wakeup(&tfds[i].wakeup_fd));
- }
-}
-
-static void verify_readable_and_reset(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- /* Verify that the on_readable callback was called */
- GPR_ASSERT(tfds[i].is_on_readable_called);
-
- /* Reset the tfd[i] structure */
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_wakeup_fd_consume_wakeup(&tfds[i].wakeup_fd));
- reset_test_fd(&tfds[i]);
- }
-}
-
-/*******************************************************************************
- * Main tests
- */
-
-/* Test some typical scenarios in pollset_set */
-static void pollset_set_test_basic() {
- /* We construct the following structure for this test:
- *
- * +---> FD0 (Added before PSS1, PS1 and PS2 are added to PSS0)
- * |
- * +---> FD5 (Added after PSS1, PS1 and PS2 are added to PSS0)
- * |
- * |
- * | +---> FD1 (Added before PSS1 is added to PSS0)
- * | |
- * | +---> FD6 (Added after PSS1 is added to PSS0)
- * | |
- * +---> PSS1--+ +--> FD2 (Added before PS0 is added to PSS1)
- * | | |
- * | +---> PS0---+
- * | |
- * PSS0---+ +--> FD7 (Added after PS0 is added to PSS1)
- * |
- * |
- * | +---> FD3 (Added before PS1 is added to PSS0)
- * | |
- * +---> PS1---+
- * | |
- * | +---> FD8 (Added after PS1 added to PSS0)
- * |
- * |
- * | +---> FD4 (Added before PS2 is added to PSS0)
- * | |
- * +---> PS2---+
- * |
- * +---> FD9 (Added after PS2 is added to PSS0)
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[10];
- test_pollset pollsets[3];
- test_pollset_set pollset_sets[2];
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = GPR_ARRAY_SIZE(pollsets);
- const int num_pss = GPR_ARRAY_SIZE(pollset_sets);
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(pollsets, num_ps);
- init_test_pollset_sets(pollset_sets, num_pss);
-
- /* Construct the pollset_set/pollset/fd tree (see diagram above) */
-
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_add_fd(pollsets[0].ps, tfds[2].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[3].fd);
- grpc_pollset_add_fd(pollsets[2].ps, tfds[4].fd);
-
- grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
-
- grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollsets[0].ps);
- grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[1].ps);
- grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[2].ps);
-
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[5].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[6].fd);
-
- grpc_pollset_add_fd(pollsets[0].ps, tfds[7].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[8].fd);
- grpc_pollset_add_fd(pollsets[2].ps, tfds[9].fd);
-
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Test that if any FD in the above structure is readable, it is observable by
- * doing grpc_pollset_work on any pollset
- *
- * For every pollset, do the following:
- * - (Ensure that all FDs are in reset state)
- * - Make all FDs readable
- * - Call grpc_pollset_work() on the pollset
- * - Flush the exec_ctx
- * - Verify that on_readable call back was called for all FDs (and
- * reset the FDs)
- * */
- for (int i = 0; i < num_ps; i++) {
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollsets[i].mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollsets[i].ps, &worker, deadline));
- gpr_mu_unlock(pollsets[i].mu);
-
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* Test tear down */
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[5].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[6].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollsets[0].ps);
- grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[1].ps);
- grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[2].ps);
-
- grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(pollsets, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
-}
-
-/* Same FD added multiple times to the pollset_set tree */
-void pollset_set_test_dup_fds() {
- /* We construct the following structure for this test:
- *
- * +---> FD0
- * |
- * |
- * PSS0---+
- * | +---> FD0 (also under PSS0)
- * | |
- * +---> PSS1--+ +--> FD1 (also under PSS1)
- * | |
- * +---> PS ---+
- * | |
- * | +--> FD2
- * +---> FD1
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[3];
- test_pollset pollset;
- test_pollset_set pollset_sets[2];
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = 1;
- const int num_pss = GPR_ARRAY_SIZE(pollset_sets);
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(&pollset, num_ps);
- init_test_pollset_sets(pollset_sets, num_pss);
-
- /* Construct the structure */
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_add_fd(pollset.ps, tfds[1].fd);
- grpc_pollset_add_fd(pollset.ps, tfds[2].fd);
-
- grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollset.ps);
- grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
-
- /* Test. Make all FDs readable and make sure that can be observed by doing a
- * grpc_pollset_work on the pollset 'PS' */
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollset.mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollset.ps, &worker, deadline));
- gpr_mu_unlock(pollset.mu);
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Tear down */
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollset.ps);
- grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(&pollset, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
-}
-
-/* Pollset_set with an empty pollset */
-void pollset_set_test_empty_pollset() {
- /* We construct the following structure for this test:
- *
- * +---> PS0 (EMPTY)
- * |
- * +---> FD0
- * |
- * PSS0---+
- * | +---> FD1
- * | |
- * +---> PS1--+
- * |
- * +---> FD2
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[3];
- test_pollset pollsets[2];
- test_pollset_set pollset_set;
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = GPR_ARRAY_SIZE(pollsets);
- const int num_pss = 1;
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(pollsets, num_ps);
- init_test_pollset_sets(&pollset_set, num_pss);
-
- /* Construct the structure */
- grpc_pollset_set_add_fd(pollset_set.pss, tfds[0].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[1].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[2].fd);
-
- grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[0].ps);
- grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[1].ps);
-
- /* Test. Make all FDs readable and make sure that can be observed by doing
- * grpc_pollset_work on the empty pollset 'PS0' */
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollsets[0].mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollsets[0].ps, &worker, deadline));
- gpr_mu_unlock(pollsets[0].mu);
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Tear down */
- grpc_pollset_set_del_fd(pollset_set.pss, tfds[0].fd);
- grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[0].ps);
- grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[1].ps);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(pollsets, num_ps);
- cleanup_test_pollset_sets(&pollset_set, num_pss);
-}
-
-int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
- grpc_init();
- {
- grpc_core::ExecCtx exec_ctx;
- const char* poll_strategy = grpc_get_poll_strategy_name();
-
- if (poll_strategy != nullptr &&
- (strcmp(poll_strategy, "epollsig") == 0 ||
- strcmp(poll_strategy, "epoll-threadpool") == 0)) {
- pollset_set_test_basic();
- pollset_set_test_dup_fds();
- pollset_set_test_empty_pollset();
- } else {
- gpr_log(GPR_INFO,
- "Skipping the test. The test is only relevant for 'epoll' "
- "strategy. and the current strategy is: '%s'",
- poll_strategy);
- }
- }
- grpc_shutdown();
- return 0;
-}
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-int main(int argc, char** argv) { return 0; }
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/test/core/iomgr/resolve_address_test.cc b/test/core/iomgr/resolve_address_test.cc
index 2fb831a6a4..8d69bab5b1 100644
--- a/test/core/iomgr/resolve_address_test.cc
+++ b/test/core/iomgr/resolve_address_test.cc
@@ -22,8 +22,14 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
+
+#include <string.h>
+
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "test/core/util/cmdline.h"
#include "test/core/util/test_config.h"
static gpr_timespec test_deadline(void) {
@@ -240,6 +246,31 @@ static void test_unparseable_hostports(void) {
}
int main(int argc, char** argv) {
+ // First set the resolver type based off of --resolver
+ const char* resolver_type = nullptr;
+ gpr_cmdline* cl = gpr_cmdline_create("resolve address test");
+ gpr_cmdline_add_string(cl, "resolver", "Resolver type (ares or native)",
+ &resolver_type);
+ // In case that there are more than one argument on the command line,
+ // --resolver will always be the first one, so only parse the first argument
+ // (other arguments may be unknown to cl)
+ gpr_cmdline_parse(cl, argc > 2 ? 2 : argc, argv);
+ const char* cur_resolver = gpr_getenv("GRPC_DNS_RESOLVER");
+ if (cur_resolver != nullptr && strlen(cur_resolver) != 0) {
+ gpr_log(GPR_INFO, "Warning: overriding resolver setting of %s",
+ cur_resolver);
+ }
+ if (gpr_stricmp(resolver_type, "native") == 0) {
+ gpr_setenv("GRPC_DNS_RESOLVER", "native");
+ } else if (gpr_stricmp(resolver_type, "ares") == 0) {
+#ifndef GRPC_UV
+ gpr_setenv("GRPC_DNS_RESOLVER", "ares");
+#endif
+ } else {
+ gpr_log(GPR_ERROR, "--resolver_type was not set to ares or native");
+ abort();
+ }
+ // Run the test.
grpc_test_init(argc, argv);
grpc_init();
{
@@ -250,10 +281,18 @@ int main(int argc, char** argv) {
test_missing_default_port();
test_ipv6_with_port();
test_ipv6_without_port();
- test_invalid_ip_addresses();
- test_unparseable_hostports();
+ if (gpr_stricmp(resolver_type, "ares") != 0) {
+ // These tests can trigger DNS queries to the nearby nameserver
+ // that need to come back in order for the test to succeed.
+ // c-ares is prone to not using the local system caches that the
+ // native getaddrinfo implementations take advantage of, so running
+ // these unit tests under c-ares risks flakiness.
+ test_invalid_ip_addresses();
+ test_unparseable_hostports();
+ }
grpc_executor_shutdown();
}
+ gpr_cmdline_destroy(cl);
grpc_shutdown();
return 0;
diff --git a/test/core/iomgr/tcp_client_posix_test.cc b/test/core/iomgr/tcp_client_posix_test.cc
index a4c38af86f..90fc5aecfc 100644
--- a/test/core/iomgr/tcp_client_posix_test.cc
+++ b/test/core/iomgr/tcp_client_posix_test.cc
@@ -170,7 +170,7 @@ void test_fails(void) {
break;
case GRPC_TIMERS_NOT_CHECKED:
polling_deadline = 0;
- /* fall through */
+ // fallthrough
case GRPC_TIMERS_CHECKED_AND_EMPTY:
GPR_ASSERT(GRPC_LOG_IF_ERROR(
"pollset_work",
diff --git a/test/core/iomgr/tcp_client_uv_test.cc b/test/core/iomgr/tcp_client_uv_test.cc
index 0c6250ed7f..27f894e3f3 100644
--- a/test/core/iomgr/tcp_client_uv_test.cc
+++ b/test/core/iomgr/tcp_client_uv_test.cc
@@ -129,6 +129,7 @@ void test_succeeds(void) {
uv_close((uv_handle_t*)svr_handle, close_cb);
gpr_mu_unlock(g_mu);
+ grpc_core::ExecCtx::Get()->Flush();
}
void test_fails(void) {
@@ -165,7 +166,7 @@ void test_fails(void) {
break;
case GRPC_TIMERS_NOT_CHECKED:
polling_deadline = grpc_timespec_to_millis_round_up(now);
- /* fall through */
+ // fallthrough
case GRPC_TIMERS_CHECKED_AND_EMPTY:
GPR_ASSERT(GRPC_LOG_IF_ERROR(
"pollset_work",
@@ -178,6 +179,7 @@ void test_fails(void) {
}
gpr_mu_unlock(g_mu);
+ grpc_core::ExecCtx::Get()->Flush();
}
static void destroy_pollset(void* p, grpc_error* error) {
@@ -186,21 +188,22 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_core::ExecCtx exec_ctx;
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size()));
- grpc_pollset_init(g_pollset, &g_mu);
-
- test_succeeds();
- gpr_log(GPR_ERROR, "End of first test");
- test_fails();
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(g_pollset, &destroyed);
-
+ {
+ grpc_core::ExecCtx exec_ctx;
+ g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size()));
+ grpc_pollset_init(g_pollset, &g_mu);
+
+ test_succeeds();
+ gpr_log(GPR_ERROR, "End of first test");
+ test_fails();
+ GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(g_pollset, &destroyed);
+ gpr_free(g_pollset);
+ }
grpc_shutdown();
- gpr_free(g_pollset);
return 0;
}
diff --git a/test/core/iomgr/tcp_server_uv_test.cc b/test/core/iomgr/tcp_server_uv_test.cc
index 35d62b51b7..e99fa79bfd 100644
--- a/test/core/iomgr/tcp_server_uv_test.cc
+++ b/test/core/iomgr/tcp_server_uv_test.cc
@@ -119,6 +119,7 @@ static void test_no_op(void) {
grpc_tcp_server* s;
GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(NULL, NULL, &s));
grpc_tcp_server_unref(s);
+ grpc_core::ExecCtx::Get()->Flush();
}
static void test_no_op_with_start(void) {
@@ -128,6 +129,7 @@ static void test_no_op_with_start(void) {
LOG_TEST("test_no_op_with_start");
grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
grpc_tcp_server_unref(s);
+ grpc_core::ExecCtx::Get()->Flush();
}
static void test_no_op_with_port(void) {
@@ -147,6 +149,7 @@ static void test_no_op_with_port(void) {
port > 0);
grpc_tcp_server_unref(s);
+ grpc_core::ExecCtx::Get()->Flush();
}
static void test_no_op_with_port_and_start(void) {
@@ -168,6 +171,7 @@ static void test_no_op_with_port_and_start(void) {
grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
grpc_tcp_server_unref(s);
+ grpc_core::ExecCtx::Get()->Flush();
}
static void connect_cb(uv_connect_t* req, int status) {
@@ -273,7 +277,7 @@ static void test_connect(unsigned n) {
GPR_ASSERT(weak_ref.server != NULL);
grpc_tcp_server_unref(s);
-
+ grpc_core::ExecCtx::Get()->Flush();
/* Weak ref lost. */
GPR_ASSERT(weak_ref.server == NULL);
}
@@ -284,25 +288,27 @@ static void destroy_pollset(void* p, grpc_error* error) {
int main(int argc, char** argv) {
grpc_closure destroyed;
- grpc_core::ExecCtx exec_ctx;
grpc_test_init(argc, argv);
grpc_init();
- g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size()));
- grpc_pollset_init(g_pollset, &g_mu);
-
- test_no_op();
- test_no_op_with_start();
- test_no_op_with_port();
- test_no_op_with_port_and_start();
- test_connect(1);
- test_connect(10);
-
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(g_pollset, &destroyed);
-
+ {
+ grpc_core::ExecCtx exec_ctx;
+ g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size()));
+ grpc_pollset_init(g_pollset, &g_mu);
+
+ test_no_op();
+ test_no_op_with_start();
+ test_no_op_with_port();
+ test_no_op_with_port_and_start();
+ test_connect(1);
+ test_connect(10);
+
+ GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset,
+ grpc_schedule_on_exec_ctx);
+ grpc_pollset_shutdown(g_pollset, &destroyed);
+
+ gpr_free(g_pollset);
+ }
grpc_shutdown();
- gpr_free(g_pollset);
return 0;
}
diff --git a/test/core/iomgr/timer_list_test.cc b/test/core/iomgr/timer_list_test.cc
index feedf3f149..fd65d1abf1 100644
--- a/test/core/iomgr/timer_list_test.cc
+++ b/test/core/iomgr/timer_list_test.cc
@@ -248,11 +248,7 @@ int main(int argc, char** argv) {
grpc_determine_iomgr_platform();
grpc_iomgr_platform_init();
gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
-#ifndef GPR_WINDOWS
- /* Skip this test on Windows until we figure out why it fails */
- /* https://github.com/grpc/grpc/issues/16417 */
long_running_service_cleanup_test();
-#endif // GPR_WINDOWS
add_test();
destruction_test();
grpc_iomgr_platform_shutdown();
diff --git a/test/core/memory_usage/BUILD b/test/core/memory_usage/BUILD
new file mode 100644
index 0000000000..f39c309e36
--- /dev/null
+++ b/test/core/memory_usage/BUILD
@@ -0,0 +1,60 @@
+# Copyright 2017 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_package")
+
+grpc_package(name = "test/core/memory_usage")
+
+licenses(["notice"]) # Apache v2
+
+grpc_cc_library(
+ name = "client",
+ testonly = 1,
+ srcs = ["client.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
+grpc_cc_library(
+ name = "server",
+ testonly = 1,
+ srcs = ["server.cc"],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/core/end2end:ssl_test_data"
+ ],
+)
+
+grpc_cc_test(
+ name = "memory_usage_test",
+ srcs = ["memory_usage_test.cc"],
+ language = "C++",
+ data = [
+ ":client",
+ ":server",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/memory_usage/memory_usage_test.cc b/test/core/memory_usage/memory_usage_test.cc
index c170f5ad26..5c35b4e1d3 100644
--- a/test/core/memory_usage/memory_usage_test.cc
+++ b/test/core/memory_usage/memory_usage_test.cc
@@ -43,7 +43,7 @@ int main(int argc, char** argv) {
strcpy(root, ".");
}
/* start the server */
- gpr_asprintf(&args[0], "%s/memory_profile_server%s", root,
+ gpr_asprintf(&args[0], "%s/memory_usage_server%s", root,
gpr_subprocess_binary_extension());
args[1] = const_cast<char*>("--bind");
gpr_join_host_port(&args[2], "::", port);
@@ -53,7 +53,7 @@ int main(int argc, char** argv) {
gpr_free(args[2]);
/* start the client */
- gpr_asprintf(&args[0], "%s/memory_profile_client%s", root,
+ gpr_asprintf(&args[0], "%s/memory_usage_client%s", root,
gpr_subprocess_binary_extension());
args[1] = const_cast<char*>("--target");
gpr_join_host_port(&args[2], "127.0.0.1", port);
diff --git a/test/core/memory_usage/server.cc b/test/core/memory_usage/server.cc
index 3e7bb7e11f..6f8a9bc0d4 100644
--- a/test/core/memory_usage/server.cc
+++ b/test/core/memory_usage/server.cc
@@ -292,9 +292,9 @@ int main(int argc, char** argv) {
send_status(&calls[k]);
}
}
+ /* fallthrough */
// no break here since we want to continue to case
// FLING_SERVER_SEND_STATUS_SNAPSHOT to destroy the snapshot call
- /* fallthrough */
case FLING_SERVER_SEND_STATUS_SNAPSHOT:
grpc_byte_buffer_destroy(payload_buffer);
grpc_byte_buffer_destroy(terminal_buffer);
diff --git a/test/core/security/alts_security_connector_test.cc b/test/core/security/alts_security_connector_test.cc
index 103a493526..9378236338 100644
--- a/test/core/security/alts_security_connector_test.cc
+++ b/test/core/security/alts_security_connector_test.cc
@@ -24,7 +24,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include "src/core/lib/security/security_connector/alts_security_connector.h"
+#include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
#include "src/core/tsi/transport_security.h"
diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc
index 97156761bd..56c4c9c0ae 100644
--- a/test/core/security/credentials_test.cc
+++ b/test/core/security/credentials_test.cc
@@ -43,6 +43,7 @@
#include "src/core/lib/security/transport/auth_filters.h"
#include "test/core/util/test_config.h"
+using grpc_core::internal::grpc_flush_cached_google_default_credentials;
using grpc_core::internal::set_gce_tenancy_checker_for_testing;
/* -- Mock channel credentials. -- */
@@ -954,17 +955,9 @@ static void test_google_default_creds_gce(void) {
run_request_metadata_test(creds->call_creds, auth_md_ctx, state);
grpc_core::ExecCtx::Get()->Flush();
- /* Check that we get a cached creds if we call
- grpc_google_default_credentials_create again.
- GCE detection should not occur anymore either. */
- g_test_gce_tenancy_checker_called = false;
- grpc_channel_credentials* cached_creds =
- grpc_google_default_credentials_create();
- GPR_ASSERT(cached_creds == &creds->base);
- GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
+ GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
/* Cleanup. */
- grpc_channel_credentials_unref(cached_creds);
grpc_channel_credentials_unref(&creds->base);
grpc_httpcli_set_override(nullptr, nullptr);
grpc_override_well_known_credentials_path_getter(nullptr);
@@ -983,7 +976,7 @@ static void test_no_google_default_creds(void) {
/* Simulate a successful detection of GCE. */
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
- /* Try a cached one. GCE detection should not occur anymore. */
+ /* Try a second one. GCE detection should not occur anymore. */
g_test_gce_tenancy_checker_called = false;
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
diff --git a/test/core/security/linux_system_roots_test.cc b/test/core/security/linux_system_roots_test.cc
index fce9c8dcc5..24d446de35 100644
--- a/test/core/security/linux_system_roots_test.cc
+++ b/test/core/security/linux_system_roots_test.cc
@@ -41,10 +41,6 @@
#include "gtest/gtest.h"
-#ifndef GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR
-#define GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_USE_SYSTEM_SSL_ROOTS"
-#endif
-
namespace grpc {
namespace {
@@ -68,7 +64,6 @@ TEST(CreateRootCertsBundleTest, ReturnsEmpty) {
}
TEST(CreateRootCertsBundleTest, BundlesCorrectly) {
- gpr_setenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR, "true");
// Test that CreateRootCertsBundle returns a correct slice.
grpc_slice roots_bundle = grpc_empty_slice();
GRPC_LOG_IF_ERROR(
@@ -81,7 +76,6 @@ TEST(CreateRootCertsBundleTest, BundlesCorrectly) {
char* bundle_str = grpc_slice_to_c_string(roots_bundle);
EXPECT_STREQ(result_str, bundle_str);
// Clean up.
- unsetenv(GRPC_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
gpr_free(result_str);
gpr_free(bundle_str);
grpc_slice_unref(roots_bundle);
diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc
index 82d77eef8b..fef0ea71f7 100644
--- a/test/core/security/security_connector_test.cc
+++ b/test/core/security/security_connector_test.cc
@@ -29,6 +29,7 @@
#include "src/core/lib/gpr/tmpfile.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/security_connector/security_connector.h"
+#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
@@ -415,6 +416,7 @@ static void test_default_ssl_roots(void) {
/* Now setup a permanent failure for the overridden roots and we should get
an empty slice. */
+ gpr_setenv("GRPC_NOT_USE_SYSTEM_SSL_ROOTS", "true");
grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
diff --git a/test/core/security/ssl_server_fuzzer.cc b/test/core/security/ssl_server_fuzzer.cc
index cb74e3bae1..d2bbb7c1c2 100644
--- a/test/core/security/ssl_server_fuzzer.cc
+++ b/test/core/security/ssl_server_fuzzer.cc
@@ -91,11 +91,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
struct handshake_state state;
state.done_callback_called = false;
grpc_handshake_manager* handshake_mgr = grpc_handshake_manager_create();
- grpc_server_security_connector_add_handshakers(sc, handshake_mgr);
+ grpc_server_security_connector_add_handshakers(sc, nullptr, handshake_mgr);
grpc_handshake_manager_do_handshake(
- handshake_mgr, nullptr /* interested_parties */, mock_endpoint,
- nullptr /* channel_args */, deadline, nullptr /* acceptor */,
- on_handshake_done, &state);
+ handshake_mgr, mock_endpoint, nullptr /* channel_args */, deadline,
+ nullptr /* acceptor */, on_handshake_done, &state);
grpc_core::ExecCtx::Get()->Flush();
// If the given string happens to be part of the correct client hello, the
diff --git a/test/core/surface/completion_queue_test.cc b/test/core/surface/completion_queue_test.cc
index b889fd0fc6..f7ce8a7042 100644
--- a/test/core/surface/completion_queue_test.cc
+++ b/test/core/surface/completion_queue_test.cc
@@ -369,11 +369,15 @@ static void test_callback(void) {
LOG_TEST("test_callback");
bool got_shutdown = false;
- class ShutdownCallback : public grpc_core::CQCallbackInterface {
+ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
- ShutdownCallback(bool* done) : done_(done) {}
+ ShutdownCallback(bool* done) : done_(done) {
+ functor_run = &ShutdownCallback::Run;
+ }
~ShutdownCallback() {}
- void Run(bool ok) override { *done_ = ok; }
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ *static_cast<ShutdownCallback*>(cb)->done_ = static_cast<bool>(ok);
+ }
private:
bool* done_;
@@ -391,14 +395,17 @@ static void test_callback(void) {
grpc_completion_queue_factory_lookup(&attr), &attr, nullptr);
int counter = 0;
- class TagCallback : public grpc_core::CQCallbackInterface {
+ class TagCallback : public grpc_experimental_completion_queue_functor {
public:
- TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {}
+ TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {
+ functor_run = &TagCallback::Run;
+ }
~TagCallback() {}
- void Run(bool ok) override {
- GPR_ASSERT(ok);
- *counter_ += tag_;
- grpc_core::Delete(this);
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ GPR_ASSERT(static_cast<bool>(ok));
+ auto* callback = static_cast<TagCallback*>(cb);
+ *callback->counter_ += callback->tag_;
+ grpc_core::Delete(callback);
};
private:
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index b832a1661b..426ef1e8b1 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -136,7 +136,12 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_resource_quota_set_max_threads);
printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable);
printf("%lx", (unsigned long) grpc_channelz_get_top_channels);
+ printf("%lx", (unsigned long) grpc_channelz_get_servers);
+ printf("%lx", (unsigned long) grpc_channelz_get_server);
+ printf("%lx", (unsigned long) grpc_channelz_get_server_sockets);
printf("%lx", (unsigned long) grpc_channelz_get_channel);
+ printf("%lx", (unsigned long) grpc_channelz_get_subchannel);
+ printf("%lx", (unsigned long) grpc_channelz_get_socket);
printf("%lx", (unsigned long) grpc_auth_property_iterator_next);
printf("%lx", (unsigned long) grpc_auth_context_property_iterator);
printf("%lx", (unsigned long) grpc_auth_context_peer_identity);
diff --git a/test/core/transport/chttp2/hpack_encoder_test.cc b/test/core/transport/chttp2/hpack_encoder_test.cc
index 2a57198ab6..ab819f9092 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.cc
+++ b/test/core/transport/chttp2/hpack_encoder_test.cc
@@ -202,7 +202,7 @@ static void verify_table_size_change_match_elem_size(const char* key,
grpc_mdelem elem = grpc_mdelem_from_slices(
grpc_slice_intern(grpc_slice_from_static_string(key)),
grpc_slice_intern(grpc_slice_from_static_string(value)));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, use_true_binary);
size_t initial_table_size = g_compressor.table_size;
grpc_linked_mdelem* e =
static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e)));
diff --git a/test/core/transport/chttp2/settings_timeout_test.cc b/test/core/transport/chttp2/settings_timeout_test.cc
index 39ae587bae..2d6f0a9a62 100644
--- a/test/core/transport/chttp2/settings_timeout_test.cc
+++ b/test/core/transport/chttp2/settings_timeout_test.cc
@@ -196,6 +196,8 @@ class Client {
"grpc_pollset_work",
grpc_pollset_work(pollset_, &worker,
grpc_core::ExecCtx::Get()->Now() + 1000));
+ // Flushes any work scheduled before or during polling.
+ grpc_core::ExecCtx::Get()->Flush();
gpr_mu_unlock(mu_);
if (state != nullptr && state->done()) return true;
if (grpc_core::ExecCtx::Get()->Now() >= deadline) return false;
diff --git a/test/core/transport/metadata_test.cc b/test/core/transport/metadata_test.cc
index 4be34f72d9..8ab9639dfa 100644
--- a/test/core/transport/metadata_test.cc
+++ b/test/core/transport/metadata_test.cc
@@ -27,6 +27,7 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
@@ -293,7 +294,7 @@ static void verify_ascii_header_size(const char* key, const char* value,
grpc_mdelem elem = grpc_mdelem_from_slices(
maybe_intern(grpc_slice_from_static_string(key), intern_key),
maybe_intern(grpc_slice_from_static_string(value), intern_value));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
size_t expected_size = 32 + strlen(key) + strlen(value);
GPR_ASSERT(expected_size == elem_size);
GRPC_MDELEM_UNREF(elem);
@@ -307,7 +308,7 @@ static void verify_binary_header_size(const char* key, const uint8_t* value,
maybe_intern(grpc_slice_from_static_buffer(value, value_len),
intern_value));
GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
grpc_slice value_slice = grpc_slice_from_copied_buffer(
reinterpret_cast<const char*>(value), value_len);
grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);
diff --git a/test/core/tsi/alts/fake_handshaker/BUILD b/test/core/tsi/alts/fake_handshaker/BUILD
index a09a046d27..98cd628a7d 100644
--- a/test/core/tsi/alts/fake_handshaker/BUILD
+++ b/test/core/tsi/alts/fake_handshaker/BUILD
@@ -37,21 +37,22 @@ grpc_cc_library(
name = "fake_handshaker_lib",
testonly = True,
srcs = ["fake_handshaker_server.cc"],
+ hdrs = ["fake_handshaker_server.h"],
language = "C++",
deps = [
"handshaker_proto",
"transport_security_common_proto",
"//:grpc++",
- "//test/cpp/util:test_config",
],
)
grpc_cc_binary(
name = "fake_handshaker_server",
testonly = True,
- srcs = ["fake_handshaker_server.cc"],
+ srcs = ["fake_handshaker_server_main.cc"],
language = "C++",
deps = [
+ "//test/cpp/util:test_config",
"fake_handshaker_lib",
],
)
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
index f6a4791b49..ba246b07eb 100644
--- a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
@@ -15,12 +15,12 @@
* limitations under the License.
*
*/
+#include "test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h"
#include <memory>
#include <sstream>
#include <string>
-#include <gflags/gflags.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpcpp/impl/codegen/async_stream.h>
@@ -32,10 +32,6 @@
#include "test/core/tsi/alts/fake_handshaker/handshaker.grpc.pb.h"
#include "test/core/tsi/alts/fake_handshaker/handshaker.pb.h"
#include "test/core/tsi/alts/fake_handshaker/transport_security_common.pb.h"
-#include "test/cpp/util/test_config.h"
-
-DEFINE_int32(handshaker_port, 55056,
- "TCP port on which the fake handshaker server listens to.");
// Fake handshake messages.
constexpr char kClientInitFrame[] = "ClientInit";
@@ -243,26 +239,9 @@ class FakeHandshakerService : public HandshakerService::Service {
}
};
-} // namespace gcp
-} // namespace grpc
-
-void RunServer() {
- GPR_ASSERT(FLAGS_handshaker_port != 0);
- std::ostringstream server_address;
- server_address << "[::1]:" << FLAGS_handshaker_port;
- grpc::gcp::FakeHandshakerService service;
- grpc::ServerBuilder builder;
- builder.AddListeningPort(server_address.str(),
- grpc::InsecureServerCredentials());
- builder.RegisterService(&service);
- std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
- gpr_log(GPR_INFO, "Fake handshaker server listening on %s",
- server_address.str().c_str());
- server->Wait();
+std::unique_ptr<grpc::Service> CreateFakeHandshakerService() {
+ return std::unique_ptr<grpc::Service>{new grpc::gcp::FakeHandshakerService};
}
-int main(int argc, char** argv) {
- grpc::testing::InitTest(&argc, &argv, true);
- RunServer();
- return 0;
-}
+} // namespace gcp
+} // namespace grpc
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h
new file mode 100644
index 0000000000..eb4bfdffa1
--- /dev/null
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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 <memory>
+#include <string>
+
+#include <grpcpp/grpcpp.h>
+
+namespace grpc {
+namespace gcp {
+
+std::unique_ptr<grpc::Service> CreateFakeHandshakerService();
+
+} // namespace gcp
+} // namespace grpc
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc
new file mode 100644
index 0000000000..60351533d9
--- /dev/null
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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 "test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h"
+
+#include <sstream>
+
+#include <gflags/gflags.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/server_builder.h>
+
+#include "test/cpp/util/test_config.h"
+
+DEFINE_int32(handshaker_port, 55056,
+ "TCP port on which the fake handshaker server listens to.");
+
+static void RunFakeHandshakerServer(const std::string& server_address) {
+ std::unique_ptr<grpc::Service> service =
+ grpc::gcp::CreateFakeHandshakerService();
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(service.get());
+ gpr_log(GPR_INFO, "Fake handshaker server listening on %s",
+ server_address.c_str());
+ std::unique_ptr<grpc::Server> server = builder.BuildAndStart();
+ server->Wait();
+}
+
+int main(int argc, char** argv) {
+ grpc::testing::InitTest(&argc, &argv, true);
+
+ GPR_ASSERT(FLAGS_handshaker_port != 0);
+ std::ostringstream server_address;
+ server_address << "[::1]:" << FLAGS_handshaker_port;
+
+ RunFakeHandshakerServer(server_address.str());
+ return 0;
+}
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 85a58114ba..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,
- &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/core/tsi/fake_transport_security_test.cc b/test/core/tsi/fake_transport_security_test.cc
index 5e6671965d..587d8f5dda 100644
--- a/test/core/tsi/fake_transport_security_test.cc
+++ b/test/core/tsi/fake_transport_security_test.cc
@@ -22,6 +22,7 @@
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/tsi/fake_transport_security.h"
+#include "src/core/tsi/transport_security.h"
#include "test/core/tsi/transport_security_test_lib.h"
#include "test/core/util/test_config.h"
diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc
index b477904d60..baffad6ea3 100644
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -208,9 +208,11 @@ static void check_session_reusage(ssl_tsi_test_fixture* ssl_fixture,
tsi_peer_get_property_by_name(peer, TSI_SSL_SESSION_REUSED_PEER_PROPERTY);
GPR_ASSERT(session_reused != nullptr);
if (ssl_fixture->session_reused) {
- GPR_ASSERT(strcmp(session_reused->value.data, "true") == 0);
+ GPR_ASSERT(strncmp(session_reused->value.data, "true",
+ session_reused->value.length) == 0);
} else {
- GPR_ASSERT(strcmp(session_reused->value.data, "false") == 0);
+ GPR_ASSERT(strncmp(session_reused->value.data, "false",
+ session_reused->value.length) == 0);
}
}
diff --git a/test/core/util/port_isolated_runtime_environment.cc b/test/core/util/port_isolated_runtime_environment.cc
index ff8342ff4a..1f678c08e5 100644
--- a/test/core/util/port_isolated_runtime_environment.cc
+++ b/test/core/util/port_isolated_runtime_environment.cc
@@ -16,9 +16,12 @@
*
*/
-/* When running tests on remote machines, the framework takes a round-robin pick
- * of a port within certain range. There is no need to recycle ports.
+/* When individual tests run in an isolated runtime environment (e.g. each test
+ * runs in a separate container) the framework takes a round-robin pick of a
+ * port within certain range. There is no need to recycle ports.
*/
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <stdlib.h>
#include "src/core/lib/iomgr/port.h"
@@ -27,23 +30,25 @@
#include "test/core/util/port.h"
-#define MIN_PORT 49152
-#define MAX_PORT 65536
+#define MIN_PORT 1025
+#define MAX_PORT 32766
-int get_random_starting_port() {
+static int get_random_port_offset() {
srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
- return rand() % (MAX_PORT - MIN_PORT + 1) + MIN_PORT;
+ double rnd = static_cast<double>(rand()) /
+ (static_cast<double>(RAND_MAX) + 1.0); // values from [0,1)
+ return static_cast<int>(rnd * (MAX_PORT - MIN_PORT + 1));
}
-static int s_allocated_port = get_random_starting_port();
+static int s_initial_offset = get_random_port_offset();
+static gpr_atm s_pick_counter = 0;
int grpc_pick_unused_port_or_die(void) {
- int allocated_port = s_allocated_port++;
- if (s_allocated_port == MAX_PORT) {
- s_allocated_port = MIN_PORT;
- }
-
- return allocated_port;
+ int orig_counter_val =
+ static_cast<int>(gpr_atm_full_fetch_add(&s_pick_counter, 1));
+ GPR_ASSERT(orig_counter_val < (MAX_PORT - MIN_PORT + 1));
+ return MIN_PORT +
+ (s_initial_offset + orig_counter_val) % (MAX_PORT - MIN_PORT + 1);
}
void grpc_recycle_unused_port(int port) { (void)port; }
diff --git a/test/core/util/ubsan_suppressions.txt b/test/core/util/ubsan_suppressions.txt
index 2268adc169..63898ea3b1 100644
--- a/test/core/util/ubsan_suppressions.txt
+++ b/test/core/util/ubsan_suppressions.txt
@@ -15,3 +15,17 @@ enum:message_compress_test
enum:transport_security_test
enum:algorithm_test
alignment:transport_security_test
+# TODO(jtattermusch): address issues and remove the supressions
+nonnull-attribute:gsec_aes_gcm_aead_crypter_decrypt_iovec
+nonnull-attribute:gsec_test_random_encrypt_decrypt
+nonnull-attribute:gsec_test_multiple_random_encrypt_decrypt
+nonnull-attribute:gsec_test_copy
+nonnull-attribute:gsec_test_encrypt_decrypt_test_vector
+alignment:absl::little_endian::Store64
+alignment:absl::little_endian::Load64
+float-divide-by-zero:grpc::testing::postprocess_scenario_result
+enum:grpc_op_string
+nonnull-attribute:grpc_lb_addresses_copy
+signed-integer-overflow:chrono
+enum:grpc_http2_error_to_grpc_status
+enum:grpc_chttp2_cancel_stream \ No newline at end of file
diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc
index 826907ae4e..976eeb6aea 100644
--- a/test/cpp/client/client_channel_stress_test.cc
+++ b/test/cpp/client/client_channel_stress_test.cc
@@ -245,7 +245,7 @@ class ClientChannelStressTest {
EchoResponse response;
{
std::lock_guard<std::mutex> lock(stub_mutex_);
- stub_->Echo(&context, request, &response);
+ Status status = stub_->Echo(&context, request, &response);
}
}
gpr_log(GPR_INFO, "Finish sending requests.");
diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden
index 756f6a0224..fdc67969d9 100644
--- a/test/cpp/codegen/compiler_test_golden
+++ b/test/cpp/codegen/compiler_test_golden
@@ -26,12 +26,14 @@
#include "src/proto/grpc/testing/compiler_test.pb.h"
+#include <functional>
#include <grpcpp/impl/codegen/async_generic_service.h>
#include <grpcpp/impl/codegen/async_stream.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
#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>
@@ -105,6 +107,23 @@ class ServiceA final {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
// Method A4 trailing comment 1
+ class experimental_async_interface {
+ public:
+ virtual ~experimental_async_interface() {}
+ // MethodA1 leading comment 1
+ virtual void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
+ // MethodA1 trailing comment 1
+ // MethodA2 detached leading comment 1
+ //
+ // Method A2 leading comment 1
+ // Method A2 leading comment 2
+ // MethodA2 trailing comment 1
+ // Method A3 leading comment 1
+ // Method A3 trailing comment 1
+ // Method A4 leading comment 1
+ // Method A4 trailing comment 1
+ };
+ virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@@ -155,9 +174,21 @@ class ServiceA final {
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> PrepareAsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
+ class experimental_async final :
+ public StubInterface::experimental_async_interface {
+ public:
+ void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
+ private:
+ friend class Stub;
+ explicit experimental_async(Stub* stub): stub_(stub) { }
+ Stub* stub() { return stub_; }
+ Stub* stub_;
+ };
+ class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override;
@@ -278,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) {}
@@ -426,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) {}
@@ -488,6 +666,14 @@ class ServiceB final {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
// MethodB1 trailing comment 1
+ class experimental_async_interface {
+ public:
+ virtual ~experimental_async_interface() {}
+ // MethodB1 leading comment 1
+ virtual void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
+ // MethodB1 trailing comment 1
+ };
+ virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@@ -502,9 +688,21 @@ class ServiceB final {
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>> PrepareAsyncMethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
+ class experimental_async final :
+ public StubInterface::experimental_async_interface {
+ public:
+ void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
+ private:
+ friend class Stub;
+ explicit experimental_async(Stub* stub): stub_(stub) { }
+ Stub* stub() { return stub_; }
+ Stub* stub_;
+ };
+ class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
const ::grpc::internal::RpcMethod rpcmethod_MethodB1_;
@@ -541,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) {}
@@ -578,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/common/alarm_test.cc b/test/cpp/common/alarm_test.cc
index 57d958349e..e909d03658 100644
--- a/test/cpp/common/alarm_test.cc
+++ b/test/cpp/common/alarm_test.cc
@@ -16,9 +16,13 @@
*
*/
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+
#include <grpcpp/alarm.h>
#include <grpcpp/completion_queue.h>
-#include <thread>
#include <gtest/gtest.h>
@@ -43,6 +47,66 @@ TEST(AlarmTest, RegularExpiry) {
EXPECT_EQ(junk, output_tag);
}
+struct Completion {
+ bool completed = false;
+ std::mutex mu;
+ std::condition_variable cv;
+};
+
+TEST(AlarmTest, CallbackRegularExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(1), [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
+TEST(AlarmTest, CallbackZeroExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(grpc_timeout_seconds_to_deadline(0), [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
+TEST(AlarmTest, CallbackNegativeExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(-1),
+ [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, MultithreadedRegularExpiry) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@@ -182,6 +246,26 @@ TEST(AlarmTest, Cancellation) {
EXPECT_EQ(junk, output_tag);
}
+TEST(AlarmTest, CallbackCancellation) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c](bool ok) {
+ EXPECT_FALSE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+ alarm.Cancel();
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(1),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, SetDestruction) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@@ -200,6 +284,26 @@ TEST(AlarmTest, SetDestruction) {
EXPECT_EQ(junk, output_tag);
}
+TEST(AlarmTest, CallbackSetDestruction) {
+ auto c = std::make_shared<Completion>();
+ {
+ Alarm alarm;
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c](bool ok) {
+ EXPECT_FALSE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+ }
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(1),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, UnsetDestruction) {
CompletionQueue cq;
Alarm alarm;
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index 75dec56a60..4e3d841db0 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -35,6 +35,20 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "interceptors_util",
+ testonly = True,
+ srcs = ["interceptors_util.cc"],
+ hdrs = ["interceptors_util.h"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/cpp/util:test_util",
+ ],
+)
+
grpc_cc_test(
name = "async_end2end_test",
srcs = ["async_end2end_test.cc"],
@@ -98,6 +112,45 @@ grpc_cc_binary(
],
)
+grpc_cc_test(
+ name = "client_callback_end2end_test",
+ srcs = ["client_callback_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+grpc_cc_test(
+ name = "client_interceptors_end2end_test",
+ srcs = ["client_interceptors_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":interceptors_util",
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
grpc_cc_library(
name = "end2end_test_lib",
testonly = True,
@@ -106,6 +159,7 @@ grpc_cc_library(
"gtest",
],
deps = [
+ ":interceptors_util",
":test_service_impl",
"//:gpr",
"//:grpc",
@@ -451,6 +505,26 @@ grpc_cc_binary(
)
grpc_cc_test(
+ name = "server_interceptors_end2end_test",
+ srcs = ["server_interceptors_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":interceptors_util",
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
+grpc_cc_test(
name = "server_load_reporting_end2end_test",
srcs = ["server_load_reporting_end2end_test.cc"],
external_deps = [
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index c9246f0806..6ecb957801 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -178,7 +178,7 @@ class Verifier {
EXPECT_EQ(it2->second.ok, ok);
}
} else {
- gpr_log(GPR_ERROR, "Unexpected tag: %p", tag);
+ gpr_log(GPR_ERROR, "Unexpected tag: %p", got_tag);
abort();
}
}
@@ -953,6 +953,114 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) {
EXPECT_TRUE(recv_status.ok());
}
+// 1 ping, 2 pongs.
+TEST_P(AsyncEnd2endTest, ServerInitialMetadataServerStreaming) {
+ ResetStub();
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
+
+ std::pair<::grpc::string, ::grpc::string> meta1("key1", "val1");
+ std::pair<::grpc::string, ::grpc::string> meta2("key2", "val2");
+
+ std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
+ stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
+ cli_stream->ReadInitialMetadata(tag(11));
+ service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
+ cq_.get(), cq_.get(), tag(2));
+
+ Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
+
+ srv_ctx.AddInitialMetadata(meta1.first, meta1.second);
+ srv_ctx.AddInitialMetadata(meta2.first, meta2.second);
+ srv_stream.SendInitialMetadata(tag(10));
+ Verifier().Expect(10, true).Expect(11, true).Verify(cq_.get());
+ auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
+ EXPECT_EQ(meta1.second,
+ ToString(server_initial_metadata.find(meta1.first)->second));
+ EXPECT_EQ(meta2.second,
+ ToString(server_initial_metadata.find(meta2.first)->second));
+ EXPECT_EQ(static_cast<size_t>(2), server_initial_metadata.size());
+
+ srv_stream.Write(send_response, tag(3));
+
+ cli_stream->Read(&recv_response, tag(4));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
+
+ srv_stream.Write(send_response, tag(5));
+ cli_stream->Read(&recv_response, tag(6));
+ Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
+
+ srv_stream.Finish(Status::OK, tag(7));
+ cli_stream->Read(&recv_response, tag(8));
+ Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get());
+
+ cli_stream->Finish(&recv_status, tag(9));
+ Verifier().Expect(9, true).Verify(cq_.get());
+
+ EXPECT_TRUE(recv_status.ok());
+}
+
+// 1 ping, 2 pongs.
+// Test for server initial metadata being sent implicitly
+TEST_P(AsyncEnd2endTest, ServerInitialMetadataServerStreamingImplicit) {
+ ResetStub();
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
+
+ send_request.set_message(GetParam().message_content);
+ std::pair<::grpc::string, ::grpc::string> meta1("key1", "val1");
+ std::pair<::grpc::string, ::grpc::string> meta2("key2", "val2");
+
+ std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
+ stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
+ service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
+ cq_.get(), cq_.get(), tag(2));
+
+ Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ srv_ctx.AddInitialMetadata(meta1.first, meta1.second);
+ srv_ctx.AddInitialMetadata(meta2.first, meta2.second);
+ send_response.set_message(recv_request.message());
+ srv_stream.Write(send_response, tag(3));
+
+ cli_stream->Read(&recv_response, tag(4));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
+ EXPECT_EQ(meta1.second,
+ ToString(server_initial_metadata.find(meta1.first)->second));
+ EXPECT_EQ(meta2.second,
+ ToString(server_initial_metadata.find(meta2.first)->second));
+ EXPECT_EQ(static_cast<size_t>(2), server_initial_metadata.size());
+
+ srv_stream.Write(send_response, tag(5));
+ cli_stream->Read(&recv_response, tag(6));
+ Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
+
+ srv_stream.Finish(Status::OK, tag(7));
+ cli_stream->Read(&recv_response, tag(8));
+ Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get());
+
+ cli_stream->Finish(&recv_status, tag(9));
+ Verifier().Expect(9, true).Verify(cq_.get());
+
+ EXPECT_TRUE(recv_status.ok());
+}
+
TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) {
ResetStub();
diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc
index 933e4a1ff6..f04ffe4f2d 100644
--- a/test/cpp/end2end/channelz_service_test.cc
+++ b/test/cpp/end2end/channelz_service_test.cc
@@ -35,10 +35,22 @@
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
+#include <google/protobuf/text_format.h>
+
#include <gtest/gtest.h>
using grpc::channelz::v1::GetChannelRequest;
using grpc::channelz::v1::GetChannelResponse;
+using grpc::channelz::v1::GetServerRequest;
+using grpc::channelz::v1::GetServerResponse;
+using grpc::channelz::v1::GetServerSocketsRequest;
+using grpc::channelz::v1::GetServerSocketsResponse;
+using grpc::channelz::v1::GetServersRequest;
+using grpc::channelz::v1::GetServersResponse;
+using grpc::channelz::v1::GetSocketRequest;
+using grpc::channelz::v1::GetSocketResponse;
+using grpc::channelz::v1::GetSubchannelRequest;
+using grpc::channelz::v1::GetSubchannelResponse;
using grpc::channelz::v1::GetTopChannelsRequest;
using grpc::channelz::v1::GetTopChannelsResponse;
@@ -65,6 +77,26 @@ class Proxy : public ::grpc::testing::EchoTestService::Service {
return stubs_[idx]->Echo(client_context.get(), *request, response);
}
+ Status BidiStream(ServerContext* server_context,
+ ServerReaderWriter<EchoResponse, EchoRequest>*
+ stream_from_client) override {
+ EchoRequest request;
+ EchoResponse response;
+ std::unique_ptr<ClientContext> client_context =
+ ClientContext::FromServerContext(*server_context);
+
+ // always use the first proxy for streaming
+ auto stream_to_backend = stubs_[0]->BidiStream(client_context.get());
+ while (stream_from_client->Read(&request)) {
+ stream_to_backend->Write(request);
+ stream_to_backend->Read(&response);
+ stream_from_client->Write(response);
+ }
+
+ stream_to_backend->WritesDone();
+ return stream_to_backend->Finish();
+ }
+
private:
std::vector<std::unique_ptr<::grpc::testing::EchoTestService::Stub>> stubs_;
};
@@ -87,8 +119,8 @@ class ChannelzServerTest : public ::testing::Test {
InsecureServerCredentials());
// forces channelz and channel tracing to be enabled.
proxy_builder.AddChannelArgument(GRPC_ARG_ENABLE_CHANNELZ, 1);
- proxy_builder.AddChannelArgument(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE,
- 10);
+ proxy_builder.AddChannelArgument(
+ GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, 1024);
proxy_builder.RegisterService(&proxy_service_);
proxy_server_ = proxy_builder.BuildAndStart();
}
@@ -114,7 +146,7 @@ class ChannelzServerTest : public ::testing::Test {
// are the ones that our test will actually be validating.
ChannelArguments args;
args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 1);
- args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE, 10);
+ args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, 1024);
std::shared_ptr<Channel> channel_to_backend = CreateCustomChannel(
backend_server_address, InsecureChannelCredentials(), args);
proxy_service_.AddChannelToBackend(channel_to_backend);
@@ -140,7 +172,22 @@ class ChannelzServerTest : public ::testing::Test {
ClientContext context;
Status s = echo_stub_->Echo(&context, request, &response);
EXPECT_EQ(response.message(), request.message());
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ }
+
+ void SendSuccessfulStream(int num_messages) {
+ EchoRequest request;
+ EchoResponse response;
+ request.set_message("Hello channelz");
+ ClientContext context;
+ auto stream_to_proxy = echo_stub_->BidiStream(&context);
+ for (int i = 0; i < num_messages; ++i) {
+ EXPECT_TRUE(stream_to_proxy->Write(request));
+ EXPECT_TRUE(stream_to_proxy->Read(&response));
+ }
+ stream_to_proxy->WritesDone();
+ Status s = stream_to_proxy->Finish();
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
}
void SendFailedEcho(int channel_idx) {
@@ -156,6 +203,19 @@ class ChannelzServerTest : public ::testing::Test {
EXPECT_FALSE(s.ok());
}
+ // Uses GetTopChannels to return the channel_id of a particular channel,
+ // so that the unit tests may test GetChannel call.
+ intptr_t GetChannelId(int channel_idx) {
+ GetTopChannelsRequest request;
+ GetTopChannelsResponse response;
+ request.set_start_channel_id(0);
+ ClientContext context;
+ Status s = channelz_stub_->GetTopChannels(&context, request, &response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_GT(response.channel_size(), channel_idx);
+ return response.channel(channel_idx).ref().channel_id();
+ }
+
static string to_string(const int number) {
std::stringstream strs;
strs << number;
@@ -190,7 +250,7 @@ TEST_F(ChannelzServerTest, BasicTest) {
request.set_start_channel_id(0);
ClientContext context;
Status s = channelz_stub_->GetTopChannels(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel_size(), 1);
}
@@ -202,7 +262,7 @@ TEST_F(ChannelzServerTest, HighStartId) {
request.set_start_channel_id(10000);
ClientContext context;
Status s = channelz_stub_->GetTopChannels(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel_size(), 0);
}
@@ -212,10 +272,10 @@ TEST_F(ChannelzServerTest, SuccessfulRequestTest) {
SendSuccessfulEcho(0);
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(1);
+ request.set_channel_id(GetChannelId(0));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(), 1);
EXPECT_EQ(response.channel().data().calls_succeeded(), 1);
EXPECT_EQ(response.channel().data().calls_failed(), 0);
@@ -227,10 +287,10 @@ TEST_F(ChannelzServerTest, FailedRequestTest) {
SendFailedEcho(0);
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(1);
+ request.set_channel_id(GetChannelId(0));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(), 1);
EXPECT_EQ(response.channel().data().calls_succeeded(), 0);
EXPECT_EQ(response.channel().data().calls_failed(), 1);
@@ -250,10 +310,10 @@ TEST_F(ChannelzServerTest, ManyRequestsTest) {
}
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(1);
+ request.set_channel_id(GetChannelId(0));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(),
kNumSuccess + kNumFailed);
EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess);
@@ -269,7 +329,7 @@ TEST_F(ChannelzServerTest, ManyChannels) {
request.set_start_channel_id(0);
ClientContext context;
Status s = channelz_stub_->GetTopChannels(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel_size(), kNumChannels);
}
@@ -292,10 +352,10 @@ TEST_F(ChannelzServerTest, ManyRequestsManyChannels) {
{
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(1);
+ request.set_channel_id(GetChannelId(0));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(), kNumSuccess);
EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess);
EXPECT_EQ(response.channel().data().calls_failed(), 0);
@@ -305,10 +365,10 @@ TEST_F(ChannelzServerTest, ManyRequestsManyChannels) {
{
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(2);
+ request.set_channel_id(GetChannelId(1));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(), kNumFailed);
EXPECT_EQ(response.channel().data().calls_succeeded(), 0);
EXPECT_EQ(response.channel().data().calls_failed(), kNumFailed);
@@ -318,10 +378,10 @@ TEST_F(ChannelzServerTest, ManyRequestsManyChannels) {
{
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(3);
+ request.set_channel_id(GetChannelId(2));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(),
kNumSuccess + kNumFailed);
EXPECT_EQ(response.channel().data().calls_succeeded(), kNumSuccess);
@@ -332,16 +392,287 @@ TEST_F(ChannelzServerTest, ManyRequestsManyChannels) {
{
GetChannelRequest request;
GetChannelResponse response;
- request.set_channel_id(4);
+ request.set_channel_id(GetChannelId(3));
ClientContext context;
Status s = channelz_stub_->GetChannel(&context, request, &response);
- EXPECT_TRUE(s.ok());
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
EXPECT_EQ(response.channel().data().calls_started(), 0);
EXPECT_EQ(response.channel().data().calls_succeeded(), 0);
EXPECT_EQ(response.channel().data().calls_failed(), 0);
}
}
+TEST_F(ChannelzServerTest, ManySubchannels) {
+ ResetStubs();
+ const int kNumChannels = 4;
+ ConfigureProxy(kNumChannels);
+ const int kNumSuccess = 10;
+ const int kNumFailed = 11;
+ for (int i = 0; i < kNumSuccess; ++i) {
+ SendSuccessfulEcho(0);
+ SendSuccessfulEcho(2);
+ }
+ for (int i = 0; i < kNumFailed; ++i) {
+ SendFailedEcho(1);
+ SendFailedEcho(2);
+ }
+ GetTopChannelsRequest gtc_request;
+ GetTopChannelsResponse gtc_response;
+ gtc_request.set_start_channel_id(0);
+ ClientContext context;
+ Status s =
+ channelz_stub_->GetTopChannels(&context, gtc_request, &gtc_response);
+ EXPECT_TRUE(s.ok()) << s.error_message();
+ EXPECT_EQ(gtc_response.channel_size(), kNumChannels);
+ for (int i = 0; i < gtc_response.channel_size(); ++i) {
+ // if the channel sent no RPCs, then expect no subchannels to have been
+ // created.
+ if (gtc_response.channel(i).data().calls_started() == 0) {
+ EXPECT_EQ(gtc_response.channel(i).subchannel_ref_size(), 0);
+ continue;
+ }
+ // The resolver must return at least one address.
+ ASSERT_GT(gtc_response.channel(i).subchannel_ref_size(), 0);
+ GetSubchannelRequest gsc_request;
+ GetSubchannelResponse gsc_response;
+ gsc_request.set_subchannel_id(
+ gtc_response.channel(i).subchannel_ref(0).subchannel_id());
+ ClientContext context;
+ Status s =
+ channelz_stub_->GetSubchannel(&context, gsc_request, &gsc_response);
+ EXPECT_TRUE(s.ok()) << s.error_message();
+ EXPECT_EQ(gtc_response.channel(i).data().calls_started(),
+ gsc_response.subchannel().data().calls_started());
+ EXPECT_EQ(gtc_response.channel(i).data().calls_succeeded(),
+ gsc_response.subchannel().data().calls_succeeded());
+ EXPECT_EQ(gtc_response.channel(i).data().calls_failed(),
+ gsc_response.subchannel().data().calls_failed());
+ }
+}
+
+TEST_F(ChannelzServerTest, BasicServerTest) {
+ ResetStubs();
+ ConfigureProxy(1);
+ GetServersRequest request;
+ GetServersResponse response;
+ request.set_start_server_id(0);
+ ClientContext context;
+ Status s = channelz_stub_->GetServers(&context, request, &response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(response.server_size(), 1);
+}
+
+TEST_F(ChannelzServerTest, BasicGetServerTest) {
+ ResetStubs();
+ ConfigureProxy(1);
+ GetServersRequest get_servers_request;
+ GetServersResponse get_servers_response;
+ get_servers_request.set_start_server_id(0);
+ ClientContext get_servers_context;
+ Status s = channelz_stub_->GetServers(
+ &get_servers_context, get_servers_request, &get_servers_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_servers_response.server_size(), 1);
+ GetServerRequest get_server_request;
+ GetServerResponse get_server_response;
+ get_server_request.set_server_id(
+ get_servers_response.server(0).ref().server_id());
+ ClientContext get_server_context;
+ s = channelz_stub_->GetServer(&get_server_context, get_server_request,
+ &get_server_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_servers_response.server(0).ref().server_id(),
+ get_server_response.server().ref().server_id());
+}
+
+TEST_F(ChannelzServerTest, ServerCallTest) {
+ ResetStubs();
+ ConfigureProxy(1);
+ const int kNumSuccess = 10;
+ const int kNumFailed = 11;
+ for (int i = 0; i < kNumSuccess; ++i) {
+ SendSuccessfulEcho(0);
+ }
+ for (int i = 0; i < kNumFailed; ++i) {
+ SendFailedEcho(0);
+ }
+ GetServersRequest request;
+ GetServersResponse response;
+ request.set_start_server_id(0);
+ ClientContext context;
+ Status s = channelz_stub_->GetServers(&context, request, &response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(response.server_size(), 1);
+ EXPECT_EQ(response.server(0).data().calls_succeeded(), kNumSuccess);
+ EXPECT_EQ(response.server(0).data().calls_failed(), kNumFailed);
+ // This is success+failure+1 because the call that retrieved this information
+ // will be counted as started. It will not track success/failure until after
+ // it has returned, so that is not included in the response.
+ EXPECT_EQ(response.server(0).data().calls_started(),
+ kNumSuccess + kNumFailed + 1);
+}
+
+TEST_F(ChannelzServerTest, ManySubchannelsAndSockets) {
+ ResetStubs();
+ const int kNumChannels = 4;
+ ConfigureProxy(kNumChannels);
+ const int kNumSuccess = 10;
+ const int kNumFailed = 11;
+ for (int i = 0; i < kNumSuccess; ++i) {
+ SendSuccessfulEcho(0);
+ SendSuccessfulEcho(2);
+ }
+ for (int i = 0; i < kNumFailed; ++i) {
+ SendFailedEcho(1);
+ SendFailedEcho(2);
+ }
+ GetTopChannelsRequest gtc_request;
+ GetTopChannelsResponse gtc_response;
+ gtc_request.set_start_channel_id(0);
+ ClientContext context;
+ Status s =
+ channelz_stub_->GetTopChannels(&context, gtc_request, &gtc_response);
+ EXPECT_TRUE(s.ok()) << s.error_message();
+ EXPECT_EQ(gtc_response.channel_size(), kNumChannels);
+ for (int i = 0; i < gtc_response.channel_size(); ++i) {
+ // if the channel sent no RPCs, then expect no subchannels to have been
+ // created.
+ if (gtc_response.channel(i).data().calls_started() == 0) {
+ EXPECT_EQ(gtc_response.channel(i).subchannel_ref_size(), 0);
+ continue;
+ }
+ // The resolver must return at least one address.
+ ASSERT_GT(gtc_response.channel(i).subchannel_ref_size(), 0);
+ // First grab the subchannel
+ GetSubchannelRequest get_subchannel_req;
+ GetSubchannelResponse get_subchannel_resp;
+ get_subchannel_req.set_subchannel_id(
+ gtc_response.channel(i).subchannel_ref(0).subchannel_id());
+ ClientContext get_subchannel_ctx;
+ Status s = channelz_stub_->GetSubchannel(
+ &get_subchannel_ctx, get_subchannel_req, &get_subchannel_resp);
+ EXPECT_TRUE(s.ok()) << s.error_message();
+ EXPECT_EQ(get_subchannel_resp.subchannel().socket_ref_size(), 1);
+ // Now grab the socket.
+ GetSocketRequest get_socket_req;
+ GetSocketResponse get_socket_resp;
+ ClientContext get_socket_ctx;
+ get_socket_req.set_socket_id(
+ get_subchannel_resp.subchannel().socket_ref(0).socket_id());
+ s = channelz_stub_->GetSocket(&get_socket_ctx, get_socket_req,
+ &get_socket_resp);
+ EXPECT_TRUE(s.ok()) << s.error_message();
+ // calls started == streams started AND stream succeeded. Since none of
+ // these RPCs were canceled, all of the streams will succeeded even though
+ // the RPCs they represent might have failed.
+ EXPECT_EQ(get_subchannel_resp.subchannel().data().calls_started(),
+ get_socket_resp.socket().data().streams_started());
+ EXPECT_EQ(get_subchannel_resp.subchannel().data().calls_started(),
+ get_socket_resp.socket().data().streams_succeeded());
+ // All of the calls were unary, so calls started == messages sent.
+ EXPECT_EQ(get_subchannel_resp.subchannel().data().calls_started(),
+ get_socket_resp.socket().data().messages_sent());
+ // We only get responses when the RPC was successful, so
+ // calls succeeded == messages received.
+ EXPECT_EQ(get_subchannel_resp.subchannel().data().calls_succeeded(),
+ get_socket_resp.socket().data().messages_received());
+ }
+}
+
+TEST_F(ChannelzServerTest, StreamingRPC) {
+ ResetStubs();
+ ConfigureProxy(1);
+ const int kNumMessages = 5;
+ SendSuccessfulStream(kNumMessages);
+ // Get the channel
+ GetChannelRequest get_channel_request;
+ GetChannelResponse get_channel_response;
+ get_channel_request.set_channel_id(GetChannelId(0));
+ ClientContext get_channel_context;
+ Status s = channelz_stub_->GetChannel(
+ &get_channel_context, get_channel_request, &get_channel_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_channel_response.channel().data().calls_started(), 1);
+ EXPECT_EQ(get_channel_response.channel().data().calls_succeeded(), 1);
+ EXPECT_EQ(get_channel_response.channel().data().calls_failed(), 0);
+ // Get the subchannel
+ ASSERT_GT(get_channel_response.channel().subchannel_ref_size(), 0);
+ GetSubchannelRequest get_subchannel_request;
+ GetSubchannelResponse get_subchannel_response;
+ ClientContext get_subchannel_context;
+ get_subchannel_request.set_subchannel_id(
+ get_channel_response.channel().subchannel_ref(0).subchannel_id());
+ s = channelz_stub_->GetSubchannel(&get_subchannel_context,
+ get_subchannel_request,
+ &get_subchannel_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_subchannel_response.subchannel().data().calls_started(), 1);
+ EXPECT_EQ(get_subchannel_response.subchannel().data().calls_succeeded(), 1);
+ EXPECT_EQ(get_subchannel_response.subchannel().data().calls_failed(), 0);
+ // Get the socket
+ ASSERT_GT(get_subchannel_response.subchannel().socket_ref_size(), 0);
+ GetSocketRequest get_socket_request;
+ GetSocketResponse get_socket_response;
+ ClientContext get_socket_context;
+ get_socket_request.set_socket_id(
+ get_subchannel_response.subchannel().socket_ref(0).socket_id());
+ s = channelz_stub_->GetSocket(&get_socket_context, get_socket_request,
+ &get_socket_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ EXPECT_EQ(get_socket_response.socket().data().streams_started(), 1);
+ EXPECT_EQ(get_socket_response.socket().data().streams_succeeded(), 1);
+ EXPECT_EQ(get_socket_response.socket().data().streams_failed(), 0);
+ EXPECT_EQ(get_socket_response.socket().data().messages_sent(), kNumMessages);
+ EXPECT_EQ(get_socket_response.socket().data().messages_received(),
+ kNumMessages);
+}
+
+TEST_F(ChannelzServerTest, GetServerSocketsTest) {
+ 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);
+ GetServerSocketsRequest get_server_sockets_request;
+ GetServerSocketsResponse get_server_sockets_response;
+ get_server_sockets_request.set_server_id(
+ get_server_response.server(0).ref().server_id());
+ get_server_sockets_request.set_start_socket_id(0);
+ ClientContext get_server_sockets_context;
+ s = channelz_stub_->GetServerSockets(&get_server_sockets_context,
+ get_server_sockets_request,
+ &get_server_sockets_response);
+ EXPECT_TRUE(s.ok()) << "s.error_message() = " << s.error_message();
+ 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
new file mode 100644
index 0000000000..a35991396a
--- /dev/null
+++ b/test/cpp/end2end/client_callback_end2end_test.cc
@@ -0,0 +1,283 @@
+/*
+ *
+ * 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 <functional>
+#include <mutex>
+#include <thread>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/client_callback.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+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() { GetParam().Log(); }
+
+ void SetUp() override {
+ ServerBuilder builder;
+
+ if (!GetParam().callback_server) {
+ builder.RegisterService(&service_);
+ } else {
+ builder.RegisterService(&callback_service_);
+ }
+
+ server_ = builder.BuildAndStart();
+ is_server_started_ = true;
+ }
+
+ void ResetStub() {
+ ChannelArguments args;
+ channel_ = server_->InProcessChannel(args);
+ stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+ generic_stub_.reset(new GenericStub(channel_));
+ }
+
+ void TearDown() override {
+ if (is_server_started_) {
+ server_->Shutdown();
+ }
+ }
+
+ void SendRpcs(int num_rpcs, bool with_binary_metadata) {
+ grpc::string test_string("");
+ for (int i = 0; i < num_rpcs; i++) {
+ EchoRequest request;
+ EchoResponse response;
+ ClientContext cli_ctx;
+
+ test_string += "Hello world. ";
+ request.set_message(test_string);
+ grpc::string val;
+ if (with_binary_metadata) {
+ request.mutable_param()->set_echo_metadata(true);
+ char bytes[8] = {'\0', '\1', '\2', '\3',
+ '\4', '\5', '\6', static_cast<char>(i)};
+ val = grpc::string(bytes, 8);
+ cli_ctx.AddMetadata("custom-bin", val);
+ }
+
+ cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ stub_->experimental_async()->Echo(
+ &cli_ctx, &request, &response,
+ [&cli_ctx, &request, &response, &done, &mu, &cv, val,
+ with_binary_metadata](Status s) {
+ GPR_ASSERT(s.ok());
+
+ EXPECT_EQ(request.message(), response.message());
+ if (with_binary_metadata) {
+ EXPECT_EQ(
+ 1u, cli_ctx.GetServerTrailingMetadata().count("custom-bin"));
+ EXPECT_EQ(val, ToString(cli_ctx.GetServerTrailingMetadata()
+ .find("custom-bin")
+ ->second));
+ }
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+ }
+ }
+
+ void SendRpcsGeneric(int num_rpcs, bool maybe_except) {
+ const grpc::string kMethodName("/grpc.testing.EchoTestService/Echo");
+ grpc::string test_string("");
+ for (int i = 0; i < num_rpcs; i++) {
+ EchoRequest request;
+ std::unique_ptr<ByteBuffer> send_buf;
+ ByteBuffer recv_buf;
+ ClientContext cli_ctx;
+
+ test_string += "Hello world. ";
+ request.set_message(test_string);
+ send_buf = SerializeToByteBuffer(&request);
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ generic_stub_->experimental().UnaryCall(
+ &cli_ctx, kMethodName, send_buf.get(), &recv_buf,
+ [&request, &recv_buf, &done, &mu, &cv, maybe_except](Status s) {
+ GPR_ASSERT(s.ok());
+
+ EchoResponse response;
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buf, &response));
+ EXPECT_EQ(request.message(), response.message());
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+#if GRPC_ALLOW_EXCEPTIONS
+ if (maybe_except) {
+ throw - 1;
+ }
+#else
+ GPR_ASSERT(!maybe_except);
+#endif
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+ }
+ }
+
+ bool is_server_started_;
+ std::shared_ptr<Channel> channel_;
+ 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_P(ClientCallbackEnd2endTest, SimpleRpc) {
+ ResetStub();
+ SendRpcs(1, false);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialRpcs) {
+ ResetStub();
+ SendRpcs(10, false);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
+ ResetStub();
+ SendRpcs(10, true);
+}
+
+TEST_P(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
+ ResetStub();
+ SendRpcsGeneric(10, false);
+}
+
+#if GRPC_ALLOW_EXCEPTIONS
+TEST_P(ClientCallbackEnd2endTest, ExceptingRpc) {
+ ResetStub();
+ SendRpcsGeneric(10, true);
+}
+#endif
+
+TEST_P(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
+ ResetStub();
+ std::vector<std::thread> threads;
+ threads.reserve(10);
+ for (int i = 0; i < 10; ++i) {
+ threads.emplace_back([this] { SendRpcs(10, true); });
+ }
+ for (int i = 0; i < 10; ++i) {
+ threads[i].join();
+ }
+}
+
+TEST_P(ClientCallbackEnd2endTest, MultipleRpcs) {
+ ResetStub();
+ std::vector<std::thread> threads;
+ threads.reserve(10);
+ for (int i = 0; i < 10; ++i) {
+ threads.emplace_back([this] { SendRpcs(10, false); });
+ }
+ for (int i = 0; i < 10; ++i) {
+ threads[i].join();
+ }
+}
+
+TEST_P(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
+ ResetStub();
+ EchoRequest request;
+ EchoResponse response;
+ ClientContext context;
+ request.set_message("hello");
+ context.TryCancel();
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ stub_->experimental_async()->Echo(
+ &context, &request, &response, [&response, &done, &mu, &cv](Status s) {
+ EXPECT_EQ("", response.message());
+ EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+}
+
+TestScenario scenarios[] = {TestScenario{false}, TestScenario{true}};
+
+INSTANTIATE_TEST_CASE_P(ClientCallbackEnd2endTest, ClientCallbackEnd2endTest,
+ ::testing::ValuesIn(scenarios));
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/client_interceptors_end2end_test.cc b/test/cpp/end2end/client_interceptors_end2end_test.cc
new file mode 100644
index 0000000000..0b34ec93ae
--- /dev/null
+++ b/test/cpp/end2end/client_interceptors_end2end_test.cc
@@ -0,0 +1,667 @@
+/*
+ *
+ * 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 <memory>
+#include <vector>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/client_interceptor.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+/* Hijacks Echo RPC and fills in the expected values */
+class HijackingInterceptor : public experimental::Interceptor {
+ public:
+ HijackingInterceptor(experimental::ClientRpcInfo* info) {
+ info_ = info;
+ // Make sure it is the right method
+ EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+ }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ bool hijack = false;
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ hijack = true;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_EQ(req.message(), "Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ // Check that we got the hijacked message, and re-insert the expected
+ // message
+ EXPECT_EQ(resp->message(), "Hello1");
+ resp->set_message("Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here at the moment
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) {
+ // Insert a different message than expected
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ resp->set_message("Hello1");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ // insert the metadata that we want
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ map->insert(std::make_pair("testkey", "testvalue"));
+ auto* status = methods->GetRecvStatus();
+ *status = Status(StatusCode::OK, "");
+ }
+ if (hijack) {
+ methods->Hijack();
+ } else {
+ methods->Proceed();
+ }
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+};
+
+class HijackingInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new HijackingInterceptor(info);
+ }
+};
+
+class HijackingInterceptorMakesAnotherCall : public experimental::Interceptor {
+ public:
+ HijackingInterceptorMakesAnotherCall(experimental::ClientRpcInfo* info) {
+ info_ = info;
+ // Make sure it is the right method
+ EXPECT_EQ(strcmp("/grpc.testing.EchoTestService/Echo", info->method()), 0);
+ }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ // Make a copy of the map
+ metadata_map_ = *map;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_EQ(req.message(), "Hello");
+ req_ = req;
+ stub_ = grpc::testing::EchoTestService::NewStub(
+ methods->GetInterceptedChannel());
+ ctx_.AddMetadata(metadata_map_.begin()->first,
+ metadata_map_.begin()->second);
+ stub_->experimental_async()->Echo(&ctx_, &req_, &resp_,
+ [this, methods](Status s) {
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp_.message(), "Hello");
+ methods->Hijack();
+ });
+ // There isn't going to be any other interesting operation in this batch,
+ // so it is fine to return
+ return;
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ // Check that we got the hijacked message, and re-insert the expected
+ // message
+ EXPECT_EQ(resp->message(), "Hello");
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here at the moment
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) {
+ // Insert a different message than expected
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ resp->set_message(resp_.message());
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ // insert the metadata that we want
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ map->insert(std::make_pair("testkey", "testvalue"));
+ auto* status = methods->GetRecvStatus();
+ *status = Status(StatusCode::OK, "");
+ }
+
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+ std::multimap<grpc::string, grpc::string> metadata_map_;
+ ClientContext ctx_;
+ EchoRequest req_;
+ EchoResponse resp_;
+ std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+};
+
+class HijackingInterceptorMakesAnotherCallFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new HijackingInterceptorMakesAnotherCall(info);
+ }
+};
+
+class LoggingInterceptor : public experimental::Interceptor {
+ public:
+ LoggingInterceptor(experimental::ClientRpcInfo* info) { info_ = info; }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Check that we can see the test metadata
+ ASSERT_EQ(map->size(), static_cast<unsigned>(1));
+ auto iterator = map->begin();
+ EXPECT_EQ("testkey", iterator->first);
+ EXPECT_EQ("testvalue", iterator->second);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_TRUE(req.message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) {
+ // Got nothing to do here for now
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ EXPECT_TRUE(resp->message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_STATUS)) {
+ auto* map = methods->GetRecvTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.starts_with("testkey") &&
+ pair.second.starts_with("testvalue");
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto* status = methods->GetRecvStatus();
+ EXPECT_EQ(status->ok(), true);
+ }
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ClientRpcInfo* info_;
+};
+
+class LoggingInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new LoggingInterceptor(info);
+ }
+};
+
+class ClientInterceptorsEnd2endTest : public ::testing::Test {
+ protected:
+ ClientInterceptorsEnd2endTest() {
+ 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();
+ }
+
+ ~ClientInterceptorsEnd2endTest() { server_->Shutdown(); }
+
+ std::string server_address_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLoggingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // 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);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorHijackingTest) {
+ 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 before hijacking interceptor
+ for (auto i = 0; i < 20; i++) {
+ creators->push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ creators->push_back(std::unique_ptr<HijackingInterceptorFactory>(
+ new HijackingInterceptorFactory()));
+ // Add 20 dummy interceptors after hijacking interceptor
+ 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 only 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest, ClientInterceptorLogThenHijackTest) {
+ ChannelArguments args;
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ creators->push_back(std::unique_ptr<HijackingInterceptorFactory>(
+ new HijackingInterceptorFactory()));
+ auto channel = experimental::CreateCustomChannelWithInterceptors(
+ server_address_, InsecureChannelCredentials(), args, std::move(creators));
+
+ MakeCall(channel);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest,
+ ClientInterceptorHijackingMakesAnotherCallTest) {
+ 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 5 dummy interceptors before hijacking interceptor
+ for (auto i = 0; i < 5; i++) {
+ creators->push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ creators->push_back(
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>(
+ new HijackingInterceptorMakesAnotherCallFactory()));
+ // Add 7 dummy interceptors after hijacking interceptor
+ for (auto i = 0; i < 7; i++) {
+ creators->push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = server_->experimental().InProcessChannelWithInterceptors(
+ args, std::move(creators));
+
+ MakeCall(channel);
+ // Make sure all interceptors were run once, since the hijacking interceptor
+ // makes an RPC on the intercepted channel
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 12);
+}
+
+TEST_F(ClientInterceptorsEnd2endTest,
+ ClientInterceptorLoggingTestWithCallback) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // Add 20 dummy interceptors
+ for (auto i = 0; i < 20; i++) {
+ creators->push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ auto channel = server_->experimental().InProcessChannelWithInterceptors(
+ args, std::move(creators));
+ MakeCallbackCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ClientInterceptorsStreamingEnd2endTest : public ::testing::Test {
+ protected:
+ ClientInterceptorsStreamingEnd2endTest() {
+ 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();
+ }
+
+ ~ClientInterceptorsStreamingEnd2endTest() { server_->Shutdown(); }
+
+ std::string server_address_;
+ EchoTestServiceStreamingImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, ClientStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // 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));
+ MakeClientStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, ServerStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // 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));
+ MakeServerStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ClientInterceptorsStreamingEnd2endTest, BidiStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ creators->push_back(std::unique_ptr<LoggingInterceptorFactory>(
+ new LoggingInterceptorFactory()));
+ // 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));
+ MakeBidiStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ 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
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc
index 68219c16dc..d13fb23796 100644
--- a/test/cpp/end2end/client_lb_end2end_test.cc
+++ b/test/cpp/end2end/client_lb_end2end_test.cc
@@ -31,6 +31,7 @@
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
+#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
@@ -41,6 +42,9 @@
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+#include "src/cpp/client/secure_credentials.h"
+#include "src/cpp/server/secure_server_credentials.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
@@ -119,6 +123,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
}
void SetUp() override {
+ grpc_init();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
@@ -127,14 +132,26 @@ class ClientLbEnd2endTest : public ::testing::Test {
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i]->Shutdown();
}
+ grpc_shutdown();
}
- void StartServers(size_t num_servers,
- std::vector<int> ports = std::vector<int>()) {
+ void CreateServers(size_t num_servers,
+ std::vector<int> ports = std::vector<int>()) {
+ servers_.clear();
for (size_t i = 0; i < num_servers; ++i) {
int port = 0;
if (ports.size() == num_servers) port = ports[i];
- servers_.emplace_back(new ServerData(server_host_, port));
+ servers_.emplace_back(new ServerData(port));
+ }
+ }
+
+ void StartServer(size_t index) { servers_[index]->Start(server_host_); }
+
+ void StartServers(size_t num_servers,
+ std::vector<int> ports = std::vector<int>()) {
+ CreateServers(num_servers, std::move(ports));
+ for (size_t i = 0; i < num_servers; ++i) {
+ StartServer(i);
}
}
@@ -193,19 +210,22 @@ class ClientLbEnd2endTest : public ::testing::Test {
} // else, default to pick first
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
response_generator_.get());
- return CreateCustomChannel("fake:///", InsecureChannelCredentials(), args);
+ std::shared_ptr<ChannelCredentials> creds(new SecureChannelCredentials(
+ grpc_fake_transport_security_credentials_create()));
+ return CreateCustomChannel("fake:///", std::move(creds), args);
}
bool SendRpc(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
EchoResponse* response = nullptr, int timeout_ms = 1000,
- Status* result = nullptr) {
+ Status* result = nullptr, bool wait_for_ready = false) {
const bool local_response = (response == nullptr);
if (local_response) response = new EchoResponse;
EchoRequest request;
request.set_message(kRequestMessage_);
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
+ if (wait_for_ready) context.set_wait_for_ready(true);
Status status = stub->Echo(&context, request, response);
if (result != nullptr) *result = status;
if (local_response) delete response;
@@ -214,10 +234,11 @@ class ClientLbEnd2endTest : public ::testing::Test {
void CheckRpcSendOk(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
- const grpc_core::DebugLocation& location) {
+ const grpc_core::DebugLocation& location, bool wait_for_ready = false) {
EchoResponse response;
Status status;
- const bool success = SendRpc(stub, &response, 2000, &status);
+ const bool success =
+ SendRpc(stub, &response, 2000, &status, wait_for_ready);
ASSERT_TRUE(success) << "From " << location.file() << ":" << location.line()
<< "\n"
<< "Error: " << status.error_message() << " "
@@ -240,26 +261,30 @@ class ClientLbEnd2endTest : public ::testing::Test {
std::unique_ptr<std::thread> thread_;
bool server_ready_ = false;
- explicit ServerData(const grpc::string& server_host, int port = 0) {
+ explicit ServerData(int port = 0) {
port_ = port > 0 ? port : grpc_pick_unused_port_or_die();
+ }
+
+ void Start(const grpc::string& server_host) {
gpr_log(GPR_INFO, "starting server on port %d", port_);
std::mutex mu;
std::unique_lock<std::mutex> lock(mu);
std::condition_variable cond;
thread_.reset(new std::thread(
- std::bind(&ServerData::Start, this, server_host, &mu, &cond)));
+ std::bind(&ServerData::Serve, this, server_host, &mu, &cond)));
cond.wait(lock, [this] { return server_ready_; });
server_ready_ = false;
gpr_log(GPR_INFO, "server startup complete");
}
- void Start(const grpc::string& server_host, std::mutex* mu,
+ void Serve(const grpc::string& server_host, std::mutex* mu,
std::condition_variable* cond) {
std::ostringstream server_address;
server_address << server_host << ":" << port_;
ServerBuilder builder;
- builder.AddListeningPort(server_address.str(),
- InsecureServerCredentials());
+ std::shared_ptr<ServerCredentials> creds(new SecureServerCredentials(
+ grpc_fake_transport_security_server_credentials_create()));
+ builder.AddListeningPort(server_address.str(), std::move(creds));
builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
std::lock_guard<std::mutex> lock(*mu);
@@ -271,6 +296,10 @@ class ClientLbEnd2endTest : public ::testing::Test {
server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
if (join) thread_->join();
}
+
+ void SetServingStatus(const grpc::string& service, bool serving) {
+ server_->GetHealthCheckService()->SetServingStatus(service, serving);
+ }
};
void ResetCounters() {
@@ -285,7 +314,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
if (ignore_failure) {
SendRpc(stub);
} else {
- CheckRpcSendOk(stub, location);
+ CheckRpcSendOk(stub, location, true);
}
} while (servers_[server_idx]->service_.request_count() == 0);
ResetCounters();
@@ -302,6 +331,17 @@ class ClientLbEnd2endTest : public ::testing::Test {
return true;
}
+ bool WaitForChannelReady(Channel* channel, int timeout_seconds = 5) {
+ const gpr_timespec deadline =
+ grpc_timeout_seconds_to_deadline(timeout_seconds);
+ grpc_connectivity_state state;
+ while ((state = channel->GetState(true /* try_to_connect */)) !=
+ GRPC_CHANNEL_READY) {
+ if (!channel->WaitForStateChange(state, deadline)) return false;
+ }
+ return true;
+ }
+
bool SeenAllServers() {
for (const auto& server : servers_) {
if (server->service_.request_count() == 0) return false;
@@ -341,11 +381,7 @@ TEST_F(ClientLbEnd2endTest, PickFirst) {
StartServers(kNumServers);
auto channel = BuildChannel(""); // test that pick first is the default.
auto stub = BuildStub(channel);
- std::vector<int> ports;
- for (size_t i = 0; i < servers_.size(); ++i) {
- ports.emplace_back(servers_[i]->port_);
- }
- SetNextResolution(ports);
+ SetNextResolution(GetServersPorts());
for (size_t i = 0; i < servers_.size(); ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
}
@@ -490,7 +526,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) {
do {
channel_state = channel->GetState(true /* try to connect */);
} while (channel_state == GRPC_CHANNEL_READY);
- GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
+ ASSERT_NE(channel_state, GRPC_CHANNEL_READY);
servers_[0]->service_.ResetCounters();
// Next update introduces servers_[1], making the channel recover.
@@ -546,30 +582,44 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
-TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
+class ClientLbEnd2endWithParamTest
+ : public ClientLbEnd2endTest,
+ public ::testing::WithParamInterface<bool> {
+ protected:
+ void SetUp() override {
+ grpc_subchannel_index_test_only_set_force_creation(GetParam());
+ ClientLbEnd2endTest::SetUp();
+ }
+
+ void TearDown() override {
+ ClientLbEnd2endTest::TearDown();
+ grpc_subchannel_index_test_only_set_force_creation(false);
+ }
+};
+
+TEST_P(ClientLbEnd2endWithParamTest, PickFirstManyUpdates) {
+ gpr_log(GPR_INFO, "subchannel force creation: %d", GetParam());
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
auto channel = BuildChannel("pick_first");
auto stub = BuildStub(channel);
- std::vector<int> ports;
- for (size_t i = 0; i < servers_.size(); ++i) {
- ports.emplace_back(servers_[i]->port_);
- }
- for (const bool force_creation : {true, false}) {
- grpc_subchannel_index_test_only_set_force_creation(force_creation);
- gpr_log(GPR_INFO, "Force subchannel creation: %d", force_creation);
- for (size_t i = 0; i < 1000; ++i) {
- std::shuffle(ports.begin(), ports.end(),
- std::mt19937(std::random_device()()));
- SetNextResolution(ports);
- if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
- }
+ std::vector<int> ports = GetServersPorts();
+ for (size_t i = 0; i < 1000; ++i) {
+ std::shuffle(ports.begin(), ports.end(),
+ std::mt19937(std::random_device()()));
+ SetNextResolution(ports);
+ // We should re-enter core at the end of the loop to give the resolution
+ // setting closure a chance to run.
+ if ((i + 1) % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
}
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
+INSTANTIATE_TEST_CASE_P(SubchannelForceCreation, ClientLbEnd2endWithParamTest,
+ ::testing::Bool());
+
TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
// Prepare the ports for up servers and down servers.
const int kNumServers = 3;
@@ -601,6 +651,41 @@ TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
+TEST_F(ClientLbEnd2endTest, PickFirstReconnectWithoutNewResolverResult) {
+ std::vector<int> ports = {grpc_pick_unused_port_or_die()};
+ StartServers(1, ports);
+ auto channel = BuildChannel("pick_first");
+ auto stub = BuildStub(channel);
+ SetNextResolution(ports);
+ gpr_log(GPR_INFO, "****** INITIAL CONNECTION *******");
+ WaitForServer(stub, 0, DEBUG_LOCATION);
+ gpr_log(GPR_INFO, "****** STOPPING SERVER ******");
+ servers_[0]->Shutdown();
+ EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
+ gpr_log(GPR_INFO, "****** RESTARTING SERVER ******");
+ StartServers(1, ports);
+ WaitForServer(stub, 0, DEBUG_LOCATION);
+}
+
+TEST_F(ClientLbEnd2endTest,
+ PickFirstReconnectWithoutNewResolverResultStartsFromTopOfList) {
+ std::vector<int> ports = {grpc_pick_unused_port_or_die(),
+ grpc_pick_unused_port_or_die()};
+ CreateServers(2, ports);
+ StartServer(1);
+ auto channel = BuildChannel("pick_first");
+ auto stub = BuildStub(channel);
+ SetNextResolution(ports);
+ gpr_log(GPR_INFO, "****** INITIAL CONNECTION *******");
+ WaitForServer(stub, 1, DEBUG_LOCATION);
+ gpr_log(GPR_INFO, "****** STOPPING SERVER ******");
+ servers_[1]->Shutdown();
+ EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
+ gpr_log(GPR_INFO, "****** STARTING BOTH SERVERS ******");
+ StartServers(2, ports);
+ WaitForServer(stub, 0, DEBUG_LOCATION);
+}
+
TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
std::vector<int> ports = {grpc_pick_unused_port_or_die()};
StartServers(1, ports);
@@ -613,7 +698,6 @@ TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
servers_[0]->Shutdown();
// Channel 1 will receive a re-resolution containing the same server. It will
// create a new subchannel and hold a ref to it.
- servers_.clear();
StartServers(1, ports);
gpr_log(GPR_INFO, "****** SERVER RESTARTED *******");
auto channel_2 = BuildChannel("pick_first");
@@ -632,7 +716,6 @@ TEST_F(ClientLbEnd2endTest, PickFirstCheckStateBeforeStartWatch) {
EXPECT_TRUE(WaitForChannelNotReady(channel_2.get()));
// Channel 2 will also receive a re-resolution containing the same server.
// Both channels will ref the same subchannel that failed.
- servers_.clear();
StartServers(1, ports);
gpr_log(GPR_INFO, "****** SERVER RESTARTED AGAIN *******");
gpr_log(GPR_INFO, "****** CHANNEL 2 STARTING A CALL *******");
@@ -651,11 +734,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobin) {
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto stub = BuildStub(channel);
- std::vector<int> ports;
- for (const auto& server : servers_) {
- ports.emplace_back(server->port_);
- }
- SetNextResolution(ports);
+ SetNextResolution(GetServersPorts());
// Wait until all backends are ready.
do {
CheckRpcSendOk(stub, DEBUG_LOCATION);
@@ -764,7 +843,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
do {
channel_state = channel->GetState(true /* try to connect */);
} while (channel_state == GRPC_CHANNEL_READY);
- GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
+ ASSERT_NE(channel_state, GRPC_CHANNEL_READY);
servers_[0]->service_.ResetCounters();
// Next update introduces servers_[1], making the channel recover.
@@ -773,7 +852,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
SetNextResolution(ports);
WaitForServer(stub, 1, DEBUG_LOCATION);
channel_state = channel->GetState(false /* try to connect */);
- GPR_ASSERT(channel_state == GRPC_CHANNEL_READY);
+ ASSERT_EQ(channel_state, GRPC_CHANNEL_READY);
// Check LB policy name for the channel.
EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
@@ -817,10 +896,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinManyUpdates) {
StartServers(kNumServers);
auto channel = BuildChannel("round_robin");
auto stub = BuildStub(channel);
- std::vector<int> ports;
- for (size_t i = 0; i < servers_.size(); ++i) {
- ports.emplace_back(servers_[i]->port_);
- }
+ std::vector<int> ports = GetServersPorts();
for (size_t i = 0; i < 1000; ++i) {
std::shuffle(ports.begin(), ports.end(),
std::mt19937(std::random_device()()));
@@ -860,7 +936,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
// Kill all servers
gpr_log(GPR_INFO, "****** ABOUT TO KILL SERVERS *******");
for (size_t i = 0; i < servers_.size(); ++i) {
- servers_[i]->Shutdown(false);
+ servers_[i]->Shutdown(true);
}
gpr_log(GPR_INFO, "****** SERVERS KILLED *******");
gpr_log(GPR_INFO, "****** SENDING DOOMED REQUESTS *******");
@@ -886,7 +962,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
if (SendRpc(stub)) break;
now = gpr_now(GPR_CLOCK_MONOTONIC);
}
- GPR_ASSERT(gpr_time_cmp(deadline, now) > 0);
+ ASSERT_GT(gpr_time_cmp(deadline, now), 0);
}
TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
@@ -921,7 +997,8 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
// No requests have gone to the deceased server.
EXPECT_EQ(pre_death, post_death);
// Bring the first server back up.
- servers_[0].reset(new ServerData(server_host_, ports[0]));
+ servers_[0].reset(new ServerData(ports[0]));
+ StartServer(0);
// Requests should start arriving at the first server either right away (if
// the server managed to start before the RR policy retried the subchannel) or
// after the subchannel retry delay otherwise (RR's subchannel retried before
@@ -929,6 +1006,125 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
WaitForServer(stub, 0, DEBUG_LOCATION);
}
+// If health checking is required by client but health checking service
+// is not running on the server, the channel should be treated as healthy.
+TEST_F(ClientLbEnd2endTest,
+ RoundRobinServersHealthCheckingUnimplementedTreatedAsHealthy) {
+ StartServers(1); // Single server
+ ChannelArguments args;
+ args.SetServiceConfigJSON(
+ "{\"healthCheckConfig\": "
+ "{\"serviceName\": \"health_check_service_name\"}}");
+ auto channel = BuildChannel("round_robin", args);
+ auto stub = BuildStub(channel);
+ SetNextResolution({servers_[0]->port_});
+ EXPECT_TRUE(WaitForChannelReady(channel.get()));
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+}
+
+TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthChecking) {
+ EnableDefaultHealthCheckService(true);
+ // Start servers.
+ const int kNumServers = 3;
+ StartServers(kNumServers);
+ ChannelArguments args;
+ args.SetServiceConfigJSON(
+ "{\"healthCheckConfig\": "
+ "{\"serviceName\": \"health_check_service_name\"}}");
+ auto channel = BuildChannel("round_robin", args);
+ auto stub = BuildStub(channel);
+ SetNextResolution(GetServersPorts());
+ // Channel should not become READY, because health checks should be failing.
+ gpr_log(GPR_INFO,
+ "*** initial state: unknown health check service name for "
+ "all servers");
+ EXPECT_FALSE(WaitForChannelReady(channel.get(), 1));
+ // Now set one of the servers to be healthy.
+ // The channel should become healthy and all requests should go to
+ // the healthy server.
+ gpr_log(GPR_INFO, "*** server 0 healthy");
+ servers_[0]->SetServingStatus("health_check_service_name", true);
+ EXPECT_TRUE(WaitForChannelReady(channel.get()));
+ for (int i = 0; i < 10; ++i) {
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+ }
+ EXPECT_EQ(10, servers_[0]->service_.request_count());
+ EXPECT_EQ(0, servers_[1]->service_.request_count());
+ EXPECT_EQ(0, servers_[2]->service_.request_count());
+ // Now set a second server to be healthy.
+ gpr_log(GPR_INFO, "*** server 2 healthy");
+ servers_[2]->SetServingStatus("health_check_service_name", true);
+ WaitForServer(stub, 2, DEBUG_LOCATION);
+ for (int i = 0; i < 10; ++i) {
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+ }
+ EXPECT_EQ(5, servers_[0]->service_.request_count());
+ EXPECT_EQ(0, servers_[1]->service_.request_count());
+ EXPECT_EQ(5, servers_[2]->service_.request_count());
+ // Now set the remaining server to be healthy.
+ gpr_log(GPR_INFO, "*** server 1 healthy");
+ servers_[1]->SetServingStatus("health_check_service_name", true);
+ WaitForServer(stub, 1, DEBUG_LOCATION);
+ for (int i = 0; i < 9; ++i) {
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+ }
+ EXPECT_EQ(3, servers_[0]->service_.request_count());
+ EXPECT_EQ(3, servers_[1]->service_.request_count());
+ EXPECT_EQ(3, servers_[2]->service_.request_count());
+ // Now set one server to be unhealthy again. Then wait until the
+ // unhealthiness has hit the client. We know that the client will see
+ // this when we send kNumServers requests and one of the remaining servers
+ // sees two of the requests.
+ gpr_log(GPR_INFO, "*** server 0 unhealthy");
+ servers_[0]->SetServingStatus("health_check_service_name", false);
+ do {
+ ResetCounters();
+ for (int i = 0; i < kNumServers; ++i) {
+ CheckRpcSendOk(stub, DEBUG_LOCATION);
+ }
+ } while (servers_[1]->service_.request_count() != 2 &&
+ servers_[2]->service_.request_count() != 2);
+ // Now set the remaining two servers to be unhealthy. Make sure the
+ // channel leaves READY state and that RPCs fail.
+ gpr_log(GPR_INFO, "*** all servers unhealthy");
+ servers_[1]->SetServingStatus("health_check_service_name", false);
+ servers_[2]->SetServingStatus("health_check_service_name", false);
+ EXPECT_TRUE(WaitForChannelNotReady(channel.get()));
+ CheckRpcSendFailure(stub);
+ // Clean up.
+ EnableDefaultHealthCheckService(false);
+}
+
+TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingInhibitPerChannel) {
+ EnableDefaultHealthCheckService(true);
+ // Start server.
+ const int kNumServers = 1;
+ StartServers(kNumServers);
+ // Create a channel with health-checking enabled.
+ ChannelArguments args;
+ args.SetServiceConfigJSON(
+ "{\"healthCheckConfig\": "
+ "{\"serviceName\": \"health_check_service_name\"}}");
+ auto channel1 = BuildChannel("round_robin", args);
+ auto stub1 = BuildStub(channel1);
+ std::vector<int> ports = GetServersPorts();
+ SetNextResolution(ports);
+ // Create a channel with health checking enabled but inhibited.
+ args.SetInt(GRPC_ARG_INHIBIT_HEALTH_CHECKING, 1);
+ auto channel2 = BuildChannel("round_robin", args);
+ auto stub2 = BuildStub(channel2);
+ SetNextResolution(ports);
+ // First channel should not become READY, because health checks should be
+ // failing.
+ EXPECT_FALSE(WaitForChannelReady(channel1.get(), 1));
+ CheckRpcSendFailure(stub1);
+ // Second channel should be READY.
+ EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1));
+ CheckRpcSendOk(stub2, DEBUG_LOCATION);
+ // Clean up.
+ EnableDefaultHealthCheckService(false);
+}
+
} // namespace
} // namespace testing
} // namespace grpc
@@ -936,8 +1132,6 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_test_init(argc, argv);
- grpc_init();
const auto result = RUN_ALL_TESTS();
- grpc_shutdown();
return result;
}
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index fc07681535..03291e1785 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -40,6 +40,7 @@
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
#include "test/cpp/end2end/test_service_impl.h"
#include "test/cpp/util/string_ref_helper.h"
#include "test/cpp/util/test_credentials_provider.h"
@@ -179,7 +180,7 @@ class Proxy : public ::grpc::testing::EchoTestService::Service {
}
private:
- std::unique_ptr< ::grpc::testing::EchoTestService::Stub> stub_;
+ std::unique_ptr<::grpc::testing::EchoTestService::Stub> stub_;
};
class TestServiceImplDupPkg
@@ -194,9 +195,14 @@ class TestServiceImplDupPkg
class TestScenario {
public:
- TestScenario(bool proxy, bool inproc_stub, const grpc::string& creds_type)
- : use_proxy(proxy), inproc(inproc_stub), credentials_type(creds_type) {}
+ TestScenario(bool interceptors, bool proxy, bool inproc_stub,
+ const grpc::string& creds_type)
+ : use_interceptors(interceptors),
+ use_proxy(proxy),
+ inproc(inproc_stub),
+ credentials_type(creds_type) {}
void Log() const;
+ bool use_interceptors;
bool use_proxy;
bool inproc;
const grpc::string credentials_type;
@@ -204,8 +210,9 @@ class TestScenario {
static std::ostream& operator<<(std::ostream& out,
const TestScenario& scenario) {
- return out << "TestScenario{use_proxy="
- << (scenario.use_proxy ? "true" : "false")
+ return out << "TestScenario{use_interceptors="
+ << (scenario.use_interceptors ? "true" : "false")
+ << ", use_proxy=" << (scenario.use_proxy ? "true" : "false")
<< ", inproc=" << (scenario.inproc ? "true" : "false")
<< ", credentials='" << scenario.credentials_type << "'}";
}
@@ -260,6 +267,18 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
if (GetParam().credentials_type != kInsecureCredentialsType) {
server_creds->SetAuthMetadataProcessor(processor);
}
+ if (GetParam().use_interceptors) {
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ // Add 20 dummy server interceptors
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ }
builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_);
builder.RegisterService("foo.test.youtube.com", &special_service_);
@@ -292,10 +311,21 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
if (!GetParam().inproc) {
- channel_ =
- CreateCustomChannel(server_address_.str(), channel_creds, args);
+ if (!GetParam().use_interceptors) {
+ channel_ =
+ CreateCustomChannel(server_address_.str(), channel_creds, args);
+ } else {
+ channel_ = CreateCustomChannelWithInterceptors(
+ server_address_.str(), channel_creds, args,
+ CreateDummyClientInterceptors());
+ }
} else {
- channel_ = server_->InProcessChannel(args);
+ if (!GetParam().use_interceptors) {
+ channel_ = server_->InProcessChannel(args);
+ } else {
+ channel_ = server_->experimental().InProcessChannelWithInterceptors(
+ args, CreateDummyClientInterceptors());
+ }
}
}
@@ -320,6 +350,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
}
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+ DummyInterceptor::Reset();
}
bool is_server_started_;
@@ -376,6 +407,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestRequestStreamServerCancel(
ServerTryCancelRequestPhase server_try_cancel, int num_msgs_to_send) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -432,6 +464,10 @@ class End2endServerTryCancelTest : public End2endTest {
EXPECT_FALSE(s.ok());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Helper for testing server-streaming RPCs which are cancelled on the server.
@@ -449,6 +485,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestResponseStreamServerCancel(
ServerTryCancelRequestPhase server_try_cancel) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -508,7 +545,10 @@ class End2endServerTryCancelTest : public End2endTest {
}
EXPECT_FALSE(s.ok());
- EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Helper for testing bidirectional-streaming RPCs which are cancelled on the
@@ -526,6 +566,7 @@ class End2endServerTryCancelTest : public End2endTest {
// NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
void TestBidiStreamServerCancel(ServerTryCancelRequestPhase server_try_cancel,
int num_messages) {
+ RestartServer(std::shared_ptr<AuthMetadataProcessor>());
ResetStub();
EchoRequest request;
EchoResponse response;
@@ -592,6 +633,10 @@ class End2endServerTryCancelTest : public End2endTest {
EXPECT_FALSE(s.ok());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ // Make sure that the server interceptors were notified
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
};
@@ -989,6 +1034,9 @@ TEST_P(End2endTest, CancelRpcBeforeStart) {
Status s = stub_->Echo(&context, request, &response);
EXPECT_EQ("", response.message());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels request stream after sending two messages
@@ -1009,6 +1057,9 @@ TEST_P(End2endTest, ClientCancelsRequestStream) {
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
EXPECT_EQ(response.message(), "");
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels server stream after sending some messages
@@ -1041,6 +1092,9 @@ TEST_P(End2endTest, ClientCancelsResponseStream) {
// The final status could be either of CANCELLED or OK depending on
// who won the race.
EXPECT_GE(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
// Client cancels bidi stream after sending some messages
@@ -1074,6 +1128,9 @@ TEST_P(End2endTest, ClientCancelsBidi) {
Status s = stream->Finish();
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ if (GetParam().use_interceptors) {
+ EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel());
+ }
}
TEST_P(End2endTest, RpcMaxMessageSize) {
@@ -1802,13 +1859,16 @@ std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
}
GPR_ASSERT(!credentials_types.empty());
for (const auto& cred : credentials_types) {
- scenarios.emplace_back(false, false, cred);
+ scenarios.emplace_back(false, false, false, cred);
+ scenarios.emplace_back(true, false, false, cred);
if (use_proxy) {
- scenarios.emplace_back(true, false, cred);
+ scenarios.emplace_back(false, true, false, cred);
+ scenarios.emplace_back(true, true, false, cred);
}
}
if (test_inproc && insec_ok()) {
- scenarios.emplace_back(false, true, kInsecureCredentialsType);
+ scenarios.emplace_back(false, false, true, kInsecureCredentialsType);
+ scenarios.emplace_back(true, false, true, kInsecureCredentialsType);
}
return scenarios;
}
diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc
index b69b861fcf..6ce0696114 100644
--- a/test/cpp/end2end/grpclb_end2end_test.cc
+++ b/test/cpp/end2end/grpclb_end2end_test.cc
@@ -539,13 +539,15 @@ class GrpclbEnd2endTest : public ::testing::Test {
balancers_.at(i)->add_response(response, delay_ms);
}
- Status SendRpc(EchoResponse* response = nullptr, int timeout_ms = 1000) {
+ Status SendRpc(EchoResponse* response = nullptr, int timeout_ms = 1000,
+ bool wait_for_ready = false) {
const bool local_response = (response == nullptr);
if (local_response) response = new EchoResponse;
EchoRequest request;
request.set_message(kRequestMessage_);
ClientContext context;
context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
+ if (wait_for_ready) context.set_wait_for_ready(true);
Status status = stub_->Echo(&context, request, response);
if (local_response) delete response;
return status;
@@ -1366,7 +1368,7 @@ TEST_F(SingleBalancerTest, DropAllFirst) {
{}, {{"rate_limiting", num_of_drop_by_rate_limiting_addresses},
{"load_balancing", num_of_drop_by_load_balancing_addresses}}),
0);
- const Status status = SendRpc();
+ const Status status = SendRpc(nullptr, 1000, true);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
}
@@ -1391,7 +1393,7 @@ TEST_F(SingleBalancerTest, DropAll) {
// fail.
Status status;
do {
- status = SendRpc();
+ status = SendRpc(nullptr, 1000, true);
} while (status.ok());
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
index 1c48b9d151..fca65dfc13 100644
--- a/test/cpp/end2end/health_service_end2end_test.cc
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -64,6 +64,29 @@ class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service {
return Status::OK;
}
+ Status Watch(ServerContext* context, const HealthCheckRequest* request,
+ ::grpc::ServerWriter<HealthCheckResponse>* writer) override {
+ auto last_state = HealthCheckResponse::UNKNOWN;
+ while (!context->IsCancelled()) {
+ {
+ std::lock_guard<std::mutex> lock(mu_);
+ HealthCheckResponse response;
+ auto iter = status_map_.find(request->service());
+ if (iter == status_map_.end()) {
+ response.set_status(response.SERVICE_UNKNOWN);
+ } else {
+ response.set_status(iter->second);
+ }
+ if (response.status() != last_state) {
+ writer->Write(response, ::grpc::WriteOptions());
+ }
+ }
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_millis(1000, GPR_TIMESPAN)));
+ }
+ return Status::OK;
+ }
+
void SetStatus(const grpc::string& service_name,
HealthCheckResponse::ServingStatus status) {
std::lock_guard<std::mutex> lock(mu_);
@@ -106,14 +129,6 @@ class CustomHealthCheckService : public HealthCheckServiceInterface {
HealthCheckServiceImpl* impl_; // not owned
};
-void LoopCompletionQueue(ServerCompletionQueue* cq) {
- void* tag;
- bool ok;
- while (cq->Next(&tag, &ok)) {
- abort(); // Nothing should come out of the cq.
- }
-}
-
class HealthServiceEnd2endTest : public ::testing::Test {
protected:
HealthServiceEnd2endTest() {}
@@ -218,6 +233,33 @@ class HealthServiceEnd2endTest : public ::testing::Test {
Status(StatusCode::NOT_FOUND, ""));
}
+ void VerifyHealthCheckServiceStreaming() {
+ const grpc::string kServiceName("service_name");
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ // Start Watch for service.
+ ClientContext context;
+ HealthCheckRequest request;
+ request.set_service(kServiceName);
+ std::unique_ptr<::grpc::ClientReaderInterface<HealthCheckResponse>> reader =
+ hc_stub_->Watch(&context, request);
+ // Initial response will be SERVICE_UNKNOWN.
+ HealthCheckResponse response;
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.SERVICE_UNKNOWN, response.status());
+ response.Clear();
+ // Now set service to NOT_SERVING and make sure we get an update.
+ service->SetServingStatus(kServiceName, false);
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.NOT_SERVING, response.status());
+ response.Clear();
+ // Now set service to SERVING and make sure we get another update.
+ service->SetServingStatus(kServiceName, true);
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.SERVING, response.status());
+ // Finish call.
+ context.TryCancel();
+ }
+
TestServiceImpl echo_test_service_;
HealthCheckServiceImpl health_check_service_impl_;
std::unique_ptr<Health::Stub> hc_stub_;
@@ -245,6 +287,7 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
SetUpServer(true, false, false, nullptr);
VerifyHealthCheckService();
+ VerifyHealthCheckServiceStreaming();
// The default service has a size limit of the service name.
const grpc::string kTooLongServiceName(201, 'x');
@@ -252,22 +295,6 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
Status(StatusCode::INVALID_ARGUMENT, ""));
}
-// The server has no sync service.
-TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceAsyncOnly) {
- EnableDefaultHealthCheckService(true);
- EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
- SetUpServer(false, true, false, nullptr);
- cq_thread_ = std::thread(LoopCompletionQueue, cq_.get());
-
- HealthCheckServiceInterface* default_service =
- server_->GetHealthCheckService();
- EXPECT_TRUE(default_service == nullptr);
-
- ResetStubs();
-
- SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
-}
-
// Provide an empty service to disable the default service.
TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) {
EnableDefaultHealthCheckService(true);
@@ -296,6 +323,7 @@ TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) {
ResetStubs();
VerifyHealthCheckService();
+ VerifyHealthCheckServiceStreaming();
}
} // namespace
diff --git a/test/cpp/end2end/interceptors_util.cc b/test/cpp/end2end/interceptors_util.cc
new file mode 100644
index 0000000000..602d1695a3
--- /dev/null
+++ b/test/cpp/end2end/interceptors_util.cc
@@ -0,0 +1,151 @@
+/*
+ *
+ * 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 "test/cpp/end2end/interceptors_util.h"
+
+namespace grpc {
+namespace testing {
+
+std::atomic<int> DummyInterceptor::num_times_run_;
+std::atomic<int> DummyInterceptor::num_times_run_reverse_;
+std::atomic<int> DummyInterceptor::num_times_cancel_;
+
+void MakeCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ Status s = stub->Echo(&ctx, req, &resp);
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), "Hello");
+}
+
+void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ string expected_resp = "";
+ auto writer = stub->RequestStream(&ctx, &resp);
+ for (int i = 0; i < 10; i++) {
+ writer->Write(req);
+ expected_resp += "Hello";
+ }
+ writer->WritesDone();
+ Status s = writer->Finish();
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), expected_resp);
+}
+
+void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ string expected_resp = "";
+ auto reader = stub->ResponseStream(&ctx, req);
+ int count = 0;
+ while (reader->Read(&resp)) {
+ EXPECT_EQ(resp.message(), "Hello");
+ count++;
+ }
+ ASSERT_EQ(count, 10);
+ Status s = reader->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ EchoResponse resp;
+ ctx.AddMetadata("testkey", "testvalue");
+ auto stream = stub->BidiStream(&ctx);
+ for (auto i = 0; i < 10; i++) {
+ req.set_message("Hello" + std::to_string(i));
+ stream->Write(req);
+ stream->Read(&resp);
+ EXPECT_EQ(req.message(), resp.message());
+ }
+ ASSERT_TRUE(stream->WritesDone());
+ Status s = stream->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+void MakeCallbackCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ req.mutable_param()->set_echo_metadata(true);
+ ctx.AddMetadata("testkey", "testvalue");
+ req.set_message("Hello");
+ EchoResponse resp;
+ stub->experimental_async()->Echo(&ctx, &req, &resp,
+ [&resp, &mu, &done, &cv](Status s) {
+ // gpr_log(GPR_ERROR, "got the callback");
+ EXPECT_EQ(s.ok(), true);
+ EXPECT_EQ(resp.message(), "Hello");
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+}
+
+bool CheckMetadata(const std::multimap<grpc::string_ref, grpc::string_ref>& map,
+ const string& key, const string& value) {
+ for (const auto& pair : map) {
+ if (pair.first.starts_with(key) && pair.second.starts_with(value)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+CreateDummyClientInterceptors() {
+ auto creators = std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>(
+ new std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
+ // Add 20 dummy interceptors before hijacking interceptor
+ for (auto i = 0; i < 20; i++) {
+ creators->push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ return creators;
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/end2end/interceptors_util.h b/test/cpp/end2end/interceptors_util.h
new file mode 100644
index 0000000000..b4c4791fca
--- /dev/null
+++ b/test/cpp/end2end/interceptors_util.h
@@ -0,0 +1,279 @@
+/*
+ *
+ * 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 <condition_variable>
+
+#include <grpcpp/channel.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+/* This interceptor does nothing. Just keeps a global count on the number of
+ * times it was invoked. */
+class DummyInterceptor : public experimental::Interceptor {
+ public:
+ DummyInterceptor() {}
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ num_times_run_++;
+ } else if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::
+ POST_RECV_INITIAL_METADATA)) {
+ num_times_run_reverse_++;
+ } else if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_CANCEL)) {
+ num_times_cancel_++;
+ }
+ methods->Proceed();
+ }
+
+ static void Reset() {
+ num_times_run_.store(0);
+ num_times_run_reverse_.store(0);
+ num_times_cancel_.store(0);
+ }
+
+ static int GetNumTimesRun() {
+ EXPECT_EQ(num_times_run_.load(), num_times_run_reverse_.load());
+ return num_times_run_.load();
+ }
+
+ static int GetNumTimesCancel() { return num_times_cancel_.load(); }
+
+ private:
+ static std::atomic<int> num_times_run_;
+ static std::atomic<int> num_times_run_reverse_;
+ static std::atomic<int> num_times_cancel_;
+};
+
+class DummyInterceptorFactory
+ : public experimental::ClientInterceptorFactoryInterface,
+ public experimental::ServerInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateClientInterceptor(
+ experimental::ClientRpcInfo* info) override {
+ return new DummyInterceptor();
+ }
+
+ virtual experimental::Interceptor* CreateServerInterceptor(
+ experimental::ServerRpcInfo* info) override {
+ return new DummyInterceptor();
+ }
+};
+
+class EchoTestServiceStreamingImpl : public EchoTestService::Service {
+ public:
+ ~EchoTestServiceStreamingImpl() override {}
+
+ Status BidiStream(
+ ServerContext* context,
+ grpc::ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
+ EchoRequest req;
+ EchoResponse resp;
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ while (stream->Read(&req)) {
+ resp.set_message(req.message());
+ EXPECT_TRUE(stream->Write(resp, grpc::WriteOptions()));
+ }
+ return Status::OK;
+ }
+
+ Status RequestStream(ServerContext* context,
+ ServerReader<EchoRequest>* reader,
+ EchoResponse* resp) override {
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ EchoRequest req;
+ string response_str = "";
+ while (reader->Read(&req)) {
+ response_str += req.message();
+ }
+ resp->set_message(response_str);
+ return Status::OK;
+ }
+
+ Status ResponseStream(ServerContext* context, const EchoRequest* req,
+ ServerWriter<EchoResponse>* writer) override {
+ auto client_metadata = context->client_metadata();
+ for (const auto& pair : client_metadata) {
+ context->AddTrailingMetadata(ToString(pair.first), ToString(pair.second));
+ }
+
+ EchoResponse resp;
+ resp.set_message(req->message());
+ for (int i = 0; i < 10; i++) {
+ EXPECT_TRUE(writer->Write(resp));
+ }
+ return Status::OK;
+ }
+};
+
+void MakeCall(const std::shared_ptr<Channel>& channel);
+
+void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel);
+
+void MakeCallbackCall(const std::shared_ptr<Channel>& channel);
+
+bool CheckMetadata(const std::multimap<grpc::string_ref, grpc::string_ref>& map,
+ const string& key, const string& value);
+
+std::unique_ptr<std::vector<
+ std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
+CreateDummyClientInterceptors();
+
+inline void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
+inline int detag(void* p) {
+ return static_cast<int>(reinterpret_cast<intptr_t>(p));
+}
+
+class Verifier {
+ public:
+ Verifier() : lambda_run_(false) {}
+ // Expect sets the expected ok value for a specific tag
+ Verifier& Expect(int i, bool expect_ok) {
+ return ExpectUnless(i, expect_ok, false);
+ }
+ // ExpectUnless sets the expected ok value for a specific tag
+ // unless the tag was already marked seen (as a result of ExpectMaybe)
+ Verifier& ExpectUnless(int i, bool expect_ok, bool seen) {
+ if (!seen) {
+ expectations_[tag(i)] = expect_ok;
+ }
+ return *this;
+ }
+ // ExpectMaybe sets the expected ok value for a specific tag, but does not
+ // require it to appear
+ // If it does, sets *seen to true
+ Verifier& ExpectMaybe(int i, bool expect_ok, bool* seen) {
+ if (!*seen) {
+ maybe_expectations_[tag(i)] = MaybeExpect{expect_ok, seen};
+ }
+ return *this;
+ }
+
+ // Next waits for 1 async tag to complete, checks its
+ // expectations, and returns the tag
+ int Next(CompletionQueue* cq, bool ignore_ok) {
+ bool ok;
+ void* got_tag;
+ EXPECT_TRUE(cq->Next(&got_tag, &ok));
+ GotTag(got_tag, ok, ignore_ok);
+ return detag(got_tag);
+ }
+
+ template <typename T>
+ CompletionQueue::NextStatus DoOnceThenAsyncNext(
+ CompletionQueue* cq, void** got_tag, bool* ok, T deadline,
+ std::function<void(void)> lambda) {
+ if (lambda_run_) {
+ return cq->AsyncNext(got_tag, ok, deadline);
+ } else {
+ lambda_run_ = true;
+ return cq->DoThenAsyncNext(lambda, got_tag, ok, deadline);
+ }
+ }
+
+ // Verify keeps calling Next until all currently set
+ // expected tags are complete
+ void Verify(CompletionQueue* cq) { Verify(cq, false); }
+
+ // This version of Verify allows optionally ignoring the
+ // outcome of the expectation
+ void Verify(CompletionQueue* cq, bool ignore_ok) {
+ GPR_ASSERT(!expectations_.empty() || !maybe_expectations_.empty());
+ while (!expectations_.empty()) {
+ Next(cq, ignore_ok);
+ }
+ }
+
+ // This version of Verify stops after a certain deadline, and uses the
+ // DoThenAsyncNext API
+ // to call the lambda
+ void Verify(CompletionQueue* cq,
+ std::chrono::system_clock::time_point deadline,
+ const std::function<void(void)>& lambda) {
+ if (expectations_.empty()) {
+ bool ok;
+ void* got_tag;
+ EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+ CompletionQueue::TIMEOUT);
+ } else {
+ while (!expectations_.empty()) {
+ bool ok;
+ void* got_tag;
+ EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+ CompletionQueue::GOT_EVENT);
+ GotTag(got_tag, ok, false);
+ }
+ }
+ }
+
+ private:
+ void GotTag(void* got_tag, bool ok, bool ignore_ok) {
+ auto it = expectations_.find(got_tag);
+ if (it != expectations_.end()) {
+ if (!ignore_ok) {
+ EXPECT_EQ(it->second, ok);
+ }
+ expectations_.erase(it);
+ } else {
+ auto it2 = maybe_expectations_.find(got_tag);
+ if (it2 != maybe_expectations_.end()) {
+ if (it2->second.seen != nullptr) {
+ EXPECT_FALSE(*it2->second.seen);
+ *it2->second.seen = true;
+ }
+ if (!ignore_ok) {
+ EXPECT_EQ(it2->second.ok, ok);
+ }
+ } else {
+ gpr_log(GPR_ERROR, "Unexpected tag: %p", got_tag);
+ abort();
+ }
+ }
+ }
+
+ struct MaybeExpect {
+ bool ok;
+ bool* seen;
+ };
+
+ std::map<void*, bool> expectations_;
+ std::map<void*, MaybeExpect> maybe_expectations_;
+ bool lambda_run_;
+};
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc
new file mode 100644
index 0000000000..295d63516b
--- /dev/null
+++ b/test/cpp/end2end/server_interceptors_end2end_test.cc
@@ -0,0 +1,583 @@
+/*
+ *
+ * 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 <memory>
+#include <vector>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/impl/codegen/server_interceptor.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/interceptors_util.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class LoggingInterceptor : public experimental::Interceptor {
+ public:
+ LoggingInterceptor(experimental::ServerRpcInfo* info) { info_ = info; }
+
+ virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
+ auto* map = methods->GetSendInitialMetadata();
+ // Got nothing better to do here for now
+ EXPECT_EQ(map->size(), static_cast<unsigned>(0));
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) {
+ EchoRequest req;
+ auto* buffer = methods->GetSendMessage();
+ auto copied_buffer = *buffer;
+ EXPECT_TRUE(
+ SerializationTraits<EchoRequest>::Deserialize(&copied_buffer, &req)
+ .ok());
+ EXPECT_TRUE(req.message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::PRE_SEND_STATUS)) {
+ auto* map = methods->GetSendTrailingMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.find("testkey") == 0 &&
+ pair.second.find("testvalue") == 0;
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ auto status = methods->GetSendStatus();
+ EXPECT_EQ(status.ok(), true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
+ auto* map = methods->GetRecvInitialMetadata();
+ bool found = false;
+ // Check that we received the metadata as an echo
+ for (const auto& pair : *map) {
+ found = pair.first.find("testkey") == 0 &&
+ pair.second.find("testvalue") == 0;
+ if (found) break;
+ }
+ EXPECT_EQ(found, true);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) {
+ EchoResponse* resp =
+ static_cast<EchoResponse*>(methods->GetRecvMessage());
+ EXPECT_TRUE(resp->message().find("Hello") == 0);
+ }
+ if (methods->QueryInterceptionHookPoint(
+ experimental::InterceptionHookPoints::POST_RECV_CLOSE)) {
+ // Got nothing interesting to do here
+ }
+ methods->Proceed();
+ }
+
+ private:
+ experimental::ServerRpcInfo* info_;
+};
+
+class LoggingInterceptorFactory
+ : public experimental::ServerInterceptorFactoryInterface {
+ public:
+ virtual experimental::Interceptor* CreateServerInterceptor(
+ experimental::ServerRpcInfo* info) override {
+ return new LoggingInterceptor(info);
+ }
+};
+
+void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+ ClientContext ctx;
+ EchoRequest req;
+ EchoResponse resp;
+ ctx.AddMetadata("testkey", "testvalue");
+ auto stream = stub->BidiStream(&ctx);
+ for (auto i = 0; i < 10; i++) {
+ req.set_message("Hello" + std::to_string(i));
+ stream->Write(req);
+ stream->Read(&resp);
+ EXPECT_EQ(req.message(), resp.message());
+ }
+ ASSERT_TRUE(stream->WritesDone());
+ Status s = stream->Finish();
+ EXPECT_EQ(s.ok(), true);
+}
+
+class ServerInterceptorsEnd2endSyncUnaryTest : public ::testing::Test {
+ protected:
+ ServerInterceptorsEnd2endSyncUnaryTest() {
+ 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_);
+
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ server_ = builder.BuildAndStart();
+ }
+ std::string server_address_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ServerInterceptorsEnd2endSyncUnaryTest, UnaryTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ServerInterceptorsEnd2endSyncStreamingTest : public ::testing::Test {
+ protected:
+ ServerInterceptorsEnd2endSyncStreamingTest() {
+ 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_);
+
+ std::vector<
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ server_ = builder.BuildAndStart();
+ }
+ std::string server_address_;
+ EchoTestServiceStreamingImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ClientStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeClientStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ServerStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeServerStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, BidiStreamingTest) {
+ ChannelArguments args;
+ DummyInterceptor::Reset();
+ auto channel = CreateChannel(server_address_, InsecureChannelCredentials());
+ MakeBidiStreamingCall(channel);
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+}
+
+class ServerInterceptorsAsyncEnd2endTest : public ::testing::Test {};
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, UnaryTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ EchoTestService::AsyncService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+ std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+ stub->AsyncEcho(&cli_ctx, send_request, cq.get()));
+
+ service.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq.get(),
+ cq.get(), tag(2));
+
+ response_reader->Finish(&recv_response, &recv_status, tag(4));
+
+ Verifier().Expect(2, true).Verify(cq.get());
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ send_response.set_message(recv_request.message());
+ response_writer.Finish(send_response, Status::OK, tag(3));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq.get());
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, BidiStreamingTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ EchoTestService::AsyncService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.push_back(
+ std::unique_ptr<experimental::ServerInterceptorFactoryInterface>(
+ new LoggingInterceptorFactory()));
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ auto stub = grpc::testing::EchoTestService::NewStub(channel);
+
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ ServerContext srv_ctx;
+ grpc::ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+ std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
+ cli_stream(stub->AsyncBidiStream(&cli_ctx, cq.get(), tag(1)));
+
+ service.RequestBidiStream(&srv_ctx, &srv_stream, cq.get(), cq.get(), tag(2));
+
+ Verifier().Expect(1, true).Expect(2, true).Verify(cq.get());
+
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ cli_stream->Write(send_request, tag(3));
+ srv_stream.Read(&recv_request, tag(4));
+ Verifier().Expect(3, true).Expect(4, true).Verify(cq.get());
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ srv_stream.Write(send_response, tag(5));
+ cli_stream->Read(&recv_response, tag(6));
+ Verifier().Expect(5, true).Expect(6, true).Verify(cq.get());
+ EXPECT_EQ(send_response.message(), recv_response.message());
+
+ cli_stream->WritesDone(tag(7));
+ srv_stream.Read(&recv_request, tag(8));
+ Verifier().Expect(7, true).Expect(8, false).Verify(cq.get());
+
+ srv_stream.Finish(Status::OK, tag(9));
+ cli_stream->Finish(&recv_status, tag(10));
+ Verifier().Expect(9, true).Expect(10, true).Verify(cq.get());
+
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, GenericRPCTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ AsyncGenericService service;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ builder.RegisterAsyncGenericService(&service);
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ auto channel = CreateChannel(server_address, InsecureChannelCredentials());
+ GenericStub generic_stub(channel);
+
+ const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
+ EchoRequest send_request;
+ EchoRequest recv_request;
+ EchoResponse send_response;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ GenericServerContext srv_ctx;
+ GenericServerAsyncReaderWriter stream(&srv_ctx);
+
+ // The string needs to be long enough to test heap-based slice.
+ send_request.set_message("Hello");
+ cli_ctx.AddMetadata("testkey", "testvalue");
+
+ std::unique_ptr<GenericClientAsyncReaderWriter> call =
+ generic_stub.PrepareCall(&cli_ctx, kMethodName, cq.get());
+ call->StartCall(tag(1));
+ Verifier().Expect(1, true).Verify(cq.get());
+ std::unique_ptr<ByteBuffer> send_buffer =
+ SerializeToByteBuffer(&send_request);
+ call->Write(*send_buffer, tag(2));
+ // Send ByteBuffer can be destroyed after calling Write.
+ send_buffer.reset();
+ Verifier().Expect(2, true).Verify(cq.get());
+ call->WritesDone(tag(3));
+ Verifier().Expect(3, true).Verify(cq.get());
+
+ service.RequestCall(&srv_ctx, &stream, cq.get(), cq.get(), tag(4));
+
+ Verifier().Expect(4, true).Verify(cq.get());
+ EXPECT_EQ(kMethodName, srv_ctx.method());
+ EXPECT_TRUE(CheckMetadata(srv_ctx.client_metadata(), "testkey", "testvalue"));
+ srv_ctx.AddTrailingMetadata("testkey", "testvalue");
+
+ ByteBuffer recv_buffer;
+ stream.Read(&recv_buffer, tag(5));
+ Verifier().Expect(5, true).Verify(cq.get());
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+ EXPECT_EQ(send_request.message(), recv_request.message());
+
+ send_response.set_message(recv_request.message());
+ send_buffer = SerializeToByteBuffer(&send_response);
+ stream.Write(*send_buffer, tag(6));
+ send_buffer.reset();
+ Verifier().Expect(6, true).Verify(cq.get());
+
+ stream.Finish(Status::OK, tag(7));
+ Verifier().Expect(7, true).Verify(cq.get());
+
+ recv_buffer.Clear();
+ call->Read(&recv_buffer, tag(8));
+ Verifier().Expect(8, true).Verify(cq.get());
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
+
+ call->Finish(&recv_status, tag(9));
+ Verifier().Expect(9, true).Verify(cq.get());
+
+ EXPECT_EQ(send_response.message(), recv_response.message());
+ EXPECT_TRUE(recv_status.ok());
+ EXPECT_TRUE(CheckMetadata(cli_ctx.GetServerTrailingMetadata(), "testkey",
+ "testvalue"));
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+TEST_F(ServerInterceptorsAsyncEnd2endTest, UnimplementedRpcTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ std::shared_ptr<Channel> channel =
+ CreateChannel(server_address, InsecureChannelCredentials());
+ std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
+ stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
+ EchoRequest send_request;
+ EchoResponse recv_response;
+ Status recv_status;
+
+ ClientContext cli_ctx;
+ send_request.set_message("Hello");
+ std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+ stub->AsyncUnimplemented(&cli_ctx, send_request, cq.get()));
+
+ response_reader->Finish(&recv_response, &recv_status, tag(4));
+ Verifier().Expect(4, true).Verify(cq.get());
+
+ EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
+ EXPECT_EQ("", recv_status.error_message());
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ cq->Shutdown();
+ void* ignored_tag;
+ bool ignored_ok;
+ while (cq->Next(&ignored_tag, &ignored_ok))
+ ;
+ grpc_recycle_unused_port(port);
+}
+
+class ServerInterceptorsSyncUnimplementedEnd2endTest : public ::testing::Test {
+};
+
+TEST_F(ServerInterceptorsSyncUnimplementedEnd2endTest, UnimplementedRpcTest) {
+ DummyInterceptor::Reset();
+ int port = grpc_pick_unused_port_or_die();
+ string server_address = "localhost:" + std::to_string(port);
+ ServerBuilder builder;
+ TestServiceImpl service;
+ builder.RegisterService(&service);
+ builder.AddListeningPort(server_address, InsecureServerCredentials());
+ std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
+ creators;
+ creators.reserve(20);
+ for (auto i = 0; i < 20; i++) {
+ creators.push_back(std::unique_ptr<DummyInterceptorFactory>(
+ new DummyInterceptorFactory()));
+ }
+ builder.experimental().SetInterceptorCreators(std::move(creators));
+ auto server = builder.BuildAndStart();
+
+ ChannelArguments args;
+ std::shared_ptr<Channel> channel =
+ CreateChannel(server_address, InsecureChannelCredentials());
+ std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
+ stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
+ EchoRequest send_request;
+ EchoResponse recv_response;
+
+ ClientContext cli_ctx;
+ send_request.set_message("Hello");
+ Status recv_status =
+ stub->Unimplemented(&cli_ctx, send_request, &recv_response);
+
+ EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
+ EXPECT_EQ("", recv_status.error_message());
+
+ // Make sure all 20 dummy interceptors were run
+ EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20);
+
+ server->Shutdown();
+ grpc_recycle_unused_port(port);
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
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/interop/BUILD b/test/cpp/interop/BUILD
index 4f21551ff4..0f81305405 100644
--- a/test/cpp/interop/BUILD
+++ b/test/cpp/interop/BUILD
@@ -142,3 +142,24 @@ grpc_cc_binary(
"//test/cpp/util:test_config",
],
)
+
+grpc_cc_test(
+ name = "interop_test",
+ srcs = ["interop_test.cc"],
+ data = [
+ ":interop_client",
+ ":interop_server",
+ ],
+ external_deps = [
+ "gflags",
+ ],
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_config",
+ "//test/cpp/util:test_util",
+ ],
+)
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 7bcf23c0eb..a4b1a85f85 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -57,6 +57,7 @@ DEFINE_string(
"half_duplex : half-duplex streaming;\n"
"jwt_token_creds: large_unary with JWT token auth;\n"
"large_unary : single request and (large) response;\n"
+ "long_lived_channel: sends large_unary rpcs over a long-lived channel;\n"
"oauth2_auth_token: raw oauth2 access token auth;\n"
"per_rpc_creds: raw oauth2 access token on a single rpc;\n"
"ping_pong : full-duplex streaming;\n"
@@ -84,10 +85,12 @@ DEFINE_bool(do_not_abort_on_transient_failures, false,
"whether abort() is called or not. It does not control whether the "
"test is retried in case of transient failures (and currently the "
"interop tests are not retried even if this flag is set to true)");
-
DEFINE_int32(soak_iterations, 1000,
"number of iterations to use for the two soak tests; rpc_soak and "
"channel_soak");
+DEFINE_int32(iteration_interval, 10,
+ "The interval in seconds between rpcs. This is used by "
+ "long_connection test");
using grpc::testing::CreateChannelForTestCase;
using grpc::testing::GetServiceAccountJsonKey;
@@ -163,6 +166,9 @@ int main(int argc, char** argv) {
FLAGS_soak_iterations);
actions["rpc_soak"] = std::bind(&grpc::testing::InteropClient::DoRpcSoakTest,
&client, FLAGS_soak_iterations);
+ actions["long_lived_channel"] =
+ std::bind(&grpc::testing::InteropClient::DoLongLivedChannelTest, &client,
+ FLAGS_soak_iterations, FLAGS_iteration_interval);
UpdateActions(&actions);
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index eada2f671f..7dee85cc98 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -19,10 +19,12 @@
#ifndef GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
#define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
+#include <functional>
#include <memory>
#include <unordered_map>
#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
#include "src/core/lib/surface/call_test_only.h"
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index b7ce90803b..4ff153f980 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -76,7 +76,7 @@ void UnaryCompressionChecks(const InteropClientContextInspector& inspector,
InteropClient::ServiceStub::ServiceStub(
ChannelCreationFunc channel_creation_func, bool new_stub_every_call)
- : channel_creation_func_(channel_creation_func),
+ : channel_creation_func_(std::move(channel_creation_func)),
channel_(channel_creation_func_()),
new_stub_every_call_(new_stub_every_call) {
// If new_stub_every_call is false, then this is our chance to initialize
@@ -112,7 +112,7 @@ void InteropClient::ServiceStub::ResetChannel() {
InteropClient::InteropClient(ChannelCreationFunc channel_creation_func,
bool new_stub_every_test_case,
bool do_not_abort_on_transient_failures)
- : serviceStub_(channel_creation_func, new_stub_every_test_case),
+ : serviceStub_(std::move(channel_creation_func), new_stub_every_test_case),
do_not_abort_on_transient_failures_(do_not_abort_on_transient_failures) {}
bool InteropClient::AssertStatusOk(const Status& s,
@@ -1052,6 +1052,34 @@ bool InteropClient::DoChannelSoakTest(int32_t soak_iterations) {
return true;
}
+bool InteropClient::DoLongLivedChannelTest(int32_t soak_iterations,
+ int32_t iteration_interval) {
+ gpr_log(GPR_DEBUG, "Sending %d RPCs...", soak_iterations);
+ GPR_ASSERT(soak_iterations > 0);
+ GPR_ASSERT(iteration_interval > 0);
+ SimpleRequest request;
+ SimpleResponse response;
+ int num_failures = 0;
+ for (int i = 0; i < soak_iterations; ++i) {
+ gpr_log(GPR_DEBUG, "Sending RPC number %d...", i);
+ if (!PerformLargeUnary(&request, &response)) {
+ gpr_log(GPR_ERROR, "Iteration %d failed.", i);
+ num_failures++;
+ }
+ gpr_sleep_until(
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_seconds(iteration_interval, GPR_TIMESPAN)));
+ }
+ if (num_failures == 0) {
+ gpr_log(GPR_DEBUG, "long_lived_channel test done.");
+ return true;
+ } else {
+ gpr_log(GPR_DEBUG, "long_lived_channel test failed with %d rpc failures.",
+ num_failures);
+ return false;
+ }
+}
+
bool InteropClient::DoUnimplementedService() {
gpr_log(GPR_DEBUG, "Sending a request for an unimplemented service...");
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index e5be44d1d4..0ceff55c5c 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -76,6 +76,8 @@ class InteropClient {
// languages
bool DoChannelSoakTest(int32_t soak_iterations);
bool DoRpcSoakTest(int32_t soak_iterations);
+ bool DoLongLivedChannelTest(int32_t soak_iterations,
+ int32_t iteration_interval);
// Auth tests.
// username is a string containing the user email
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 7dc1956f78..5bbe913365 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -73,7 +73,7 @@ StressTestInteropClient::StressTestInteropClient(
long sleep_duration_ms, bool do_not_abort_on_transient_failures)
: test_id_(test_id),
server_address_(server_address),
- channel_creation_func_(channel_creation_func),
+ channel_creation_func_(std::move(channel_creation_func)),
interop_client_(new InteropClient(channel_creation_func_, false,
do_not_abort_on_transient_failures)),
test_selector_(test_selector),
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 0c3b9ef816..097e92f583 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -24,7 +24,7 @@ grpc_cc_test(
external_deps = [
"benchmark",
],
- deps = ["//test/core/util:gpr_test_util",]
+ deps = ["//test/core/util:gpr_test_util"],
)
grpc_cc_library(
@@ -69,6 +69,13 @@ grpc_cc_binary(
)
grpc_cc_binary(
+ name = "bm_call_create",
+ testonly = 1,
+ srcs = ["bm_call_create.cc"],
+ deps = [":helpers"],
+)
+
+grpc_cc_binary(
name = "bm_cq",
testonly = 1,
srcs = ["bm_cq.cc"],
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 9516b2e3e2..446dc93edb 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -34,7 +34,6 @@
#include "src/core/ext/filters/http/client/http_client_filter.h"
#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
#include "src/core/ext/filters/http/server/http_server_filter.h"
-#include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
#include "src/core/ext/filters/message_size/message_size_filter.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/connected_channel.h"
@@ -133,8 +132,10 @@ static void BM_LameChannelCallCreateCpp(benchmark::State& state) {
TrackCounters track_counters;
auto stub =
grpc::testing::EchoTestService::NewStub(grpc::CreateChannelInternal(
- "", grpc_lame_client_channel_create(
- "localhost:1234", GRPC_STATUS_UNAUTHENTICATED, "blah")));
+ "",
+ grpc_lame_client_channel_create("localhost:1234",
+ GRPC_STATUS_UNAUTHENTICATED, "blah"),
+ nullptr));
grpc::CompletionQueue cq;
grpc::testing::EchoRequest send_request;
grpc::testing::EchoResponse recv_response;
@@ -467,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 6fcf048bf3..85d233dd26 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -27,6 +27,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -456,8 +457,9 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
grpc_chttp2_hpack_parser p;
grpc_chttp2_hpack_parser_init(&p);
+ const int kArenaSize = 4096 * 4096;
+ p.on_header_user_data = gpr_arena_create(kArenaSize);
p.on_header = OnHeader;
- p.on_header_user_data = nullptr;
for (auto slice : init_slices) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
@@ -466,7 +468,14 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
grpc_core::ExecCtx::Get()->Flush();
+ // Recreate arena every 4k iterations to avoid oom
+ if (0 == (state.iterations() & 0xfff)) {
+ gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
+ p.on_header_user_data = gpr_arena_create(kArenaSize);
+ }
}
+ // Clean up
+ gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
for (auto slice : init_slices) grpc_slice_unref(slice);
for (auto slice : benchmark_slices) grpc_slice_unref(slice);
grpc_chttp2_hpack_parser_destroy(&p);
@@ -766,8 +775,56 @@ class RepresentativeServerTrailingMetadata {
static void free_timeout(void* p) { gpr_free(p); }
-// New implementation.
-static void OnHeaderNew(void* user_data, grpc_mdelem md) {
+// 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((gpr_arena*)user_data);
+ bool seen_error = false;
+
+ // Below here is the code we actually care about benchmarking
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ seen_error = true;
+ }
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
+ grpc_millis* cached_timeout =
+ static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
+ grpc_millis timeout;
+ if (cached_timeout != nullptr) {
+ timeout = *cached_timeout;
+ } else {
+ if (GPR_UNLIKELY(
+ !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
+ char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+ gpr_free(val);
+ timeout = GRPC_MILLIS_INF_FUTURE;
+ }
+ if (GRPC_MDELEM_IS_INTERNED(md)) {
+ /* not already parsed: parse it now, and store the
+ * result away */
+ cached_timeout =
+ static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
+ *cached_timeout = timeout;
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ }
+ }
+ benchmark::DoNotOptimize(timeout);
+ GRPC_MDELEM_UNREF(md);
+ } else {
+ const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
+ if (!seen_error) {
+ buffer.size = new_size;
+ }
+ grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
+ if (error != GRPC_ERROR_NONE) {
+ GPR_ASSERT(0);
+ }
+ }
+}
+
+// Benchmark timeout handling
+static void OnHeaderTimeout(void* user_data, grpc_mdelem md) {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
@@ -853,8 +910,13 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata, UnrefHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerTrailingMetadata, UnrefHeader);
-
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderNew);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeClientInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ MoreRepresentativeClientInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
} // namespace hpack_parser_fixtures
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/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
index 5a7a8d5baf..d4bd58b983 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
@@ -31,6 +31,8 @@ auto& force_library_initialization = Library::get();
* CONFIGURATIONS
*/
+// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use
+// internal microbenchmarking tooling
static void SweepSizesArgs(benchmark::internal::Benchmark* b) {
b->Args({0, 0});
for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index 9d70277fbc..e57eb6ddd1 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -48,6 +48,7 @@ namespace testing {
class FixtureConfiguration {
public:
+ virtual ~FixtureConfiguration() {}
virtual void ApplyCommonChannelArguments(ChannelArguments* c) const {
c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
@@ -199,7 +200,7 @@ class EndpointPairFixture : public BaseFixture {
}
grpc_server_setup_transport(server_->c_server(), server_transport_,
- nullptr, server_args);
+ nullptr, server_args, 0);
grpc_chttp2_transport_start_reading(server_transport_, nullptr, nullptr);
}
@@ -217,7 +218,7 @@ class EndpointPairFixture : public BaseFixture {
"target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport_);
grpc_chttp2_transport_start_reading(client_transport_, nullptr, nullptr);
- channel_ = CreateChannelInternal("", channel);
+ channel_ = CreateChannelInternal("", channel, nullptr);
}
}
diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc
index e4ba37e2d6..bce72985dc 100644
--- a/test/cpp/microbenchmarks/helpers.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -38,6 +38,7 @@ void TrackCounters::AddLabel(const grpc::string& label) {
}
void TrackCounters::AddToLabel(std::ostream& out, benchmark::State& state) {
+#ifdef GRPC_COLLECT_STATS
grpc_stats_data stats_end;
grpc_stats_collect(&stats_end);
grpc_stats_data stats;
@@ -53,6 +54,7 @@ void TrackCounters::AddToLabel(std::ostream& out, benchmark::State& state) {
<< " " << grpc_stats_histogram_name[i] << "-99p:"
<< grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0);
}
+#endif
#ifdef GPR_LOW_LEVEL_COUNTERS
grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
out << " locks/iter:"
diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h
index 4aabd4094a..25d34b5f87 100644
--- a/test/cpp/microbenchmarks/helpers.h
+++ b/test/cpp/microbenchmarks/helpers.h
@@ -63,6 +63,7 @@ extern gpr_atm gpr_now_call_count;
class TrackCounters {
public:
TrackCounters() { grpc_stats_collect(&stats_begin_); }
+ virtual ~TrackCounters() {}
virtual void Finish(benchmark::State& state);
virtual void AddLabel(const grpc::string& label);
virtual void AddToLabel(std::ostream& out, benchmark::State& state);
diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc
index 04c300876c..fc6721d0ba 100644
--- a/test/cpp/naming/address_sorting_test.cc
+++ b/test/cpp/naming/address_sorting_test.cc
@@ -216,7 +216,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) {
{"1.2.3.4:443", AF_INET},
{"5.6.7.8:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"1.2.3.4:443",
"5.6.7.8:443",
@@ -235,7 +235,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) {
{"[2607:f8b0:400a:801::1002]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"1.2.3.4:443",
"[2607:f8b0:400a:801::1002]:443",
@@ -255,7 +255,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) {
{"[2607:f8b0:400a:801::1002]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2607:f8b0:400a:801::1002]:443",
"1.2.3.4:443",
@@ -279,7 +279,7 @@ TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) {
{"[2000:f8b0:400a:801::1002]:443", AF_INET6},
{"[fec0::5000]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fec0::5000]:443",
"[2000:f8b0:400a:801::1002]:443",
@@ -302,7 +302,7 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) {
{"[2002::5001]:443", AF_INET6},
{"[2001::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2001::5001]:443",
"[2002::5001]:443",
@@ -325,7 +325,7 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) {
{"[2001::5001]:443", AF_INET6},
{"[2002::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2001::5001]:443",
"[2002::5001]:443",
@@ -348,7 +348,7 @@ TEST_F(AddressSortingTest,
{"[3ffe::5001]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs, {
// The AF_INET address should be IPv4-mapped by the sort,
@@ -381,7 +381,7 @@ TEST_F(AddressSortingTest,
{v4_compat_dest, AF_INET6},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
v4_compat_dest,
@@ -404,7 +404,7 @@ TEST_F(AddressSortingTest,
{"[1234::2]:443", AF_INET6},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs,
{
@@ -428,7 +428,7 @@ TEST_F(AddressSortingTest,
{"[2001::1234]:443", AF_INET6},
{"[2000::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs, {
// The 2000::/16 address should match the ::/0 prefix rule
@@ -452,7 +452,7 @@ TEST_F(
{"[2001::1231]:443", AF_INET6},
{"[2000::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2000::5001]:443",
"[2001::1231]:443",
@@ -473,7 +473,7 @@ TEST_F(AddressSortingTest,
{"[fec0::1234]:443", AF_INET6},
{"[fc00::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fc00::5001]:443",
"[fec0::1234]:443",
@@ -498,7 +498,7 @@ TEST_F(
{"[::ffff:1.1.1.2]:443", AF_INET6},
{"[1234::2]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
// ::ffff:0:2 should match the v4-mapped
// precedence entry and be deprioritized.
@@ -525,7 +525,7 @@ TEST_F(AddressSortingTest, TestPrefersSmallerScope) {
{"[3ffe::5001]:443", AF_INET6},
{"[fec0::1234]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fec0::1234]:443",
"[3ffe::5001]:443",
@@ -550,7 +550,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) {
{"[3ffe:5001::]:443", AF_INET6},
{"[3ffe:1234::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:1234::]:443",
"[3ffe:5001::]:443",
@@ -571,7 +571,7 @@ TEST_F(AddressSortingTest,
{"[3ffe::5001]:443", AF_INET6},
{"[3ffe::1234]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1234]:443",
"[3ffe::5001]:443",
@@ -591,7 +591,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) {
{"[3ffe:8000::]:443", AF_INET6},
{"[3ffe:2000::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:2000::]:443",
"[3ffe:8000::]:443",
@@ -611,7 +611,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) {
{"[3ffe:6::]:443", AF_INET6},
{"[3ffe:c::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:c::]:443",
"[3ffe:6::]:443",
@@ -633,7 +633,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) {
{"[3ffe:1111:1111:1110::]:443", AF_INET6},
{"[3ffe:1111:1111:1111::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:1111:1111:1111::]:443",
"[3ffe:1111:1111:1110::]:443",
@@ -655,7 +655,7 @@ TEST_F(AddressSortingTest, TestStableSort) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1234]:443",
"[3ffe::1235]:443",
@@ -681,7 +681,7 @@ TEST_F(AddressSortingTest, TestStableSortFiveElements) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1231]:443",
"[3ffe::1232]:443",
@@ -702,7 +702,7 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1231]:443",
"[3ffe::1232]:443",
@@ -720,7 +720,7 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) {
{"[::ffff:5.6.7.8]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::ffff:5.6.7.8]:443",
"1.2.3.4:443",
@@ -748,7 +748,7 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) {
{"[fec0::2000]:443", AF_INET6},
{v4_compat_dest, AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs,
{
// The sort should be stable since
@@ -769,7 +769,7 @@ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) {
{"[::1]:443", AF_INET6},
{"127.0.0.1:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
"127.0.0.1:443",
@@ -783,7 +783,7 @@ TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) {
{"127.0.0.1:443", AF_INET},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
"127.0.0.1:443",
diff --git a/test/cpp/naming/utils/dns_server.py b/test/cpp/naming/utils/dns_server.py
index 1e8e2e3287..bf11d14c30 100755
--- a/test/cpp/naming/utils/dns_server.py
+++ b/test/cpp/naming/utils/dns_server.py
@@ -93,6 +93,10 @@ def start_local_dns_server(args):
_push_record(record_full_name, dns.Record_SRV(p, w, port, target_full_name, ttl=r_ttl))
if r_type == 'TXT':
_maybe_split_up_txt_data(record_full_name, r_data, r_ttl)
+ # Add an optional IPv4 record is specified
+ if args.add_a_record:
+ extra_host, extra_host_ipv4 = args.add_a_record.split(':')
+ _push_record(extra_host, dns.Record_A(extra_host_ipv4, ttl=0))
# Server health check record
_push_record(_SERVER_HEALTH_CHECK_RECORD_NAME, dns.Record_A(_SERVER_HEALTH_CHECK_RECORD_DATA, ttl=0))
soa_record = dns.Record_SOA(mname = common_zone_name)
@@ -122,7 +126,7 @@ def flush_stdout_loop():
num_timeouts_so_far = 0
sleep_time = 1
# Prevent zombies. Tests that use this server are short-lived.
- max_timeouts = 60 * 2
+ max_timeouts = 60 * 10
while num_timeouts_so_far < max_timeouts:
sys.stdout.flush()
time.sleep(sleep_time)
@@ -136,7 +140,14 @@ def main():
help='Port for DNS server to listen on for TCP and UDP.')
argp.add_argument('-r', '--records_config_path', default=None, type=str,
help=('Directory of resolver_test_record_groups.yaml file. '
- 'Defauls to path needed when the test is invoked as part of run_tests.py.'))
+ 'Defaults to path needed when the test is invoked as part '
+ 'of run_tests.py.'))
+ argp.add_argument('--add_a_record', default=None, type=str,
+ help=('Add an A record via the command line. Useful for when we '
+ 'need to serve a one-off A record that is under a '
+ 'different domain then the rest the records configured in '
+ '--records_config_path (which all need to be under the '
+ 'same domain). Format: <name>:<ipv4 address>'))
args = argp.parse_args()
signal.signal(signal.SIGTERM, _quit_on_signal)
signal.signal(signal.SIGINT, _quit_on_signal)
diff --git a/test/cpp/naming/utils/run_dns_server_for_lb_interop_tests.py b/test/cpp/naming/utils/run_dns_server_for_lb_interop_tests.py
new file mode 100755
index 0000000000..97171e21da
--- /dev/null
+++ b/test/cpp/naming/utils/run_dns_server_for_lb_interop_tests.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python2.7
+# Copyright 2015 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.
+
+
+import argparse
+import subprocess
+import os
+import tempfile
+import sys
+import time
+import signal
+import yaml
+
+argp = argparse.ArgumentParser(description='Runs a DNS server for LB interop tests')
+argp.add_argument('-l', '--grpclb_ips', default=None, type=str,
+ help='Comma-separated list of IP addresses of balancers')
+argp.add_argument('-f', '--fallback_ips', default=None, type=str,
+ help='Comma-separated list of IP addresses of fallback servers')
+argp.add_argument('-c', '--cause_no_error_no_data_for_balancer_a_record',
+ default=False, action='store_const', const=True,
+ help=('Used for testing the case in which the grpclb '
+ 'balancer A record lookup results in a DNS NOERROR response '
+ 'but with no ANSWER section i.e. no addresses'))
+args = argp.parse_args()
+
+balancer_records = []
+grpclb_ips = args.grpclb_ips.split(',')
+if grpclb_ips[0]:
+ for ip in grpclb_ips:
+ balancer_records.append({
+ 'TTL': '2100',
+ 'data': ip,
+ 'type': 'A',
+ })
+fallback_records = []
+fallback_ips = args.fallback_ips.split(',')
+if fallback_ips[0]:
+ for ip in fallback_ips:
+ fallback_records.append({
+ 'TTL': '2100',
+ 'data': ip,
+ 'type': 'A',
+ })
+records_config_yaml = {
+ 'resolver_tests_common_zone_name':
+ 'test.google.fr.',
+ 'resolver_component_tests': [{
+ 'records': {
+ '_grpclb._tcp.server': [
+ {
+ 'TTL': '2100',
+ 'data': '0 0 12000 balancer',
+ 'type': 'SRV'
+ },
+ ],
+ 'balancer':
+ balancer_records,
+ 'server':
+ fallback_records,
+ }
+ }]
+}
+if args.cause_no_error_no_data_for_balancer_a_record:
+ balancer_records = records_config_yaml[
+ 'resolver_component_tests'][0]['records']['balancer']
+ assert not balancer_records
+ # Insert a TXT record at the balancer.test.google.fr. domain.
+ # This TXT record won't actually be resolved or used by gRPC clients;
+ # inserting this record is just a way get the balancer.test.google.fr.
+ # A record queries to return NOERROR DNS responses that also have no
+ # ANSWER section, in order to simulate this failure case.
+ balancer_records.append({
+ 'TTL': '2100',
+ 'data': 'arbitrary string that wont actually be resolved',
+ 'type': 'TXT',
+ })
+# Generate the actual DNS server records config file
+records_config_path = tempfile.mktemp()
+with open(records_config_path, 'w') as records_config_generated:
+ records_config_generated.write(yaml.dump(records_config_yaml))
+
+with open(records_config_path, 'r') as records_config_generated:
+ sys.stderr.write('===== DNS server records config: =====\n')
+ sys.stderr.write(records_config_generated.read())
+ sys.stderr.write('======================================\n')
+
+# Run the DNS server
+# Note that we need to add the extra
+# A record for metadata.google.internal in order for compute engine
+# OAuth creds and ALTS creds to work.
+# TODO(apolcyn): should metadata.google.internal always resolve
+# to 169.254.169.254?
+subprocess.check_output([
+ '/var/local/git/grpc/test/cpp/naming/utils/dns_server.py', '--port=53',
+ '--records_config_path', records_config_path,
+ '--add_a_record=metadata.google.internal:169.254.169.254',
+])
diff --git a/test/cpp/naming/utils/tcp_connect.py b/test/cpp/naming/utils/tcp_connect.py
index 5773c7cae8..f3ad5891fd 100755
--- a/test/cpp/naming/utils/tcp_connect.py
+++ b/test/cpp/naming/utils/tcp_connect.py
@@ -31,7 +31,8 @@ def main():
argp.add_argument('-t', '--timeout', default=1, type=int,
help='Force process exit after this number of seconds.')
args = argp.parse_args()
- socket.create_connection([args.server_host, args.server_port])
+ socket.create_connection([args.server_host, args.server_port],
+ timeout=args.timeout)
if __name__ == '__main__':
main()
diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc
index 0ea3181f7e..32eab1fc44 100644
--- a/test/cpp/performance/writes_per_rpc_test.cc
+++ b/test/cpp/performance/writes_per_rpc_test.cc
@@ -100,7 +100,7 @@ class EndpointPairFixture {
}
grpc_server_setup_transport(server_->c_server(), transport, nullptr,
- server_args);
+ server_args, 0);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
}
@@ -118,7 +118,7 @@ class EndpointPairFixture {
"target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
- channel_ = CreateChannelInternal("", channel);
+ channel_ = CreateChannelInternal("", channel, nullptr);
}
}
diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD
index b958c75fc7..26f43284a6 100644
--- a/test/cpp/qps/BUILD
+++ b/test/cpp/qps/BUILD
@@ -15,6 +15,7 @@
licenses(["notice"]) # Apache v2
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary", "grpc_package")
+load("//test/cpp/qps:qps_benchmark_script.bzl", "qps_json_driver_batch", "json_run_localhost_batch")
grpc_package(name = "test/cpp/qps")
@@ -22,25 +23,30 @@ grpc_cc_library(
name = "parse_json",
srcs = ["parse_json.cc"],
hdrs = ["parse_json.h"],
- deps = ["//:grpc++"],
external_deps = ["protobuf"],
+ deps = ["//:grpc++"],
)
grpc_cc_library(
name = "qps_worker_impl",
srcs = [
"client_async.cc",
+ "client_callback.cc",
"client_sync.cc",
+ "qps_server_builder.cc",
"qps_worker.cc",
"server_async.cc",
+ "server_callback.cc",
"server_sync.cc",
- "qps_server_builder.cc",
],
hdrs = [
"client.h",
+ "qps_server_builder.h",
"qps_worker.h",
"server.h",
- "qps_server_builder.h",
+ ],
+ external_deps = [
+ "gflags",
],
deps = [
":histogram",
@@ -56,11 +62,8 @@ grpc_cc_library(
"//test/core/end2end:ssl_test_data",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
- "//test/cpp/util:test_util",
"//test/cpp/util:test_config",
- ],
- external_deps = [
- "gflags",
+ "//test/cpp/util:test_util",
],
)
@@ -97,15 +100,15 @@ grpc_cc_library(
hdrs = [
"benchmark_config.h",
],
+ external_deps = [
+ "gflags",
+ ],
deps = [
":driver_impl",
":histogram",
"//:grpc++",
"//src/proto/grpc/testing:control_proto",
],
- external_deps = [
- "gflags",
- ],
)
grpc_cc_library(
@@ -117,6 +120,21 @@ grpc_cc_library(
deps = ["//test/core/util:grpc_test_util"],
)
+grpc_cc_binary(
+ name = "qps_json_driver",
+ srcs = ["qps_json_driver.cc"],
+ external_deps = [
+ "gflags",
+ ],
+ deps = [
+ ":benchmark_config",
+ ":driver_impl",
+ "//:grpc++",
+ "//test/cpp/util:test_config",
+ "//test/cpp/util:test_util",
+ ],
+)
+
grpc_cc_test(
name = "inproc_sync_unary_ping_pong_test",
srcs = ["inproc_sync_unary_ping_pong_test.cc"],
@@ -135,17 +153,9 @@ grpc_cc_library(
deps = ["//:grpc++"],
)
-grpc_cc_binary(
- name = "json_run_localhost",
- srcs = ["json_run_localhost.cc"],
- deps = [
- "//:gpr",
- "//test/core/util:gpr_test_util",
- "//test/core/util:grpc_test_util",
- "//test/cpp/util:test_config",
- "//test/cpp/util:test_util",
- ],
-)
+qps_json_driver_batch()
+
+json_run_localhost_batch()
grpc_cc_test(
name = "qps_interarrival_test",
@@ -157,24 +167,10 @@ grpc_cc_test(
],
)
-grpc_cc_binary(
- name = "qps_json_driver",
- srcs = ["qps_json_driver.cc"],
- deps = [
- ":benchmark_config",
- ":driver_impl",
- "//:grpc++",
- "//test/cpp/util:test_config",
- "//test/cpp/util:test_util",
- ],
- external_deps = [
- "gflags",
- ],
-)
-
grpc_cc_test(
name = "qps_openloop_test",
srcs = ["qps_openloop_test.cc"],
+ data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
deps = [
":benchmark_config",
":driver_impl",
@@ -182,7 +178,6 @@ grpc_cc_test(
"//test/cpp/util:test_config",
"//test/cpp/util:test_util",
],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
)
grpc_cc_test(
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 9d7469c9b5..668d941916 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -94,9 +94,11 @@ class ClientRequestCreator<ByteBuffer> {
public:
ClientRequestCreator(ByteBuffer* req, const PayloadConfig& payload_config) {
if (payload_config.has_bytebuf_params()) {
- std::unique_ptr<char[]> buf(
- new char[payload_config.bytebuf_params().req_size()]);
- Slice slice(buf.get(), payload_config.bytebuf_params().req_size());
+ size_t req_sz =
+ static_cast<size_t>(payload_config.bytebuf_params().req_size());
+ std::unique_ptr<char[]> buf(new char[req_sz]);
+ memset(buf.get(), 0, req_sz);
+ Slice slice(buf.get(), req_sz);
*req = ByteBuffer(&slice, 1);
} else {
GPR_ASSERT(false); // not appropriate for this specialization
@@ -180,6 +182,19 @@ class Client {
timer_result = timer_->Mark();
}
+ // Print the median latency per interval for one thread.
+ // If the number of warmup seconds is x, then the first x + 1 numbers in the
+ // vector are from the warmup period and should be discarded.
+ if (median_latency_collection_interval_seconds_ > 0) {
+ std::vector<double> medians_per_interval =
+ threads_[0]->GetMedianPerIntervalList();
+ gpr_log(GPR_INFO, "Num threads: %ld", threads_.size());
+ gpr_log(GPR_INFO, "Number of medians: %ld", medians_per_interval.size());
+ for (size_t j = 0; j < medians_per_interval.size(); j++) {
+ gpr_log(GPR_INFO, "%f", medians_per_interval[j]);
+ }
+ }
+
grpc_stats_data core_stats;
grpc_stats_collect(&core_stats);
@@ -210,6 +225,12 @@ class Client {
}
}
+ // Returns the interval (in seconds) between collecting latency medians. If 0,
+ // no periodic median latencies will be collected.
+ double GetLatencyCollectionIntervalInSeconds() {
+ return median_latency_collection_interval_seconds_;
+ }
+
virtual int GetPollCount() {
// For sync client.
return 0;
@@ -218,6 +239,7 @@ class Client {
protected:
bool closed_loop_;
gpr_atm thread_pool_done_;
+ double median_latency_collection_interval_seconds_; // In seconds
void StartThreads(size_t num_threads) {
gpr_atm_rel_store(&thread_pool_done_, static_cast<gpr_atm>(false));
@@ -299,10 +321,27 @@ class Client {
MergeStatusHistogram(statuses_, s);
}
+ std::vector<double> GetMedianPerIntervalList() {
+ return medians_each_interval_list_;
+ }
+
void UpdateHistogram(HistogramEntry* entry) {
std::lock_guard<std::mutex> g(mu_);
if (entry->value_used()) {
histogram_.Add(entry->value());
+ if (client_->GetLatencyCollectionIntervalInSeconds() > 0) {
+ histogram_per_interval_.Add(entry->value());
+ double now = UsageTimer::Now();
+ if ((now - interval_start_time_) >=
+ client_->GetLatencyCollectionIntervalInSeconds()) {
+ // Record the median latency of requests from the last interval.
+ // Divide by 1e3 to get microseconds.
+ medians_each_interval_list_.push_back(
+ histogram_per_interval_.Percentile(50) / 1e3);
+ histogram_per_interval_.Reset();
+ interval_start_time_ = now;
+ }
+ }
}
if (entry->status_used()) {
statuses_[entry->status()]++;
@@ -334,6 +373,11 @@ class Client {
Client* client_;
const size_t idx_;
std::thread impl_;
+ // The following are used only if
+ // median_latency_collection_interval_seconds_ is greater than 0
+ Histogram histogram_per_interval_;
+ std::vector<double> medians_each_interval_list_;
+ double interval_start_time_;
};
bool ThreadCompleted() {
@@ -392,7 +436,8 @@ class ClientImpl : public Client {
for (auto& t : connecting_threads) {
t->join();
}
-
+ median_latency_collection_interval_seconds_ =
+ config.median_latency_collection_interval_millis() / 1e3;
ClientRequestCreator<RequestType> create_req(&request_,
config.payload_config());
}
@@ -490,6 +535,7 @@ class ClientImpl : public Client {
std::unique_ptr<Client> CreateSynchronousClient(const ClientConfig& args);
std::unique_ptr<Client> CreateAsyncClient(const ClientConfig& args);
+std::unique_ptr<Client> CreateCallbackClient(const ClientConfig& args);
std::unique_ptr<Client> CreateGenericAsyncStreamingClient(
const ClientConfig& args);
diff --git a/test/cpp/qps/client_callback.cc b/test/cpp/qps/client_callback.cc
new file mode 100644
index 0000000000..87889e36dc
--- /dev/null
+++ b/test/cpp/qps/client_callback.cc
@@ -0,0 +1,219 @@
+/*
+ *
+ * Copyright 2015 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 <list>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#include <grpc/grpc.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
+#include <grpcpp/alarm.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+
+#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
+#include "test/cpp/qps/client.h"
+#include "test/cpp/qps/usage_timer.h"
+
+namespace grpc {
+namespace testing {
+
+/**
+ * Maintains context info per RPC
+ */
+struct CallbackClientRpcContext {
+ CallbackClientRpcContext(BenchmarkService::Stub* stub) : stub_(stub) {}
+
+ ~CallbackClientRpcContext() {}
+
+ SimpleResponse response_;
+ ClientContext context_;
+ Alarm alarm_;
+ BenchmarkService::Stub* stub_;
+};
+
+static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator(
+ const std::shared_ptr<Channel>& ch) {
+ return BenchmarkService::NewStub(ch);
+}
+
+class CallbackClient
+ : public ClientImpl<BenchmarkService::Stub, SimpleRequest> {
+ public:
+ CallbackClient(const ClientConfig& config)
+ : ClientImpl<BenchmarkService::Stub, SimpleRequest>(
+ config, BenchmarkStubCreator) {
+ num_threads_ = NumThreads(config);
+ rpcs_done_ = 0;
+ SetupLoadTest(config, num_threads_);
+ total_outstanding_rpcs_ =
+ config.client_channels() * config.outstanding_rpcs_per_channel();
+ }
+
+ virtual ~CallbackClient() {}
+
+ protected:
+ size_t num_threads_;
+ size_t total_outstanding_rpcs_;
+ // The below mutex and condition variable is used by main benchmark thread to
+ // wait on completion of all RPCs before shutdown
+ std::mutex shutdown_mu_;
+ std::condition_variable shutdown_cv_;
+ // Number of rpcs done after thread completion
+ size_t rpcs_done_;
+ // Vector of Context data pointers for running a RPC
+ std::vector<std::unique_ptr<CallbackClientRpcContext>> ctx_;
+
+ virtual void InitThreadFuncImpl(size_t thread_idx) = 0;
+ virtual bool ThreadFuncImpl(Thread* t, size_t thread_idx) = 0;
+
+ void ThreadFunc(size_t thread_idx, Thread* t) override {
+ InitThreadFuncImpl(thread_idx);
+ ThreadFuncImpl(t, thread_idx);
+ }
+
+ virtual void ScheduleRpc(Thread* t, size_t thread_idx,
+ size_t ctx_vector_idx) = 0;
+
+ /**
+ * The main thread of the benchmark will be waiting on DestroyMultithreading.
+ * Increment the rpcs_done_ variable to signify that the Callback RPC
+ * after thread completion is done. When the last outstanding rpc increments
+ * the counter it should also signal the main thread's conditional variable.
+ */
+ void NotifyMainThreadOfThreadCompletion() {
+ std::lock_guard<std::mutex> l(shutdown_mu_);
+ rpcs_done_++;
+ if (rpcs_done_ == total_outstanding_rpcs_) {
+ shutdown_cv_.notify_one();
+ }
+ }
+
+ private:
+ int NumThreads(const ClientConfig& config) {
+ int num_threads = config.async_client_threads();
+ if (num_threads <= 0) { // Use dynamic sizing
+ num_threads = cores_;
+ gpr_log(GPR_INFO, "Sizing callback client to %d threads", num_threads);
+ }
+ return num_threads;
+ }
+
+ /**
+ * Wait until all outstanding Callback RPCs are done
+ */
+ void DestroyMultithreading() final {
+ std::unique_lock<std::mutex> l(shutdown_mu_);
+ while (rpcs_done_ != total_outstanding_rpcs_) {
+ shutdown_cv_.wait(l);
+ }
+ EndThreads();
+ }
+};
+
+class CallbackUnaryClient final : public CallbackClient {
+ public:
+ CallbackUnaryClient(const ClientConfig& config) : CallbackClient(config) {
+ for (int ch = 0; ch < config.client_channels(); ch++) {
+ for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
+ ctx_.emplace_back(
+ new CallbackClientRpcContext(channels_[ch].get_stub()));
+ }
+ }
+ StartThreads(num_threads_);
+ }
+ ~CallbackUnaryClient() {}
+
+ protected:
+ bool ThreadFuncImpl(Thread* t, size_t thread_idx) override {
+ for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
+ vector_idx += num_threads_) {
+ ScheduleRpc(t, thread_idx, vector_idx);
+ }
+ return true;
+ }
+
+ void InitThreadFuncImpl(size_t thread_idx) override { return; }
+
+ private:
+ void ScheduleRpc(Thread* t, size_t thread_idx, size_t vector_idx) override {
+ if (!closed_loop_) {
+ gpr_timespec next_issue_time = NextIssueTime(thread_idx);
+ // Start an alarm callback to run the internal callback after
+ // next_issue_time
+ ctx_[vector_idx]->alarm_.experimental().Set(
+ next_issue_time, [this, t, thread_idx, vector_idx](bool ok) {
+ IssueUnaryCallbackRpc(t, thread_idx, vector_idx);
+ });
+ } else {
+ IssueUnaryCallbackRpc(t, thread_idx, vector_idx);
+ }
+ }
+
+ void IssueUnaryCallbackRpc(Thread* t, size_t thread_idx, size_t vector_idx) {
+ GPR_TIMER_SCOPE("CallbackUnaryClient::ThreadFunc", 0);
+ double start = UsageTimer::Now();
+ ctx_[vector_idx]->stub_->experimental_async()->UnaryCall(
+ (&ctx_[vector_idx]->context_), &request_, &ctx_[vector_idx]->response_,
+ [this, t, thread_idx, start, vector_idx](grpc::Status s) {
+ // Update Histogram with data from the callback run
+ HistogramEntry entry;
+ if (s.ok()) {
+ entry.set_value((UsageTimer::Now() - start) * 1e9);
+ }
+ entry.set_status(s.error_code());
+ t->UpdateHistogram(&entry);
+
+ if (ThreadCompleted() || !s.ok()) {
+ // Notify thread of completion
+ NotifyMainThreadOfThreadCompletion();
+ } else {
+ // Reallocate ctx for next RPC
+ ctx_[vector_idx].reset(
+ new CallbackClientRpcContext(ctx_[vector_idx]->stub_));
+ // Schedule a new RPC
+ ScheduleRpc(t, thread_idx, vector_idx);
+ }
+ });
+ }
+};
+
+std::unique_ptr<Client> CreateCallbackClient(const ClientConfig& config) {
+ switch (config.rpc_type()) {
+ case UNARY:
+ return std::unique_ptr<Client>(new CallbackUnaryClient(config));
+ case STREAMING:
+ case STREAMING_FROM_CLIENT:
+ case STREAMING_FROM_SERVER:
+ case STREAMING_BOTH_WAYS:
+ assert(false);
+ return nullptr;
+ default:
+ assert(false);
+ return nullptr;
+ }
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index cabbd51843..11cfb4aa05 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -198,7 +198,8 @@ std::unique_ptr<ScenarioResult> RunScenario(
const ServerConfig& initial_server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
- const grpc::string& credential_type, bool run_inproc) {
+ const grpc::string& credential_type, bool run_inproc,
+ int32_t median_latency_collection_interval_millis) {
if (run_inproc) {
g_inproc_servers = new std::vector<grpc::testing::Server*>;
}
@@ -317,6 +318,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
}
}
+ client_config.set_median_latency_collection_interval_millis(
+ median_latency_collection_interval_millis);
+
// Targets are all set by now
result_client_config = client_config;
// Start clients
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index fede4d8045..cda89f7ddf 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -32,7 +32,8 @@ std::unique_ptr<ScenarioResult> RunScenario(
const grpc::testing::ServerConfig& server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
- const grpc::string& credential_type, bool run_inproc);
+ const grpc::string& credential_type, bool run_inproc,
+ int32_t median_latency_collection_interval_millis);
bool RunQuit(const grpc::string& credential_type);
} // namespace testing
diff --git a/test/cpp/qps/gen_build_yaml.py b/test/cpp/qps/gen_build_yaml.py
index 776283c25a..fb2caf5486 100755
--- a/test/cpp/qps/gen_build_yaml.py
+++ b/test/cpp/qps/gen_build_yaml.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import print_function
import json
import pipes
import shutil
@@ -68,62 +69,66 @@ def maybe_exclude_gcov(scenario_json):
return ['gcov']
return []
-print yaml.dump({
- 'tests': [
- {
- 'name': 'json_run_localhost',
- 'shortname': 'json_run_localhost:%s' % scenario_json['name'],
- 'args': ['--scenarios_json', _scenario_json_string(scenario_json, False)],
- 'ci_platforms': ['linux'],
- 'platforms': ['linux'],
- 'flaky': False,
- 'language': 'c++',
- 'boringssl': True,
- 'defaults': 'boringssl',
- 'cpu_cost': guess_cpu(scenario_json, False),
- 'exclude_configs': ['tsan', 'asan'] + maybe_exclude_gcov(scenario_json),
- 'timeout_seconds': 2*60,
- 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
- 'auto_timeout_scaling': False
- }
- for scenario_json in scenario_config.CXXLanguage().scenarios()
- if 'scalable' in scenario_json.get('CATEGORIES', [])
- ] + [
- {
- 'name': 'qps_json_driver',
- 'shortname': 'qps_json_driver:inproc_%s' % scenario_json['name'],
- 'args': ['--run_inproc', '--scenarios_json', _scenario_json_string(scenario_json, False)],
- 'ci_platforms': ['linux'],
- 'platforms': ['linux'],
- 'flaky': False,
- 'language': 'c++',
- 'boringssl': True,
- 'defaults': 'boringssl',
- 'cpu_cost': guess_cpu(scenario_json, False),
- 'exclude_configs': ['tsan', 'asan'],
- 'timeout_seconds': 6*60,
- 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', [])
- }
- for scenario_json in scenario_config.CXXLanguage().scenarios()
- if 'inproc' in scenario_json.get('CATEGORIES', [])
- ] + [
- {
- 'name': 'json_run_localhost',
- 'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'],
- 'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
- 'ci_platforms': ['linux'],
- 'platforms': ['linux'],
- 'flaky': False,
- 'language': 'c++',
- 'boringssl': True,
- 'defaults': 'boringssl',
- 'cpu_cost': guess_cpu(scenario_json, True),
- 'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')),
- 'timeout_seconds': 10*60,
- 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
- 'auto_timeout_scaling': False
- }
- for scenario_json in scenario_config.CXXLanguage().scenarios()
- if 'scalable' in scenario_json.get('CATEGORIES', [])
- ]
-})
+def generate_yaml():
+ return {
+ 'tests': [
+ {
+ 'name': 'json_run_localhost',
+ 'shortname': 'json_run_localhost:%s' % scenario_json['name'],
+ 'args': ['--scenarios_json', _scenario_json_string(scenario_json, False)],
+ 'ci_platforms': ['linux'],
+ 'platforms': ['linux'],
+ 'flaky': False,
+ 'language': 'c++',
+ 'boringssl': True,
+ 'defaults': 'boringssl',
+ 'cpu_cost': guess_cpu(scenario_json, False),
+ 'exclude_configs': ['tsan', 'asan'] + maybe_exclude_gcov(scenario_json),
+ 'timeout_seconds': 2*60,
+ 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
+ 'auto_timeout_scaling': False
+ }
+ for scenario_json in scenario_config.CXXLanguage().scenarios()
+ if 'scalable' in scenario_json.get('CATEGORIES', [])
+ ] + [
+ {
+ 'name': 'qps_json_driver',
+ 'shortname': 'qps_json_driver:inproc_%s' % scenario_json['name'],
+ 'args': ['--run_inproc', '--scenarios_json', _scenario_json_string(scenario_json, False)],
+ 'ci_platforms': ['linux'],
+ 'platforms': ['linux'],
+ 'flaky': False,
+ 'language': 'c++',
+ 'boringssl': True,
+ 'defaults': 'boringssl',
+ 'cpu_cost': guess_cpu(scenario_json, False),
+ 'exclude_configs': ['tsan', 'asan'],
+ 'timeout_seconds': 6*60,
+ 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', [])
+ }
+ for scenario_json in scenario_config.CXXLanguage().scenarios()
+ if 'inproc' in scenario_json.get('CATEGORIES', [])
+ ] + [
+ {
+ 'name': 'json_run_localhost',
+ 'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'],
+ 'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
+ 'ci_platforms': ['linux'],
+ 'platforms': ['linux'],
+ 'flaky': False,
+ 'language': 'c++',
+ 'boringssl': True,
+ 'defaults': 'boringssl',
+ 'cpu_cost': guess_cpu(scenario_json, True),
+ 'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')),
+ 'timeout_seconds': 10*60,
+ 'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
+ 'auto_timeout_scaling': False
+ }
+ for scenario_json in scenario_config.CXXLanguage().scenarios()
+ if 'scalable' in scenario_json.get('CATEGORIES', [])
+ ]
+ }
+
+
+print(yaml.dump(generate_yaml())) \ No newline at end of file
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index ba72b5b332..6275128f34 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -34,6 +34,11 @@ class Histogram {
~Histogram() {
if (impl_) grpc_histogram_destroy(impl_);
}
+ void Reset() {
+ if (impl_) grpc_histogram_destroy(impl_);
+ impl_ = grpc_histogram_create(default_resolution(), default_max_possible());
+ }
+
Histogram(Histogram&& other) : impl_(other.impl_) { other.impl_ = nullptr; }
void Merge(const Histogram& h) { grpc_histogram_merge(impl_, h.impl_); }
diff --git a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
index f2e977d48b..56d1730252 100644
--- a/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
@@ -48,7 +48,7 @@ static void RunSynchronousUnaryPingPong() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, true);
+ kInsecureCredentialsType, true, 0);
GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/json_run_localhost_scenario_gen.py b/test/cpp/qps/json_run_localhost_scenario_gen.py
new file mode 100755
index 0000000000..ab14f0e4a5
--- /dev/null
+++ b/test/cpp/qps/json_run_localhost_scenario_gen.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import gen_build_yaml as gen
+import json
+
+def generate_args():
+ all_scenario_set = gen.generate_yaml()
+ all_scenario_set = all_scenario_set['tests']
+ json_run_localhost_scenarios = \
+ [item for item in all_scenario_set if item['name'] == 'json_run_localhost']
+ json_run_localhost_arg_set = \
+ [item['args'][1] for item in json_run_localhost_scenarios \
+ if 'args' in item and len(item['args']) > 1]
+ deserialized_scenarios = [json.loads(item)['scenarios'][0] \
+ for item in json_run_localhost_arg_set]
+ all_scenarios = {scenario['name'].encode('ascii', 'ignore'): \
+ '\'{\'scenarios\' : [' + json.dumps(scenario) + ']}\'' \
+ for scenario in deserialized_scenarios}
+
+ serialized_scenarios_str = str(all_scenarios).encode('ascii', 'ignore')
+ with open('json_run_localhost_scenarios.bzl', 'wb') as f:
+ f.write('"""Scenarios run on localhost."""\n\n')
+ f.write('JSON_RUN_LOCALHOST_SCENARIOS = ' + serialized_scenarios_str + '\n')
+
+generate_args()
diff --git a/test/cpp/qps/json_run_localhost_scenarios.bzl b/test/cpp/qps/json_run_localhost_scenarios.bzl
new file mode 100644
index 0000000000..5bfb0bca76
--- /dev/null
+++ b/test/cpp/qps/json_run_localhost_scenarios.bzl
@@ -0,0 +1,3 @@
+"""Scenarios run on localhost."""
+
+JSON_RUN_LOCALHOST_SCENARIOS = {'cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 16, "threads_per_cq": 1, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"poisson": {"offered_load": 37500}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 50, "req_size": 300}}, "client_channels": 300, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_from_client_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_client_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_client_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_1channel_1MBmsg_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_1channel_1MBmsg_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_server_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_server_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_64KBmsg_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_64KBmsg_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1mps_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1cq_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1cq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_10mps_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_10mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_ping_pong_insecure_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_ping_pong_insecure_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_one_server_core_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_one_server_core_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 1, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 2}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 1, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_from_server_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_server_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_unary_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_unary_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_from_client_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_client_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_from_client_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_client_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 1000000}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_server_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_server_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 8388608, "req_size": 128}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_client_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_from_client_1channel_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_1channel_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_unary_1channel_100rpcs_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_1channel_100rpcs_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 10, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 8388608, "req_size": 128}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 1, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_from_server_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_server_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_1cq_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_1cq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_unary_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_unary_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 10, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_one_server_core_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_one_server_core_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 1, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 10, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_server_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_server_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 2}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_unary_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_unary_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_from_server_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_server_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 10, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1cq_secure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1cq_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 1000000}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_ping_pong_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_ping_pong_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 1, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_from_client_qps_unconstrained_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_qps_unconstrained_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_ping_pong_secure_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_ping_pong_secure_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": {"use_test_ca": true, "server_host_override": "foo.test.google.fr"}, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\''}
diff --git a/test/cpp/qps/qps_benchmark_script.bzl b/test/cpp/qps/qps_benchmark_script.bzl
new file mode 100644
index 0000000000..b2b67d988c
--- /dev/null
+++ b/test/cpp/qps/qps_benchmark_script.bzl
@@ -0,0 +1,80 @@
+# 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.
+
+#
+# This is for the gRPC build system. This isn't intended to be used outsite of
+# the BUILD file for gRPC. It contains the mapping for the template system we
+# use to generate other platform's build system files.
+#
+# Please consider that there should be a high bar for additions and changes to
+# this file.
+# Each rule listed must be re-written for Google's internal build system, and
+# each change must be ported from one to the other.
+#
+
+"""Script to run qps benchmark."""
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
+load("//test/cpp/qps:qps_json_driver_scenarios.bzl", "QPS_JSON_DRIVER_SCENARIOS")
+load("//test/cpp/qps:json_run_localhost_scenarios.bzl", "JSON_RUN_LOCALHOST_SCENARIOS")
+
+def qps_json_driver_batch():
+ for scenario in QPS_JSON_DRIVER_SCENARIOS:
+ grpc_cc_test(
+ name = "qps_json_driver_test_%s" % scenario,
+ srcs = ["qps_json_driver.cc"],
+ args = [
+ "--run_inproc",
+ "--scenarios_json",
+ QPS_JSON_DRIVER_SCENARIOS[scenario],
+ ],
+ external_deps = [
+ "gflags",
+ ],
+ deps = [
+ ":benchmark_config",
+ ":driver_impl",
+ "//:grpc++",
+ "//test/cpp/util:test_config",
+ "//test/cpp/util:test_util",
+ ],
+ tags = [
+ "qps_json_driver",
+ ],
+ )
+
+def json_run_localhost_batch():
+ for scenario in JSON_RUN_LOCALHOST_SCENARIOS:
+ grpc_cc_test(
+ name = "json_run_localhost_%s" % scenario,
+ srcs = ["json_run_localhost.cc"],
+ args = [
+ "--scenarios_json",
+ JSON_RUN_LOCALHOST_SCENARIOS[scenario],
+ ],
+ data = [
+ "//test/cpp/qps:qps_json_driver",
+ "//test/cpp/qps:qps_worker",
+ ],
+ deps = [
+ "//:gpr",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_config",
+ "//test/cpp/util:test_util",
+ ],
+ tags = [
+ "json_run_localhost",
+ ],
+ )
diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc
index 0ff692255c..eaa0dd992c 100644
--- a/test/cpp/qps/qps_json_driver.cc
+++ b/test/cpp/qps/qps_json_driver.cc
@@ -66,6 +66,11 @@ DEFINE_string(json_file_out, "", "File to write the JSON output to.");
DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType,
"Credential type for communication with workers");
DEFINE_bool(run_inproc, false, "Perform an in-process transport test");
+DEFINE_int32(
+ median_latency_collection_interval_millis, 0,
+ "Specifies the period between gathering latency medians in "
+ "milliseconds. The medians will be logged out on the client at the "
+ "end of the benchmark run. If 0, this periodic collection is disabled.");
namespace grpc {
namespace testing {
@@ -73,13 +78,13 @@ namespace testing {
static std::unique_ptr<ScenarioResult> RunAndReport(const Scenario& scenario,
bool* success) {
std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
- auto result =
- RunScenario(scenario.client_config(), scenario.num_clients(),
- scenario.server_config(), scenario.num_servers(),
- scenario.warmup_seconds(), scenario.benchmark_seconds(),
- !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
- FLAGS_qps_server_target_override, FLAGS_credential_type,
- FLAGS_run_inproc);
+ auto result = RunScenario(
+ scenario.client_config(), scenario.num_clients(),
+ scenario.server_config(), scenario.num_servers(),
+ scenario.warmup_seconds(), scenario.benchmark_seconds(),
+ !FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
+ FLAGS_qps_server_target_override, FLAGS_credential_type, FLAGS_run_inproc,
+ FLAGS_median_latency_collection_interval_millis);
// Amend the result with scenario config. Eventually we should adjust
// RunScenario contract so we don't need to touch the result here.
diff --git a/test/cpp/qps/qps_json_driver_scenario_gen.py b/test/cpp/qps/qps_json_driver_scenario_gen.py
new file mode 100755
index 0000000000..2b66c69d8a
--- /dev/null
+++ b/test/cpp/qps/qps_json_driver_scenario_gen.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import gen_build_yaml as gen
+import json
+
+def generate_args():
+ all_scenario_set = gen.generate_yaml()
+ all_scenario_set = all_scenario_set['tests']
+ qps_json_driver_scenario_set = \
+ [item for item in all_scenario_set if item['name'] == 'qps_json_driver']
+ qps_json_driver_arg_set = \
+ [item['args'][2] for item in qps_json_driver_scenario_set \
+ if 'args' in item and len(item['args']) > 2]
+ deserialized_scenarios = [json.loads(item)['scenarios'][0] \
+ for item in qps_json_driver_arg_set]
+ all_scenarios = {scenario['name'].encode('ascii', 'ignore'): \
+ '\'{\'scenarios\' : [' + json.dumps(scenario) + ']}\'' \
+ for scenario in deserialized_scenarios}
+
+ serialized_scenarios_str = str(all_scenarios).encode('ascii', 'ignore')
+ with open('qps_json_driver_scenarios.bzl', 'w') as f:
+ f.write('"""Scenarios of qps driver."""\n\n')
+ f.write('QPS_JSON_DRIVER_SCENARIOS = ' + serialized_scenarios_str + '\n')
+
+generate_args()
diff --git a/test/cpp/qps/qps_json_driver_scenarios.bzl b/test/cpp/qps/qps_json_driver_scenarios.bzl
new file mode 100644
index 0000000000..95b4911325
--- /dev/null
+++ b/test/cpp/qps/qps_json_driver_scenarios.bzl
@@ -0,0 +1,3 @@
+"""Scenarios of qps driver."""
+
+QPS_JSON_DRIVER_SCENARIOS = {'cpp_protobuf_sync_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_ping_pong_insecure_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_ping_pong_insecure_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 2, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 1000000}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 65536, "req_size": 65536}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 1000000, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 13, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 1000000}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_client_1channel_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_1channel_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_unary_1channel_100rpcs_1MB': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_1channel_100rpcs_1MB", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 1048576, "req_size": 1048576}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 8388608, "req_size": 128}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING_FROM_CLIENT", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 2}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 2}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "SYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 16, "rpc_type": "STREAMING_FROM_SERVER", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "SYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_protobuf_async_unary_qps_unconstrained_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_unary_qps_unconstrained_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 3, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "UNARY", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 3}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_qps_unconstrained_10mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_qps_unconstrained_10mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 0, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 10, "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\'', 'cpp_generic_async_streaming_ping_pong_insecure': '\'{\'scenarios\' : [{"name": "cpp_generic_async_streaming_ping_pong_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"async_server_threads": 1, "security_params": null, "server_type": "ASYNC_GENERIC_SERVER", "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "threads_per_cq": 0}, "client_config": {"security_params": null, "channel_args": [{"str_value": "latency", "name": "grpc.optimization_target"}], "async_client_threads": 1, "outstanding_rpcs_per_channel": 1, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "payload_config": {"bytebuf_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 1, "threads_per_cq": 0}, "num_clients": 1}]}\'', 'cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure': '\'{\'scenarios\' : [{"name": "cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure", "warmup_seconds": 0, "benchmark_seconds": 1, "num_servers": 1, "server_config": {"security_params": null, "server_type": "ASYNC_SERVER", "async_server_threads": 0, "threads_per_cq": 0, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}]}, "client_config": {"security_params": null, "channel_args": [{"str_value": "throughput", "name": "grpc.optimization_target"}, {"int_value": 1, "name": "grpc.minimal_stack"}], "async_client_threads": 0, "outstanding_rpcs_per_channel": 100, "rpc_type": "STREAMING", "load_params": {"closed_loop": {}}, "histogram_params": {"resolution": 0.01, "max_possible": 60000000000.0}, "client_type": "ASYNC_CLIENT", "messages_per_stream": 1, "payload_config": {"simple_params": {"resp_size": 0, "req_size": 0}}, "client_channels": 64, "threads_per_cq": 0}, "num_clients": 0}]}\''}
diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc
index df929b9811..6044f4265a 100644
--- a/test/cpp/qps/qps_openloop_test.cc
+++ b/test/cpp/qps/qps_openloop_test.cc
@@ -52,7 +52,7 @@ static void RunQPS() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, false);
+ kInsecureCredentialsType, false, 0);
GetReporter()->ReportQPSPerCore(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index 7ddf3c1cf3..23fe72316a 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -60,6 +60,8 @@ static std::unique_ptr<Client> CreateClient(const ClientConfig& config) {
return config.payload_config().has_bytebuf_params()
? CreateGenericAsyncStreamingClient(config)
: CreateAsyncClient(config);
+ case ClientType::CALLBACK_CLIENT:
+ return CreateCallbackClient(config);
default:
abort();
}
@@ -77,6 +79,8 @@ static std::unique_ptr<Server> CreateServer(const ServerConfig& config) {
return CreateAsyncServer(config);
case ServerType::ASYNC_GENERIC_SERVER:
return CreateAsyncGenericServer(config);
+ case ServerType::CALLBACK_SERVER:
+ return CreateCallbackServer(config);
default:
abort();
}
diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
index bb415e9d63..a559c82cc8 100644
--- a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
@@ -55,7 +55,7 @@ static void RunSynchronousUnaryPingPong() {
const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
- kInsecureCredentialsType, false);
+ kInsecureCredentialsType, false, 0);
GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 6b1ef93617..89b0e3af4b 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -152,6 +152,7 @@ class Server {
std::unique_ptr<Server> CreateSynchronousServer(const ServerConfig& config);
std::unique_ptr<Server> CreateAsyncServer(const ServerConfig& config);
std::unique_ptr<Server> CreateAsyncGenericServer(const ServerConfig& config);
+std::unique_ptr<Server> CreateCallbackServer(const ServerConfig& config);
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 5cd975cf74..a5f8347c26 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -562,6 +562,7 @@ static Status ProcessGenericRPC(const PayloadConfig& payload_config,
request->Clear();
int resp_size = payload_config.bytebuf_params().resp_size();
std::unique_ptr<char[]> buf(new char[resp_size]);
+ memset(buf.get(), 0, static_cast<size_t>(resp_size));
Slice slice(buf.get(), resp_size);
*response = ByteBuffer(&slice, 1);
return Status::OK;
diff --git a/test/cpp/qps/server_callback.cc b/test/cpp/qps/server_callback.cc
new file mode 100644
index 0000000000..8bedd44739
--- /dev/null
+++ b/test/cpp/qps/server_callback.cc
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2015 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/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_context.h>
+
+#include "src/core/lib/gpr/host_port.h"
+#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
+#include "test/cpp/qps/qps_server_builder.h"
+#include "test/cpp/qps/server.h"
+#include "test/cpp/qps/usage_timer.h"
+
+namespace grpc {
+namespace testing {
+
+class BenchmarkCallbackServiceImpl final
+ : public BenchmarkService::ExperimentalCallbackService {
+ public:
+ void UnaryCall(
+ ServerContext* context, const SimpleRequest* request,
+ SimpleResponse* response,
+ experimental::ServerCallbackRpcController* controller) override {
+ auto s = SetResponse(request, response);
+ controller->Finish(s);
+ }
+
+ private:
+ static Status SetResponse(const SimpleRequest* request,
+ SimpleResponse* response) {
+ if (request->response_size() > 0) {
+ if (!Server::SetPayload(request->response_type(),
+ request->response_size(),
+ response->mutable_payload())) {
+ return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
+ }
+ }
+ return Status::OK;
+ }
+};
+
+class CallbackServer final : public grpc::testing::Server {
+ public:
+ explicit CallbackServer(const ServerConfig& config) : Server(config) {
+ std::unique_ptr<ServerBuilder> builder = CreateQpsServerBuilder();
+
+ auto port_num = port();
+ // Negative port number means inproc server, so no listen port needed
+ if (port_num >= 0) {
+ char* server_address = nullptr;
+ gpr_join_host_port(&server_address, "::", port_num);
+ builder->AddListeningPort(server_address,
+ Server::CreateServerCredentials(config));
+ gpr_free(server_address);
+ }
+
+ ApplyConfigToBuilder(config, builder.get());
+
+ builder->RegisterService(&service_);
+
+ impl_ = builder->BuildAndStart();
+ }
+
+ std::shared_ptr<Channel> InProcessChannel(
+ const ChannelArguments& args) override {
+ return impl_->InProcessChannel(args);
+ }
+
+ private:
+ BenchmarkCallbackServiceImpl service_;
+ std::unique_ptr<grpc::Server> impl_;
+};
+
+std::unique_ptr<grpc::testing::Server> CreateCallbackServer(
+ const ServerConfig& config) {
+ return std::unique_ptr<Server>(new CallbackServer(config));
+}
+
+} // namespace testing
+} // namespace grpc
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index 477862a0ee..57eaf3baf2 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -117,11 +117,10 @@ grpc_cc_library(
)
grpc_cc_library(
- name = "grpc_cli_libs",
+ name = "grpc_cli_utils",
srcs = [
"cli_call.cc",
"cli_credentials.cc",
- "grpc_tool.cc",
"proto_file_parser.cc",
"service_describer.cc",
],
@@ -129,7 +128,6 @@ grpc_cc_library(
"cli_call.h",
"cli_credentials.h",
"config_grpc_cli.h",
- "grpc_tool.h",
"proto_file_parser.h",
"service_describer.h",
],
@@ -146,6 +144,22 @@ grpc_cc_library(
)
grpc_cc_library(
+ name = "grpc_cli_libs",
+ srcs = [
+ "grpc_tool.cc",
+ ],
+ hdrs = [
+ "grpc_tool.h",
+ ],
+ external_deps = [
+ "gflags",
+ ],
+ deps = [
+ ":grpc_cli_utils",
+ ],
+)
+
+grpc_cc_library(
name = "metrics_server_lib",
srcs = [
"metrics_server.cc",
@@ -171,6 +185,7 @@ grpc_cc_test(
external_deps = [
"gtest",
],
+ tags = ["nomsan"], # death tests seem to be incompatible with msan
deps = [
":grpc_cli_libs",
":test_util",
diff --git a/test/cpp/util/byte_buffer_proto_helper.h b/test/cpp/util/byte_buffer_proto_helper.h
index eb923eccb5..3d01fb2468 100644
--- a/test/cpp/util/byte_buffer_proto_helper.h
+++ b/test/cpp/util/byte_buffer_proto_helper.h
@@ -27,12 +27,13 @@
namespace grpc {
namespace testing {
-bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message);
+bool ParseFromByteBuffer(ByteBuffer* buffer,
+ ::grpc::protobuf::Message* message);
std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
- grpc::protobuf::Message* message);
+ ::grpc::protobuf::Message* message);
-bool SerializeToByteBufferInPlace(grpc::protobuf::Message* message,
+bool SerializeToByteBufferInPlace(::grpc::protobuf::Message* message,
ByteBuffer* buffer);
} // namespace testing
diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc
index b4704bfe6a..ff9d887385 100644
--- a/test/cpp/util/channel_trace_proto_helper.cc
+++ b/test/cpp/util/channel_trace_proto_helper.cc
@@ -82,5 +82,23 @@ void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str) {
json_c_str);
}
+void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetServerResponse>(
+ json_c_str);
+}
+
+void ValidateSubchannelProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Subchannel>(json_c_str);
+}
+
+void ValidateServerProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Server>(json_c_str);
+}
+
+void ValidateGetServersResponseProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetServersResponse>(
+ json_c_str);
+}
+
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h
index 18e3d54b6b..4f74e02f10 100644
--- a/test/cpp/util/channel_trace_proto_helper.h
+++ b/test/cpp/util/channel_trace_proto_helper.h
@@ -26,6 +26,10 @@ void ValidateChannelTraceProtoJsonTranslation(char* json_c_str);
void ValidateChannelProtoJsonTranslation(char* json_c_str);
void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str);
void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str);
+void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str);
+void ValidateSubchannelProtoJsonTranslation(char* json_c_str);
+void ValidateServerProtoJsonTranslation(char* json_c_str);
+void ValidateGetServersResponseProtoJsonTranslation(char* json_c_str);
} // namespace testing
} // namespace grpc
diff --git a/test/cpp/util/cli_credentials.cc b/test/cpp/util/cli_credentials.cc
index acf4ef8ef1..91acc904aa 100644
--- a/test/cpp/util/cli_credentials.cc
+++ b/test/cpp/util/cli_credentials.cc
@@ -19,6 +19,11 @@
#include "test/cpp/util/cli_credentials.h"
#include <gflags/gflags.h>
+#include <grpc/slice.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/slice.h>
+
+#include "src/core/lib/iomgr/load_file.h"
DEFINE_bool(
enable_ssl, false,
@@ -28,19 +33,52 @@ DEFINE_bool(use_auth, false,
"--channel_creds_type=gdc.");
DEFINE_string(
access_token, "",
- "The access token that will be sent to the server to authenticate RPCs.");
+ "The access token that will be sent to the server to authenticate RPCs. "
+ "Deprecated. Use --call_creds=access_token=<token>.");
DEFINE_string(
ssl_target, "",
"If not empty, treat the server host name as this for ssl/tls certificate "
"validation.");
DEFINE_string(
+ ssl_client_cert, "",
+ "If not empty, load this PEM formated client certificate file. Requires "
+ "use of --ssl_client_key.");
+DEFINE_string(
+ ssl_client_key, "",
+ "If not empty, load this PEM formated private key. Requires use of "
+ "--ssl_client_cert");
+DEFINE_string(
channel_creds_type, "",
"The channel creds type: insecure, ssl, gdc (Google Default Credentials) "
"or alts.");
+DEFINE_string(
+ call_creds, "",
+ "Call credentials to use: none (default), or access_token=<token>. If "
+ "provided, the call creds are composited on top of channel creds.");
namespace grpc {
namespace testing {
+namespace {
+
+const char ACCESS_TOKEN_PREFIX[] = "access_token=";
+constexpr int ACCESS_TOKEN_PREFIX_LEN =
+ sizeof(ACCESS_TOKEN_PREFIX) / sizeof(*ACCESS_TOKEN_PREFIX) - 1;
+
+bool IsAccessToken(const grpc::string& auth) {
+ return auth.length() > ACCESS_TOKEN_PREFIX_LEN &&
+ auth.compare(0, ACCESS_TOKEN_PREFIX_LEN, ACCESS_TOKEN_PREFIX) == 0;
+}
+
+grpc::string AccessToken(const grpc::string& auth) {
+ if (!IsAccessToken(auth)) {
+ return "";
+ }
+ return grpc::string(auth, ACCESS_TOKEN_PREFIX_LEN);
+}
+
+} // namespace
+
grpc::string CliCredentials::GetDefaultChannelCredsType() const {
// Compatibility logic for --enable_ssl.
if (FLAGS_enable_ssl) {
@@ -59,12 +97,42 @@ grpc::string CliCredentials::GetDefaultChannelCredsType() const {
return "insecure";
}
+grpc::string CliCredentials::GetDefaultCallCreds() const {
+ if (!FLAGS_access_token.empty()) {
+ fprintf(stderr,
+ "warning: --access_token is deprecated. Use "
+ "--call_creds=access_token=<token>.\n");
+ return grpc::string("access_token=") + FLAGS_access_token;
+ }
+ return "none";
+}
+
std::shared_ptr<grpc::ChannelCredentials>
CliCredentials::GetChannelCredentials() const {
if (FLAGS_channel_creds_type.compare("insecure") == 0) {
return grpc::InsecureChannelCredentials();
} else if (FLAGS_channel_creds_type.compare("ssl") == 0) {
- return grpc::SslCredentials(grpc::SslCredentialsOptions());
+ grpc::SslCredentialsOptions ssl_creds_options;
+ // TODO(@Capstan): This won't affect Google Default Credentials using SSL.
+ if (!FLAGS_ssl_client_cert.empty()) {
+ grpc_slice cert_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_cert.c_str(), 1, &cert_slice));
+ ssl_creds_options.pem_cert_chain =
+ grpc::StringFromCopiedSlice(cert_slice);
+ grpc_slice_unref(cert_slice);
+ }
+ if (!FLAGS_ssl_client_key.empty()) {
+ grpc_slice key_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_key.c_str(), 1, &key_slice));
+ ssl_creds_options.pem_private_key =
+ grpc::StringFromCopiedSlice(key_slice);
+ grpc_slice_unref(key_slice);
+ }
+ return grpc::SslCredentials(ssl_creds_options);
} else if (FLAGS_channel_creds_type.compare("gdc") == 0) {
return grpc::GoogleDefaultCredentials();
} else if (FLAGS_channel_creds_type.compare("alts") == 0) {
@@ -80,18 +148,30 @@ CliCredentials::GetChannelCredentials() const {
std::shared_ptr<grpc::CallCredentials> CliCredentials::GetCallCredentials()
const {
- if (!FLAGS_access_token.empty()) {
- if (FLAGS_use_auth) {
- fprintf(stderr,
- "warning: use_auth is ignored when access_token is provided.");
- }
- return grpc::AccessTokenCredentials(FLAGS_access_token);
+ if (IsAccessToken(FLAGS_call_creds)) {
+ return grpc::AccessTokenCredentials(AccessToken(FLAGS_call_creds));
+ }
+ if (FLAGS_call_creds.compare("none") == 0) {
+ // Nothing to do; creds, if any, are baked into the channel.
+ return std::shared_ptr<grpc::CallCredentials>();
}
+ fprintf(stderr,
+ "--call_creds=%s invalid; must be none "
+ "or access_token=<token>.\n",
+ FLAGS_call_creds.c_str());
return std::shared_ptr<grpc::CallCredentials>();
}
std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials()
const {
+ if (FLAGS_call_creds.empty()) {
+ FLAGS_call_creds = GetDefaultCallCreds();
+ } else if (!FLAGS_access_token.empty() && !IsAccessToken(FLAGS_call_creds)) {
+ fprintf(stderr,
+ "warning: ignoring --access_token because --call_creds "
+ "already set to %s.\n",
+ FLAGS_call_creds.c_str());
+ }
if (FLAGS_channel_creds_type.empty()) {
FLAGS_channel_creds_type = GetDefaultChannelCredsType();
} else if (FLAGS_enable_ssl && FLAGS_channel_creds_type.compare("ssl") != 0) {
@@ -106,7 +186,7 @@ std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials()
FLAGS_channel_creds_type.c_str());
}
// Legacy transport upgrade logic for insecure requests.
- if (!FLAGS_access_token.empty() &&
+ if (IsAccessToken(FLAGS_call_creds) &&
FLAGS_channel_creds_type.compare("insecure") == 0) {
fprintf(stderr,
"warning: --channel_creds_type=insecure upgraded to ssl because "
@@ -126,10 +206,16 @@ const grpc::string CliCredentials::GetCredentialUsage() const {
return " --enable_ssl ; Set whether to use ssl (deprecated)\n"
" --use_auth ; Set whether to create default google"
" credentials\n"
+ " ; (deprecated)\n"
" --access_token ; Set the access token in metadata,"
" overrides --use_auth\n"
+ " ; (deprecated)\n"
" --ssl_target ; Set server host for ssl validation\n"
- " --channel_creds_type ; Set to insecure, ssl, gdc, or alts\n";
+ " --ssl_client_cert ; Client cert for ssl\n"
+ " --ssl_client_key ; Client private key for ssl\n"
+ " --channel_creds_type ; Set to insecure, ssl, gdc, or alts\n"
+ " --call_creds ; Set to none, or"
+ " access_token=<token>\n";
}
const grpc::string CliCredentials::GetSslTargetNameOverride() const {
diff --git a/test/cpp/util/cli_credentials.h b/test/cpp/util/cli_credentials.h
index 4636d3ca14..472c7abef2 100644
--- a/test/cpp/util/cli_credentials.h
+++ b/test/cpp/util/cli_credentials.h
@@ -36,6 +36,9 @@ class CliCredentials {
// Returns the appropriate channel_creds_type value for the set of legacy
// flag arguments.
virtual grpc::string GetDefaultChannelCredsType() const;
+ // Returns the appropriate call_creds value for the set of legacy flag
+ // arguments.
+ virtual grpc::string GetDefaultCallCreds() const;
// Returns the base transport channel credentials. Child classes can override
// to support additional channel_creds_types unknown to this base class.
virtual std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials()
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index ccc60cca27..80eaf4f727 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -57,6 +57,8 @@ DEFINE_string(proto_path, ".", "Path to look for the proto file.");
DEFINE_string(protofiles, "", "Name of the proto file.");
DEFINE_bool(binary_input, false, "Input in binary format");
DEFINE_bool(binary_output, false, "Output in binary format");
+DEFINE_bool(json_input, false, "Input in json format");
+DEFINE_bool(json_output, false, "Output in json format");
DEFINE_string(infile, "", "Input file (default is stdin)");
DEFINE_bool(batch, false,
"Input contains multiple requests. Please do not use this to send "
@@ -88,6 +90,8 @@ class GrpcTool {
GrpcToolOutputCallback callback);
bool ToText(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback);
+ bool ToJson(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback);
bool ToBinary(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback);
@@ -189,8 +193,9 @@ void ReadResponse(CliCall* call, const grpc::string& method_name,
fprintf(stderr, "got response.\n");
if (!FLAGS_binary_output) {
gpr_mu_lock(parser_mu);
- serialized_response_proto = parser->GetTextFormatFromMethod(
- method_name, serialized_response_proto, false /* is_request */);
+ serialized_response_proto = parser->GetFormattedStringFromMethod(
+ method_name, serialized_response_proto, false /* is_request */,
+ FLAGS_json_output);
if (parser->HasError() && print_mode) {
fprintf(stderr, "Failed to parse response.\n");
}
@@ -233,6 +238,7 @@ const Command ops[] = {
{"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
{"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
{"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
+ {"tojson", BindWith5Args(&GrpcTool::ToJson), 2, 3},
};
void Usage(const grpc::string& msg) {
@@ -244,6 +250,7 @@ void Usage(const grpc::string& msg) {
" grpc_cli type ... ; Print type\n"
" grpc_cli parse ... ; Parse message\n"
" grpc_cli totext ... ; Convert binary message to text\n"
+ " grpc_cli tojson ... ; Convert binary message to json\n"
" grpc_cli tobinary ... ; Convert text message to binary\n"
" grpc_cli help ... ; Print this message, or per-command usage\n"
"\n",
@@ -465,7 +472,9 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
" --infile ; Input filename (defaults to stdin)\n"
" --outfile ; Output filename (defaults to stdout)\n"
" --binary_input ; Input in binary format\n"
- " --binary_output ; Output in binary format\n" +
+ " --binary_output ; Output in binary format\n"
+ " --json_input ; Input in json format\n"
+ " --json_output ; Output in json format\n" +
cred.GetCredentialUsage());
std::stringstream output_ss;
@@ -548,7 +557,8 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
} else {
gpr_mu_lock(&parser_mu);
serialized_request_proto = parser->GetSerializedProtoFromMethod(
- method_name, request_text, true /* is_request */);
+ method_name, request_text, true /* is_request */,
+ FLAGS_json_input);
request_text.clear();
if (parser->HasError()) {
if (print_mode) {
@@ -632,7 +642,8 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
request_text.clear();
} else {
serialized_request_proto = parser->GetSerializedProtoFromMethod(
- method_name, request_text, true /* is_request */);
+ method_name, request_text, true /* is_request */,
+ FLAGS_json_input);
request_text.clear();
if (parser->HasError()) {
if (print_mode) {
@@ -668,9 +679,10 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
break;
}
} else {
- grpc::string response_text = parser->GetTextFormatFromMethod(
+ grpc::string response_text = parser->GetFormattedStringFromMethod(
method_name, serialized_response_proto,
- false /* is_request */);
+ false /* is_request */, FLAGS_json_output);
+
if (parser->HasError() && print_mode) {
fprintf(stderr, "Failed to parse response.\n");
} else {
@@ -727,7 +739,7 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
serialized_request_proto = request_text;
} else {
serialized_request_proto = parser->GetSerializedProtoFromMethod(
- method_name, request_text, true /* is_request */);
+ method_name, request_text, true /* is_request */, FLAGS_json_input);
if (parser->HasError()) {
fprintf(stderr, "Failed to parse request.\n");
return false;
@@ -751,13 +763,15 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
receive_initial_metadata ? &server_initial_metadata : nullptr);
receive_initial_metadata = false) {
if (!FLAGS_binary_output) {
- serialized_response_proto = parser->GetTextFormatFromMethod(
- method_name, serialized_response_proto, false /* is_request */);
+ serialized_response_proto = parser->GetFormattedStringFromMethod(
+ method_name, serialized_response_proto, false /* is_request */,
+ FLAGS_json_output);
if (parser->HasError()) {
fprintf(stderr, "Failed to parse response.\n");
return false;
}
}
+
if (receive_initial_metadata) {
PrintMetadata(server_initial_metadata,
"Received initial metadata from server:");
@@ -797,7 +811,9 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
" --infile ; Input filename (defaults to stdin)\n"
" --outfile ; Output filename (defaults to stdout)\n"
" --binary_input ; Input in binary format\n"
- " --binary_output ; Output in binary format\n" +
+ " --binary_output ; Output in binary format\n"
+ " --json_input ; Input in json format\n"
+ " --json_output ; Output in json format\n" +
cred.GetCredentialUsage());
std::stringstream output_ss;
@@ -844,8 +860,8 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
if (FLAGS_binary_input) {
serialized_request_proto = message_text;
} else {
- serialized_request_proto =
- parser->GetSerializedProtoFromMessageType(type_name, message_text);
+ serialized_request_proto = parser->GetSerializedProtoFromMessageType(
+ type_name, message_text, FLAGS_json_input);
if (parser->HasError()) {
fprintf(stderr, "Failed to serialize the message.\n");
return false;
@@ -855,12 +871,14 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
if (FLAGS_binary_output) {
output_ss << serialized_request_proto;
} else {
- grpc::string output_text = parser->GetTextFormatFromMessageType(
- type_name, serialized_request_proto);
+ grpc::string output_text;
+ output_text = parser->GetFormattedStringFromMessageType(
+ type_name, serialized_request_proto, FLAGS_json_output);
if (parser->HasError()) {
fprintf(stderr, "Failed to deserialize the message.\n");
return false;
}
+
output_ss << output_text << std::endl;
}
@@ -885,6 +903,25 @@ bool GrpcTool::ToText(int argc, const char** argv, const CliCredentials& cred,
return ParseMessage(argc, argv, cred, callback);
}
+bool GrpcTool::ToJson(int argc, const char** argv, const CliCredentials& cred,
+ GrpcToolOutputCallback callback) {
+ CommandUsage(
+ "Convert binary message to json\n"
+ " grpc_cli tojson <protofiles> <type>\n"
+ " <protofiles> ; Comma separated list of proto files\n"
+ " <type> ; Protocol buffer type name\n"
+ " --proto_path ; The search path of proto files\n"
+ " --infile ; Input filename (defaults to stdin)\n"
+ " --outfile ; Output filename (defaults to stdout)\n");
+
+ FLAGS_protofiles = argv[0];
+ FLAGS_remotedb = false;
+ FLAGS_binary_input = true;
+ FLAGS_binary_output = false;
+ FLAGS_json_output = true;
+ return ParseMessage(argc, argv, cred, callback);
+}
+
bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback) {
CommandUsage(
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
index 3aae090e81..be9a624a2c 100644
--- a/test/cpp/util/grpc_tool_test.cc
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -74,11 +74,20 @@ using grpc::testing::EchoResponse;
" rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
"{}\n"
-#define ECHO_RESPONSE_MESSAGE \
- "message: \"echo\"\n" \
- "param {\n" \
- " host: \"localhost\"\n" \
- " peer: \"peer\"\n" \
+#define ECHO_RESPONSE_MESSAGE_TEXT_FORMAT \
+ "message: \"echo\"\n" \
+ "param {\n" \
+ " host: \"localhost\"\n" \
+ " peer: \"peer\"\n" \
+ "}\n\n"
+
+#define ECHO_RESPONSE_MESSAGE_JSON_FORMAT \
+ "{\n" \
+ " \"message\": \"echo\",\n" \
+ " \"param\": {\n" \
+ " \"host\": \"localhost\",\n" \
+ " \"peer\": \"peer\"\n" \
+ " }\n" \
"}\n\n"
DECLARE_string(channel_creds_type);
@@ -89,6 +98,8 @@ namespace testing {
DECLARE_bool(binary_input);
DECLARE_bool(binary_output);
+DECLARE_bool(json_input);
+DECLARE_bool(json_output);
DECLARE_bool(l);
DECLARE_bool(batch);
DECLARE_string(metadata);
@@ -426,6 +437,61 @@ TEST_F(GrpcToolTest, CallCommand) {
// Expected output: "message: \"Hello\""
EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "message: \"Hello\""));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello"
+ // }
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello\"\n}"));
+
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandJsonInput) {
+ // Test input "grpc_cli call localhost:<port> Echo "{ \"message\": \"Hello\"}"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{ \"message\": \"Hello\"}"};
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ // Expected output: "message: \"Hello\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello\""));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello"
+ // }
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello\"\n}"));
+
ShutdownServer();
}
@@ -453,6 +519,101 @@ TEST_F(GrpcToolTest, CallCommandBatch) {
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: "
"\"Hello1\"\nmessage: \"Hello2\"\n"));
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello1"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello1\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatchJsonInput) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{\"message\": \"Hello0\"}"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{\"message\": \"Hello1\"}\n\n{\"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ FLAGS_batch = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: "
+ "\"Hello1\"\nmessage: \"Hello2\"\n"));
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+ FLAGS_json_input = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello1"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello1\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
std::cin.rdbuf(orig);
ShutdownServer();
}
@@ -479,6 +640,95 @@ TEST_F(GrpcToolTest, CallCommandBatchWithBadRequest) {
// Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: \"Hello2\"\n"));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, CallCommandBatchJsonInputWithBadRequest) {
+ // Test input "grpc_cli call Echo"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+ "{ \"message\": \"Hello0\"}"};
+
+ // Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"message\": 1 }\n\n { \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+ FLAGS_batch = false;
+
+ // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+ ss.clear();
+ ss.seekg(0);
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_batch = true;
+ FLAGS_json_input = true;
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+ FLAGS_batch = false;
+
+ // Expected output:
+ // {
+ // "message": "Hello0"
+ // }
+ // {
+ // "message": "Hello2"
+ // }
+ // Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
+ // "Hello2"\n"
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "{\n \"message\": \"Hello0\"\n}\n"
+ "{\n \"message\": \"Hello2\"\n}\n"));
+
std::cin.rdbuf(orig);
ShutdownServer();
}
@@ -508,6 +758,34 @@ TEST_F(GrpcToolTest, CallCommandRequestStream) {
ShutdownServer();
}
+TEST_F(GrpcToolTest, CallCommandRequestStreamJsonInput) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "{ \"message\":
+ // \"Hello0\"}"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "{ \"message\": \"Hello0\" }"};
+
+ // Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"message\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+
+ // Expected output: "message: \"Hello0Hello1Hello2\""
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ "message: \"Hello0Hello1Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
// Test input: grpc_cli call localhost:<port> RequestStream "message:
// 'Hello0'"
@@ -533,6 +811,34 @@ TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
ShutdownServer();
}
+TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequestJsonInput) {
+ // Test input: grpc_cli call localhost:<port> RequestStream "message:
+ // 'Hello0'"
+ std::stringstream output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
+ "RequestStream", "{ \"message\": \"Hello0\" }"};
+
+ // Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
+ std::streambuf* orig = std::cin.rdbuf();
+ std::istringstream ss(
+ "{ \"bad_field\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
+ std::cin.rdbuf(ss.rdbuf());
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_input = false;
+
+ // Expected output: "message: \"Hello0Hello2\""
+ EXPECT_TRUE(nullptr !=
+ strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
+ std::cin.rdbuf(orig);
+ ShutdownServer();
+}
+
TEST_F(GrpcToolTest, CallCommandResponseStream) {
// Test input: grpc_cli call localhost:<port> ResponseStream "message:
// 'Hello'"
@@ -554,6 +860,24 @@ TEST_F(GrpcToolTest, CallCommandResponseStream) {
expected_response_text.c_str()));
}
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output: "{\n \"message\": \"Hello{n}\"\n}\n"
+ for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
+ grpc::string expected_response_text =
+ "{\n \"message\": \"Hello" + grpc::to_string(i) + "\"\n}\n";
+ EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
+ expected_response_text.c_str()));
+ }
+
ShutdownServer();
}
@@ -617,15 +941,31 @@ TEST_F(GrpcToolTest, ParseCommand) {
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
- "grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE};
+ "grpc.testing.EchoResponse",
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT};
FLAGS_binary_input = false;
FLAGS_binary_output = false;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
- // Expected output: ECHO_RESPONSE_MESSAGE
- EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
+ // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
// Parse text message to binary message and then parse it back to text message
output_stream.str(grpc::string());
@@ -645,13 +985,52 @@ TEST_F(GrpcToolTest, ParseCommand) {
std::placeholders::_1)));
// Expected output: ECHO_RESPONSE_MESSAGE
- EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
FLAGS_binary_input = false;
FLAGS_binary_output = false;
ShutdownServer();
}
+TEST_F(GrpcToolTest, ParseCommandJsonFormat) {
+ // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
+ // ECHO_RESPONSE_MESSAGE_JSON_FORMAT"
+ std::stringstream output_stream;
+ std::stringstream binary_output_stream;
+
+ const grpc::string server_address = SetUpServer();
+ const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
+ "grpc.testing.EchoResponse",
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT};
+
+ FLAGS_json_input = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
+
+ // with json_output
+ output_stream.str(grpc::string());
+ output_stream.clear();
+
+ FLAGS_json_output = true;
+ EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+ std::bind(PrintStream, &output_stream,
+ std::placeholders::_1)));
+ FLAGS_json_output = false;
+ FLAGS_json_input = false;
+
+ // Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
+ EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(),
+ ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
+
+ ShutdownServer();
+}
+
TEST_F(GrpcToolTest, TooFewArguments) {
// Test input "grpc_cli call Echo"
std::stringstream output_stream;
diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc
index a530ed1ffc..68ecfeae2c 100644
--- a/test/cpp/util/proto_file_parser.cc
+++ b/test/cpp/util/proto_file_parser.cc
@@ -217,31 +217,32 @@ bool ProtoFileParser::IsStreaming(const grpc::string& method, bool is_request) {
}
grpc::string ProtoFileParser::GetSerializedProtoFromMethod(
- const grpc::string& method, const grpc::string& text_format_proto,
- bool is_request) {
+ const grpc::string& method, const grpc::string& formatted_proto,
+ bool is_request, bool is_json_format) {
has_error_ = false;
grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
if (has_error_) {
return "";
}
- return GetSerializedProtoFromMessageType(message_type_name,
- text_format_proto);
+ return GetSerializedProtoFromMessageType(message_type_name, formatted_proto,
+ is_json_format);
}
-grpc::string ProtoFileParser::GetTextFormatFromMethod(
+grpc::string ProtoFileParser::GetFormattedStringFromMethod(
const grpc::string& method, const grpc::string& serialized_proto,
- bool is_request) {
+ bool is_request, bool is_json_format) {
has_error_ = false;
grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
if (has_error_) {
return "";
}
- return GetTextFormatFromMessageType(message_type_name, serialized_proto);
+ return GetFormattedStringFromMessageType(message_type_name, serialized_proto,
+ is_json_format);
}
grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
- const grpc::string& message_type_name,
- const grpc::string& text_format_proto) {
+ const grpc::string& message_type_name, const grpc::string& formatted_proto,
+ bool is_json_format) {
has_error_ = false;
grpc::string serialized;
const protobuf::Descriptor* desc =
@@ -252,11 +253,23 @@ grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
}
std::unique_ptr<grpc::protobuf::Message> msg(
dynamic_factory_->GetPrototype(desc)->New());
- bool ok = protobuf::TextFormat::ParseFromString(text_format_proto, msg.get());
- if (!ok) {
- LogError("Failed to parse text format to proto.");
- return "";
+
+ bool ok;
+ if (is_json_format) {
+ ok = grpc::protobuf::json::JsonStringToMessage(formatted_proto, msg.get())
+ .ok();
+ if (!ok) {
+ LogError("Failed to convert json format to proto.");
+ return "";
+ }
+ } else {
+ ok = protobuf::TextFormat::ParseFromString(formatted_proto, msg.get());
+ if (!ok) {
+ LogError("Failed to convert text format to proto.");
+ return "";
+ }
}
+
ok = msg->SerializeToString(&serialized);
if (!ok) {
LogError("Failed to serialize proto.");
@@ -265,9 +278,9 @@ grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
return serialized;
}
-grpc::string ProtoFileParser::GetTextFormatFromMessageType(
- const grpc::string& message_type_name,
- const grpc::string& serialized_proto) {
+grpc::string ProtoFileParser::GetFormattedStringFromMessageType(
+ const grpc::string& message_type_name, const grpc::string& serialized_proto,
+ bool is_json_format) {
has_error_ = false;
const protobuf::Descriptor* desc =
desc_pool_->FindMessageTypeByName(message_type_name);
@@ -281,12 +294,24 @@ grpc::string ProtoFileParser::GetTextFormatFromMessageType(
LogError("Failed to deserialize proto.");
return "";
}
- grpc::string text_format;
- if (!protobuf::TextFormat::PrintToString(*msg.get(), &text_format)) {
- LogError("Failed to print proto message to text format");
- return "";
+ grpc::string formatted_string;
+
+ if (is_json_format) {
+ grpc::protobuf::json::JsonPrintOptions jsonPrintOptions;
+ jsonPrintOptions.add_whitespace = true;
+ if (!grpc::protobuf::json::MessageToJsonString(
+ *msg.get(), &formatted_string, jsonPrintOptions)
+ .ok()) {
+ LogError("Failed to print proto message to json format");
+ return "";
+ }
+ } else {
+ if (!protobuf::TextFormat::PrintToString(*msg.get(), &formatted_string)) {
+ LogError("Failed to print proto message to text format");
+ return "";
+ }
}
- return text_format;
+ return formatted_string;
}
void ProtoFileParser::LogError(const grpc::string& error_msg) {
diff --git a/test/cpp/util/proto_file_parser.h b/test/cpp/util/proto_file_parser.h
index eb1d793c2b..1e49c98daf 100644
--- a/test/cpp/util/proto_file_parser.h
+++ b/test/cpp/util/proto_file_parser.h
@@ -53,21 +53,49 @@ class ProtoFileParser {
// used as the argument of Stub::Call()
grpc::string GetFormattedMethodName(const grpc::string& method);
- grpc::string GetSerializedProtoFromMethod(
- const grpc::string& method, const grpc::string& text_format_proto,
- bool is_request);
-
- grpc::string GetTextFormatFromMethod(const grpc::string& method,
- const grpc::string& serialized_proto,
- bool is_request);
-
+ /// Converts a text or json string to its binary proto representation for the
+ /// given method's input or return type.
+ /// \param method the name of the method (does not need to be fully qualified
+ /// name)
+ /// \param formatted_proto the text- or json-formatted proto string
+ /// \param is_request if \c true the resolved type is that of the input
+ /// parameter of the method, otherwise it is the output type
+ /// \param is_json_format if \c true the \c formatted_proto is treated as a
+ /// json-formatted proto, otherwise it is treated as a text-formatted
+ /// proto
+ /// \return the serialised binary proto represenation of \c formatted_proto
+ grpc::string GetSerializedProtoFromMethod(const grpc::string& method,
+ const grpc::string& formatted_proto,
+ bool is_request,
+ bool is_json_format);
+
+ /// Converts a text or json string to its proto representation for the given
+ /// message type.
+ /// \param formatted_proto the text- or json-formatted proto string
+ /// \return the serialised binary proto represenation of \c formatted_proto
grpc::string GetSerializedProtoFromMessageType(
const grpc::string& message_type_name,
- const grpc::string& text_format_proto);
-
- grpc::string GetTextFormatFromMessageType(
+ const grpc::string& formatted_proto, bool is_json_format);
+
+ /// Converts a binary proto string to its text or json string representation
+ /// for the given method's input or return type.
+ /// \param method the name of the method (does not need to be a fully
+ /// qualified name)
+ /// \param the serialised binary proto representation of type
+ /// \c message_type_name
+ /// \return the text- or json-formatted proto string of \c serialized_proto
+ grpc::string GetFormattedStringFromMethod(
+ const grpc::string& method, const grpc::string& serialized_proto,
+ bool is_request, bool is_json_format);
+
+ /// Converts a binary proto string to its text or json string representation
+ /// for the given message type.
+ /// \param the serialised binary proto representation of type
+ /// \c message_type_name
+ /// \return the text- or json-formatted proto string of \c serialized_proto
+ grpc::string GetFormattedStringFromMessageType(
const grpc::string& message_type_name,
- const grpc::string& serialized_proto);
+ const grpc::string& serialized_proto, bool is_json_format);
bool IsStreaming(const grpc::string& method, bool is_request);
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index f9371410e7..61924b91df 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -21,7 +21,8 @@ unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip
./update_version.sh auto
-nuget restore
+# Retry "nuget restore" to work around https://github.com/grpc/grpc/issues/16312
+nuget restore || nuget restore || nuget restore
xbuild DistribTest.sln
diff --git a/third_party/boringssl-with-bazel b/third_party/boringssl-with-bazel
-Subproject 8149b351bf797bd80e063787886b7618f508e45
+Subproject afc30d43eef92979b05776ec0963c9cede5fb80
diff --git a/tools/bazel.rc b/tools/bazel.rc
index 39f8071535..59e597b472 100644
--- a/tools/bazel.rc
+++ b/tools/bazel.rc
@@ -1,51 +1,59 @@
+# bazelrc file
+# bazel >= 0.18 looks for %workspace%/.bazelrc (which redirects here)
+# Older bazel versions look for %workspace%/tools/bazel.rc (this file)
+# See https://github.com/bazelbuild/bazel/issues/6319
+
build --client_env=CC=clang
-build --copt -DGRPC_BAZEL_BUILD
+build --copt=-DGRPC_BAZEL_BUILD
+
+build:opt --compilation_mode=opt
+build:opt --copt=-Wframe-larger-than=16384
-build:opt --copt -Wframe-larger-than=16384
+build:dbg --compilation_mode=dbg
build:asan --strip=never
-build:asan --copt -fsanitize-coverage=edge
-build:asan --copt -fsanitize=address
-build:asan --copt -O0
-build:asan --copt -fno-omit-frame-pointer
-build:asan --copt -DGPR_NO_DIRECT_SYSCALLS
-build:asan --linkopt -fsanitize=address
+build:asan --copt=-fsanitize=address
+build:asan --copt=-O0
+build:asan --copt=-fno-omit-frame-pointer
+build:asan --copt=-DGPR_NO_DIRECT_SYSCALLS
+build:asan --copt=-DADDRESS_SANITIZER # used by absl
+build:asan --linkopt=-fsanitize=address
build:asan --action_env=ASAN_OPTIONS=detect_leaks=1:color=always
build:asan --action_env=LSAN_OPTIONS=suppressions=test/core/util/lsan_suppressions.txt:report_objects=1
build:msan --strip=never
-build:msan --copt -fsanitize-coverage=edge
-build:msan --copt -fsanitize=memory
-build:msan --copt -O0
-build:msan --copt -fsanitize-memory-track-origins
-build:msan --copt -fsanitize-memory-use-after-dtor
-build:msan --copt -fno-omit-frame-pointer
-build:msan --copt -fPIE
-build:msan --copt -DGPR_NO_DIRECT_SYSCALLS
-build:msan --linkopt -fsanitize=memory
-build:msan --linkopt -fPIE
+build:msan --copt=-fsanitize=memory
+build:msan --copt=-O0
+build:msan --copt=-fsanitize-memory-track-origins
+build:msan --copt=-fsanitize-memory-use-after-dtor
+build:msan --copt=-fno-omit-frame-pointer
+build:msan --copt=-DGPR_NO_DIRECT_SYSCALLS
+build:msan --copt=-DMEMORY_SANITIZER # used by absl
+build:msan --linkopt=-fsanitize=memory
build:msan --action_env=MSAN_OPTIONS=poison_in_dtor=1
build:tsan --strip=never
-build:tsan --copt -fsanitize=thread
-build:tsan --copt -fno-omit-frame-pointer
-build:tsan --copt -DGPR_NO_DIRECT_SYSCALLS
-build:tsan --copt -DGRPC_TSAN
-build:tsan --linkopt -fsanitize=thread
+build:tsan --copt=-fsanitize=thread
+build:tsan --copt=-fno-omit-frame-pointer
+build:tsan --copt=-DGPR_NO_DIRECT_SYSCALLS
+build:tsan --copt=-DGRPC_TSAN
+# TODO(jtattermusch): ideally we would set --copt=-DTHREAD_SANITIZER (used by absl)
+# but it seems to do more harm than good and triggers #17175
+build:tsan --linkopt=-fsanitize=thread
build:tsan --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
build:ubsan --strip=never
-build:ubsan --copt -fsanitize-coverage=edge
-build:ubsan --copt -fsanitize=undefined
-build:ubsan --copt -fno-omit-frame-pointer
-build:ubsan --copt -DGRPC_UBSAN
-build:ubsan --copt -DNDEBUG
-build:ubsan --copt -fno-sanitize=function,vptr
-build:ubsan --linkopt -fsanitize=undefined
+build:ubsan --copt=-fsanitize=undefined
+build:ubsan --copt=-fno-omit-frame-pointer
+build:ubsan --copt=-DGRPC_UBSAN
+build:ubsan --copt=-DNDEBUG
+build:ubsan --copt=-DUNDEFINED_BEHAVIOR_SANITIZER # used by absl
+build:ubsan --copt=-fno-sanitize=function,vptr
+build:ubsan --linkopt=-fsanitize=undefined
build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1:suppressions=test/core/util/ubsan_suppressions.txt
build:basicprof --strip=never
-build:basicprof --copt -DNDEBUG
-build:basicprof --copt -O2
-build:basicprof --copt -DGRPC_BASIC_PROFILER
-build:basicprof --copt -DGRPC_TIMERS_RDTSC
+build:basicprof --copt=-DNDEBUG
+build:basicprof --copt=-O2
+build:basicprof --copt=-DGRPC_BASIC_PROFILER
+build:basicprof --copt=-DGRPC_TIMERS_RDTSC
diff --git a/tools/buildgen/generate_build_additions.sh b/tools/buildgen/generate_build_additions.sh
index 693c02fdb2..5a1f4a598a 100644..100755
--- a/tools/buildgen/generate_build_additions.sh
+++ b/tools/buildgen/generate_build_additions.sh
@@ -25,7 +25,8 @@ gen_build_yaml_dirs=" \
test/core/bad_ssl \
test/core/end2end \
test/cpp/naming \
- test/cpp/qps"
+ test/cpp/qps \
+ tools/run_tests/lb_interop_tests"
gen_build_files=""
for gen_build_yaml in $gen_build_yaml_dirs
do
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 25da3fdd5f..adfd4a24f9 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -23,10 +23,14 @@ import subprocess
import re
import perfection
-# configuration: a list of either strings or 2-tuples of strings
-# a single string represents a static grpc_mdstr
-# a 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
-# also be created)
+# Configuration: a list of either strings or 2-tuples of strings.
+# A single string represents a static grpc_mdstr.
+# A 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
+# also be created).
+# The list of 2-tuples must begin with the static hpack table elements as
+# defined by RFC 7541 and be in the same order because of an hpack encoding
+# performance optimization that relies on this. If you want to change this, then
+# you must change the implementation of the encoding optimization as well.
CONFIG = [
# metadata strings
@@ -59,37 +63,28 @@ CONFIG = [
'grpc.max_response_message_bytes',
# well known method names
'/grpc.lb.v1.LoadBalancer/BalanceLoad',
+ '/grpc.health.v1.Health/Watch',
# compression algorithm names
'deflate',
'gzip',
'stream/gzip',
# metadata elements
- ('grpc-status', '0'),
- ('grpc-status', '1'),
- ('grpc-status', '2'),
- ('grpc-encoding', 'identity'),
- ('grpc-encoding', 'gzip'),
- ('grpc-encoding', 'deflate'),
- ('te', 'trailers'),
- ('content-type', 'application/grpc'),
- (':method', 'POST'),
- (':status', '200'),
- (':status', '404'),
- (':scheme', 'http'),
- (':scheme', 'https'),
- (':scheme', 'grpc'),
+ # begin hpack static elements
(':authority', ''),
(':method', 'GET'),
- (':method', 'PUT'),
+ (':method', 'POST'),
(':path', '/'),
(':path', '/index.html'),
+ (':scheme', 'http'),
+ (':scheme', 'https'),
+ (':status', '200'),
(':status', '204'),
(':status', '206'),
(':status', '304'),
(':status', '400'),
+ (':status', '404'),
(':status', '500'),
('accept-charset', ''),
- ('accept-encoding', ''),
('accept-encoding', 'gzip, deflate'),
('accept-language', ''),
('accept-ranges', ''),
@@ -100,8 +95,6 @@ CONFIG = [
('authorization', ''),
('cache-control', ''),
('content-disposition', ''),
- ('content-encoding', 'identity'),
- ('content-encoding', 'gzip'),
('content-encoding', ''),
('content-language', ''),
('content-length', ''),
@@ -121,8 +114,6 @@ CONFIG = [
('if-range', ''),
('if-unmodified-since', ''),
('last-modified', ''),
- ('lb-token', ''),
- ('lb-cost-bin', ''),
('link', ''),
('location', ''),
('max-forwards', ''),
@@ -140,37 +131,52 @@ CONFIG = [
('vary', ''),
('via', ''),
('www-authenticate', ''),
+ # end hpack static elements
+ ('grpc-status', '0'),
+ ('grpc-status', '1'),
+ ('grpc-status', '2'),
+ ('grpc-encoding', 'identity'),
+ ('grpc-encoding', 'gzip'),
+ ('grpc-encoding', 'deflate'),
+ ('te', 'trailers'),
+ ('content-type', 'application/grpc'),
+ (':scheme', 'grpc'),
+ (':method', 'PUT'),
+ ('accept-encoding', ''),
+ ('content-encoding', 'identity'),
+ ('content-encoding', 'gzip'),
+ ('lb-token', ''),
+ ('lb-cost-bin', ''),
]
-# Entries marked with is_default=True are ignored when counting
-# non-default initial metadata that prevents the chttp2 server from
-# sending a Trailers-Only response.
+# All entries here are ignored when counting non-default initial metadata that
+# prevents the chttp2 server from sending a Trailers-Only response.
METADATA_BATCH_CALLOUTS = [
- # (name, is_default)
- (':path', True),
- (':method', True),
- (':status', True),
- (':authority', True),
- (':scheme', True),
- ('te', True),
- ('grpc-message', True),
- ('grpc-status', True),
- ('grpc-payload-bin', True),
- ('grpc-encoding', True),
- ('grpc-accept-encoding', True),
- ('grpc-server-stats-bin', True),
- ('grpc-tags-bin', True),
- ('grpc-trace-bin', True),
- ('content-type', True),
- ('content-encoding', True),
- ('accept-encoding', True),
- ('grpc-internal-encoding-request', True),
- ('grpc-internal-stream-encoding-request', True),
- ('user-agent', True),
- ('host', True),
- ('lb-token', True),
- ('grpc-previous-rpc-attempts', True),
- ('grpc-retry-pushback-ms', True),
+ # (name)
+ (':path'),
+ (':method'),
+ (':status'),
+ (':authority'),
+ (':scheme'),
+ ('te'),
+ ('grpc-message'),
+ ('grpc-status'),
+ ('grpc-payload-bin'),
+ ('grpc-encoding'),
+ ('grpc-accept-encoding'),
+ ('grpc-server-stats-bin'),
+ ('grpc-tags-bin'),
+ ('grpc-trace-bin'),
+ ('content-type'),
+ ('content-encoding'),
+ ('accept-encoding'),
+ ('grpc-internal-encoding-request'),
+ ('grpc-internal-stream-encoding-request'),
+ ('user-agent'),
+ ('host'),
+ ('lb-token'),
+ ('grpc-previous-rpc-attempts'),
+ ('grpc-retry-pushback-ms'),
]
COMPRESSION_ALGORITHMS = [
@@ -252,7 +258,7 @@ all_elems = list()
static_userdata = {}
# put metadata batch callouts first, to make the check of if a static metadata
# string is a callout trivial
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
if elem not in all_strs:
all_strs.append(elem)
for elem in CONFIG:
@@ -367,9 +373,12 @@ an explanation of what's going on.
print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H
+print >> H, '#include <grpc/support/port_platform.h>'
+print >> H
print >> H, '#include "src/core/lib/transport/metadata.h"'
print >> H
-
+print >> C, '#include <grpc/support/port_platform.h>'
+print >> C
print >> C, '#include "src/core/lib/transport/static_metadata.h"'
print >> C
print >> C, '#include "src/core/lib/slice/slice_internal.h"'
@@ -388,7 +397,7 @@ def slice_def(i):
# validate configuration
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
assert elem in all_strs
print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
@@ -454,6 +463,7 @@ for i, elem in enumerate(all_elems):
print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], '
'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i)
print >> H
+
print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] '
'= {')
print >> C, ' %s' % ','.join(
@@ -551,7 +561,7 @@ for a, b in all_elems:
print >> C, '};'
print >> H, 'typedef enum {'
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' %s,' % mangle(elem, 'batch').upper()
print >> H, ' GRPC_BATCH_CALLOUTS_COUNT'
print >> H, '} grpc_metadata_batch_callouts_index;'
@@ -559,7 +569,7 @@ print >> H
print >> H, 'typedef union {'
print >> H, ' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
print >> H, ' struct {'
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
print >> H, ' } named;'
print >> H, '} grpc_metadata_batch_callouts;'
@@ -567,14 +577,6 @@ print >> H
print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
print >> H
-print >> H, ('extern bool grpc_static_callout_is_default['
- 'GRPC_BATCH_CALLOUTS_COUNT];')
-print >> H
-print >> C, 'bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {'
-for elem, is_default in METADATA_BATCH_CALLOUTS:
- print >> C, ' %s, // %s' % (str(is_default).lower(), elem)
-print >> C, '};'
-print >> C
print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (
1 << len(COMPRESSION_ALGORITHMS))
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 77f602ad1f..787bef1778 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -75,6 +75,8 @@ _EXEMPT = frozenset((
'examples/python/multiplex/route_guide_pb2_grpc.py',
'examples/python/route_guide/route_guide_pb2.py',
'examples/python/route_guide/route_guide_pb2_grpc.py',
+ 'src/core/ext/filters/client_channel/health/health.pb.h',
+ 'src/core/ext/filters/client_channel/health/health.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
@@ -87,8 +89,6 @@ _EXEMPT = frozenset((
'src/core/tsi/alts/handshaker/handshaker.pb.c',
'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
- 'src/cpp/server/health/health.pb.h',
- 'src/cpp/server/health/health.pb.c',
# An older file originally from outside gRPC.
'src/php/tests/bootstrap.php',
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
index 56f48af56a..b8d530cce0 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -156,6 +156,7 @@ argp.add_argument('--precommit', default=False, action='store_true')
args = argp.parse_args()
KNOWN_BAD = set([
+ 'src/core/ext/filters/client_channel/health/health.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index 6b98619c32..018cbb7b66 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -16,6 +16,7 @@
set -ex
readonly NANOPB_ALTS_TMP_OUTPUT="$(mktemp -d)"
+readonly NANOPB_HEALTH_TMP_OUTPUT="$(mktemp -d)"
readonly NANOPB_TMP_OUTPUT="$(mktemp -d)"
readonly PROTOBUF_INSTALL_PREFIX="$(mktemp -d)"
@@ -68,6 +69,23 @@ if ! diff -r "$NANOPB_TMP_OUTPUT" src/core/ext/filters/client_channel/lb_policy/
fi
#
+# checks for health.proto
+#
+readonly HEALTH_GRPC_OUTPUT_PATH='src/core/ext/filters/client_channel/health'
+# nanopb-compile the proto to a temp location
+./tools/codegen/core/gen_nano_proto.sh \
+ src/proto/grpc/health/v1/health.proto \
+ "$NANOPB_HEALTH_TMP_OUTPUT" \
+ "$HEALTH_GRPC_OUTPUT_PATH"
+# compare outputs to checked compiled code
+for NANOPB_OUTPUT_FILE in $NANOPB_HEALTH_TMP_OUTPUT/*.pb.*; do
+ if ! diff "$NANOPB_OUTPUT_FILE" "${HEALTH_GRPC_OUTPUT_PATH}/$(basename $NANOPB_OUTPUT_FILE)"; then
+ echo "Outputs differ: $NANOPB_HEALTH_TMP_OUTPUT vs $HEALTH_GRPC_OUTPUT_PATH"
+ exit 2
+ fi
+done
+
+#
# Checks for handshaker.proto and transport_security_common.proto
#
readonly HANDSHAKER_GRPC_OUTPUT_PATH='src/core/tsi/alts/handshaker'
diff --git a/tools/distrib/python/grpcio_tools/MANIFEST.in b/tools/distrib/python/grpcio_tools/MANIFEST.in
index 11ce367747..4943751879 100644
--- a/tools/distrib/python/grpcio_tools/MANIFEST.in
+++ b/tools/distrib/python/grpcio_tools/MANIFEST.in
@@ -1,3 +1,4 @@
+include _parallel_compile_patch.py
include grpc_version.py
include protoc_deps.py
include protoc_lib_deps.py
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/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index ccb69a8ebc..4b775e667e 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
-VERSION = '1.15.0.dev0'
+VERSION = '1.17.0.dev0'
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/dockerfile/OWNERS b/tools/dockerfile/OWNERS
index 5f0ad58d61..8ad09b7e83 100644
--- a/tools/dockerfile/OWNERS
+++ b/tools/dockerfile/OWNERS
@@ -7,5 +7,5 @@ set noparent
# for kokoro to be able to access the pre-built images.
@jtattermusch
-@mehrdada
+@apolcyn
@nicolasnoble
diff --git a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
index 0251b2b392..7ec061ebe5 100644
--- a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
@@ -16,10 +16,8 @@
FROM debian:jessie
-RUN apt-get update && apt-get install debian-keyring && apt-key update
-
# Install Git and basic packages.
-RUN apt-get update && apt-key update && apt-get install -y \
+RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
build-essential \
@@ -46,11 +44,6 @@ RUN apt-get update && apt-key update && apt-get install -y \
wget \
zip && apt-get clean
-# Install Node dependencies
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 8 && npm install -g node-pre-gyp"
-
##################
# Ruby dependencies
@@ -72,15 +65,15 @@ RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
# PHP dependencies
RUN apt-get update && apt-get install -y \
- php5 php5-dev php-pear phpunit
+ php5 php5-dev php-pear phpunit && apt-get clean
-##################
-# Install cross compiler for ARM
-RUN echo 'deb http://emdebian.org/tools/debian/ jessie main' | tee -a /etc/apt/sources.list.d/crosstools.list && \
- curl http://emdebian.org/tools/debian/emdebian-toolchain-archive.key | apt-key add -
+##################
+# C# dependencies (needed to build grpc_csharp_ext)
-RUN dpkg --add-architecture armhf && apt-get update && apt-get install -y crossbuild-essential-armhf
+# Use cmake 3.6 from jessie-backports
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
RUN mkdir /var/local/jenkins
diff --git a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
index 2d179c8c45..f81d8e5ba0 100644
--- a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
@@ -16,10 +16,8 @@
FROM 32bit/debian:jessie
-RUN apt-get update && apt-get install debian-keyring && apt-key update
-
# Install Git and basic packages.
-RUN apt-get update && apt-key update && apt-get install -y \
+RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
build-essential \
@@ -46,11 +44,6 @@ RUN apt-get update && apt-key update && apt-get install -y \
wget \
zip && apt-get clean
-# Install Node dependencies
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 8 && npm install -g node-pre-gyp"
-
##################
# Ruby dependencies
@@ -67,6 +60,13 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+##################
+# C# dependencies (needed to build grpc_csharp_ext)
+
+# Use cmake 3.6 from jessie-backports
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+
RUN mkdir /var/local/jenkins
# Define the default command.
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 511e2932d6..b2216c79d4 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -82,6 +82,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
RUN nuget update -self
+#=================
+# Use cmake 3.6 from jessie-backports
+# needed to build grpc_csharp_ext with cmake
+
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+
# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
RUN apt-get update && apt-get install -y curl libunwind8 gettext
# dotnet-dev-1.0.0-preview2-003131
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index 511e2932d6..b2216c79d4 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -82,6 +82,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
RUN nuget update -self
+#=================
+# Use cmake 3.6 from jessie-backports
+# needed to build grpc_csharp_ext with cmake
+
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+
# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
RUN apt-get update && apt-get install -y curl libunwind8 gettext
# dotnet-dev-1.0.0-preview2-003131
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
index 2f31bea69b..8b8c6be8f1 100755
--- a/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
@@ -28,10 +28,10 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-make install-certs
+make install-certs -j4
# build C++ interop client & server
-make interop_client interop_server
+make interop_client interop_server -j4
# build C++ http2 client
-make http2_client
+make http2_client -j4
diff --git a/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
index bff20b5d06..897354891c 100644
--- a/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM google/dart:latest
+FROM google/dart:2.0
# Upgrade Dart to version 2.
RUN apt-get update && apt-get upgrade -y dart
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index b136259ce9..e5e68943a4 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM golang:latest
+FROM golang:1.11
# Using login shell removes Go from path, so we add it.
RUN ln -s /usr/local/go/bin/go /usr/local/bin
diff --git a/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
index b651ac5b88..0e36c193c9 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
@@ -26,3 +26,11 @@ cd /var/local/git/grpc-java
./gradlew :grpc-interop-testing:installDist -PskipCodegen=true
+# enable extra java logging
+mkdir -p /var/local/grpc_java_logging
+echo "handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = ALL
+.level = FINE
+io.grpc.netty.NettyClientHandler = ALL
+io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
+
diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh
index 521111acaa..4c5ba4b7a3 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/build_interop.sh
@@ -25,4 +25,12 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc-java
./gradlew :grpc-interop-testing:installDist -PskipCodegen=true
+
+# enable extra java logging
+mkdir -p /var/local/grpc_java_logging
+echo "handlers = java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = ALL
+.level = FINE
+io.grpc.netty.NettyClientHandler = ALL
+io.grpc.netty.NettyServerHandler = ALL" > /var/local/grpc_java_logging/logconf.txt
diff --git a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
index 999976d15d..fc5c22083a 100755
--- a/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
@@ -28,12 +28,13 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-# gRPC core and protobuf need to be installed
-make install
+# Install gRPC C core and build codegen plugins
+make -j4 install_c plugins
-(cd src/php/ext/grpc && phpize && ./configure && make)
+(cd src/php/ext/grpc && phpize && ./configure && make -j4)
-(cd third_party/protobuf && make install)
+# Install protobuf (need access to protoc)
+(cd third_party/protobuf && make -j4 install)
(cd src/php && php -d extension=ext/grpc/modules/grpc.so /usr/local/bin/composer install)
diff --git a/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
index efa97530c8..248a8f680b 100755
--- a/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php7/build_interop.sh
@@ -28,12 +28,13 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
-# gRPC core and protobuf need to be installed
-make install
+# Install gRPC C core and build codegen plugins
+make -j4 install_c plugins
-(cd src/php/ext/grpc && phpize && ./configure && make)
+(cd src/php/ext/grpc && phpize && ./configure && make -j4)
-(cd third_party/protobuf && make install)
+# Install protobuf (need access to protoc)
+(cd third_party/protobuf && make -j4 install)
(cd src/php && php -d extension=ext/grpc/modules/grpc.so /usr/local/bin/composer install)
diff --git a/tools/dockerfile/interoptest/lb_interop_fake_servers/Dockerfile b/tools/dockerfile/interoptest/lb_interop_fake_servers/Dockerfile
new file mode 100644
index 0000000000..22963f7f83
--- /dev/null
+++ b/tools/dockerfile/interoptest/lb_interop_fake_servers/Dockerfile
@@ -0,0 +1,34 @@
+# Copyright 2015 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.
+
+FROM golang:1.10
+
+RUN apt-get update && apt-get install -y \
+ dnsutils \
+ git \
+ vim \
+ curl \
+ python-pip \
+ python-yaml \
+ make && apt-get clean
+
+RUN ln -s /usr/local/go/bin/go /usr/local/bin
+
+# Install Python packages from PyPI
+RUN pip install --upgrade pip==10.0.1
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/lb_interop_fake_servers/build_interop.sh b/tools/dockerfile/interoptest/lb_interop_fake_servers/build_interop.sh
new file mode 100644
index 0000000000..1846d51753
--- /dev/null
+++ b/tools/dockerfile/interoptest/lb_interop_fake_servers/build_interop.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2015 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.
+#
+# Gets a built Go interop server, fake balancer server, and python
+# DNS server into a base image.
+set -e
+
+# Clone just the grpc-go source code without any dependencies.
+# We are cloning from a local git repo that contains the right revision
+# to test instead of using "go get" to download from Github directly.
+git clone --recursive /var/local/jenkins/grpc-go src/google.golang.org/grpc
+
+# Get all gRPC Go dependencies
+(cd src/google.golang.org/grpc && make deps && make testdeps)
+
+# Build the interop server and fake balancer
+(cd src/google.golang.org/grpc/interop/server && go install)
+(cd src/google.golang.org/grpc/interop/fake_grpclb && go install)
+
+# Clone the grpc/grpc repo to get the python DNS server.
+# Hack: we don't need to init submodules for the scripts we need.
+mkdir -p /var/local/git/grpc
+git clone /var/local/jenkins/grpc /var/local/git/grpc
diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile
index 4f913dc396..0aa6209f4f 100644
--- a/tools/dockerfile/test/bazel/Dockerfile
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -44,9 +44,10 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t
#========================
# Bazel installation
-RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
-RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
-RUN apt-get -y update && apt-get -y install bazel=0.15.0 && apt-get clean
+
+RUN apt-get update && apt-get install -y wget && apt-get clean
+RUN wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O /usr/local/bin/bazel
+RUN chmod 755 /usr/local/bin/bazel
RUN mkdir -p /var/local/jenkins
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index 56bfb89925..030d301a40 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
@@ -86,6 +86,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
RUN nuget update -self
+#=================
+# Use cmake 3.6 from jessie-backports
+# needed to build grpc_csharp_ext with cmake
+
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+
# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
RUN apt-get update && apt-get install -y curl libunwind8 gettext
# dotnet-dev-1.0.0-preview2-003131
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index c4f959fc1d..f9dc8f20d7 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index d07ea9a9b0..76015c8c42 100644
--- a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/cxx_sanitizers_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_sanitizers_jessie_x64/Dockerfile
index f60f67665d..77aac3cdec 100644
--- a/tools/dockerfile/test/cxx_sanitizers_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_sanitizers_jessie_x64/Dockerfile
@@ -52,7 +52,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
index b0d9261af2..09479ba2f7 100644
--- a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
index 439baadc2c..3a87639794 100644
--- a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
index b80249d2d8..d4117f83c8 100644
--- a/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile
index 986cfcbada..7f871f2f62 100644
--- a/tools/dockerfile/test/fuzzer/Dockerfile
+++ b/tools/dockerfile/test/fuzzer/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index a82e7050fc..3c95554b02 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#================
# C# dependencies
@@ -71,6 +71,13 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
RUN nuget update -self
+#=================
+# Use cmake 3.6 from jessie-backports
+# needed to build grpc_csharp_ext with cmake
+
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
+RUN apt-get update && apt-get install -t jessie-backports -y cmake && apt-get clean
+
# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
RUN apt-get update && apt-get install -y curl libunwind8 gettext
# dotnet-dev-1.0.0-preview2-003131
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index 1fe44b6dd7..7c36fb3734 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
# Install Electron apt dependencies
diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
index 53ef7b3443..0dff839904 100644
--- a/tools/dockerfile/test/php7_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -62,7 +62,7 @@ RUN cd /var/local/git/php-src \
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
index e884572640..ed59e56995 100644
--- a/tools/dockerfile/test/php_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
index c2b4c1845b..a4c3a9f91e 100644
--- a/tools/dockerfile/test/python_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile b/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile
new file mode 100644
index 0000000000..a7a8174db4
--- /dev/null
+++ b/tools/dockerfile/test/python_stretch_2.7_x64/Dockerfile
@@ -0,0 +1,69 @@
+# 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.
+
+FROM debian:stretch
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ dnsutils \
+ gcc \
+ gcc-multilib \
+ git \
+ golang \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libgtest-dev \
+ libtool \
+ make \
+ perl \
+ strace \
+ python-dev \
+ python-setuptools \
+ python-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client oauth2client
+
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
+
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
+
diff --git a/tools/dockerfile/test/python_pyenv_x64/Dockerfile b/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile
index c23e67c904..0e97e77e2f 100644
--- a/tools/dockerfile/test/python_pyenv_x64/Dockerfile
+++ b/tools/dockerfile/test/python_stretch_3.5_x64/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2016 gRPC authors.
+# 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.
@@ -13,7 +13,7 @@
# limitations under the License.
FROM debian:stretch
-
+
# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
@@ -51,53 +51,22 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
-
-#====================
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
- python-all-dev \
- python3-all-dev \
- python-pip
-
-# Install Python packages from PyPI
-RUN pip install --upgrade pip==10.0.1
-RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
+RUN pip install --upgrade google-api-python-client oauth2client
-# Install dependencies for pyenv
-RUN apt-get update && apt-get install -y \
- libbz2-dev \
- libncurses5-dev \
- libncursesw5-dev \
- libreadline-dev \
- libsqlite3-dev \
- libssl-dev \
- llvm \
- mercurial \
- zlib1g-dev && apt-get clean
-
-# Install Pyenv and dev Python versions 3.{5,6,7}
-RUN curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
-ENV PATH /root/.pyenv/bin:$PATH
-RUN eval "$(pyenv init -)"
-RUN eval "$(pyenv virtualenv-init -)"
-RUN pyenv update
-RUN pyenv install 3.5-dev
-RUN pyenv install 3.6-dev
-RUN pyenv install 3.7-dev
-RUN pyenv install pypy-5.3.1
-RUN pyenv local 3.5-dev 3.6-dev 3.7-dev pypy-5.3.1
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
-# Install pip and virtualenv for Python 3.5
-RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
-RUN python3.5 -m pip install virtualenv
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]
+
+
+RUN apt-get update && apt-get install -y python3.5 python3-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
diff --git a/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile b/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile
new file mode 100644
index 0000000000..9b16b2d3a1
--- /dev/null
+++ b/tools/dockerfile/test/python_stretch_3.6_x64/Dockerfile
@@ -0,0 +1,72 @@
+# 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.
+
+FROM debian:stretch
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ dnsutils \
+ gcc \
+ gcc-multilib \
+ git \
+ golang \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libgtest-dev \
+ libtool \
+ make \
+ perl \
+ strace \
+ python-dev \
+ python-setuptools \
+ python-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client oauth2client
+
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
+
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
+
+
+RUN apt-get update && apt-get -t testing install -y python3.6 python3-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.6
diff --git a/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile b/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
new file mode 100644
index 0000000000..add1cc509d
--- /dev/null
+++ b/tools/dockerfile/test/python_stretch_3.7_x64/Dockerfile
@@ -0,0 +1,72 @@
+# 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.
+
+FROM debian:stretch
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ autotools-dev \
+ build-essential \
+ bzip2 \
+ ccache \
+ curl \
+ dnsutils \
+ gcc \
+ gcc-multilib \
+ git \
+ golang \
+ gyp \
+ lcov \
+ libc6 \
+ libc6-dbg \
+ libc6-dev \
+ libgtest-dev \
+ libtool \
+ make \
+ perl \
+ strace \
+ python-dev \
+ python-setuptools \
+ python-yaml \
+ telnet \
+ unzip \
+ wget \
+ zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client oauth2client
+
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
+
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
+
+
+RUN apt-get update && apt-get -t testing install -y python3.7 python3-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
index d6f7459685..321b501de2 100644
--- a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index cb153012ea..e6bdb4ee03 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -51,7 +51,7 @@ RUN apt-get update && apt-get install -y time && apt-get clean
# Google Cloud platform API libraries
RUN apt-get update && apt-get install -y python-pip && apt-get clean
-RUN pip install --upgrade google-api-python-client
+RUN pip install --upgrade google-api-python-client oauth2client
#====================
# Python dependencies
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 688c271fea..392113c284 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.15.0-dev
+PROJECT_NUMBER = 1.17.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -764,7 +764,6 @@ INPUT = doc/PROTOCOL-HTTP2.md \
doc/PROTOCOL-WEB.md \
doc/binary-logging.md \
doc/c-style-guide.md \
-doc/combiner-explainer.md \
doc/command_line_tool.md \
doc/compression.md \
doc/compression_cookbook.md \
@@ -775,7 +774,6 @@ doc/cpp-style-guide.md \
doc/cpp/pending_api_cleanups.md \
doc/cpp/perf_notes.md \
doc/environment_variables.md \
-doc/epoll-polling-engine.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
@@ -945,8 +943,13 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/call_op_set.h \
+include/grpcpp/impl/codegen/call_op_set_interface.h \
+include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -956,6 +959,9 @@ include/grpcpp/impl/codegen/core_codegen.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/intercepted_channel.h \
+include/grpcpp/impl/codegen/interceptor.h \
+include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/proto_buffer_reader.h \
@@ -965,7 +971,9 @@ 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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -997,9 +1005,11 @@ include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+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 e6d4b1d98f..a96683883c 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.15.0-dev
+PROJECT_NUMBER = 1.17.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -764,7 +764,6 @@ INPUT = doc/PROTOCOL-HTTP2.md \
doc/PROTOCOL-WEB.md \
doc/binary-logging.md \
doc/c-style-guide.md \
-doc/combiner-explainer.md \
doc/command_line_tool.md \
doc/compression.md \
doc/compression_cookbook.md \
@@ -775,7 +774,6 @@ doc/cpp-style-guide.md \
doc/cpp/pending_api_cleanups.md \
doc/cpp/perf_notes.md \
doc/environment_variables.md \
-doc/epoll-polling-engine.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
@@ -946,8 +944,13 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/call_op_set.h \
+include/grpcpp/impl/codegen/call_op_set_interface.h \
+include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
@@ -958,6 +961,9 @@ include/grpcpp/impl/codegen/core_codegen.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
include/grpcpp/impl/codegen/create_auth_context.h \
include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/intercepted_channel.h \
+include/grpcpp/impl/codegen/interceptor.h \
+include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/proto_buffer_reader.h \
@@ -967,7 +973,9 @@ 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 \
include/grpcpp/impl/codegen/service_type.h \
include/grpcpp/impl/codegen/slice.h \
@@ -999,9 +1007,11 @@ include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+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 \
@@ -1009,6 +1019,8 @@ include/grpcpp/support/string_ref.h \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
+src/core/ext/filters/client_channel/health/health.pb.c \
+src/core/ext/filters/client_channel/health/health.pb.h \
src/core/ext/transport/inproc/inproc_transport.h \
src/core/lib/avl/avl.h \
src/core/lib/backoff/backoff.h \
@@ -1077,7 +1089,6 @@ src/core/lib/iomgr/error.h \
src/core/lib/iomgr/error_internal.h \
src/core/lib/iomgr/ev_epoll1_linux.h \
src/core/lib/iomgr/ev_epollex_linux.h \
-src/core/lib/iomgr/ev_epollsig_linux.h \
src/core/lib/iomgr/ev_poll_posix.h \
src/core/lib/iomgr/ev_posix.h \
src/core/lib/iomgr/exec_ctx.h \
@@ -1172,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 \
@@ -1206,8 +1219,6 @@ src/cpp/server/dynamic_thread_pool.cc \
src/cpp/server/dynamic_thread_pool.h \
src/cpp/server/health/default_health_check_service.cc \
src/cpp/server/health/default_health_check_service.h \
-src/cpp/server/health/health.pb.c \
-src/cpp/server/health/health.pb.h \
src/cpp/server/health/health_check_service.cc \
src/cpp/server/health/health_check_service_server_builder_option.cc \
src/cpp/server/insecure_server_credentials.cc \
@@ -1226,8 +1237,11 @@ src/cpp/util/status.cc \
src/cpp/util/string_ref.cc \
src/cpp/util/time_cc.cc \
third_party/nanopb/pb.h \
+third_party/nanopb/pb_common.c \
third_party/nanopb/pb_common.h \
+third_party/nanopb/pb_decode.c \
third_party/nanopb/pb_decode.h \
+third_party/nanopb/pb_encode.c \
third_party/nanopb/pb_encode.h
# This tag can be used to specify the character encoding of the source files
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index aa75bc6828..b78fb607ad 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 6.0.0-dev
+PROJECT_NUMBER = 7.0.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -764,20 +764,23 @@ INPUT = doc/PROTOCOL-HTTP2.md \
doc/PROTOCOL-WEB.md \
doc/binary-logging.md \
doc/c-style-guide.md \
-doc/combiner-explainer.md \
doc/command_line_tool.md \
doc/compression.md \
doc/compression_cookbook.md \
doc/connection-backoff-interop-test-description.md \
doc/connection-backoff.md \
doc/connectivity-semantics-and-api.md \
+doc/core/combiner-explainer.md \
+doc/core/epoll-polling-engine.md \
+doc/core/grpc-client-server-polling-engine-usage.md \
+doc/core/grpc-cq.md \
doc/core/grpc-error.md \
+doc/core/grpc-polling-engines.md \
doc/core/moving-to-c++.md \
doc/core/pending_api_cleanups.md \
doc/core/transport_explainer.md \
doc/cpp-style-guide.md \
doc/environment_variables.md \
-doc/epoll-polling-engine.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index bfdb356c76..881e4cec0b 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 6.0.0-dev
+PROJECT_NUMBER = 7.0.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -764,20 +764,23 @@ INPUT = doc/PROTOCOL-HTTP2.md \
doc/PROTOCOL-WEB.md \
doc/binary-logging.md \
doc/c-style-guide.md \
-doc/combiner-explainer.md \
doc/command_line_tool.md \
doc/compression.md \
doc/compression_cookbook.md \
doc/connection-backoff-interop-test-description.md \
doc/connection-backoff.md \
doc/connectivity-semantics-and-api.md \
+doc/core/combiner-explainer.md \
+doc/core/epoll-polling-engine.md \
+doc/core/grpc-client-server-polling-engine-usage.md \
+doc/core/grpc-cq.md \
doc/core/grpc-error.md \
+doc/core/grpc-polling-engines.md \
doc/core/moving-to-c++.md \
doc/core/pending_api_cleanups.md \
doc/core/transport_explainer.md \
doc/cpp-style-guide.md \
doc/environment_variables.md \
-doc/epoll-polling-engine.md \
doc/fail_fast.md \
doc/fork_support.md \
doc/g_stands_for.md \
@@ -882,6 +885,10 @@ src/core/ext/filters/client_channel/client_channel_factory.h \
src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/connector.cc \
src/core/ext/filters/client_channel/connector.h \
+src/core/ext/filters/client_channel/health/health.pb.c \
+src/core/ext/filters/client_channel/health/health.pb.h \
+src/core/ext/filters/client_channel/health/health_check_client.cc \
+src/core/ext/filters/client_channel/health/health_check_client.h \
src/core/ext/filters/client_channel/http_connect_handshaker.cc \
src/core/ext/filters/client_channel/http_connect_handshaker.h \
src/core/ext/filters/client_channel/http_proxy.cc \
@@ -907,6 +914,14 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balan
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/subchannel_list.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_factory.h \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
@@ -947,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 \
@@ -1181,8 +1194,6 @@ src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epoll1_linux.h \
src/core/lib/iomgr/ev_epollex_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.h \
-src/core/lib/iomgr/ev_epollsig_linux.cc \
-src/core/lib/iomgr/ev_epollsig_linux.h \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_poll_posix.h \
src/core/lib/iomgr/ev_posix.cc \
@@ -1362,16 +1373,22 @@ src/core/lib/security/credentials/plugin/plugin_credentials.cc \
src/core/lib/security/credentials/plugin/plugin_credentials.h \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/credentials/ssl/ssl_credentials.h \
-src/core/lib/security/security_connector/alts_security_connector.cc \
-src/core/lib/security/security_connector/alts_security_connector.h \
+src/core/lib/security/security_connector/alts/alts_security_connector.cc \
+src/core/lib/security/security_connector/alts/alts_security_connector.h \
+src/core/lib/security/security_connector/fake/fake_security_connector.cc \
+src/core/lib/security/security_connector/fake/fake_security_connector.h \
src/core/lib/security/security_connector/load_system_roots.h \
src/core/lib/security/security_connector/load_system_roots_fallback.cc \
src/core/lib/security/security_connector/load_system_roots_linux.cc \
src/core/lib/security/security_connector/load_system_roots_linux.h \
-src/core/lib/security/security_connector/local_security_connector.cc \
-src/core/lib/security/security_connector/local_security_connector.h \
+src/core/lib/security/security_connector/local/local_security_connector.cc \
+src/core/lib/security/security_connector/local/local_security_connector.h \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/security_connector/security_connector.h \
+src/core/lib/security/security_connector/ssl/ssl_security_connector.cc \
+src/core/lib/security/security_connector/ssl/ssl_security_connector.h \
+src/core/lib/security/security_connector/ssl_utils.cc \
+src/core/lib/security/security_connector/ssl_utils.h \
src/core/lib/security/transport/auth_filters.h \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/secure_endpoint.cc \
@@ -1461,6 +1478,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 \
@@ -1484,8 +1503,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 \
@@ -1510,8 +1529,6 @@ src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h \
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h \
-src/core/tsi/alts_transport_security.cc \
-src/core/tsi/alts_transport_security.h \
src/core/tsi/fake_transport_security.cc \
src/core/tsi/fake_transport_security.h \
src/core/tsi/grpc_shadow_boringssl.h \
diff --git a/tools/gce/create_interop_worker.sh b/tools/gce/create_interop_worker.sh
deleted file mode 100755
index 205c0bf8c5..0000000000
--- a/tools/gce/create_interop_worker.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-# Copyright 2015 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.
-
-# Creates an interop worker on GCE.
-# IMPORTANT: After this script finishes, there are still some manual
-# steps needed there are hard to automatize.
-# See go/grpc-jenkins-setup for followup instructions.
-
-set -ex
-
-cd "$(dirname "$0")"
-
-CLOUD_PROJECT=grpc-testing
-ZONE=us-east1-a # canary gateway is reachable from this zone
-
-INSTANCE_NAME="${1:-grpc-canary-interop2}"
-
-gcloud compute instances create "$INSTANCE_NAME" \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- --machine-type n1-standard-16 \
- --image ubuntu-15-10 \
- --boot-disk-size 1000 \
- --scopes https://www.googleapis.com/auth/xapi.zoo \
- --tags=allow-ssh
-
-echo 'Created GCE instance, waiting 60 seconds for it to come online.'
-sleep 60
-
-gcloud compute copy-files \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- jenkins_master.pub linux_worker_init.sh "${INSTANCE_NAME}":~
-
-gcloud compute ssh \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- "$INSTANCE_NAME" --command "./linux_worker_init.sh"
diff --git a/tools/gce/create_linux_kokoro_performance_worker.sh b/tools/gce/create_linux_kokoro_performance_worker.sh
index d08a1aa2c6..63d54a48bf 100755
--- a/tools/gce/create_linux_kokoro_performance_worker.sh
+++ b/tools/gce/create_linux_kokoro_performance_worker.sh
@@ -15,6 +15,13 @@
# Creates a performance worker on GCE to be used on Kokoro.
+# IMPORTANT: Instructions for updating
+# If the VM configuration / installed software is updated,
+# - all existing performance worker VMs need to be updated to reflect the changes
+# - a new GCE image named "grpc-performance-kokoro-v1" needs to be created,
+# incrementing the version number.
+# - kokoro jobs need to be reconfigured to use the new image version
+
set -ex
cd "$(dirname "$0")"
@@ -30,7 +37,7 @@ gcloud compute instances create "$INSTANCE_NAME" \
--zone "$ZONE" \
--machine-type $MACHINE_TYPE \
--image-project ubuntu-os-cloud \
- --image-family ubuntu-1710 \
+ --image-family ubuntu-1804-lts \
--boot-disk-size 300 \
--scopes https://www.googleapis.com/auth/bigquery \
--tags=allow-ssh
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
index a93d8c5e83..0f7939be4c 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright 2015 gRPC authors.
+# 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.
@@ -13,36 +13,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Creates a standard jenkins worker on GCE.
+# Creates a performance worker on GCE from an image that's used for kokoro
+# perf workers.
set -ex
cd "$(dirname "$0")"
CLOUD_PROJECT=grpc-testing
-ZONE=us-central1-a
+ZONE=us-central1-b # this zone allows 32core machines
+LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v2 # update if newer image exists
-INSTANCE_NAME="${1:-grpc-jenkins-worker1}"
+INSTANCE_NAME="${1:-grpc-kokoro-performance-server}"
+MACHINE_TYPE="${2:-n1-standard-32}"
gcloud compute instances create "$INSTANCE_NAME" \
--project="$CLOUD_PROJECT" \
--zone "$ZONE" \
- --machine-type n1-standard-16 \
- --image=ubuntu-1510 \
- --image-project=grpc-testing \
- --boot-disk-size 1000 \
+ --machine-type "$MACHINE_TYPE" \
+ --image-project "$CLOUD_PROJECT" \
+ --image "$LATEST_PERF_WORKER_IMAGE" \
+ --boot-disk-size 300 \
--scopes https://www.googleapis.com/auth/bigquery \
--tags=allow-ssh
-
-echo 'Created GCE instance, waiting 60 seconds for it to come online.'
-sleep 60
-
-gcloud compute copy-files \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- jenkins_master.pub linux_worker_init.sh "${INSTANCE_NAME}":~
-
-gcloud compute ssh \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- "$INSTANCE_NAME" --command "./linux_worker_init.sh"
diff --git a/tools/gce/create_linux_performance_worker.sh b/tools/gce/create_linux_performance_worker.sh
deleted file mode 100755
index e9033ec443..0000000000
--- a/tools/gce/create_linux_performance_worker.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-# Copyright 2015 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.
-
-# Creates a performance worker on GCE.
-# IMPORTANT: After creating the worker, one needs to manually add the pubkey
-# of jenkins@the-machine-where-jenkins-starts-perf-tests
-# to ~/.ssh/authorized_keys so that multi-machine scenarios can work.
-# See tools/run_tests/run_performance_tests.py for details.
-
-set -ex
-
-cd "$(dirname "$0")"
-
-CLOUD_PROJECT=grpc-testing
-ZONE=us-central1-b # this zone allows 32core machines
-
-INSTANCE_NAME="${1:-grpc-performance-server1}"
-MACHINE_TYPE=n1-standard-32
-
-gcloud compute instances create "$INSTANCE_NAME" \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- --machine-type $MACHINE_TYPE \
- --image-project ubuntu-os-cloud \
- --image-family ubuntu-1710 \
- --boot-disk-size 300 \
- --scopes https://www.googleapis.com/auth/bigquery \
- --tags=allow-ssh
-
-echo 'Created GCE instance, waiting 60 seconds for it to come online.'
-sleep 60
-
-gcloud compute copy-files \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- jenkins_master.pub linux_performance_worker_init.sh "jenkins@${INSTANCE_NAME}":~
-
-gcloud compute ssh \
- --project="$CLOUD_PROJECT" \
- --zone "$ZONE" \
- "jenkins@${INSTANCE_NAME}" --command "./linux_performance_worker_init.sh"
diff --git a/tools/gce/jenkins_master.pub b/tools/gce/jenkins_master.pub
deleted file mode 100644
index e9853224e1..0000000000
--- a/tools/gce/jenkins_master.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzj9l7Tp4yKnMV8sSMNvm5Q9v/F2F187xF93niJFY8lz6ig4bhusqvNbAxPoeypds9NYjLDK6kONN9teemgv2+IcmmlAI4wkCkkWcL/kzdNNH0h5J7+YbPiUGFAu0hZNHg5jzwrZ3VFKwv6d/7dUdPOYmPaOG1JOEcxXcBvm1hMIe474jpUTTiG4/gMDJ1GhMg5T3cuCm2l0gCiv7ybRAgwaZ2EKEEWLy9qAL/pnr3umBjQvzAUGcOgXJyG0mbr977YdJo9kb+EELRTVN2q8mKZJEZ1BJAylkaI9783K2+cGaM8hPtKFcX4ImEYEkWgfOyGNolGDquWtvusGGzQXwF jenkins@grpc-jenkins-master
diff --git a/tools/gce/kokoro_performance.pub b/tools/gce/kokoro_performance.pub
index 1154debe78..4eca916b8a 100644
--- a/tools/gce/kokoro_performance.pub
+++ b/tools/gce/kokoro_performance.pub
@@ -1 +1,4 @@
+# Enable Kokoro CI to SSH to the VM (Added by linux_kokoro_performance_worker_init.sh)
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDg7L/ZaEauETWrPklUTky3kvxqQfe2Ax/2CsSqhNIGNMnK/8d79CHlmY9+dE1FFQ/RzKNCaltgy7XcN/fCYiCZr5jm2ZtnLuGNOTzupMNhaYiPL419qmL+5rZXt4/dWTrsHbFRACxT8j51PcRMO5wgbL0Bg2XXimbx8kDFaurL2gqduQYqlu4lxWCaJqOL71WogcimeL63Nq/yeH5PJPWpqE4P9VUQSwAzBWFK/hLeds/AiP3MgVS65qHBnhq0JsHy8JQsqjZbG7Iidt/Ll0+gqzEbi62gDIcczG4KC0iOVzDDP/1BxDtt1lKeA23ll769Fcm3rJyoBMYxjvdw1TDx sabujp@trigger.mtv.corp.google.com
+# Enable kokoro multi-machine benchmark driver VM to SSH to the VM (Added by linux_kokoro_performance_worker_init.sh)
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKQ5UEX4AFefec9BKICupFS7x9Hoq4ZyLKy+QX0J31I49ew9mG2AJlr3sp8ql15eX+A2Ml9MKJkmgZGHpJtw+SfvmI94SmomSyiCLAK92sQ85NMzaRdo4b9e30E9nhXnAvAaemvIEQbgCMYFvzk0C8AtXj6+htCrN4jFaLqTCPISJhX3ETc4TgX1qaHQHyl31tdaXHYlITvBDsfokcGcZQnhmCUDtD8wyaSC8GFk9gZbXshkfaYCuuLPPA0vwWGBw+YPbonHsFCsOog1IYSzYPCkIjq8dt6evsusK6Kaoyw/Z+l2kYty2FKTj+wU3l06QMoxwcfNT4WxdhcnVbY71r kbuilder@kokoro-performance-driver
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
index 4a1e3e608b..b78695d802 100755
--- a/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -47,7 +47,6 @@ sudo apt-get install -y \
libtool \
make \
strace \
- pypy \
python-dev \
python-pip \
python-setuptools \
@@ -68,30 +67,34 @@ sudo apt-get install -y google-perftools libgoogle-perftools-dev
# netperf
sudo apt-get install -y netperf
+# required to run kokoro_log_reader.py
+sudo apt-get install -y python-psutil python3-psutil
+
+# gcloud tools, including gsutil
+sudo apt-get install -y google-cloud-sdk
+
# C++ dependencies
sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
# Python dependencies
sudo pip install --upgrade pip==10.0.1
sudo pip install tabulate
-sudo pip install google-api-python-client
+sudo pip install google-api-python-client oauth2client
sudo pip install virtualenv
-# Building gRPC Python depends on python3.4 being installed, but python3.4
-# is not available on Ubuntu 16.10, so install from source
-curl -O https://www.python.org/ftp/python/3.4.6/Python-3.4.6.tgz
-tar xzvf Python-3.4.6.tgz
-(
-cd Python-3.4.6 || exit
-./configure --enable-shared --prefix=/usr/local LDFLAGS="-Wl,--rpath=/usr/local/lib"
-sudo make altinstall
-)
-rm Python-3.4.6.tgz
-
+# pypy is used instead of python for postprocessing benchmark outputs
+# because some reports are huge and pypy is much faster.
+# TODO(jtattermusch): get rid of pypy once possible, it's hard to
+# keep track of all the installed variants of python.
+sudo apt-get install -y pypy pypy-dev
curl -O https://bootstrap.pypa.io/get-pip.py
sudo pypy get-pip.py
sudo pypy -m pip install tabulate
-sudo pip install google-api-python-client
+sudo pypy -m pip install google-api-python-client oauth2client
+# TODO(jtattermusch): for some reason, we need psutil installed
+# in pypy for kokoro_log_reader.py (strange, because the comand is
+# "python kokoro_log_reader.py" and pypy is not the system default)
+sudo pypy -m pip install psutil
# Node dependencies (nvm has to be installed under user kbuilder)
touch .profile
@@ -104,31 +107,31 @@ nvm install 4 && npm config set cache /tmp/npm-cache
nvm install 5 && npm config set cache /tmp/npm-cache
nvm alias default 4
+# C# dependencies
+sudo apt-get install -y cmake
+
# C# mono dependencies (http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives)
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
+echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
sudo apt-get update
-sudo apt-get install -y mono-devel nuget
+sudo apt-get install -y mono-devel
-# C# .NET Core dependencies (https://www.microsoft.com/net/core#ubuntu)
-sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ yakkety main" > /etc/apt/sources.list.d/dotnetdev.list'
-sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
+# C# .NET Core dependencies (https://www.microsoft.com/net/download)
+wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
+sudo dpkg -i packages-microsoft-prod.deb
+
+sudo apt-get install -y apt-transport-https
sudo apt-get update
-sudo apt-get install -y dotnet-dev-1.0.0-preview2.1-003155
-sudo apt-get install -y dotnet-dev-1.0.1
-
-# C# 1.0.4 SDK
-curl -O https://download.microsoft.com/download/2/4/A/24A06858-E8AC-469B-8AE6-D0CEC9BA982A/dotnet-ubuntu.16.04-x64.1.0.5.tar.gz
-sudo mkdir -p /opt/dotnet
-sudo tar zxf dotnet-ubuntu.16.04-x64.1.0.5.tar.gz -C /opt/dotnet
-sudo ln -s /opt/dotnet/dotnet /usr/local/bin
-
-# C# .NET dependencies
-wget http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-8ubuntu0.2_amd64.deb
-sudo dpkg -i libicu52_52.1-8ubuntu0.2_amd64.deb
-wget http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu55_55.1-7ubuntu0.3_amd64.deb
-sudo dpkg -i libicu55_55.1-7ubuntu0.3_amd64.deb
-sudo apt-get update && sudo apt-get install -y libicu55
+sudo apt-get install -y dotnet-sdk-2.1
+
+# Install .NET Core 1.0.5 Runtime (required to run netcoreapp1.0)
+wget -q https://download.microsoft.com/download/2/4/A/24A06858-E8AC-469B-8AE6-D0CEC9BA982A/dotnet-ubuntu.16.04-x64.1.0.5.tar.gz
+mkdir -p dotnet105_download
+tar zxf dotnet-ubuntu.16.04-x64.1.0.5.tar.gz -C dotnet105_download
+sudo cp -r dotnet105_download/shared/Microsoft.NETCore.App/1.0.5/ /usr/share/dotnet/shared/Microsoft.NETCore.App/
+# To prevent "Failed to initialize CoreCLR, HRESULT: 0x80131500" with .NET Core 1.0.5 runtime
+wget -q http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu55_55.1-7ubuntu0.4_amd64.deb
+sudo dpkg -i libicu55_55.1-7ubuntu0.4_amd64.deb
# Ruby dependencies
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
@@ -163,7 +166,7 @@ sudo mv composer.phar /usr/local/bin/composer
# Significant performance improvements with grpc-go have been observed after
# upgrading from go 1.5 to a later version, so a later go version is preferred.
# Following go install instructions from https://golang.org/doc/install
-GO_VERSION=1.8
+GO_VERSION=1.10
OS=linux
ARCH=amd64
curl -O https://storage.googleapis.com/golang/go${GO_VERSION}.${OS}-${ARCH}.tar.gz
@@ -190,11 +193,22 @@ git clone -v https://github.com/brendangregg/FlameGraph ~/FlameGraph
# Install scipy and numpy for benchmarking scripts
sudo apt-get install -y python-scipy python-numpy
+# Install docker
+curl -sSL https://get.docker.com/ | sh
+# Enable kbuilder to use docker without sudo:
+sudo usermod -aG docker kbuilder
+
# Add pubkey of Kokoro driver VM to allow SSH
# silence false-positive shellcheck warning ("< redirect does not affect sudo")
# shellcheck disable=SC2024
sudo tee --append ~kbuilder/.ssh/authorized_keys < kokoro_performance.pub
+# Kokoro requires /tmpfs/READY file to exist the directory and file itself should
+# be owned by kbuilder.
+sudo mkdir /tmpfs
+sudo chown kbuilder /tmpfs
+touch /tmpfs/READY
+
# Restart for VM to pick up kernel update
echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
sleep 10
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
deleted file mode 100755
index 7222cef9a2..0000000000
--- a/tools/gce/linux_performance_worker_init.sh
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/bin/bash
-# Copyright 2015 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.
-
-# Initializes a fresh GCE VM to become a jenkins linux performance worker.
-# You shouldn't run this script on your own,
-# use create_linux_performance_worker.sh instead.
-
-set -ex
-
-sudo apt-get update
-
-# Install Java 8 JDK (to build gRPC Java)
-sudo apt-get install -y openjdk-8-jdk
-sudo apt-get install -y unzip lsof
-
-sudo apt-get install -y \
- autoconf \
- autotools-dev \
- build-essential \
- bzip2 \
- ccache \
- curl \
- gcc \
- gcc-multilib \
- git \
- gyp \
- lcov \
- libc6 \
- libc6-dbg \
- libc6-dev \
- libcurl4-openssl-dev \
- libgtest-dev \
- libreadline-dev \
- libssl-dev \
- libtool \
- make \
- strace \
- pypy \
- python-dev \
- python-pip \
- python-setuptools \
- python-yaml \
- python3-dev \
- python3-pip \
- python3-setuptools \
- python3-yaml \
- telnet \
- unzip \
- wget \
- zip \
- zlib1g-dev
-
-# perftools
-sudo apt-get install -y google-perftools libgoogle-perftools-dev
-
-# netperf
-sudo apt-get install -y netperf
-
-# C++ dependencies
-sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
-
-# Python dependencies
-sudo pip install --upgrade pip==10.0.1
-sudo pip install tabulate
-sudo pip install google-api-python-client
-sudo pip install virtualenv
-
-# Building gRPC Python depends on python3.4 being installed, but python3.4
-# is not available on Ubuntu 16.10, so install from source
-curl -O https://www.python.org/ftp/python/3.4.6/Python-3.4.6.tgz
-tar xzvf Python-3.4.6.tgz
-(
-cd Python-3.4.6 || exit
-./configure --enable-shared --prefix=/usr/local LDFLAGS="-Wl,--rpath=/usr/local/lib"
-sudo make altinstall
-)
-rm Python-3.4.6.tgz
-
-curl -O https://bootstrap.pypa.io/get-pip.py
-sudo pypy get-pip.py
-sudo pypy -m pip install tabulate
-sudo pip install google-api-python-client
-
-# Node dependencies (nvm has to be installed under user jenkins)
-touch .profile
-curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-# silence shellcheck warning as it cannot follow the `source` path statically:
-# shellcheck disable=SC1090
-source ~/.nvm/nvm.sh
-nvm install 0.12 && npm config set cache /tmp/npm-cache
-nvm install 4 && npm config set cache /tmp/npm-cache
-nvm install 5 && npm config set cache /tmp/npm-cache
-nvm alias default 4
-
-# C# mono dependencies (http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives)
-sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
-sudo apt-get update
-sudo apt-get install -y mono-devel nuget
-
-# C# .NET Core dependencies (https://www.microsoft.com/net/core#ubuntu)
-sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ yakkety main" > /etc/apt/sources.list.d/dotnetdev.list'
-sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
-sudo apt-get update
-sudo apt-get install -y dotnet-dev-1.0.0-preview2.1-003155
-sudo apt-get install -y dotnet-dev-1.0.1
-
-# Ruby dependencies
-git clone https://github.com/rbenv/rbenv.git ~/.rbenv
-export PATH="$HOME/.rbenv/bin:$PATH"
-eval "$(rbenv init -)"
-
-git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
-export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
-
-rbenv install 2.4.0
-rbenv global 2.4.0
-ruby -v
-
-# Install bundler (prerequisite for gRPC Ruby)
-gem install bundler
-
-# PHP dependencies
-sudo apt-get install -y php php-dev phpunit php-pear unzip zlib1g-dev
-curl -sS https://getcomposer.org/installer | php
-sudo mv composer.phar /usr/local/bin/composer
-
-# Java dependencies - nothing as we already have Java JDK 8
-
-# Go dependencies
-# Currently, the golang package available via apt-get doesn't have the latest go.
-# Significant performance improvements with grpc-go have been observed after
-# upgrading from go 1.5 to a later version, so a later go version is preferred.
-# Following go install instructions from https://golang.org/doc/install
-GO_VERSION=1.8
-OS=linux
-ARCH=amd64
-curl -O https://storage.googleapis.com/golang/go${GO_VERSION}.${OS}-${ARCH}.tar.gz
-sudo tar -C /usr/local -xzf go$GO_VERSION.$OS-$ARCH.tar.gz
-# Put go on the PATH, keep the usual installation dir
-sudo ln -s /usr/local/go/bin/go /usr/bin/go
-rm go$GO_VERSION.$OS-$ARCH.tar.gz
-
-# Install perf, to profile benchmarks. (need to get the right linux-tools-<> for kernel version)
-sudo apt-get install -y linux-tools-common linux-tools-generic "linux-tools-$(uname -r)"
-# see http://unix.stackexchange.com/questions/14227/do-i-need-root-admin-permissions-to-run-userspace-perf-tool-perf-events-ar
-echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
-# see http://stackoverflow.com/questions/21284906/perf-couldnt-record-kernel-reference-relocation-symbol
-echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
-
-# qps workers under perf appear to need a lot of mmap pages under certain scenarios and perf args in
-# order to not lose perf events or time out
-echo 4096 | sudo tee /proc/sys/kernel/perf_event_mlock_kb
-
-# Fetch scripts to generate flame graphs from perf data collected
-# on benchmarks
-git clone -v https://github.com/brendangregg/FlameGraph ~/FlameGraph
-
-# Install scipy and numpy for benchmarking scripts
-sudo apt-get install -y python-scipy python-numpy
-
-# Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
-# This needs to happen as the last step to prevent Jenkins master from connecting
-# to a machine that hasn't been properly setup yet.
-# silence false-positive shellcheck warning ("< redirect does not affect sudo")
-# shellcheck disable=SC2024
-sudo tee --append ~jenkins/.ssh/authorized_keys < jenkins_master.pub
-
-# Restart for VM to pick up kernel update
-echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
-sleep 10
-sudo reboot
diff --git a/tools/gce/linux_worker_init.sh b/tools/gce/linux_worker_init.sh
deleted file mode 100755
index 05855354ff..0000000000
--- a/tools/gce/linux_worker_init.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/bash
-# Copyright 2015 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.
-
-# Initializes a fresh GCE VM to become a jenkins linux worker.
-# You shouldn't run this script on your own, use create_linux_worker.sh
-# instead.
-
-set -ex
-
-# Create some swap space
-sudo dd if=/dev/zero of=/swap bs=1024 count=10485760
-sudo chmod 600 /swap
-sudo mkswap /swap
-sudo sed -i '$ a\/swap none swap sw 0 0' /etc/fstab
-sudo swapon -a
-
-# Typical apt-get maintenance
-sudo apt-get update
-
-# Install JRE
-sudo apt-get install -y openjdk-8-jre
-sudo apt-get install -y unzip lsof
-
-# Install Docker
-curl -sSL https://get.docker.com/ | sh
-
-# Setup jenkins user (or the user will already exist bcuz magic)
-sudo adduser jenkins --disabled-password || true
-
-# Enable jenkins to use docker without sudo:
-sudo usermod -aG docker jenkins
-
-# Use "overlay" storage driver for docker
-# see https://github.com/grpc/grpc/issues/4988
-printf "{\n\t\"storage-driver\": \"overlay\"\n}" | sudo tee /etc/docker/daemon.json
-
-# Install pip and Google API library to enable using GCP services
-sudo apt-get install -y python-pip
-sudo pip install google-api-python-client
-
-# Install RVM
-# TODO(jtattermusch): why is RVM needed?
-gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-curl -sSL https://get.rvm.io | bash -s stable --ruby
-
-# Upgrade Linux kernel to 4.9
-wget \
- kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920_4.9.20-040920.201703310531_all.deb \
- kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-headers-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb \
- kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.20/linux-image-4.9.20-040920-generic_4.9.20-040920.201703310531_amd64.deb
-sudo dpkg -i linux-headers-4.9*.deb linux-image-4.9*.deb
-rm linux-*
-
-# Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
-# This needs to happen as the last step to prevent Jenkins master from connecting
-# to a machine that hasn't been properly setup yet.
-
-# disable superfluous warning by shellcheck:
-# shellcheck disable=SC2024
-sudo tee --append ~jenkins/.ssh/authorized_keys < jenkins_master.pub
-
-# Restart for docker to pick up the config changes.
-echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
-sleep 10
-
-sudo reboot
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/delete_nonartifacts.sh b/tools/internal_ci/helper_scripts/delete_nonartifacts.sh
index c7d6ba6d44..01e9427e1c 100755
--- a/tools/internal_ci/helper_scripts/delete_nonartifacts.sh
+++ b/tools/internal_ci/helper_scripts/delete_nonartifacts.sh
@@ -24,4 +24,4 @@ cd "$(dirname "$0")/../../.."
# after finishing each build. We only leave files we want to keep:
# - reports and artifacts
# - directory containing the kokoro scripts to prevent deleting a script while being executed.
-time find . -type f -not -iname "*sponge_log.xml" -not -path "./reports/*" -not -path "./artifacts/*" -not -path "./tools/internal_ci/*" -exec rm -f {} +
+time find . -type f -not -iname "*sponge_log.*" -not -path "./reports/*" -not -path "./artifacts/*" -not -path "./tools/internal_ci/*" -exec rm -f {} +
diff --git a/tools/internal_ci/helper_scripts/prepare_build_grpclb_interop_rc b/tools/internal_ci/helper_scripts/prepare_build_grpclb_interop_rc
new file mode 100644
index 0000000000..a8e350be58
--- /dev/null
+++ b/tools/internal_ci/helper_scripts/prepare_build_grpclb_interop_rc
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2017 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.
+
+# Source this rc script to prepare the environment for interop builds
+# This rc script must be used in the root directory of gRPC
+
+export LANG=en_US.UTF-8
+
+# Download Docker images from DockerHub
+export DOCKERHUB_ORGANIZATION=grpctesting
+
+git submodule update --init
+
+# Set up gRPC-Go and gRPC-Java to test
+git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
+git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
+
+# TODO(apolcyn): move to kokoro image?
+virtualenv env
+source env/bin/activate
+pip install twisted
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index 3212e80854..24a3545ded 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -15,14 +15,8 @@
# Source this rc script to prepare the environment for macos builds
-sudo launchctl limit maxfiles unlimited unlimited
-
-# show current maxfiles
+# show original open file limit values
launchctl limit maxfiles
-
-ulimit -n 10000
-
-# show current limits
ulimit -a
# synchronize the clock
@@ -57,25 +51,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,11 +82,12 @@ 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
ln -s /tmpfs/Build-ios-binary-size src/objective-c/examples/Sample/Build
-mkdir /tmpfs/DerivedData
+mkdir -p /tmpfs/DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData
+mkdir -p ~/Library/Developer/Xcode
ln -s /tmpfs/DerivedData ~/Library/Developer/Xcode/DerivedData
diff --git a/tools/internal_ci/linux/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
index a6367ad962..87ec60c7c0 100644..100755
--- a/tools/internal_ci/linux/grpc_asan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
@@ -13,7 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=address --linkopt=-fsanitize=address --test_timeout=3600 --cache_test_results=no"
-github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg b/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg
index 4a0badf43b..07f7f0c659 100644
--- a/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg
+++ b/tools/internal_ci/linux/grpc_basictests_c_cpp_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg b/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg
index a2cfe021e1..8f2813febf 100644
--- a/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg
+++ b/tools/internal_ci/linux/grpc_basictests_c_cpp_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_basictests_multilang.cfg b/tools/internal_ci/linux/grpc_basictests_multilang.cfg
index 4433d14cd7..f8a5a4aea5 100644
--- a/tools/internal_ci/linux/grpc_basictests_multilang.cfg
+++ b/tools/internal_ci/linux/grpc_basictests_multilang.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
index 8f9658f78a..74778d9d29 100755
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
@@ -21,42 +21,29 @@ set -ex
mkdir -p ${KOKORO_KEYSTORE_DIR}
cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5"
+# Download bazel
+temp_dir="$(mktemp -d)"
+wget -q https://github.com/bazelbuild/bazel/releases/download/0.17.1/bazel-0.17.1-linux-x86_64 -O "${temp_dir}/bazel"
+chmod 755 "${temp_dir}/bazel"
export PATH="${temp_dir}:${PATH}"
# This should show ${temp_dir}/bazel
which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
# change to grpc repo root
cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-# TODO(adelez): implement size for test targets and change test_timeout back
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
- --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
- test --jobs="200" \
- --test_output=errors \
- --verbose_failures=true \
- --keep_going \
- --remote_accept_cached=true \
- --spawn_strategy=remote \
- --remote_local_fallback=false \
- --remote_timeout=3600 \
- --strategy=Javac=remote \
- --strategy=Closure=remote \
- --genrule_strategy=remote \
- --experimental_strict_action_env=true \
- --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/default:toolchain \
- --define GRPC_PORT_ISOLATED_RUNTIME=1 \
- --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
- --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/cpp:cc-toolchain-clang-x86_64-default \
- --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --host_platform=//third_party/toolchains:rbe_ubuntu1604 \
- --platforms=//third_party/toolchains:rbe_ubuntu1604 \
- $1 \
+# to get "bazel" link for kokoro build, we need to generate
+# invocation UUID, set an env var for bazel to pick it up
+# and upload "bazel_invocation_ids" file as artifact.
+export BAZEL_INTERNAL_INVOCATION_ID="$(uuidgen)"
+echo "${BAZEL_INTERNAL_INVOCATION_ID}" >"${KOKORO_ARTIFACTS_DIR}/bazel_invocation_ids"
+
+bazel \
+ --bazelrc=tools/remote_build/kokoro.bazelrc \
+ test \
+ $@ \
-- //test/... || FAILED="true"
if [ "$UPLOAD_TEST_RESULTS" != "" ]
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
index 51cb66f5b8..fdd5b2e4cd 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600 --cache_test_results=no"
+EXTRA_FLAGS="--config=dbg --test_timeout=300,450,1200,3600 --cache_test_results=no"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
index cbba9067ad..30b2b17a67 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600 --cache_test_results=no"
+EXTRA_FLAGS="--config=opt --test_timeout=300,450,1200,3600 --cache_test_results=no"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_build_artifacts.cfg b/tools/internal_ci/linux/grpc_build_artifacts.cfg
index 88fc6b7b35..1e04a1e788 100644
--- a/tools/internal_ci/linux/grpc_build_artifacts.cfg
+++ b/tools/internal_ci/linux/grpc_build_artifacts.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg b/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg
index 619e3ea3a9..2737e2f345 100644
--- a/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg
+++ b/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts_extra.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_build_artifacts_extra_release.cfg b/tools/internal_ci/linux/grpc_build_artifacts_extra_release.cfg
index 619e3ea3a9..2737e2f345 100644
--- a/tools/internal_ci/linux/grpc_build_artifacts_extra_release.cfg
+++ b/tools/internal_ci/linux/grpc_build_artifacts_extra_release.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts_extra.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg b/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
index 11c211fd2b..9a430db0f9 100644
--- a/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
+++ b/tools/internal_ci/linux/grpc_build_boringssl_at_head.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh"
timeout_mins: 180
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_build_packages.cfg b/tools/internal_ci/linux/grpc_build_packages.cfg
index 6a4a163dfc..23a676cf72 100644
--- a/tools/internal_ci/linux/grpc_build_packages.cfg
+++ b/tools/internal_ci/linux/grpc_build_packages.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_packages.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg b/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
index 2f08e15e63..aef6a7a1dc 100644
--- a/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
+++ b/tools/internal_ci/linux/grpc_build_protobuf_at_head.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_build_submodule_at_head.sh"
timeout_mins: 180
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_coverage.cfg b/tools/internal_ci/linux/grpc_coverage.cfg
index 794a51d3f1..6eb37b7dec 100644
--- a/tools/internal_ci/linux/grpc_coverage.cfg
+++ b/tools/internal_ci/linux/grpc_coverage.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_coverage.sh"
timeout_mins: 420
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_distribtests.cfg b/tools/internal_ci/linux/grpc_distribtests.cfg
index 0f1d79355a..848d571333 100644
--- a/tools/internal_ci/linux/grpc_distribtests.cfg
+++ b/tools/internal_ci/linux/grpc_distribtests.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_distribtests.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_distribtests_standalone.cfg b/tools/internal_ci/linux/grpc_distribtests_standalone.cfg
index bc6c8e8f80..734bdfd78a 100644
--- a/tools/internal_ci/linux/grpc_distribtests_standalone.cfg
+++ b/tools/internal_ci/linux/grpc_distribtests_standalone.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_distribtests_standalone.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.cfg b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.cfg
new file mode 100644
index 0000000000..c27baad3d7
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.cfg
@@ -0,0 +1,25 @@
+# Copyright 2017 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh"
+timeout_mins: 360
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "**/perf_reports/**"
+ }
+}
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
new file mode 100755
index 0000000000..21f9d48ac4
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright 2017 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.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
+
+# "smoketest" scenarios on a single VM (=no remote VM for running qps_workers)
+tools/run_tests/run_performance_tests.py \
+ -l c++ csharp ruby java python go php7 php7_protobuf_c node \
+ --netperf \
+ --category smoketest \
+ -u kbuilder \
+ --bq_result_table performance_test.performance_experiment_singlevm \
+ --xml_report reports/singlemachine/sponge_log.xml
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.cfg b/tools/internal_ci/linux/grpc_full_performance_master.cfg
index 8852130a13..8ad93ee052 100644
--- a/tools/internal_ci/linux/grpc_full_performance_master.cfg
+++ b/tools/internal_ci/linux/grpc_full_performance_master.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_full_performance_master.sh"
timeout_mins: 600
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "**/perf_reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.sh b/tools/internal_ci/linux/grpc_full_performance_master.sh
index 24ee71edd1..05a014b88a 100755
--- a/tools/internal_ci/linux/grpc_full_performance_master.sh
+++ b/tools/internal_ci/linux/grpc_full_performance_master.sh
@@ -21,7 +21,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
# run 8core client vs 8core server
tools/run_tests/run_performance_tests.py \
- -l c++ csharp ruby java python go php7 php7_protobuf_c node node_purejs \
+ -l c++ csharp ruby java python go php7 php7_protobuf_c node \
--netperf \
--category scalable \
--remote_worker_host grpc-kokoro-performance-server-8core grpc-kokoro-performance-client-8core grpc-kokoro-performance-client2-8core \
diff --git a/tools/internal_ci/linux/grpc_full_performance_release.cfg b/tools/internal_ci/linux/grpc_full_performance_release.cfg
index e9a4bcdcaf..11a95e889f 100644
--- a/tools/internal_ci/linux/grpc_full_performance_release.cfg
+++ b/tools/internal_ci/linux/grpc_full_performance_release.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_full_performance_release.sh"
timeout_mins: 600
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "**/perf_reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_interop_alts.cfg b/tools/internal_ci/linux/grpc_interop_alts.cfg
index bda76faf44..4684aba96b 100644
--- a/tools/internal_ci/linux/grpc_interop_alts.cfg
+++ b/tools/internal_ci/linux/grpc_interop_alts.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_interop_matrix.cfg b/tools/internal_ci/linux/grpc_interop_matrix.cfg
index ae59e930f7..e13c26e8ba 100644
--- a/tools/internal_ci/linux/grpc_interop_matrix.cfg
+++ b/tools/internal_ci/linux/grpc_interop_matrix.cfg
@@ -16,11 +16,15 @@
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/linux/grpc_interop_matrix.sh"
-# grpc_interop tests can take 1 hours to complete.
timeout_mins: 300
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "--language=all --release=all --allow_flakes --report_file=sponge_log.xml --bq_result_table interop_results"
+}
diff --git a/tools/internal_ci/linux/grpc_interop_matrix.sh b/tools/internal_ci/linux/grpc_interop_matrix.sh
index 4c24c43488..a5220ea087 100755
--- a/tools/internal_ci/linux/grpc_interop_matrix.sh
+++ b/tools/internal_ci/linux/grpc_interop_matrix.sh
@@ -22,4 +22,4 @@ cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-tools/interop_matrix/run_interop_matrix_tests.py --language=all --release=all --allow_flakes --report_file=sponge_log.xml --bq_result_table interop_results $@
+tools/interop_matrix/run_interop_matrix_tests.py $RUN_TESTS_FLAGS
diff --git a/tools/internal_ci/linux/grpc_interop_tocloud.cfg b/tools/internal_ci/linux/grpc_interop_tocloud.cfg
index 81f2fe9dec..9b35adcece 100644
--- a/tools/internal_ci/linux/grpc_interop_tocloud.cfg
+++ b/tools/internal_ci/linux/grpc_interop_tocloud.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_interop_toprod.cfg b/tools/internal_ci/linux/grpc_interop_toprod.cfg
index 8dfc529947..de4db81e6b 100644
--- a/tools/internal_ci/linux/grpc_interop_toprod.cfg
+++ b/tools/internal_ci/linux/grpc_interop_toprod.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
index aa1e613d78..c7e4b1fa1a 100644
--- a/tools/internal_ci/linux/grpc_msan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
@@ -15,63 +15,5 @@
set -ex
-# A temporary solution to give Kokoro credentials.
-# The file name 4321_grpc-testing-service needs to match auth_credential in
-# the build config.
-# TODO: Use keystore.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5"
-export PATH="${temp_dir}:${PATH}"
-# This should show ${temp_dir}/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
- --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
- test --jobs="200" \
- --test_timeout="3600,3600,3600,3600" \
- --test_output=errors \
- --verbose_failures=true \
- --keep_going \
- --remote_accept_cached=true \
- --spawn_strategy=remote \
- --remote_local_fallback=false \
- --remote_timeout=3600 \
- --strategy=Javac=remote \
- --strategy=Closure=remote \
- --genrule_strategy=remote \
- --experimental_strict_action_env=true \
- --define GRPC_PORT_ISOLATED_RUNTIME=1 \
- --copt=-gmlt \
- --strip=never \
- --cxxopt=--stdlib=libc++ \
- --copt=-fsanitize=memory \
- --linkopt=-fsanitize=memory \
- --copt=-fsanitize-memory-track-origins \
- --action_env=LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH \
- --host_crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/default:toolchain \
- --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/msan:toolchain \
- --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
- --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/cpp:cc-toolchain-clang-x86_64-default \
- --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --host_platform=//third_party/toolchains:rbe_ubuntu1604 \
- --platforms=//third_party/toolchains:rbe_ubuntu1604 \
- -- //test/... || FAILED="true"
-
-# Sleep to let ResultStore finish writing results before querying
-sleep 60
-python ./tools/run_tests/python_utils/upload_rbe_results.py
-
-if [ "$FAILED" != "" ]
-then
- exit 1
-fi
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_performance_profile_daily.sh b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
index 34d41bc04c..0e08699923 100755
--- a/tools/internal_ci/linux/grpc_performance_profile_daily.sh
+++ b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
@@ -24,8 +24,8 @@ CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
./tools/run_tests/start_port_server.py || true
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
-bins/opt/memory_profile_test
+make CONFIG=opt memory_usage_test memory_usage_client memory_usage_server -j $CPUS
+bins/opt/memory_usage_test
bq load microbenchmarks.memory memory_usage.csv
tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload || FAILED="true"
diff --git a/tools/internal_ci/linux/grpc_portability.cfg b/tools/internal_ci/linux/grpc_portability.cfg
index 76e5028477..f417f24bb1 100644
--- a/tools/internal_ci/linux/grpc_portability.cfg
+++ b/tools/internal_ci/linux/grpc_portability.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_portability_build_only.cfg b/tools/internal_ci/linux/grpc_portability_build_only.cfg
index 4acd9353fb..fab9dde3e5 100644
--- a/tools/internal_ci/linux/grpc_portability_build_only.cfg
+++ b/tools/internal_ci/linux/grpc_portability_build_only.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 180
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_publish_packages.cfg b/tools/internal_ci/linux/grpc_publish_packages.cfg
index 82d571d642..dc9fe7d0a7 100644
--- a/tools/internal_ci/linux/grpc_publish_packages.cfg
+++ b/tools/internal_ci/linux/grpc_publish_packages.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_publish_packages.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/linux/grpc_pull_request_sanity.cfg b/tools/internal_ci/linux/grpc_pull_request_sanity.cfg
index b20d2ffba8..704d5c6cbc 100644
--- a/tools/internal_ci/linux/grpc_pull_request_sanity.cfg
+++ b/tools/internal_ci/linux/grpc_pull_request_sanity.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 30
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
index 4f98d0a93a..156d65955a 100755
--- a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
+++ b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh
@@ -24,4 +24,4 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
${name}')
cd /var/local/git/grpc/test
-bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/...
+bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/...
diff --git a/tools/internal_ci/linux/grpc_run_grpclb_interop_tests.sh b/tools/internal_ci/linux/grpc_run_grpclb_interop_tests.sh
new file mode 100755
index 0000000000..806b5c947e
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_run_grpclb_interop_tests.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Copyright 2017 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.
+
+set -ex
+
+export LANG=en_US.UTF-8
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+source tools/internal_ci/helper_scripts/prepare_build_grpclb_interop_rc
+
+tools/run_tests/run_grpclb_interop_tests.py -l all --scenarios_file=tools/run_tests/generated/lb_interop_test_scenarios.json
diff --git a/tools/internal_ci/linux/grpc_sanity.cfg b/tools/internal_ci/linux/grpc_sanity.cfg
index 9f65918e23..341471bbb5 100644
--- a/tools/internal_ci/linux/grpc_sanity.cfg
+++ b/tools/internal_ci/linux/grpc_sanity.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 40
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
index 2ba7d469ec..fcf3095d48 100644
--- a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+set -ex
+
export UPLOAD_TEST_RESULTS=true
-EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=thread --linkopt=-fsanitize=thread --test_timeout=3600 --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1 --cache_test_results=no"
-github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
index 338b1b6a0d..f45be4d1c9 100644
--- a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
@@ -15,60 +15,5 @@
set -ex
-# A temporary solution to give Kokoro credentials.
-# The file name 4321_grpc-testing-service needs to match auth_credential in
-# the build config.
-# TODO: Use keystore.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5"
-export PATH="${temp_dir}:${PATH}"
-# This should show ${temp_dir}/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
- --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
- test --jobs="200" \
- --test_timeout="3600,3600,3600,3600" \
- --test_output=errors \
- --verbose_failures=true \
- --keep_going \
- --remote_accept_cached=true \
- --spawn_strategy=remote \
- --remote_local_fallback=false \
- --remote_timeout=3600 \
- --strategy=Javac=remote \
- --strategy=Closure=remote \
- --genrule_strategy=remote \
- --experimental_strict_action_env=true \
- --define GRPC_PORT_ISOLATED_RUNTIME=1 \
- --copt=-gmlt \
- --strip=never \
- --copt=-fsanitize=undefined \
- --linkopt=-fsanitize=undefined \
- --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.0/bazel_0.13.0/ubsan:toolchain \
- --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
- --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/cpp:cc-toolchain-clang-x86_64-default \
- --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --host_platform=//third_party/toolchains:rbe_ubuntu1604 \
- --platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --cache_test_results=no \
- -- //test/... || FAILED="true"
-
-# Sleep to let ResultStore finish writing results before querying
-sleep 60
-python ./tools/run_tests/python_utils/upload_rbe_results.py
-
-if [ "$FAILED" != "" ]
-then
- exit 1
-fi
+export UPLOAD_TEST_RESULTS=true
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan --cache_test_results=no
diff --git a/tools/internal_ci/linux/grpclb_in_dns_interop.cfg b/tools/internal_ci/linux/grpclb_in_dns_interop.cfg
new file mode 100644
index 0000000000..6cd5f2e21a
--- /dev/null
+++ b/tools/internal_ci/linux/grpclb_in_dns_interop.cfg
@@ -0,0 +1,25 @@
+# Copyright 2017 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_run_grpclb_interop_tests.sh"
+timeout_mins: 60
+action {
+ define_artifacts {
+ regex: "**/sponge_log.xml"
+ regex: "github/grpc/reports/**"
+ }
+}
diff --git a/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
index 2aebb65552..00f92921de 100644
--- a/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh
@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=address --linkopt=-fsanitize=address --test_timeout=3600"
-github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=asan
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg
index 8124f5c1b3..8a67d28ce4 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg
index ecedc73e44..a681978b6e 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_dbg.cfg
index 577cb28ae5..249ecc99ce 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_dbg.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_opt.cfg
index 9e0b724b2e..665d7f3d2c 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_opt.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_dbg.cfg
index 0fda74cf44..163274d4dc 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_dbg.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_opt.cfg
index 199a8905d9..b65cd3e05c 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_opt.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_cpp_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg
index f7e8d8ad33..59f38f0d1b 100644
--- a/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_basictests_multilang.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
index 8e2aaebaee..f1e6588517 100644
--- a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600"
+set -ex
+
+EXTRA_FLAGS="--config=dbg --test_timeout=300,450,1200,3600"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
index ded0d368a5..77744de49f 100644
--- a/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh
@@ -13,5 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600"
+set -ex
+
+EXTRA_FLAGS="--config=opt --test_timeout=300,450,1200,3600"
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/pull_request/grpc_interop_alts.cfg b/tools/internal_ci/linux/pull_request/grpc_interop_alts.cfg
index c1253b30f7..e91a612878 100644
--- a/tools/internal_ci/linux/pull_request/grpc_interop_alts.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_interop_alts.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_interop_matrix_adhoc.cfg b/tools/internal_ci/linux/pull_request/grpc_interop_matrix_adhoc.cfg
new file mode 100644
index 0000000000..6726384f18
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_interop_matrix_adhoc.cfg
@@ -0,0 +1,30 @@
+# Copyright 2017 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_interop_matrix.sh"
+timeout_mins: 300
+action {
+ define_artifacts {
+ regex: "**/sponge_log.xml"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "--language=all --release=all --allow_flakes --report_file=sponge_log.xml"
+}
diff --git a/tools/internal_ci/linux/pull_request/grpc_interop_tocloud.cfg b/tools/internal_ci/linux/pull_request/grpc_interop_tocloud.cfg
index cb18e8e868..b1eb575605 100644
--- a/tools/internal_ci/linux/pull_request/grpc_interop_tocloud.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_interop_tocloud.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg b/tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg
index d14c79a1f6..7321effc12 100644
--- a/tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_interop_toprod.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_interop_tests.sh"
timeout_mins: 60
action {
define_artifacts {
- regex: "**/sponge_log.xml"
+ regex: "**/sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_microbenchmark_diff.cfg b/tools/internal_ci/linux/pull_request/grpc_microbenchmark_diff.cfg
index 9269c345f0..47301d6141 100644
--- a/tools/internal_ci/linux/pull_request/grpc_microbenchmark_diff.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_microbenchmark_diff.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_microbenchmark_diff.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
new file mode 100644
index 0000000000..c85a837a44
--- /dev/null
+++ b/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# 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.
+
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=msan
diff --git a/tools/internal_ci/linux/pull_request/grpc_sanity.cfg b/tools/internal_ci/linux/pull_request/grpc_sanity.cfg
index 0f83299aab..276c34f0cf 100644
--- a/tools/internal_ci/linux/pull_request/grpc_sanity.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_sanity.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 40
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_trickle_diff.cfg b/tools/internal_ci/linux/pull_request/grpc_trickle_diff.cfg
index e86b3ab475..78358eac28 100644
--- a/tools/internal_ci/linux/pull_request/grpc_trickle_diff.cfg
+++ b/tools/internal_ci/linux/pull_request/grpc_trickle_diff.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_trickle_diff.sh"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
index edd8f92975..f3e98e63da 100644
--- a/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh
@@ -13,5 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=thread --linkopt=-fsanitize=thread --test_timeout=3600 --action_env=TSAN_OPTIONS=suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
-github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
+set -ex
+
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=tsan
diff --git a/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
index c7ab5b104a..b94935eab1 100644
--- a/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
+++ b/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh
@@ -15,55 +15,4 @@
set -ex
-# A temporary solution to give Kokoro credentials.
-# The file name 4321_grpc-testing-service needs to match auth_credential in
-# the build config.
-# TODO: Use keystore.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-temp_dir=$(mktemp -d)
-ln -f "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" ${temp_dir}/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5"
-export PATH="${temp_dir}:${PATH}"
-# This should show ${temp_dir}/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
- --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
- test --jobs="200" \
- --test_timeout="3600,3600,3600,3600" \
- --test_output=errors \
- --verbose_failures=true \
- --keep_going \
- --remote_accept_cached=true \
- --spawn_strategy=remote \
- --remote_local_fallback=false \
- --remote_timeout=3600 \
- --strategy=Javac=remote \
- --strategy=Closure=remote \
- --genrule_strategy=remote \
- --experimental_strict_action_env=true \
- --define GRPC_PORT_ISOLATED_RUNTIME=1 \
- --copt=-gmlt \
- --strip=never \
- --copt=-fsanitize=undefined \
- --linkopt=-fsanitize=undefined \
- --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.0/bazel_0.13.0/ubsan:toolchain \
- --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \
- --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/cpp:cc-toolchain-clang-x86_64-default \
- --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604 \
- --host_platform=//third_party/toolchains:rbe_ubuntu1604 \
- --platforms=//third_party/toolchains:rbe_ubuntu1604 \
- -- //test/... || FAILED="true"
-
-if [ "$FAILED" != "" ]
-then
- exit 1
-fi
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh --config=ubsan
diff --git a/tools/internal_ci/linux/run_performance_profile_hourly.sh b/tools/internal_ci/linux/run_performance_profile_hourly.sh
index edf85c2e2c..2be9edf756 100755
--- a/tools/internal_ci/linux/run_performance_profile_hourly.sh
+++ b/tools/internal_ci/linux/run_performance_profile_hourly.sh
@@ -21,8 +21,8 @@ cd $(dirname $0)/../../..
CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
-bins/opt/memory_profile_test
+make CONFIG=opt memory_usage_test memory_usage_client memory_usage_server -j $CPUS
+bins/opt/memory_usage_test
bq load microbenchmarks.memory memory_usage.csv
tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload
diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
index 06a4372ce2..d6d70677dd 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_asan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
index f875327c1b..7b22c6afef 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_msan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
index 6658a804d8..6c9dd6ef8d 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_tsan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg
index 957a91ef2b..8700c74c8d 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_c_ubsan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
index dbbfce90cb..02162d860b 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_asan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
index fb0cefa160..95582184ed 100644
--- a/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/grpc_cpp_tsan.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg
index 1daf7a514e..d444596a81 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_asan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg
index a8503b7bcb..3891cc37e8 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_msan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg
index 12af4581eb..91ce1627af 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_tsan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg
index 0d3803bf23..fcdc2de37b 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_c_ubsan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg
index 557561810b..de2a74051b 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_asan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg
index cb15ca34fd..51c291f7df 100644
--- a/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg
+++ b/tools/internal_ci/linux/sanitizer/pull_request/grpc_cpp_tsan.cfg
@@ -20,7 +20,7 @@ build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh"
timeout_mins: 1440
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/macos/grpc_basictests_dbg.cfg b/tools/internal_ci/macos/grpc_basictests_dbg.cfg
index 53bda1ff0a..1c7ed26d64 100644
--- a/tools/internal_ci/macos/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/macos/grpc_basictests_dbg.cfg
@@ -20,12 +20,12 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
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_objc_dbg.cfg b/tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg
new file mode 100644
index 0000000000..068961234b
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_objc_dbg.cfg
@@ -0,0 +1,31 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc dbg --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results"
+}
diff --git a/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg b/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg
new file mode 100644
index 0000000000..927fa50deb
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_basictests_objc_opt.cfg
@@ -0,0 +1,31 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc opt --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 d359eb601a..f46ebaa786 100644
--- a/tools/internal_ci/macos/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/macos/grpc_basictests_opt.cfg
@@ -20,12 +20,12 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
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/grpc_build_artifacts.cfg b/tools/internal_ci/macos/grpc_build_artifacts.cfg
index 4da61faed3..c73cf4359f 100644
--- a/tools/internal_ci/macos/grpc_build_artifacts.cfg
+++ b/tools/internal_ci/macos/grpc_build_artifacts.cfg
@@ -20,7 +20,7 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/macos/grpc_distribtests.cfg b/tools/internal_ci/macos/grpc_distribtests.cfg
index ae88f39b90..156ec6fe33 100644
--- a/tools/internal_ci/macos/grpc_distribtests.cfg
+++ b/tools/internal_ci/macos/grpc_distribtests.cfg
@@ -20,7 +20,7 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/macos/grpc_interop.cfg b/tools/internal_ci/macos/grpc_interop.cfg
index b4b1b15cb4..434ecd19c4 100644
--- a/tools/internal_ci/macos/grpc_interop.cfg
+++ b/tools/internal_ci/macos/grpc_interop.cfg
@@ -20,7 +20,7 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/macos/grpc_interop_toprod.cfg b/tools/internal_ci/macos/grpc_interop_toprod.cfg
index c92c397daa..2cfc8a2d6d 100644
--- a/tools/internal_ci/macos/grpc_interop_toprod.cfg
+++ b/tools/internal_ci/macos/grpc_interop_toprod.cfg
@@ -21,7 +21,7 @@ gfile_resources: "/bigstore/grpc-testing-secrets/interop/service_account/GrpcTes
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
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 30c01d3e2f..c91c033916 100644
--- a/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_dbg.cfg
@@ -20,12 +20,12 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
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_objc_dbg.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg
new file mode 100644
index 0000000000..775fd355a5
--- /dev/null
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_dbg.cfg
@@ -0,0 +1,31 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc dbg --internal_ci -j 1 --inner_jobs 4 --max_time=3600"
+}
diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg
new file mode 100644
index 0000000000..652ef1bb77
--- /dev/null
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_objc_opt.cfg
@@ -0,0 +1,31 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+ define_artifacts {
+ regex: "**/*sponge_log.*"
+ regex: "github/grpc/reports/**"
+ }
+}
+
+env_vars {
+ key: "RUN_TESTS_FLAGS"
+ value: "-f basictests macos objc opt --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 b63ee713bc..532234fa84 100644
--- a/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_basictests_opt.cfg
@@ -20,12 +20,12 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
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/internal_ci/macos/pull_request/grpc_interop.cfg b/tools/internal_ci/macos/pull_request/grpc_interop.cfg
index b4b1b15cb4..434ecd19c4 100644
--- a/tools/internal_ci/macos/pull_request/grpc_interop.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_interop.cfg
@@ -20,7 +20,7 @@ gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0e
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg b/tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg
index 8942bc7ba7..fb215bdf99 100644
--- a/tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg
+++ b/tools/internal_ci/macos/pull_request/grpc_ios_binary_size.cfg
@@ -20,7 +20,7 @@ timeout_mins: 60
gfile_resources: "/bigstore/grpc-testing-secrets/github_credentials/oauth_token.txt"
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/grpc_basictests.cfg b/tools/internal_ci/windows/grpc_basictests.cfg
index 8e644e4c5e..fcf5237bf3 100644
--- a/tools/internal_ci/windows/grpc_basictests.cfg
+++ b/tools/internal_ci/windows/grpc_basictests.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/grpc_basictests_dbg.cfg b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
index 28d53cdc7b..4e5e7b6545 100644
--- a/tools/internal_ci/windows/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/grpc_basictests_opt.cfg b/tools/internal_ci/windows/grpc_basictests_opt.cfg
index 4b7a965977..f5db6a9897 100644
--- a/tools/internal_ci/windows/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/windows/grpc_basictests_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/grpc_build_artifacts.cfg b/tools/internal_ci/windows/grpc_build_artifacts.cfg
index 38b0abd519..f45cfda121 100644
--- a/tools/internal_ci/windows/grpc_build_artifacts.cfg
+++ b/tools/internal_ci/windows/grpc_build_artifacts.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_build_artifacts.bat"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/windows/grpc_build_packages.cfg b/tools/internal_ci/windows/grpc_build_packages.cfg
index 65a8b1eef3..b351bbb11b 100644
--- a/tools/internal_ci/windows/grpc_build_packages.cfg
+++ b/tools/internal_ci/windows/grpc_build_packages.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_build_packages.bat"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/windows/grpc_distribtests.cfg b/tools/internal_ci/windows/grpc_distribtests.cfg
index 1766e601e5..e12d4bf98d 100644
--- a/tools/internal_ci/windows/grpc_distribtests.cfg
+++ b/tools/internal_ci/windows/grpc_distribtests.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_distribtests.bat"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/windows/grpc_distribtests_standalone.cfg b/tools/internal_ci/windows/grpc_distribtests_standalone.cfg
index 33a50fdc45..7f32ba4c70 100644
--- a/tools/internal_ci/windows/grpc_distribtests_standalone.cfg
+++ b/tools/internal_ci/windows/grpc_distribtests_standalone.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_distribtests_standalone.bat"
timeout_mins: 120
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
regex: "github/grpc/artifacts/**"
}
diff --git a/tools/internal_ci/windows/grpc_portability.cfg b/tools/internal_ci/windows/grpc_portability.cfg
index 94e71753ef..aa86c06632 100644
--- a/tools/internal_ci/windows/grpc_portability.cfg
+++ b/tools/internal_ci/windows/grpc_portability.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/grpc_portability_build_only.cfg b/tools/internal_ci/windows/grpc_portability_build_only.cfg
index 3bc27f1f24..3dace627eb 100644
--- a/tools/internal_ci/windows/grpc_portability_build_only.cfg
+++ b/tools/internal_ci/windows/grpc_portability_build_only.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests.cfg
index 91777cd7cb..a8e6f0675b 100644
--- a/tools/internal_ci/windows/pull_request/grpc_basictests.cfg
+++ b/tools/internal_ci/windows/pull_request/grpc_basictests.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests_dbg.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests_dbg.cfg
index 81a1e9d3c8..ce957232fd 100644
--- a/tools/internal_ci/windows/pull_request/grpc_basictests_dbg.cfg
+++ b/tools/internal_ci/windows/pull_request/grpc_basictests_dbg.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests_opt.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests_opt.cfg
index 3bb6510ca7..7d2abbfb19 100644
--- a/tools/internal_ci/windows/pull_request/grpc_basictests_opt.cfg
+++ b/tools/internal_ci/windows/pull_request/grpc_basictests_opt.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/internal_ci/windows/pull_request/grpc_portability.cfg b/tools/internal_ci/windows/pull_request/grpc_portability.cfg
index 2bda487629..6f332416fe 100644
--- a/tools/internal_ci/windows/pull_request/grpc_portability.cfg
+++ b/tools/internal_ci/windows/pull_request/grpc_portability.cfg
@@ -19,7 +19,7 @@ build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
timeout_mins: 240
action {
define_artifacts {
- regex: "**/*sponge_log.xml"
+ regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index bb9222d953..ff3344cd95 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Dictionaries used for client matrix testing.
+# Defines languages, runtimes and releases for backward compatibility testing
def get_github_repo(lang):
@@ -53,8 +53,7 @@ LANG_RUNTIME_MATRIX = {
'csharp': ['csharp', 'csharpcoreclr'],
}
-# Dictionary of releases per language. For each language, we need to provide
-# a release tag pointing to the latest build of the branch.
+# Dictionary of known releases for given language.
LANG_RELEASE_MATRIX = {
'cxx': [
{
@@ -99,6 +98,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
+ },
],
'go': [
{
@@ -135,7 +140,19 @@ LANG_RELEASE_MATRIX = {
'v1.11.3': None
},
{
- 'v1.12.0': None
+ 'v1.12.2': None
+ },
+ {
+ 'v1.13.0': None
+ },
+ {
+ 'v1.14.0': None
+ },
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
},
],
'java': [
@@ -184,6 +201,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.0': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.1': None
+ },
],
'python': [
{
@@ -228,6 +251,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
+ },
],
'node': [
{
@@ -316,6 +345,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
+ },
],
'php': [
{
@@ -360,6 +395,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
+ },
],
'csharp': [
{
@@ -409,6 +450,12 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
+ {
+ 'v1.16.0': None
+ },
],
}
diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py
index 9d442346a7..6cf2a9b036 100755
--- a/tools/interop_matrix/run_interop_matrix_tests.py
+++ b/tools/interop_matrix/run_interop_matrix_tests.py
@@ -26,7 +26,7 @@ import subprocess
import sys
import uuid
-# Langauage Runtime Matrix
+# Language Runtime Matrix
import client_matrix
python_util_dir = os.path.abspath(
@@ -37,6 +37,9 @@ import jobset
import report_utils
import upload_test_results
+_TEST_TIMEOUT_SECONDS = 60
+_PULL_IMAGE_TIMEOUT_SECONDS = 15 * 60
+_MAX_PARALLEL_DOWNLOADS = 6
_LANGUAGES = client_matrix.LANG_RUNTIME_MATRIX.keys()
# All gRPC release tags, flattened, deduped and sorted.
_RELEASES = sorted(
@@ -45,7 +48,6 @@ _RELEASES = sorted(
client_matrix.get_release_tag_name(info)
for lang in client_matrix.LANG_RELEASE_MATRIX.values()
for info in lang)))
-_TEST_TIMEOUT = 60
argp = argparse.ArgumentParser(description='Run interop tests.')
argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
@@ -56,7 +58,7 @@ argp.add_argument(
argp.add_argument(
'--release',
default='all',
- choices=['all', 'master'] + _RELEASES,
+ choices=['all'] + _RELEASES,
help='Release tags to test. When testing all '
'releases defined in client_matrix.py, use "all".')
argp.add_argument(
@@ -92,136 +94,154 @@ argp.add_argument(
nargs='?',
help='The gateway to backend services.')
-args = argp.parse_args()
-
-print(str(args))
-
-def find_all_images_for_lang(lang):
+def _get_test_images_for_lang(lang, release_arg, image_path_prefix):
"""Find docker images for a language across releases and runtimes.
Returns dictionary of list of (<tag>, <image-full-path>) keyed by runtime.
"""
- # Find all defined releases.
- if args.release == 'all':
- releases = ['master'] + client_matrix.get_release_tags(lang)
+ if release_arg == 'all':
+ # Use all defined releases for given language
+ releases = client_matrix.get_release_tags(lang)
else:
# Look for a particular release.
- if args.release not in ['master'
- ] + client_matrix.get_release_tags(lang):
+ if release_arg not in client_matrix.get_release_tags(lang):
jobset.message(
'SKIPPED',
- '%s for %s is not defined' % (args.release, lang),
+ 'release %s for %s is not defined' % (release_arg, lang),
do_newline=True)
return {}
- releases = [args.release]
+ releases = [release_arg]
- # TODO(jtattermusch): why do we need to query the existing images/tags?
- # From LANG_RUNTIME_MATRIX and LANG_RELEASE_MATRIX it should be obvious
- # which tags we want to test - and it should be an error if they are
- # missing.
# Images tuples keyed by runtime.
images = {}
for runtime in client_matrix.LANG_RUNTIME_MATRIX[lang]:
- image_path = '%s/grpc_interop_%s' % (args.gcr_path, runtime)
- output = subprocess.check_output([
- 'gcloud', 'beta', 'container', 'images', 'list-tags',
- '--format=json', image_path
- ])
- docker_image_list = json.loads(output)
- # All images should have a single tag or no tag.
- # TODO(adelez): Remove tagless images.
- tags = [i['tags'][0] for i in docker_image_list if i['tags']]
- jobset.message(
- 'START',
- 'Found images for %s: %s' % (image_path, tags),
- do_newline=True)
- skipped = len(docker_image_list) - len(tags)
- jobset.message(
- 'SKIPPED',
- 'Skipped images (no-tag/unknown-tag): %d' % skipped,
- do_newline=True)
- # Filter tags based on the releases.
- images[runtime] = [(tag, '%s:%s' % (image_path, tag))
- for tag in tags
- if tag in releases]
+ image_path = '%s/grpc_interop_%s' % (image_path_prefix, runtime)
+ images[runtime] = [
+ (tag, '%s:%s' % (image_path, tag)) for tag in releases
+ ]
return images
-# caches test cases (list of JobSpec) loaded from file. Keyed by lang and runtime.
-def find_test_cases(lang, runtime, release, suite_name):
- """Returns the list of test cases from testcase files per lang/release."""
+def _read_test_cases_file(lang, runtime, release):
+ """Read test cases from a bash-like file and return a list of commands"""
testcase_dir = os.path.join(os.path.dirname(__file__), 'testcases')
filename_prefix = lang
if lang == 'csharp':
+ # TODO(jtattermusch): remove this odd specialcase
filename_prefix = runtime
# Check to see if we need to use a particular version of test cases.
lang_version = '%s_%s' % (filename_prefix, release)
if lang_version in client_matrix.TESTCASES_VERSION_MATRIX:
- testcases = os.path.join(
+ testcase_file = os.path.join(
testcase_dir, client_matrix.TESTCASES_VERSION_MATRIX[lang_version])
else:
- testcases = os.path.join(testcase_dir, '%s__master' % filename_prefix)
+ # TODO(jtattermusch): remove the double-underscore, it is pointless
+ testcase_file = os.path.join(testcase_dir,
+ '%s__master' % filename_prefix)
+
+ lines = []
+ with open(testcase_file) as f:
+ for line in f.readlines():
+ line = re.sub('\\#.*$', '', line) # remove hash comments
+ line = line.strip()
+ if line and not line.startswith('echo'):
+ # Each non-empty line is a treated as a test case command
+ lines.append(line)
+ return lines
+
+
+def _cleanup_docker_image(image):
+ jobset.message('START', 'Cleanup docker image %s' % image, do_newline=True)
+ dockerjob.remove_image(image, skip_nonexistent=True)
+
+
+args = argp.parse_args()
+
+
+# caches test cases (list of JobSpec) loaded from file. Keyed by lang and runtime.
+def _generate_test_case_jobspecs(lang, runtime, release, suite_name):
+ """Returns the list of test cases from testcase files per lang/release."""
+ testcase_lines = _read_test_cases_file(lang, runtime, release)
job_spec_list = []
- try:
- with open(testcases) as f:
- # Only line start with 'docker run' are test cases.
- for line in f.readlines():
- if line.startswith('docker run'):
- m = re.search('--test_case=(.*)"', line)
- shortname = m.group(1) if m else 'unknown_test'
- m = re.search(
- '--server_host_override=(.*).sandbox.googleapis.com',
- line)
- server = m.group(1) if m else 'unknown_server'
-
- # If server_host arg is not None, replace the original
- # server_host with the one provided or append to the end of
- # the command if server_host does not appear originally.
- if args.server_host:
- if line.find('--server_host=') > -1:
- line = re.sub('--server_host=[^ ]*',
- '--server_host=%s' % args.server_host,
- line)
- else:
- line = '%s --server_host=%s"' % (line[:-1],
- args.server_host)
- print(line)
-
- spec = jobset.JobSpec(
- cmdline=line,
- shortname='%s:%s:%s:%s' % (suite_name, lang, server,
- shortname),
- timeout_seconds=_TEST_TIMEOUT,
- shell=True,
- flake_retries=5 if args.allow_flakes else 0)
- job_spec_list.append(spec)
- jobset.message(
- 'START',
- 'Loaded %s tests from %s' % (len(job_spec_list), testcases),
- do_newline=True)
- except IOError as err:
- jobset.message('FAILED', err, do_newline=True)
+ for line in testcase_lines:
+ # TODO(jtattermusch): revisit the logic for updating test case commands
+ # what it currently being done seems fragile.
+ m = re.search('--test_case=(.*)"', line)
+ shortname = m.group(1) if m else 'unknown_test'
+ m = re.search('--server_host_override=(.*).sandbox.googleapis.com',
+ line)
+ server = m.group(1) if m else 'unknown_server'
+
+ # If server_host arg is not None, replace the original
+ # server_host with the one provided or append to the end of
+ # the command if server_host does not appear originally.
+ if args.server_host:
+ if line.find('--server_host=') > -1:
+ line = re.sub('--server_host=[^ ]*',
+ '--server_host=%s' % args.server_host, line)
+ else:
+ line = '%s --server_host=%s"' % (line[:-1], args.server_host)
+
+ spec = jobset.JobSpec(
+ cmdline=line,
+ shortname='%s:%s:%s:%s' % (suite_name, lang, server, shortname),
+ timeout_seconds=_TEST_TIMEOUT_SECONDS,
+ shell=True,
+ flake_retries=5 if args.allow_flakes else 0)
+ job_spec_list.append(spec)
return job_spec_list
-_xml_report_tree = report_utils.new_junit_xml_tree()
+def _pull_images_for_lang(lang, images):
+ """Pull all images for given lang from container registry."""
+ jobset.message(
+ 'START', 'Downloading images for language "%s"' % lang, do_newline=True)
+ download_specs = []
+ for release, image in images:
+ # Pull the image and warm it up.
+ # First time we use an image with "docker run", it takes time to unpack
+ # the image and later this delay would fail our test cases.
+ cmdline = [
+ 'time gcloud docker -- pull %s && time docker run --rm=true %s /bin/true'
+ % (image, image)
+ ]
+ spec = jobset.JobSpec(
+ cmdline=cmdline,
+ shortname='pull_image_%s' % (image),
+ timeout_seconds=_PULL_IMAGE_TIMEOUT_SECONDS,
+ shell=True)
+ download_specs.append(spec)
+ # too many image downloads at once tend to get stuck
+ max_pull_jobs = min(args.jobs, _MAX_PARALLEL_DOWNLOADS)
+ num_failures, resultset = jobset.run(
+ download_specs, newline_on_success=True, maxjobs=max_pull_jobs)
+ if num_failures:
+ jobset.message(
+ 'FAILED', 'Failed to download some images', do_newline=True)
+ return False
+ else:
+ jobset.message(
+ 'SUCCESS', 'All images downloaded successfully.', do_newline=True)
+ return True
-def run_tests_for_lang(lang, runtime, images):
+def _run_tests_for_lang(lang, runtime, images, xml_report_tree):
"""Find and run all test cases for a language.
images is a list of (<release-tag>, <image-full-path>) tuple.
"""
+ if not _pull_images_for_lang(lang, images):
+ jobset.message(
+ 'FAILED', 'Image download failed. Exiting.', do_newline=True)
+ return 1
+
total_num_failures = 0
- for image_tuple in images:
- release, image = image_tuple
- jobset.message('START', 'Testing %s' % image, do_newline=True)
- # Download the docker image before running each test case.
- subprocess.check_call(['gcloud', 'docker', '--', 'pull', image])
+ for release, image in images:
suite_name = '%s__%s_%s' % (lang, runtime, release)
- job_spec_list = find_test_cases(lang, runtime, release, suite_name)
+ job_spec_list = _generate_test_case_jobspecs(lang, runtime, release,
+ suite_name)
if not job_spec_list:
jobset.message(
@@ -235,35 +255,31 @@ def run_tests_for_lang(lang, runtime, images):
maxjobs=args.jobs)
if args.bq_result_table and resultset:
upload_test_results.upload_interop_results_to_bq(
- resultset, args.bq_result_table, args)
+ resultset, args.bq_result_table)
if num_failures:
jobset.message('FAILED', 'Some tests failed', do_newline=True)
total_num_failures += num_failures
else:
jobset.message('SUCCESS', 'All tests passed', do_newline=True)
- report_utils.append_junit_xml_results(_xml_report_tree, resultset,
+ report_utils.append_junit_xml_results(xml_report_tree, resultset,
'grpc_interop_matrix', suite_name,
str(uuid.uuid4()))
if not args.keep:
- cleanup(image)
+ _cleanup_docker_image(image)
return total_num_failures
-def cleanup(image):
- jobset.message('START', 'Cleanup docker image %s' % image, do_newline=True)
- dockerjob.remove_image(image, skip_nonexistent=True)
-
-
languages = args.language if args.language != ['all'] else _LANGUAGES
total_num_failures = 0
+_xml_report_tree = report_utils.new_junit_xml_tree()
for lang in languages:
- docker_images = find_all_images_for_lang(lang)
+ docker_images = _get_test_images_for_lang(lang, args.release, args.gcr_path)
for runtime in sorted(docker_images.keys()):
- total_num_failures += run_tests_for_lang(lang, runtime,
- docker_images[runtime])
+ total_num_failures += _run_tests_for_lang(
+ lang, runtime, docker_images[runtime], _xml_report_tree)
report_utils.create_xml_report_file(_xml_report_tree, args.report_file)
diff --git a/tools/remote_build/README.md b/tools/remote_build/README.md
new file mode 100644
index 0000000000..19739e9ee1
--- /dev/null
+++ b/tools/remote_build/README.md
@@ -0,0 +1,33 @@
+# Running Remote Builds with bazel
+
+This allows you to spawn gRPC C/C++ remote build and tests from your workstation with
+configuration that's very similar to what's used by our CI Kokoro.
+
+Note that this will only work for gRPC team members (it requires access to the
+remote build and execution cluster), others will need to rely on local test runs
+and tests run by Kokoro CI.
+
+
+## Prerequisites
+
+- See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system.
+
+- Setup application default credentials for running remote builds by following [RBE Credentials Setup](https://cloud.google.com/remote-build-execution/docs/getting-started#set_credentials)
+
+
+## Running remote build manually from dev workstation
+
+Run from repository root (opt, dbg):
+```
+# manual run of bazel tests remotely on Foundry
+bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=opt //test/...
+```
+
+Sanitizer runs (asan, msan, tsan, ubsan):
+```
+# manual run of bazel tests remotely on Foundry with given sanitizer
+bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/...
+```
+
+Available command line options can be found in
+[Bazel command line reference](https://docs.bazel.build/versions/master/command-line-reference.html)
diff --git a/tools/remote_build/kokoro.bazelrc b/tools/remote_build/kokoro.bazelrc
new file mode 100644
index 0000000000..11462bd301
--- /dev/null
+++ b/tools/remote_build/kokoro.bazelrc
@@ -0,0 +1,38 @@
+# 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.
+
+# bazelrc file for running gRPC tests on Kokoro using Foundry
+
+import %workspace%/tools/remote_build/rbe_common.bazelrc
+
+build --remote_cache=remotebuildexecution.googleapis.com
+build --remote_executor=remotebuildexecution.googleapis.com
+build --tls_enabled=true
+
+build --auth_enabled=true
+# magic location where kokoro script puts the credentials
+build --auth_credentials=/tmpfs/src/keystore/4321_grpc-testing-service
+build --auth_scope=https://www.googleapis.com/auth/cloud-source-tools
+
+build --bes_backend=buildeventservice.googleapis.com
+build --bes_best_effort=false
+build --bes_timeout=600s
+build --project_id=grpc-testing
+
+# required by kokoro for some reason
+build --test_env=USER=anon
+
+build --jobs=200
+build --test_output=errors
+build --keep_going=true
diff --git a/tools/remote_build/manual.bazelrc b/tools/remote_build/manual.bazelrc
new file mode 100644
index 0000000000..b4fdc70637
--- /dev/null
+++ b/tools/remote_build/manual.bazelrc
@@ -0,0 +1,45 @@
+# 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.
+
+# bazelrc file for running gRPC tests with Foundry (remote build execution)
+# manually from developer's workstation
+
+import %workspace%/tools/remote_build/rbe_common.bazelrc
+
+build --remote_cache=remotebuildexecution.googleapis.com
+build --remote_executor=remotebuildexecution.googleapis.com
+build --tls_enabled=true
+
+# Enable authentication. This will pick up application default credentials by
+# default. You can use --auth_credentials=some_file.json to use a service
+# account credential instead.
+# How to setup credentials:
+# See https://cloud.google.com/remote-build-execution/docs/getting-started#set_credentials
+build --auth_enabled=true
+
+# Set flags for uploading to BES in order to view results in the Bazel Build
+# Results UI.
+build --bes_backend="buildeventservice.googleapis.com"
+build --bes_timeout=60s
+build --bes_results_url="https://source.cloud.google.com/results/invocations/"
+build --project_id=grpc-testing
+
+build --jobs=100
+
+# TODO(jtattermusch): this should be part of the common config
+# but currently sanitizers use different test_timeout values
+build --test_timeout=300,450,1200,3600
+
+# print output for tests that fail (default is "summary")
+build --test_output=errors
diff --git a/tools/remote_build/rbe_common.bazelrc b/tools/remote_build/rbe_common.bazelrc
new file mode 100644
index 0000000000..75a42a317e
--- /dev/null
+++ b/tools/remote_build/rbe_common.bazelrc
@@ -0,0 +1,85 @@
+# 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.
+
+# bazelrc with Foundry setting common to both manual run and runs started by Kokoro
+# see https://github.com/bazelbuild/bazel-toolchains/tree/master/bazelrc
+# for examples and more documentation
+
+startup --host_jvm_args=-Dbazel.DigestFunction=SHA256
+
+build --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/default:toolchain
+build --extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/cpp:cc-toolchain-clang-x86_64-default
+# Use custom execution platforms defined in third_party/toolchains
+build --extra_execution_platforms=//third_party/toolchains:rbe_ubuntu1604
+build --host_platform=//third_party/toolchains:rbe_ubuntu1604
+build --platforms=//third_party/toolchains:rbe_ubuntu1604
+
+build --spawn_strategy=remote
+build --strategy=Javac=remote
+build --strategy=Closure=remote
+build --genrule_strategy=remote
+build --remote_timeout=3600
+
+build --remote_instance_name=projects/grpc-testing/instances/default_instance
+
+build --verbose_failures=true
+
+build --experimental_strict_action_env=true
+build --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
+
+# don't use port server
+build --define GRPC_PORT_ISOLATED_RUNTIME=1
+# without verbose gRPC logs the test outputs are not very useful
+test --test_env=GRPC_VERBOSITY=debug
+
+# address sanitizer: most settings are already in %workspace%/.bazelrc
+# we only need a few additional ones that are Foundry specific
+build:asan --copt=-gmlt
+# TODO(jtattermusch): use more reasonable test timeout
+build:asan --test_timeout=3600
+build:asan --test_tag_filters=-qps_json_driver
+
+# memory sanitizer: most settings are already in %workspace%/.bazelrc
+# we only need a few additional ones that are Foundry specific
+build:msan --copt=-gmlt
+# TODO(jtattermusch): use more reasonable test timeout
+build:msan --test_timeout=3600
+# TODO(jtattermusch): revisit the disabled tests
+build:msan --test_tag_filters=-nomsan,-json_run_localhost
+build:msan --cxxopt=--stdlib=libc++
+# setting LD_LIBRARY_PATH is necessary
+# to avoid "libc++.so.1: cannot open shared object file"
+build:msan --action_env=LD_LIBRARY_PATH=/usr/local/lib
+build:msan --host_crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/default:toolchain
+# override the config-agnostic crosstool_top
+build:msan --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.16.1/msan:toolchain
+
+# thread sanitizer: most settings are already in %workspace%/.bazelrc
+# we only need a few additional ones that are Foundry specific
+build:tsan --copt=-gmlt
+# TODO(jtattermusch): use more reasonable test timeout
+build:tsan --test_timeout=3600
+build:tsan --test_tag_filters=-qps_json_driver
+
+# undefined behavior sanitizer: most settings are already in %workspace%/.bazelrc
+# we only need a few additional ones that are Foundry specific
+build:ubsan --copt=-gmlt
+# TODO(jtattermusch): use more reasonable test timeout
+build:ubsan --test_timeout=3600
+# override the config-agnostic crosstool_top
+--crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.0/bazel_0.16.1/ubsan:toolchain
+# TODO(jtattermusch): remove this once Foundry adds the env to the docker image.
+# ubsan needs symbolizer to work properly, otherwise the suppression file doesn't work
+# and we get test failures.
+build:ubsan --action_env=UBSAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index bdeb258e1f..aa1d0c3bf2 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -124,6 +124,8 @@ class PythonArtifact:
# https://github.com/resin-io-projects/armv7hf-debian-qemu/issues/9
# A QEMU bug causes submodule update to hang, so we copy directly
environ['RELATIVE_COPY_PATH'] = '.'
+ # Parallel builds are counterproductive in emulated environment
+ environ['GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS'] = '1'
extra_args = ' --entrypoint=/usr/bin/qemu-arm-static '
return create_docker_jobspec(
self.name,
@@ -240,37 +242,38 @@ class CSharpExtArtifact:
['tools/run_tests/artifacts/build_artifact_csharp_ios.sh'],
use_workspace=True)
elif self.platform == 'windows':
- cmake_arch_option = 'Win32' if self.arch == 'x86' else self.arch
return create_jobspec(
self.name, [
'tools\\run_tests\\artifacts\\build_artifact_csharp.bat',
- cmake_arch_option
+ self.arch
],
use_workspace=True)
else:
- environ = {
- 'CONFIG': 'opt',
- 'EMBED_OPENSSL': 'true',
- 'EMBED_ZLIB': 'true',
- 'CFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE',
- 'CXXFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE',
- 'LDFLAGS': ''
- }
if self.platform == 'linux':
+ cmake_arch_option = '' # x64 is the default architecture
+ if self.arch == 'x86':
+ # TODO(jtattermusch): more work needed to enable
+ # boringssl assembly optimizations for 32-bit linux.
+ # Problem: currently we are building the artifact under
+ # 32-bit docker image, but CMAKE_SYSTEM_PROCESSOR is still
+ # set to x86_64, so the resulting boringssl binary
+ # would have undefined symbols.
+ cmake_arch_option = '-DOPENSSL_NO_ASM=ON'
return create_docker_jobspec(
self.name,
'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
'tools/run_tests/artifacts/build_artifact_csharp.sh',
- environ=environ)
+ environ={
+ 'CMAKE_ARCH_OPTION': cmake_arch_option
+ })
else:
- archflag = _ARCH_FLAG_MAP[self.arch]
- environ['CFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG)
- environ['CXXFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG)
- environ['LDFLAGS'] += ' %s' % archflag
+ cmake_arch_option = '' # x64 is the default architecture
+ if self.arch == 'x86':
+ cmake_arch_option = '-DCMAKE_OSX_ARCHITECTURES=i386'
return create_jobspec(
self.name,
['tools/run_tests/artifacts/build_artifact_csharp.sh'],
- environ=environ,
+ environ={'CMAKE_ARCH_OPTION': cmake_arch_option},
use_workspace=True)
def __str__(self):
diff --git a/tools/run_tests/artifacts/build_artifact_csharp.bat b/tools/run_tests/artifacts/build_artifact_csharp.bat
index ac2c92b716..713e480f72 100644
--- a/tools/run_tests/artifacts/build_artifact_csharp.bat
+++ b/tools/run_tests/artifacts/build_artifact_csharp.bat
@@ -15,16 +15,33 @@
@rem Builds C# artifacts on Windows
set ARCHITECTURE=%1
-set GRPC_SKIP_DOTNET_RESTORE=true
-@call tools\run_tests\helper_scripts\pre_build_csharp.bat %ARCHITECTURE% || goto :error
-cd cmake\build\%ARCHITECTURE%
-cmake --build . --target grpc_csharp_ext --config RelWithDebInfo
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+mkdir cmake
+cd cmake
+mkdir build
+cd build
+mkdir %ARCHITECTURE%
+cd %ARCHITECTURE%
+
+@rem TODO(jtattermusch): is there a better way to force using MSVC?
+@rem select the MSVC compiler explicitly to avoid using gcc from mingw or cygwin
+@rem (both are on path)
+set "MSVC_COMPILER=C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe"
+if "%ARCHITECTURE%" == "x64" (
+ set "MSVC_COMPILER=C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64/cl.exe"
+)
+
+call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %ARCHITECTURE%
+cmake -G Ninja -DCMAKE_C_COMPILER="%MSVC_COMPILER%" -DCMAKE_CXX_COMPILER="%MSVC_COMPILER%" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DgRPC_BUILD_TESTS=OFF -DgRPC_MSVC_STATIC_RUNTIME=ON ../../.. || goto :error
+cmake --build . --target grpc_csharp_ext
cd ..\..\..
mkdir -p %ARTIFACTS_OUT%
-copy /Y cmake\build\Win32\RelWithDebInfo\grpc_csharp_ext.dll %ARTIFACTS_OUT% || copy /Y cmake\build\x64\RelWithDebInfo\grpc_csharp_ext.dll %ARTIFACTS_OUT% || goto :error
-copy /Y cmake\build\Win32\RelWithDebInfo\grpc_csharp_ext.pdb %ARTIFACTS_OUT% || copy /Y cmake\build\x64\RelWithDebInfo\grpc_csharp_ext.pdb %ARTIFACTS_OUT% || goto :error
+copy /Y cmake\build\%ARCHITECTURE%\grpc_csharp_ext.dll %ARTIFACTS_OUT% || goto :error
+copy /Y cmake\build\%ARCHITECTURE%\grpc_csharp_ext.pdb %ARTIFACTS_OUT% || goto :error
goto :EOF
diff --git a/tools/run_tests/artifacts/build_artifact_csharp.sh b/tools/run_tests/artifacts/build_artifact_csharp.sh
index d65340261d..bb8a91b520 100755
--- a/tools/run_tests/artifacts/build_artifact_csharp.sh
+++ b/tools/run_tests/artifacts/build_artifact_csharp.sh
@@ -17,7 +17,17 @@ set -ex
cd "$(dirname "$0")/../../.."
-make grpc_csharp_ext
+mkdir -p cmake/build
+cd cmake/build
+
+cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DgRPC_BACKWARDS_COMPATIBILITY_MODE=ON \
+ -DgRPC_BUILD_TESTS=OFF \
+ "${CMAKE_ARCH_OPTION}" \
+ ../..
+
+make grpc_csharp_ext -j2
+cd ../..
mkdir -p "${ARTIFACTS_OUT}"
-cp libs/opt/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp libs/opt/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}"
+cp cmake/build/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp cmake/build/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}"
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..65f2d1c765 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -22,6 +22,11 @@ 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.
+# Use externally provided GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS value if set.
+export GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=${GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS:-2}
+
mkdir -p "${ARTIFACTS_OUT}"
ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}"
diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
index 29801a5b86..d93e8979fc 100755
--- a/tools/run_tests/artifacts/build_package_python.sh
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -19,10 +19,20 @@ cd "$(dirname "$0")/../../.."
mkdir -p artifacts/
-# All the python packages have been built in the artifact phase already
-# and we only collect them here to deliver them to the distribtest phase.
cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true
+strip_binary_wheel() {
+ TEMP_WHEEL_DIR=$(mktemp -d)
+ unzip "$1" -d "$TEMP_WHEEL_DIR"
+ find "$TEMP_WHEEL_DIR" -name "_protoc_compiler*.so" -exec strip --strip-debug {} ";"
+ find "$TEMP_WHEEL_DIR" -name "cygrpc*.so" -exec strip --strip-debug {} ";"
+ (cd "$TEMP_WHEEL_DIR" && zip -r - .) > "$1"
+}
+
+for wheel in artifacts/*.whl; do
+ strip_binary_wheel "$wheel"
+done
+
# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
# source distribution package, and only one of them will end up
# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/generated/lb_interop_test_scenarios.json b/tools/run_tests/generated/lb_interop_test_scenarios.json
new file mode 100644
index 0000000000..4f956c568a
--- /dev/null
+++ b/tools/run_tests/generated/lb_interop_test_scenarios.json
@@ -0,0 +1,1167 @@
+
+[
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_nx_domain_insecure",
+ "skip_langs": [],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_nx_domain_alts",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_nx_domain_tls",
+ "skip_langs": [],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_nx_domain_google_default_credentials",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": true,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_no_data_insecure",
+ "skip_langs": [],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": true,
+ "fallback_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_no_data_alts",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": true,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_no_data_tls",
+ "skip_langs": [],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [],
+ "cause_no_error_no_data_for_balancer_a_record": true,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "no_balancer_because_lb_a_record_returns_no_data_google_default_credentials",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_insecure_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_alts_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_tls_short_stream_True",
+ "skip_langs": [
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_google_default_credentials_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_insecure_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_alts_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_tls_short_stream_False",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_google_default_credentials_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_alts_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_tls_short_stream_True",
+ "skip_langs": [
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_google_default_credentials_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_alts_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_tls_short_stream_False",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_referred_to_backend_fallback_broken_google_default_credentials_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_insecure_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_alts_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_tls_short_stream_True",
+ "skip_langs": [
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_google_default_credentials_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ },
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_insecure_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_alts_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ },
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_tls_short_stream_False",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ },
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_backends_google_default_credentials_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_insecure_short_stream_True",
+ "skip_langs": [
+ "go",
+ "java",
+ "java"
+ ],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_alts_short_stream_True",
+ "skip_langs": [
+ "go",
+ "java",
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_tls_short_stream_True",
+ "skip_langs": [
+ "go",
+ "java",
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_google_default_credentials_short_stream_True",
+ "skip_langs": [
+ "go",
+ "java",
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_insecure_short_stream_False",
+ "skip_langs": [
+ "go",
+ "java"
+ ],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_alts_short_stream_False",
+ "skip_langs": [
+ "go",
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_tls_short_stream_False",
+ "skip_langs": [
+ "go",
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_no_backends_google_default_credentials_short_stream_False",
+ "skip_langs": [
+ "go",
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "name": "client_falls_back_because_balancer_connection_broken_alts",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_balancer_connection_broken_tls",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "name": "client_falls_back_because_balancer_connection_broken_google_default_credentials",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_insecure_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_alts_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_tls_short_stream_True",
+ "skip_langs": [
+ "java",
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": true,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_google_default_credentials_short_stream_True",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "google_default_credentials"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "insecure"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "insecure"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_insecure_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "insecure"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_alts_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "alts"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "tls"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "tls"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_tls_short_stream_False",
+ "skip_langs": [
+ "java"
+ ],
+ "transport_sec": "tls"
+ },
+ {
+ "backend_configs": [
+ {
+ "transport_sec": "alts"
+ }
+ ],
+ "balancer_configs": [
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ },
+ {
+ "short_stream": false,
+ "transport_sec": "alts"
+ }
+ ],
+ "cause_no_error_no_data_for_balancer_a_record": false,
+ "fallback_configs": [],
+ "name": "client_referred_to_backend_multiple_balancers_google_default_credentials_short_stream_False",
+ "skip_langs": [],
+ "transport_sec": "google_default_credentials"
+ }
+]
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index eb5e10abac..8d6ffdb959 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -508,23 +508,6 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "ev_epollsig_linux_test",
- "src": [
- "test/core/iomgr/ev_epollsig_linux_test.cc"
- ],
- "third_party": false,
- "type": "target"
- },
- {
- "deps": [
- "gpr",
- "gpr_test_util",
- "grpc",
- "grpc_test_util"
- ],
- "headers": [],
- "is_filegroup": false,
- "language": "c",
"name": "fake_resolver_test",
"src": [
"test/core/client_channel/resolvers/fake_resolver_test.cc"
@@ -1191,7 +1174,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "handshake_client",
+ "name": "handshake_client_ssl",
"src": [
"test/core/handshake/client_ssl.cc"
],
@@ -1210,7 +1193,7 @@
],
"is_filegroup": false,
"language": "c",
- "name": "handshake_server",
+ "name": "handshake_server_ssl",
"src": [
"test/core/handshake/server_ssl.cc",
"test/core/handshake/server_ssl_common.cc",
@@ -1625,7 +1608,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "memory_profile_client",
+ "name": "memory_usage_client",
"src": [
"test/core/memory_usage/client.cc"
],
@@ -1642,7 +1625,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "memory_profile_server",
+ "name": "memory_usage_server",
"src": [
"test/core/memory_usage/server.cc"
],
@@ -1659,7 +1642,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "memory_profile_test",
+ "name": "memory_usage_test",
"src": [
"test/core/memory_usage/memory_usage_test.cc"
],
@@ -1878,9 +1861,9 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "pollset_set_test",
+ "name": "resolve_address_posix_test",
"src": [
- "test/core/iomgr/pollset_set_test.cc"
+ "test/core/iomgr/resolve_address_posix_test.cc"
],
"third_party": false,
"type": "target"
@@ -1895,9 +1878,9 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "resolve_address_posix_test",
+ "name": "resolve_address_using_ares_resolver_test",
"src": [
- "test/core/iomgr/resolve_address_posix_test.cc"
+ "test/core/iomgr/resolve_address_test.cc"
],
"third_party": false,
"type": "target"
@@ -1912,7 +1895,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "resolve_address_test",
+ "name": "resolve_address_using_native_resolver_test",
"src": [
"test/core/iomgr/resolve_address_test.cc"
],
@@ -3346,6 +3329,25 @@
"grpc++_test_util",
"grpc_test_util"
],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "client_callback_end2end_test",
+ "src": [
+ "test/cpp/end2end/client_callback_end2end_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
"headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h",
@@ -3407,6 +3409,29 @@
"grpc++_test_util",
"grpc_test_util"
],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "client_interceptors_end2end_test",
+ "src": [
+ "test/cpp/end2end/client_interceptors_end2end_test.cc",
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
"headers": [],
"is_filegroup": false,
"language": "c++",
@@ -3591,12 +3616,16 @@
"grpc++_test_util",
"grpc_test_util"
],
- "headers": [],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
"is_filegroup": false,
"language": "c++",
"name": "end2end_test",
"src": [
- "test/cpp/end2end/end2end_test.cc"
+ "test/cpp/end2end/end2end_test.cc",
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h"
],
"third_party": false,
"type": "target"
@@ -4715,6 +4744,29 @@
"deps": [
"gpr",
"gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
+ "headers": [
+ "test/cpp/end2end/interceptors_util.h"
+ ],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "server_interceptors_end2end_test",
+ "src": [
+ "test/cpp/end2end/interceptors_util.cc",
+ "test/cpp/end2end/interceptors_util.h",
+ "test/cpp/end2end/server_interceptors_end2end_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
"grpc++_test_util_unsecure",
"grpc++_unsecure",
"grpc_test_util_unsecure",
@@ -6570,24 +6622,6 @@
},
{
"deps": [
- "end2end_nosec_tests",
- "gpr",
- "gpr_test_util",
- "grpc_test_util_unsecure",
- "grpc_unsecure"
- ],
- "headers": [],
- "is_filegroup": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "src": [
- "test/core/end2end/fixtures/inproc.cc"
- ],
- "third_party": false,
- "type": "target"
- },
- {
- "deps": [
"gpr",
"gpr_test_util",
"grpc++_test_config",
@@ -7060,6 +7094,7 @@
"grpc_lb_policy_grpclb_secure",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
+ "grpc_lb_policy_xds_secure",
"grpc_max_age_filter",
"grpc_message_size_filter",
"grpc_resolver_dns_ares",
@@ -7105,19 +7140,6 @@
{
"deps": [
"gpr",
- "grpc"
- ],
- "headers": [],
- "is_filegroup": false,
- "language": "c",
- "name": "grpc_dll",
- "src": [],
- "third_party": false,
- "type": "lib"
- },
- {
- "deps": [
- "gpr",
"gpr_test_util",
"grpc",
"grpc_test_util_base"
@@ -7166,6 +7188,7 @@
"grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
+ "grpc_lb_policy_xds",
"grpc_max_age_filter",
"grpc_message_size_filter",
"grpc_resolver_dns_ares",
@@ -7862,6 +7885,7 @@
"test/cpp/qps/benchmark_config.h",
"test/cpp/qps/client.h",
"test/cpp/qps/client_async.cc",
+ "test/cpp/qps/client_callback.cc",
"test/cpp/qps/client_sync.cc",
"test/cpp/qps/driver.cc",
"test/cpp/qps/driver.h",
@@ -7877,6 +7901,7 @@
"test/cpp/qps/report.h",
"test/cpp/qps/server.h",
"test/cpp/qps/server_async.cc",
+ "test/cpp/qps/server_callback.cc",
"test/cpp/qps/server_sync.cc",
"test/cpp/qps/stats.h",
"test/cpp/qps/usage_timer.cc",
@@ -9133,7 +9158,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",
@@ -9164,8 +9189,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",
@@ -9530,7 +9555,6 @@
"src/core/lib/iomgr/error.cc",
"src/core/lib/iomgr/ev_epoll1_linux.cc",
"src/core/lib/iomgr/ev_epollex_linux.cc",
- "src/core/lib/iomgr/ev_epollsig_linux.cc",
"src/core/lib/iomgr/ev_poll_posix.cc",
"src/core/lib/iomgr/ev_posix.cc",
"src/core/lib/iomgr/ev_windows.cc",
@@ -9646,7 +9670,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"
@@ -9711,7 +9736,6 @@
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -9804,7 +9828,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",
@@ -9863,7 +9888,6 @@
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -9956,7 +9980,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"
@@ -10010,7 +10035,8 @@
"deps": [
"gpr",
"grpc_base",
- "grpc_deadline_filter"
+ "grpc_deadline_filter",
+ "health_proto"
],
"headers": [
"src/core/ext/filters/client_channel/backup_poller.h",
@@ -10018,6 +10044,7 @@
"src/core/ext/filters/client_channel/client_channel_channelz.h",
"src/core/ext/filters/client_channel/client_channel_factory.h",
"src/core/ext/filters/client_channel/connector.h",
+ "src/core/ext/filters/client_channel/health/health_check_client.h",
"src/core/ext/filters/client_channel/http_connect_handshaker.h",
"src/core/ext/filters/client_channel/http_proxy.h",
"src/core/ext/filters/client_channel/lb_policy.h",
@@ -10032,8 +10059,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",
@@ -10051,6 +10077,8 @@
"src/core/ext/filters/client_channel/client_channel_plugin.cc",
"src/core/ext/filters/client_channel/connector.cc",
"src/core/ext/filters/client_channel/connector.h",
+ "src/core/ext/filters/client_channel/health/health_check_client.cc",
+ "src/core/ext/filters/client_channel/health/health_check_client.h",
"src/core/ext/filters/client_channel/http_connect_handshaker.cc",
"src/core/ext/filters/client_channel/http_connect_handshaker.h",
"src/core/ext/filters/client_channel/http_proxy.cc",
@@ -10079,9 +10107,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"
@@ -10165,6 +10191,7 @@
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
"nanopb"
],
"headers": [
@@ -10172,10 +10199,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
@@ -10190,13 +10214,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10208,6 +10226,7 @@
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
"nanopb"
],
"headers": [
@@ -10215,10 +10234,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
@@ -10233,13 +10249,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10282,6 +10292,69 @@
"deps": [
"gpr",
"grpc_base",
+ "grpc_client_channel",
+ "grpc_resolver_fake",
+ "grpclb_proto",
+ "nanopb"
+ ],
+ "headers": [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "grpc_lb_policy_xds",
+ "src": [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [
+ "gpr",
+ "grpc_base",
+ "grpc_client_channel",
+ "grpc_resolver_fake",
+ "grpc_secure",
+ "grpclb_proto",
+ "nanopb"
+ ],
+ "headers": [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "grpc_lb_policy_xds_secure",
+ "src": [
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [
+ "gpr",
+ "grpc_base",
"grpc_client_channel"
],
"headers": [
@@ -10423,6 +10496,7 @@
"headers": [
"include/grpc/grpc_security.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
@@ -10437,11 +10511,14 @@
"src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
- "src/core/lib/security/security_connector/alts_security_connector.h",
+ "src/core/lib/security/security_connector/alts/alts_security_connector.h",
+ "src/core/lib/security/security_connector/fake/fake_security_connector.h",
"src/core/lib/security/security_connector/load_system_roots.h",
"src/core/lib/security/security_connector/load_system_roots_linux.h",
- "src/core/lib/security/security_connector/local_security_connector.h",
+ "src/core/lib/security/security_connector/local/local_security_connector.h",
"src/core/lib/security/security_connector/security_connector.h",
+ "src/core/lib/security/security_connector/ssl/ssl_security_connector.h",
+ "src/core/lib/security/security_connector/ssl_utils.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_handshaker.h",
@@ -10455,6 +10532,7 @@
"src": [
"include/grpc/grpc_security.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/http/httpcli_security_connector.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/context/security_context.h",
@@ -10486,16 +10564,22 @@
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
- "src/core/lib/security/security_connector/alts_security_connector.cc",
- "src/core/lib/security/security_connector/alts_security_connector.h",
+ "src/core/lib/security/security_connector/alts/alts_security_connector.cc",
+ "src/core/lib/security/security_connector/alts/alts_security_connector.h",
+ "src/core/lib/security/security_connector/fake/fake_security_connector.cc",
+ "src/core/lib/security/security_connector/fake/fake_security_connector.h",
"src/core/lib/security/security_connector/load_system_roots.h",
"src/core/lib/security/security_connector/load_system_roots_fallback.cc",
"src/core/lib/security/security_connector/load_system_roots_linux.cc",
"src/core/lib/security/security_connector/load_system_roots_linux.h",
- "src/core/lib/security/security_connector/local_security_connector.cc",
- "src/core/lib/security/security_connector/local_security_connector.h",
+ "src/core/lib/security/security_connector/local/local_security_connector.cc",
+ "src/core/lib/security/security_connector/local/local_security_connector.h",
"src/core/lib/security/security_connector/security_connector.cc",
"src/core/lib/security/security_connector/security_connector.h",
+ "src/core/lib/security/security_connector/ssl/ssl_security_connector.cc",
+ "src/core/lib/security/security_connector/ssl/ssl_security_connector.h",
+ "src/core/lib/security/security_connector/ssl_utils.cc",
+ "src/core/lib/security/security_connector/ssl_utils.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/client_auth_filter.cc",
"src/core/lib/security/transport/secure_endpoint.cc",
@@ -10954,6 +11038,46 @@
},
{
"deps": [
+ "nanopb"
+ ],
+ "headers": [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "grpclb_proto",
+ "src": [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [
+ "nanopb"
+ ],
+ "headers": [
+ "src/core/ext/filters/client_channel/health/health.pb.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "health_proto",
+ "src": [
+ "src/core/ext/filters/client_channel/health/health.pb.c",
+ "src/core/ext/filters/client_channel/health/health.pb.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [
"nanopb_headers"
],
"headers": [],
@@ -11005,7 +11129,6 @@
"tsi_interface"
],
"headers": [
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.h",
"src/core/tsi/ssl/session_cache/ssl_session.h",
@@ -11018,8 +11141,6 @@
"language": "c",
"name": "tsi",
"src": [
- "src/core/tsi/alts_transport_security.cc",
- "src/core/tsi/alts_transport_security.h",
"src/core/tsi/fake_transport_security.cc",
"src/core/tsi/fake_transport_security.h",
"src/core/tsi/local_transport_security.cc",
@@ -11099,8 +11220,13 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
+ "include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
"include/grpcpp/impl/codegen/completion_queue_tag.h",
@@ -11108,13 +11234,18 @@
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
+ "include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"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",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
@@ -11165,8 +11296,13 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/call_op_set.h",
+ "include/grpcpp/impl/codegen/call_op_set_interface.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
+ "include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
"include/grpcpp/impl/codegen/completion_queue_tag.h",
@@ -11174,13 +11310,18 @@
"include/grpcpp/impl/codegen/core_codegen_interface.h",
"include/grpcpp/impl/codegen/create_auth_context.h",
"include/grpcpp/impl/codegen/grpc_library.h",
+ "include/grpcpp/impl/codegen/intercepted_channel.h",
+ "include/grpcpp/impl/codegen/interceptor.h",
+ "include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"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",
"include/grpcpp/impl/codegen/service_type.h",
"include/grpcpp/impl/codegen/slice.h",
@@ -11238,6 +11379,7 @@
"grpc++_codegen_base",
"grpc_base_headers",
"grpc_transport_inproc_headers",
+ "health_proto",
"nanopb_headers"
],
"headers": [
@@ -11323,9 +11465,11 @@
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "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",
@@ -11337,7 +11481,6 @@
"src/cpp/common/channel_filter.h",
"src/cpp/server/dynamic_thread_pool.h",
"src/cpp/server/health/default_health_check_service.h",
- "src/cpp/server/health/health.pb.h",
"src/cpp/server/thread_pool_interface.h",
"src/cpp/thread_manager/thread_manager.h"
],
@@ -11427,9 +11570,11 @@
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "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",
@@ -11439,6 +11584,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",
@@ -11461,8 +11607,6 @@
"src/cpp/server/dynamic_thread_pool.h",
"src/cpp/server/health/default_health_check_service.cc",
"src/cpp/server/health/default_health_check_service.h",
- "src/cpp/server/health/health.pb.c",
- "src/cpp/server/health/health.pb.h",
"src/cpp/server/health/health_check_service.cc",
"src/cpp/server/health/health_check_service_server_builder_option.cc",
"src/cpp/server/server_builder.cc",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index bda78360b1..30c9c6a525 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -629,26 +629,6 @@
"args": [],
"benchmark": false,
"ci_platforms": [
- "linux"
- ],
- "cpu_cost": 3,
- "exclude_configs": [],
- "exclude_iomgrs": [
- "uv"
- ],
- "flaky": false,
- "gtest": false,
- "language": "c",
- "name": "ev_epollsig_linux_test",
- "platforms": [
- "linux"
- ],
- "uses_polling": true
- },
- {
- "args": [],
- "benchmark": false,
- "ci_platforms": [
"linux",
"mac",
"posix",
@@ -1491,7 +1471,7 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "handshake_client",
+ "name": "handshake_client_ssl",
"platforms": [
"linux"
],
@@ -1511,7 +1491,7 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "handshake_server",
+ "name": "handshake_server_ssl",
"platforms": [
"linux"
],
@@ -1923,7 +1903,7 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "memory_profile_test",
+ "name": "memory_usage_test",
"platforms": [
"linux",
"mac",
@@ -2129,7 +2109,9 @@
"args": [],
"benchmark": false,
"ci_platforms": [
- "linux"
+ "linux",
+ "mac",
+ "posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
@@ -2139,38 +2121,44 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "pollset_set_test",
+ "name": "resolve_address_posix_test",
"platforms": [
- "linux"
+ "linux",
+ "mac",
+ "posix"
],
"uses_polling": true
},
{
- "args": [],
+ "args": [
+ "--resolver=ares"
+ ],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
- "posix"
+ "posix",
+ "windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
- "exclude_iomgrs": [
- "uv"
- ],
+ "exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
- "name": "resolve_address_posix_test",
+ "name": "resolve_address_using_ares_resolver_test",
"platforms": [
"linux",
"mac",
- "posix"
+ "posix",
+ "windows"
],
"uses_polling": true
},
{
- "args": [],
+ "args": [
+ "--resolver=native"
+ ],
"benchmark": false,
"ci_platforms": [
"linux",
@@ -2184,7 +2172,7 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "resolve_address_test",
+ "name": "resolve_address_using_native_resolver_test",
"platforms": [
"linux",
"mac",
@@ -4002,7 +3990,31 @@
"posix",
"windows"
],
- "cpu_cost": 1.0,
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "client_callback_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 10.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
@@ -4048,6 +4060,30 @@
"posix",
"windows"
],
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "client_interceptors_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
@@ -5138,6 +5174,30 @@
"posix",
"windows"
],
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "server_interceptors_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
@@ -56278,949 +56338,6 @@
},
{
"args": [
- "authority_not_supported"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "binary_metadata"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_after_accept"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_after_client_done"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_after_invoke"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_after_round_trip"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_before_invoke"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_in_a_vacuum"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "cancel_with_status"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "channelz"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "empty_batch"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "filter_call_init_fails"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "filter_causes_close"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "filter_latency"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "filter_status_code"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "high_initial_seqno"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "hpack_size"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "idempotent_request"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "invoke_large_request"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "large_metadata"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "max_message_length"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "negative_deadline"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "network_status_change"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "no_error_on_hotpath"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "no_logging"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "no_op"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "payload"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "ping_pong_streaming"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "registered_call"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "request_with_flags"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "request_with_payload"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "resource_quota_server"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "server_finishes_request"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "shutdown_finishes_calls"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "shutdown_finishes_tags"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "simple_cacheable_request"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "simple_metadata"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "simple_request"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "streaming_error_response"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 0.1,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "trailing_metadata"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
- "workaround_cronet_compression"
- ],
- "ci_platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "language": "c",
- "name": "inproc_nosec_test",
- "platforms": [
- "windows",
- "linux",
- "mac",
- "posix"
- ]
- },
- {
- "args": [
"--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_1channel_100rpcs_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
],
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index 6990244e51..8394f07e51 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -56,6 +56,12 @@ function is_linux() {
fi
}
+function inside_venv() {
+ if [[ -n "${VIRTUAL_ENV}" ]]; then
+ echo true
+ fi
+}
+
# Associated virtual environment name for the given python command.
function venv() {
$1 -c "import sys; print('py{}{}'.format(*sys.version_info[:2]))"
@@ -80,6 +86,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 +120,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)
@@ -128,10 +140,14 @@ fi
# Perform build operations #
############################
-# Instantiate the virtualenv from the Python version passed in.
-$PYTHON -m pip install --user virtualenv
-$PYTHON -m virtualenv "$VENV"
-VENV_PYTHON=$(script_realpath "$VENV/$VENV_RELATIVE_PYTHON")
+if [[ "$(inside_venv)" ]]; then
+ VENV_PYTHON="$PYTHON"
+else
+ # Instantiate the virtualenv from the Python version passed in.
+ $PYTHON -m pip install --user virtualenv
+ $PYTHON -m virtualenv "$VENV"
+ VENV_PYTHON=$(script_realpath "$VENV/$VENV_RELATIVE_PYTHON")
+fi
# See https://github.com/grpc/grpc/issues/14815 for more context. We cannot rely
# on pip to upgrade itself because if pip is too old, it may not have the required
@@ -149,10 +165,13 @@ pip_install_dir() {
}
case "$VENV" in
- *gevent*)
+ *py35_gevent*)
# TODO(https://github.com/grpc/grpc/issues/15411) unpin this
$VENV_PYTHON -m pip install gevent==1.3.b1
;;
+ *gevent*)
+ $VENV_PYTHON -m pip install -U gevent
+ ;;
esac
$VENV_PYTHON -m pip install --upgrade pip==10.0.1
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.bat b/tools/run_tests/helper_scripts/pre_build_csharp.bat
index 2ae870ebb1..05c6cf0f61 100644
--- a/tools/run_tests/helper_scripts/pre_build_csharp.bat
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.bat
@@ -32,9 +32,7 @@ cmake -G "Visual Studio 14 2015" -A %ARCHITECTURE% -DgRPC_BUILD_TESTS=OFF -DgRPC
cd ..\..\..\src\csharp
-if NOT DEFINED GRPC_SKIP_DOTNET_RESTORE (
- dotnet restore Grpc.sln || goto :error
-)
+dotnet restore Grpc.sln || goto :error
endlocal
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.sh b/tools/run_tests/helper_scripts/pre_build_csharp.sh
index f9f5440a61..7d83986f90 100755
--- a/tools/run_tests/helper_scripts/pre_build_csharp.sh
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.sh
@@ -15,7 +15,14 @@
set -ex
-# cd to gRPC csharp directory
-cd "$(dirname "$0")/../../../src/csharp"
+# cd to repository root
+cd "$(dirname "$0")/../../.."
+
+mkdir -p cmake/build
+cd cmake/build
+
+cmake -DgRPC_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE="${MSBUILD_CONFIG}" ../..
+
+cd ../../src/csharp
dotnet restore Grpc.sln
diff --git a/tools/run_tests/lb_interop_tests/gen_build_yaml.py b/tools/run_tests/lb_interop_tests/gen_build_yaml.py
new file mode 100755
index 0000000000..b7d655b75b
--- /dev/null
+++ b/tools/run_tests/lb_interop_tests/gen_build_yaml.py
@@ -0,0 +1,347 @@
+#!/usr/bin/env python2.7
+# Copyright 2015 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.
+"""Generates the appropriate JSON data for LB interop test scenarios."""
+
+import json
+import os
+import yaml
+
+all_scenarios = []
+
+# TODO(https://github.com/grpc/grpc-go/issues/2347): enable
+# client_falls_back_because_no_backends_* scenarios for Java/Go.
+
+# TODO(https://github.com/grpc/grpc-java/issues/4887): enable
+# *short_stream* scenarios for Java.
+
+# TODO(https://github.com/grpc/grpc-java/issues/4912): enable
+# Java TLS tests involving TLS to the balancer.
+
+
+def server_sec(transport_sec):
+ if transport_sec == 'google_default_credentials':
+ return 'alts', 'alts', 'tls'
+ return transport_sec, transport_sec, transport_sec
+
+
+def generate_no_balancer_because_lb_a_record_returns_nx_domain():
+ all_configs = []
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ config = {
+ 'name':
+ 'no_balancer_because_lb_a_record_returns_nx_domain_%s' %
+ transport_sec,
+ 'skip_langs': [],
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [],
+ 'backend_configs': [],
+ 'fallback_configs': [{
+ 'transport_sec': fallback_sec,
+ }],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_no_balancer_because_lb_a_record_returns_nx_domain()
+
+
+def generate_no_balancer_because_lb_a_record_returns_no_data():
+ all_configs = []
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ config = {
+ 'name':
+ 'no_balancer_because_lb_a_record_returns_no_data_%s' %
+ transport_sec,
+ 'skip_langs': [],
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [],
+ 'backend_configs': [],
+ 'fallback_configs': [{
+ 'transport_sec': fallback_sec,
+ }],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ True,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_no_balancer_because_lb_a_record_returns_no_data()
+
+
+def generate_client_referred_to_backend():
+ all_configs = []
+ for balancer_short_stream in [True, False]:
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = []
+ if transport_sec == 'tls':
+ skip_langs += ['java']
+ if balancer_short_stream:
+ skip_langs += ['java']
+ config = {
+ 'name':
+ 'client_referred_to_backend_%s_short_stream_%s' %
+ (transport_sec, balancer_short_stream),
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [{
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ }],
+ 'backend_configs': [{
+ 'transport_sec': backend_sec,
+ }],
+ 'fallback_configs': [],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_referred_to_backend()
+
+
+def generate_client_referred_to_backend_fallback_broken():
+ all_configs = []
+ for balancer_short_stream in [True, False]:
+ for transport_sec in ['alts', 'tls', 'google_default_credentials']:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = []
+ if transport_sec == 'tls':
+ skip_langs += ['java']
+ if balancer_short_stream:
+ skip_langs += ['java']
+ config = {
+ 'name':
+ 'client_referred_to_backend_fallback_broken_%s_short_stream_%s'
+ % (transport_sec, balancer_short_stream),
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [{
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ }],
+ 'backend_configs': [{
+ 'transport_sec': backend_sec,
+ }],
+ 'fallback_configs': [{
+ 'transport_sec': 'insecure',
+ }],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_referred_to_backend_fallback_broken()
+
+
+def generate_client_referred_to_backend_multiple_backends():
+ all_configs = []
+ for balancer_short_stream in [True, False]:
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = []
+ if transport_sec == 'tls':
+ skip_langs += ['java']
+ if balancer_short_stream:
+ skip_langs += ['java']
+ config = {
+ 'name':
+ 'client_referred_to_backend_multiple_backends_%s_short_stream_%s'
+ % (transport_sec, balancer_short_stream),
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [{
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ }],
+ 'backend_configs': [{
+ 'transport_sec': backend_sec,
+ }, {
+ 'transport_sec': backend_sec,
+ }, {
+ 'transport_sec': backend_sec,
+ }, {
+ 'transport_sec': backend_sec,
+ }, {
+ 'transport_sec': backend_sec,
+ }],
+ 'fallback_configs': [],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_referred_to_backend_multiple_backends()
+
+
+def generate_client_falls_back_because_no_backends():
+ all_configs = []
+ for balancer_short_stream in [True, False]:
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = ['go', 'java']
+ if transport_sec == 'tls':
+ skip_langs += ['java']
+ if balancer_short_stream:
+ skip_langs += ['java']
+ config = {
+ 'name':
+ 'client_falls_back_because_no_backends_%s_short_stream_%s' %
+ (transport_sec, balancer_short_stream),
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [{
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ }],
+ 'backend_configs': [],
+ 'fallback_configs': [{
+ 'transport_sec': fallback_sec,
+ }],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_falls_back_because_no_backends()
+
+
+def generate_client_falls_back_because_balancer_connection_broken():
+ all_configs = []
+ for transport_sec in ['alts', 'tls', 'google_default_credentials']:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = []
+ if transport_sec == 'tls':
+ skip_langs = ['java']
+ config = {
+ 'name':
+ 'client_falls_back_because_balancer_connection_broken_%s' %
+ transport_sec,
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [{
+ 'transport_sec': 'insecure',
+ 'short_stream': False,
+ }],
+ 'backend_configs': [],
+ 'fallback_configs': [{
+ 'transport_sec': fallback_sec,
+ }],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_falls_back_because_balancer_connection_broken()
+
+
+def generate_client_referred_to_backend_multiple_balancers():
+ all_configs = []
+ for balancer_short_stream in [True, False]:
+ for transport_sec in [
+ 'insecure', 'alts', 'tls', 'google_default_credentials'
+ ]:
+ balancer_sec, backend_sec, fallback_sec = server_sec(transport_sec)
+ skip_langs = []
+ if transport_sec == 'tls':
+ skip_langs += ['java']
+ if balancer_short_stream:
+ skip_langs += ['java']
+ config = {
+ 'name':
+ 'client_referred_to_backend_multiple_balancers_%s_short_stream_%s'
+ % (transport_sec, balancer_short_stream),
+ 'skip_langs':
+ skip_langs,
+ 'transport_sec':
+ transport_sec,
+ 'balancer_configs': [
+ {
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ },
+ {
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ },
+ {
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ },
+ {
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ },
+ {
+ 'transport_sec': balancer_sec,
+ 'short_stream': balancer_short_stream,
+ },
+ ],
+ 'backend_configs': [
+ {
+ 'transport_sec': backend_sec,
+ },
+ ],
+ 'fallback_configs': [],
+ 'cause_no_error_no_data_for_balancer_a_record':
+ False,
+ }
+ all_configs.append(config)
+ return all_configs
+
+
+all_scenarios += generate_client_referred_to_backend_multiple_balancers()
+
+print(yaml.dump({
+ 'lb_interop_test_scenarios': all_scenarios,
+}))
diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
index 35d9e90598..ab6bffdc34 100755
--- a/tools/run_tests/performance/build_performance.sh
+++ b/tools/run_tests/performance/build_performance.sh
@@ -25,10 +25,16 @@ CONFIG=${CONFIG:-opt}
# TODO(jtattermusch): C++ worker and driver are not buildable on Windows yet
if [ "$OSTYPE" != "msys" ]
then
- # TODO(jtattermusch): not embedding OpenSSL breaks the C# build because
- # grpc_csharp_ext needs OpenSSL embedded and some intermediate files from
- # this build will be reused.
- make CONFIG="${CONFIG}" EMBED_OPENSSL=true EMBED_ZLIB=true qps_worker qps_json_driver -j8
+ # build C++ with cmake as building with "make" disables boringssl assembly
+ # optimizations that can have huge impact on secure channel throughput.
+ mkdir -p cmake/build
+ cd cmake/build
+ cmake -DgRPC_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ../..
+ make qps_worker qps_json_driver -j8
+ cd ../..
+ # unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake build)
+ # See https://github.com/grpc/grpc/issues/11581
+ (cd third_party/zlib; git checkout zconf.h)
fi
PHP_ALREADY_BUILT=""
@@ -53,11 +59,18 @@ do
fi
;;
"csharp")
- python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8 --compiler coreclr
+ python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8
+ # unbreak subsequent make builds by restoring zconf.h (previously renamed by cmake portion of C#'s build)
+ # See https://github.com/grpc/grpc/issues/11581
+ (cd third_party/zlib; git checkout zconf.h)
;;
"node"|"node_purejs")
tools/run_tests/performance/build_performance_node.sh
;;
+ "python")
+ # python workers are only run with python2.7 and building with multiple python versions is costly
+ python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --compiler python2.7 --build_only -j 8
+ ;;
*)
python tools/run_tests/run_tests.py -l "$language" -c "$CONFIG" --build_only -j 8
;;
diff --git a/tools/run_tests/performance/remote_host_prepare.sh b/tools/run_tests/performance/remote_host_prepare.sh
index d69c85b40e..685c4357c9 100755
--- a/tools/run_tests/performance/remote_host_prepare.sh
+++ b/tools/run_tests/performance/remote_host_prepare.sh
@@ -38,3 +38,6 @@ ssh "${USER_AT_HOST}" "tar -xf ~/performance_workspace/grpc.tar -C ~/performance
# For consistency with local run, invoke the kill_workers script remotely.
# shellcheck disable=SC2088
ssh "${USER_AT_HOST}" "~/performance_workspace/grpc/tools/run_tests/performance/kill_workers.sh"
+
+# make sure the port server is running (required by C++ qps_worker)
+ssh "${USER_AT_HOST}" "cd ~/performance_workspace/grpc/ && python tools/run_tests/start_port_server.py"
diff --git a/tools/run_tests/performance/run_qps_driver.sh b/tools/run_tests/performance/run_qps_driver.sh
index 2d9e310dec..47a03db026 100755
--- a/tools/run_tests/performance/run_qps_driver.sh
+++ b/tools/run_tests/performance/run_qps_driver.sh
@@ -17,7 +17,7 @@ set -ex
cd "$(dirname "$0")/../../.."
-bins/opt/qps_json_driver "$@"
+cmake/build/qps_json_driver "$@"
if [ "$BQ_RESULT_TABLE" != "" ]
then
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 2e78bd07fb..481918c52e 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -231,7 +231,7 @@ class CXXLanguage:
self.safename = 'cxx'
def worker_cmdline(self):
- return ['bins/opt/qps_worker']
+ return ['cmake/build/qps_worker']
def worker_port_offset(self):
return 0
@@ -250,7 +250,7 @@ class CXXLanguage:
channels=1,
num_clients=1,
secure=False,
- categories=[SMOKETEST] + [INPROC] + [SCALABLE])
+ categories=[INPROC] + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_streaming_from_client_1channel_1MB',
@@ -280,12 +280,12 @@ class CXXLanguage:
secure=False,
async_server_threads=16,
server_threads_per_cq=1,
- categories=[SMOKETEST] + [SCALABLE])
+ categories=[SCALABLE])
for secure in [True, False]:
secstr = 'secure' if secure else 'insecure'
- smoketest_categories = ([SMOKETEST]
- if secure else [INPROC]) + [SCALABLE]
+ smoketest_categories = ([SMOKETEST] if secure else [])
+ inproc_categories = ([INPROC] if not secure else [])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_ping_pong_%s' % secstr,
@@ -295,7 +295,8 @@ class CXXLanguage:
use_generic_payload=True,
async_server_threads=1,
secure=secure,
- categories=smoketest_categories)
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_unconstrained_%s' % secstr,
@@ -306,7 +307,8 @@ class CXXLanguage:
use_generic_payload=True,
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
for mps in geometric_progression(1, 20, 10):
yield _ping_pong_scenario(
@@ -320,7 +322,8 @@ class CXXLanguage:
secure=secure,
messages_per_stream=mps,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
for mps in geometric_progression(1, 200, math.sqrt(10)):
yield _ping_pong_scenario(
@@ -347,7 +350,7 @@ class CXXLanguage:
use_generic_payload=True,
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE],
+ categories=inproc_categories + [SCALABLE],
channels=1,
outstanding=100)
@@ -363,7 +366,7 @@ class CXXLanguage:
use_generic_payload=True,
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_unconstrained_1cq_%s' % secstr,
@@ -375,7 +378,8 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=1000000,
server_threads_per_cq=1000000,
- categories=smoketest_categories + [SCALABLE])
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_%s'
@@ -388,7 +392,7 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=2,
server_threads_per_cq=2,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_streaming_qps_unconstrained_1cq_%s' %
@@ -400,7 +404,7 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=1000000,
server_threads_per_cq=1000000,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_%s'
@@ -412,7 +416,7 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=2,
server_threads_per_cq=2,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_unary_qps_unconstrained_1cq_%s' % secstr,
@@ -423,7 +427,8 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=1000000,
server_threads_per_cq=1000000,
- categories=smoketest_categories + [SCALABLE])
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_%s' %
@@ -435,7 +440,7 @@ class CXXLanguage:
secure=secure,
client_threads_per_cq=2,
server_threads_per_cq=2,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_generic_async_streaming_qps_one_server_core_%s' % secstr,
@@ -457,7 +462,8 @@ class CXXLanguage:
unconstrained_client='async',
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE],
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE],
excluded_poll_engines=['poll-cv'])
yield _ping_pong_scenario(
@@ -472,7 +478,7 @@ class CXXLanguage:
resp_size=8 * 1024 * 1024,
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_%s'
@@ -483,7 +489,8 @@ class CXXLanguage:
unconstrained_client='async',
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE],
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE],
excluded_poll_engines=['poll-cv'])
yield _ping_pong_scenario(
@@ -495,7 +502,8 @@ class CXXLanguage:
resp_size=1024 * 1024,
secure=secure,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=smoketest_categories + inproc_categories +
+ [SCALABLE])
for rpc_type in [
'unary', 'streaming', 'streaming_from_client',
@@ -538,7 +546,7 @@ class CXXLanguage:
minimal_stack=not secure,
server_threads_per_cq=3,
client_threads_per_cq=3,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
# TODO(vjpai): Re-enable this test. It has a lot of timeouts
# and hasn't yet been conclusively identified as a test failure
@@ -565,7 +573,7 @@ class CXXLanguage:
secure=secure,
messages_per_stream=mps,
minimal_stack=not secure,
- categories=smoketest_categories + [SCALABLE])
+ categories=inproc_categories + [SCALABLE])
for mps in geometric_progression(1, 200, math.sqrt(10)):
yield _ping_pong_scenario(
diff --git a/tools/run_tests/python_utils/dockerjob.py b/tools/run_tests/python_utils/dockerjob.py
index 2d22dc13a0..5260f7b44b 100755
--- a/tools/run_tests/python_utils/dockerjob.py
+++ b/tools/run_tests/python_utils/dockerjob.py
@@ -20,6 +20,7 @@ import time
import uuid
import os
import subprocess
+import json
import jobset
@@ -54,6 +55,25 @@ def docker_mapped_port(cid, port, timeout_seconds=15):
cid))
+def docker_ip_address(cid, timeout_seconds=15):
+ """Get port mapped to internal given internal port for given container."""
+ started = time.time()
+ while time.time() - started < timeout_seconds:
+ cmd = 'docker inspect %s' % cid
+ try:
+ output = subprocess.check_output(cmd, stderr=_DEVNULL, shell=True)
+ json_info = json.loads(output)
+ assert len(json_info) == 1
+ out = json_info[0]['NetworkSettings']['IPAddress']
+ if not out:
+ continue
+ return out
+ except subprocess.CalledProcessError as e:
+ pass
+ raise Exception(
+ 'Non-retryable error: Failed to get ip address of container %s.' % cid)
+
+
def wait_for_healthy(cid, shortname, timeout_seconds):
"""Wait timeout_seconds for the container to become healthy"""
started = time.time()
@@ -74,10 +94,10 @@ def wait_for_healthy(cid, shortname, timeout_seconds):
(shortname, cid))
-def finish_jobs(jobs):
+def finish_jobs(jobs, suppress_failure=True):
"""Kills given docker containers and waits for corresponding jobs to finish"""
for job in jobs:
- job.kill(suppress_failure=True)
+ job.kill(suppress_failure=suppress_failure)
while any(job.is_running() for job in jobs):
time.sleep(1)
@@ -120,6 +140,9 @@ class DockerJob:
def mapped_port(self, port):
return docker_mapped_port(self._container_name, port)
+ def ip_address(self):
+ return docker_ip_address(self._container_name)
+
def wait_for_healthy(self, timeout_seconds):
wait_for_healthy(self._container_name, self._spec.shortname,
timeout_seconds)
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 561f453da7..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
@@ -176,13 +174,15 @@ class JobSpec(object):
timeout_retries=0,
kill_handler=None,
cpu_cost=1.0,
- verbose_success=False):
+ verbose_success=False,
+ logfilename=None):
"""
Arguments:
cmdline: a list of arguments to pass as the command line
environ: a dictionary of environment variables to set in the child process
kill_handler: a handler that will be called whenever job.kill() is invoked
cpu_cost: number of cores per second this job needs
+ logfilename: use given file to store job's output, rather than using a temporary file
"""
if environ is None:
environ = {}
@@ -197,6 +197,11 @@ class JobSpec(object):
self.kill_handler = kill_handler
self.cpu_cost = cpu_cost
self.verbose_success = verbose_success
+ self.logfilename = logfilename
+ if self.logfilename and self.flake_retries != 0 and self.timeout_retries != 0:
+ # Forbidden to avoid overwriting the test log when retrying.
+ raise Exception(
+ 'Cannot use custom logfile when retries are enabled')
def identity(self):
return '%r %r' % (self.cmdline, self.environ)
@@ -261,7 +266,15 @@ class Job(object):
return self._spec
def start(self):
- self._tempfile = tempfile.TemporaryFile()
+ if self._spec.logfilename:
+ # make sure the log directory exists
+ logfile_dir = os.path.dirname(
+ os.path.abspath(self._spec.logfilename))
+ if not os.path.exists(logfile_dir):
+ os.makedirs(logfile_dir)
+ self._logfile = open(self._spec.logfilename, 'w+')
+ else:
+ self._logfile = tempfile.TemporaryFile()
env = dict(os.environ)
env.update(self._spec.environ)
env.update(self._add_env)
@@ -277,7 +290,7 @@ class Job(object):
measure_cpu_costs = False
try_start = lambda: subprocess.Popen(args=cmdline,
stderr=subprocess.STDOUT,
- stdout=self._tempfile,
+ stdout=self._logfile,
cwd=self._spec.cwd,
shell=self._spec.shell,
env=env)
@@ -300,7 +313,7 @@ class Job(object):
"""Poll current state of the job. Prints messages at completion."""
def stdout(self=self):
- stdout = read_from_start(self._tempfile)
+ stdout = read_from_start(self._logfile)
self.result.message = stdout[-_MAX_RESULT_SIZE:]
return stdout
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/upload_rbe_results.py b/tools/run_tests/python_utils/upload_rbe_results.py
index d29ebc6219..3f3bd382bb 100644
--- a/tools/run_tests/python_utils/upload_rbe_results.py
+++ b/tools/run_tests/python_utils/upload_rbe_results.py
@@ -40,13 +40,14 @@ _RESULTS_SCHEMA = [
('test_case', 'STRING', 'Name of test case'),
('result', 'STRING', 'Test or build result'),
('timestamp', 'TIMESTAMP', 'Timestamp of test run'),
+ ('duration', 'FLOAT', 'Duration of the test run'),
]
_TABLE_ID = 'rbe_test_results'
def _get_api_key():
"""Returns string with API key to access ResultStore.
- Intended to be used in Kokoro envrionment."""
+ Intended to be used in Kokoro environment."""
api_key_directory = os.getenv('KOKORO_GFILE_DIR')
api_key_file = os.path.join(api_key_directory, 'resultstore_api_key')
assert os.path.isfile(api_key_file), 'Must add --api_key arg if not on ' \
@@ -57,15 +58,25 @@ def _get_api_key():
def _get_invocation_id():
"""Returns String of Bazel invocation ID. Intended to be used in
- Kokoro envirionment."""
+ Kokoro environment."""
bazel_id_directory = os.getenv('KOKORO_ARTIFACTS_DIR')
bazel_id_file = os.path.join(bazel_id_directory, 'bazel_invocation_ids')
assert os.path.isfile(bazel_id_file), 'bazel_invocation_ids file, written ' \
- 'by bazel_wrapper.py, expected but not found.'
+ 'by RBE initialization script, expected but not found.'
with open(bazel_id_file, 'r') as f:
return f.read().replace('\n', '')
+def _parse_test_duration(duration_str):
+ """Parse test duration string in '123.567s' format"""
+ try:
+ if duration_str.endswith('s'):
+ duration_str = duration_str[:-1]
+ return float(duration_str)
+ except:
+ return None
+
+
def _upload_results_to_bq(rows):
"""Upload test results to a BQ table.
@@ -205,6 +216,8 @@ if __name__ == "__main__":
result,
'timestamp':
action['timing']['startTime'],
+ 'duration':
+ _parse_test_duration(action['timing']['duration']),
}
})
except Exception as e:
diff --git a/tools/run_tests/python_utils/upload_test_results.py b/tools/run_tests/python_utils/upload_test_results.py
index 9d99703725..0ca23f56cf 100644
--- a/tools/run_tests/python_utils/upload_test_results.py
+++ b/tools/run_tests/python_utils/upload_test_results.py
@@ -104,14 +104,13 @@ def _insert_rows_with_retries(bq, bq_table, bq_rows):
sys.exit(1)
-def upload_results_to_bq(resultset, bq_table, args, platform):
+def upload_results_to_bq(resultset, bq_table, extra_fields):
"""Upload test results to a BQ table.
Args:
resultset: dictionary generated by jobset.run
bq_table: string name of table to create/upload results to in BQ
- args: args in run_tests.py, generated by argparse
- platform: string name of platform tests were run on
+ extra_fields: dict with extra values that will be uploaded along with the results
"""
bq = big_query_utils.create_big_query()
big_query_utils.create_partitioned_table(
@@ -129,32 +128,26 @@ def upload_results_to_bq(resultset, bq_table, args, platform):
for result in results:
test_results = {}
_get_build_metadata(test_results)
- test_results['compiler'] = args.compiler
- test_results['config'] = args.config
test_results['cpu_estimated'] = result.cpu_estimated
test_results['cpu_measured'] = result.cpu_measured
test_results['elapsed_time'] = '%.2f' % result.elapsed_time
- test_results['iomgr_platform'] = args.iomgr_platform
- # args.language is a list, but will always have one element in the contexts
- # this function is used.
- test_results['language'] = args.language[0]
- test_results['platform'] = platform
test_results['result'] = result.state
test_results['return_code'] = result.returncode
test_results['test_name'] = shortname
test_results['timestamp'] = time.strftime('%Y-%m-%d %H:%M:%S')
+ for field_name, field_value in six.iteritems(extra_fields):
+ test_results[field_name] = field_value
row = big_query_utils.make_row(str(uuid.uuid4()), test_results)
bq_rows.append(row)
_insert_rows_with_retries(bq, bq_table, bq_rows)
-def upload_interop_results_to_bq(resultset, bq_table, args):
+def upload_interop_results_to_bq(resultset, bq_table):
"""Upload interop test results to a BQ table.
Args:
resultset: dictionary generated by jobset.run
bq_table: string name of table to create/upload results to in BQ
- args: args in run_interop_tests.py, generated by argparse
"""
bq = big_query_utils.create_big_query()
big_query_utils.create_partitioned_table(
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_grpclb_interop_tests.py b/tools/run_tests/run_grpclb_interop_tests.py
new file mode 100755
index 0000000000..3bfbcecf06
--- /dev/null
+++ b/tools/run_tests/run_grpclb_interop_tests.py
@@ -0,0 +1,609 @@
+#!/usr/bin/env python
+# Copyright 2015 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.
+"""Run interop (cross-language) tests in parallel."""
+
+from __future__ import print_function
+
+import argparse
+import atexit
+import itertools
+import json
+import multiprocessing
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import time
+import uuid
+import six
+import traceback
+
+import python_utils.dockerjob as dockerjob
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
+
+# Docker doesn't clean up after itself, so we do it on exit.
+atexit.register(lambda: subprocess.call(['stty', 'echo']))
+
+ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
+os.chdir(ROOT)
+
+_FALLBACK_SERVER_PORT = 443
+_BALANCER_SERVER_PORT = 12000
+_BACKEND_SERVER_PORT = 8080
+
+_TEST_TIMEOUT = 30
+
+_FAKE_SERVERS_SAFENAME = 'fake_servers'
+
+# Use a name that's verified by the test certs
+_SERVICE_NAME = 'server.test.google.fr'
+
+
+class CXXLanguage:
+
+ def __init__(self):
+ self.client_cwd = '/var/local/git/grpc'
+ self.safename = 'cxx'
+
+ def client_cmd(self, args):
+ return ['bins/opt/interop_client'] + args
+
+ def global_env(self):
+ # 1) Set c-ares as the resolver, to
+ # enable grpclb.
+ # 2) Turn on verbose logging.
+ # 3) Set the ROOTS_PATH env variable
+ # to the test CA in order for
+ # GoogleDefaultCredentials to be
+ # able to use the test CA.
+ return {
+ 'GRPC_DNS_RESOLVER':
+ 'ares',
+ 'GRPC_VERBOSITY':
+ 'DEBUG',
+ 'GRPC_TRACE':
+ 'client_channel,glb',
+ 'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
+ '/var/local/git/grpc/src/core/tsi/test_creds/ca.pem',
+ }
+
+ def __str__(self):
+ return 'c++'
+
+
+class JavaLanguage:
+
+ def __init__(self):
+ self.client_cwd = '/var/local/git/grpc-java'
+ self.safename = str(self)
+
+ def client_cmd(self, args):
+ # Take necessary steps to import our test CA into
+ # the set of test CA's that the Java runtime of the
+ # docker container will pick up, so that
+ # Java GoogleDefaultCreds can use it.
+ pem_to_der_cmd = ('openssl x509 -outform der '
+ '-in /external_mount/src/core/tsi/test_creds/ca.pem '
+ '-out /tmp/test_ca.der')
+ keystore_import_cmd = (
+ 'keytool -import '
+ '-keystore /usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts '
+ '-file /tmp/test_ca.der '
+ '-deststorepass changeit '
+ '-noprompt')
+ return [
+ 'bash', '-c', ('{pem_to_der_cmd} && '
+ '{keystore_import_cmd} && '
+ './run-test-client.sh {java_client_args}').format(
+ pem_to_der_cmd=pem_to_der_cmd,
+ keystore_import_cmd=keystore_import_cmd,
+ java_client_args=' '.join(args))
+ ]
+
+ def global_env(self):
+ # 1) Enable grpclb
+ # 2) Enable verbose logging
+ return {
+ 'JAVA_OPTS':
+ ('-Dio.grpc.internal.DnsNameResolverProvider.enable_grpclb=true '
+ '-Djava.util.logging.config.file=/var/local/grpc_java_logging/logconf.txt'
+ )
+ }
+
+ def __str__(self):
+ return 'java'
+
+
+class GoLanguage:
+
+ def __init__(self):
+ self.client_cwd = '/go/src/google.golang.org/grpc/interop/client'
+ self.safename = str(self)
+
+ def client_cmd(self, args):
+ # Copy the test CA file into the path that
+ # the Go runtime in the docker container will use, so
+ # that Go's GoogleDefaultCredentials can use it.
+ # See https://golang.org/src/crypto/x509/root_linux.go.
+ return [
+ 'bash', '-c', ('cp /external_mount/src/core/tsi/test_creds/ca.pem '
+ '/etc/ssl/certs/ca-certificates.crt && '
+ '/go/bin/client {go_client_args}'
+ ).format(go_client_args=' '.join(args))
+ ]
+
+ def global_env(self):
+ return {
+ 'GRPC_GO_LOG_VERBOSITY_LEVEL': '3',
+ 'GRPC_GO_LOG_SEVERITY_LEVEL': 'INFO'
+ }
+
+ def __str__(self):
+ return 'go'
+
+
+_LANGUAGES = {
+ 'c++': CXXLanguage(),
+ 'go': GoLanguage(),
+ 'java': JavaLanguage(),
+}
+
+
+def docker_run_cmdline(cmdline, image, docker_args, cwd, environ=None):
+ """Wraps given cmdline array to create 'docker run' cmdline from it."""
+ # turn environ into -e docker args
+ docker_cmdline = 'docker run -i --rm=true'.split()
+ if environ:
+ for k, v in environ.items():
+ docker_cmdline += ['-e', '%s=%s' % (k, v)]
+ return docker_cmdline + ['-w', cwd] + docker_args + [image] + cmdline
+
+
+def _job_kill_handler(job):
+ assert job._spec.container_name
+ dockerjob.docker_kill(job._spec.container_name)
+
+
+def transport_security_to_args(transport_security):
+ args = []
+ if transport_security == 'tls':
+ args += ['--use_tls=true']
+ elif transport_security == 'alts':
+ args += ['--use_tls=false', '--use_alts=true']
+ elif transport_security == 'insecure':
+ args += ['--use_tls=false']
+ elif transport_security == 'google_default_credentials':
+ args += ['--custom_credentials_type=google_default_credentials']
+ else:
+ print('Invalid transport security option.')
+ sys.exit(1)
+ return args
+
+
+def lb_client_interop_jobspec(language,
+ dns_server_ip,
+ docker_image,
+ transport_security='tls'):
+ """Runs a gRPC client under test in a docker container"""
+ interop_only_options = [
+ '--server_host=%s' % _SERVICE_NAME,
+ '--server_port=%d' % _FALLBACK_SERVER_PORT
+ ] + transport_security_to_args(transport_security)
+ # Don't set the server host override in any client;
+ # Go and Java default to no override.
+ # We're using a DNS server so there's no need.
+ if language.safename == 'c++':
+ interop_only_options += ['--server_host_override=""']
+ # Don't set --use_test_ca; we're configuring
+ # clients to use test CA's via alternate means.
+ interop_only_options += ['--use_test_ca=false']
+ client_args = language.client_cmd(interop_only_options)
+ container_name = dockerjob.random_name(
+ 'lb_interop_client_%s' % language.safename)
+ docker_cmdline = docker_run_cmdline(
+ client_args,
+ environ=language.global_env(),
+ image=docker_image,
+ cwd=language.client_cwd,
+ docker_args=[
+ '--dns=%s' % dns_server_ip,
+ '--net=host',
+ '--name=%s' % container_name,
+ '-v',
+ '{grpc_grpc_root_dir}:/external_mount:ro'.format(
+ grpc_grpc_root_dir=ROOT),
+ ])
+ jobset.message(
+ 'IDLE',
+ 'docker_cmdline:\b|%s|' % ' '.join(docker_cmdline),
+ do_newline=True)
+ test_job = jobset.JobSpec(
+ cmdline=docker_cmdline,
+ shortname=('lb_interop_client:%s' % language),
+ timeout_seconds=_TEST_TIMEOUT,
+ kill_handler=_job_kill_handler)
+ test_job.container_name = container_name
+ return test_job
+
+
+def fallback_server_jobspec(transport_security, shortname):
+ """Create jobspec for running a fallback server"""
+ cmdline = [
+ 'bin/server',
+ '--port=%d' % _FALLBACK_SERVER_PORT,
+ ] + transport_security_to_args(transport_security)
+ return grpc_server_in_docker_jobspec(
+ server_cmdline=cmdline, shortname=shortname)
+
+
+def backend_server_jobspec(transport_security, shortname):
+ """Create jobspec for running a backend server"""
+ cmdline = [
+ 'bin/server',
+ '--port=%d' % _BACKEND_SERVER_PORT,
+ ] + transport_security_to_args(transport_security)
+ return grpc_server_in_docker_jobspec(
+ server_cmdline=cmdline, shortname=shortname)
+
+
+def grpclb_jobspec(transport_security, short_stream, backend_addrs, shortname):
+ """Create jobspec for running a balancer server"""
+ cmdline = [
+ 'bin/fake_grpclb',
+ '--backend_addrs=%s' % ','.join(backend_addrs),
+ '--port=%d' % _BALANCER_SERVER_PORT,
+ '--short_stream=%s' % short_stream,
+ '--service_name=%s' % _SERVICE_NAME,
+ ] + transport_security_to_args(transport_security)
+ return grpc_server_in_docker_jobspec(
+ server_cmdline=cmdline, shortname=shortname)
+
+
+def grpc_server_in_docker_jobspec(server_cmdline, shortname):
+ container_name = dockerjob.random_name(shortname)
+ environ = {
+ 'GRPC_GO_LOG_VERBOSITY_LEVEL': '3',
+ 'GRPC_GO_LOG_SEVERITY_LEVEL': 'INFO ',
+ }
+ docker_cmdline = docker_run_cmdline(
+ server_cmdline,
+ cwd='/go',
+ image=docker_images.get(_FAKE_SERVERS_SAFENAME),
+ environ=environ,
+ docker_args=['--name=%s' % container_name])
+ jobset.message(
+ 'IDLE',
+ 'docker_cmdline:\b|%s|' % ' '.join(docker_cmdline),
+ do_newline=True)
+ server_job = jobset.JobSpec(
+ cmdline=docker_cmdline, shortname=shortname, timeout_seconds=30 * 60)
+ server_job.container_name = container_name
+ return server_job
+
+
+def dns_server_in_docker_jobspec(grpclb_ips, fallback_ips, shortname,
+ cause_no_error_no_data_for_balancer_a_record):
+ container_name = dockerjob.random_name(shortname)
+ run_dns_server_cmdline = [
+ 'python',
+ 'test/cpp/naming/utils/run_dns_server_for_lb_interop_tests.py',
+ '--grpclb_ips=%s' % ','.join(grpclb_ips),
+ '--fallback_ips=%s' % ','.join(fallback_ips),
+ ]
+ if cause_no_error_no_data_for_balancer_a_record:
+ run_dns_server_cmdline.append(
+ '--cause_no_error_no_data_for_balancer_a_record')
+ docker_cmdline = docker_run_cmdline(
+ run_dns_server_cmdline,
+ cwd='/var/local/git/grpc',
+ image=docker_images.get(_FAKE_SERVERS_SAFENAME),
+ docker_args=['--name=%s' % container_name])
+ jobset.message(
+ 'IDLE',
+ 'docker_cmdline:\b|%s|' % ' '.join(docker_cmdline),
+ do_newline=True)
+ server_job = jobset.JobSpec(
+ cmdline=docker_cmdline, shortname=shortname, timeout_seconds=30 * 60)
+ server_job.container_name = container_name
+ return server_job
+
+
+def build_interop_image_jobspec(lang_safename, basename_prefix='grpc_interop'):
+ """Creates jobspec for building interop docker image for a language"""
+ tag = '%s_%s:%s' % (basename_prefix, lang_safename, uuid.uuid4())
+ env = {
+ 'INTEROP_IMAGE': tag,
+ 'BASE_NAME': '%s_%s' % (basename_prefix, lang_safename),
+ }
+ build_job = jobset.JobSpec(
+ cmdline=['tools/run_tests/dockerize/build_interop_image.sh'],
+ environ=env,
+ shortname='build_docker_%s' % lang_safename,
+ timeout_seconds=30 * 60)
+ build_job.tag = tag
+ return build_job
+
+
+argp = argparse.ArgumentParser(description='Run interop tests.')
+argp.add_argument(
+ '-l',
+ '--language',
+ choices=['all'] + sorted(_LANGUAGES),
+ nargs='+',
+ default=['all'],
+ help='Clients to run.')
+argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
+argp.add_argument(
+ '-s',
+ '--scenarios_file',
+ default=None,
+ type=str,
+ help='File containing test scenarios as JSON configs.')
+argp.add_argument(
+ '-n',
+ '--scenario_name',
+ default=None,
+ type=str,
+ help=(
+ 'Useful for manual runs: specify the name of '
+ 'the scenario to run from scenarios_file. Run all scenarios if unset.'))
+argp.add_argument(
+ '--cxx_image_tag',
+ default=None,
+ type=str,
+ help=('Setting this skips the clients docker image '
+ 'build step and runs the client from the named '
+ 'image. Only supports running a one client language.'))
+argp.add_argument(
+ '--go_image_tag',
+ default=None,
+ type=str,
+ help=('Setting this skips the clients docker image build '
+ 'step and runs the client from the named image. Only '
+ 'supports running a one client language.'))
+argp.add_argument(
+ '--java_image_tag',
+ default=None,
+ type=str,
+ help=('Setting this skips the clients docker image build '
+ 'step and runs the client from the named image. Only '
+ 'supports running a one client language.'))
+argp.add_argument(
+ '--servers_image_tag',
+ default=None,
+ type=str,
+ help=('Setting this skips the fake servers docker image '
+ 'build step and runs the servers from the named image.'))
+argp.add_argument(
+ '--no_skips',
+ default=False,
+ type=bool,
+ nargs='?',
+ const=True,
+ help=('Useful for manual runs. Setting this overrides test '
+ '"skips" configured in test scenarios.'))
+argp.add_argument(
+ '--verbose',
+ default=False,
+ type=bool,
+ nargs='?',
+ const=True,
+ help='Increase logging.')
+args = argp.parse_args()
+
+docker_images = {}
+
+build_jobs = []
+if len(args.language) and args.language[0] == 'all':
+ languages = _LANGUAGES.keys()
+else:
+ languages = args.language
+for lang_name in languages:
+ l = _LANGUAGES[lang_name]
+ # First check if a pre-built image was supplied, and avoid
+ # rebuilding the particular docker image if so.
+ if lang_name == 'c++' and args.cxx_image_tag:
+ docker_images[str(l.safename)] = args.cxx_image_tag
+ elif lang_name == 'go' and args.go_image_tag:
+ docker_images[str(l.safename)] = args.go_image_tag
+ elif lang_name == 'java' and args.java_image_tag:
+ docker_images[str(l.safename)] = args.java_image_tag
+ else:
+ # Build the test client in docker and save the fully
+ # built image.
+ job = build_interop_image_jobspec(l.safename)
+ build_jobs.append(job)
+ docker_images[str(l.safename)] = job.tag
+
+# First check if a pre-built image was supplied.
+if args.servers_image_tag:
+ docker_images[_FAKE_SERVERS_SAFENAME] = args.servers_image_tag
+else:
+ # Build the test servers in docker and save the fully
+ # built image.
+ job = build_interop_image_jobspec(
+ _FAKE_SERVERS_SAFENAME, basename_prefix='lb_interop')
+ build_jobs.append(job)
+ docker_images[_FAKE_SERVERS_SAFENAME] = job.tag
+
+if build_jobs:
+ jobset.message('START', 'Building interop docker images.', do_newline=True)
+ print('Jobs to run: \n%s\n' % '\n'.join(str(j) for j in build_jobs))
+ num_failures, _ = jobset.run(
+ build_jobs, newline_on_success=True, maxjobs=args.jobs)
+ if num_failures == 0:
+ jobset.message(
+ 'SUCCESS', 'All docker images built successfully.', do_newline=True)
+ else:
+ jobset.message(
+ 'FAILED', 'Failed to build interop docker images.', do_newline=True)
+ sys.exit(1)
+
+
+def wait_until_dns_server_is_up(dns_server_ip):
+ """Probes the DNS server until it's running and safe for tests."""
+ for i in range(0, 30):
+ print('Health check: attempt to connect to DNS server over TCP.')
+ tcp_connect_subprocess = subprocess.Popen([
+ os.path.join(os.getcwd(), 'test/cpp/naming/utils/tcp_connect.py'),
+ '--server_host', dns_server_ip, '--server_port',
+ str(53), '--timeout',
+ str(1)
+ ])
+ tcp_connect_subprocess.communicate()
+ if tcp_connect_subprocess.returncode == 0:
+ print(('Health check: attempt to make an A-record '
+ 'query to DNS server.'))
+ dns_resolver_subprocess = subprocess.Popen(
+ [
+ os.path.join(os.getcwd(),
+ 'test/cpp/naming/utils/dns_resolver.py'),
+ '--qname', ('health-check-local-dns-server-is-alive.'
+ 'resolver-tests.grpctestingexp'),
+ '--server_host', dns_server_ip, '--server_port',
+ str(53)
+ ],
+ stdout=subprocess.PIPE)
+ dns_resolver_stdout, _ = dns_resolver_subprocess.communicate()
+ if dns_resolver_subprocess.returncode == 0:
+ if '123.123.123.123' in dns_resolver_stdout:
+ print(('DNS server is up! '
+ 'Successfully reached it over UDP and TCP.'))
+ return
+ time.sleep(0.1)
+ raise Exception(('Failed to reach DNS server over TCP and/or UDP. '
+ 'Exitting without running tests.'))
+
+
+def shortname(shortname_prefix, shortname, index):
+ return '%s_%s_%d' % (shortname_prefix, shortname, index)
+
+
+def run_one_scenario(scenario_config):
+ jobset.message('START', 'Run scenario: %s' % scenario_config['name'])
+ server_jobs = {}
+ server_addresses = {}
+ suppress_server_logs = True
+ try:
+ backend_addrs = []
+ fallback_ips = []
+ grpclb_ips = []
+ shortname_prefix = scenario_config['name']
+ # Start backends
+ for i in xrange(len(scenario_config['backend_configs'])):
+ backend_config = scenario_config['backend_configs'][i]
+ backend_shortname = shortname(shortname_prefix, 'backend_server', i)
+ backend_spec = backend_server_jobspec(
+ backend_config['transport_sec'], backend_shortname)
+ backend_job = dockerjob.DockerJob(backend_spec)
+ server_jobs[backend_shortname] = backend_job
+ backend_addrs.append('%s:%d' % (backend_job.ip_address(),
+ _BACKEND_SERVER_PORT))
+ # Start fallbacks
+ for i in xrange(len(scenario_config['fallback_configs'])):
+ fallback_config = scenario_config['fallback_configs'][i]
+ fallback_shortname = shortname(shortname_prefix, 'fallback_server',
+ i)
+ fallback_spec = fallback_server_jobspec(
+ fallback_config['transport_sec'], fallback_shortname)
+ fallback_job = dockerjob.DockerJob(fallback_spec)
+ server_jobs[fallback_shortname] = fallback_job
+ fallback_ips.append(fallback_job.ip_address())
+ # Start balancers
+ for i in xrange(len(scenario_config['balancer_configs'])):
+ balancer_config = scenario_config['balancer_configs'][i]
+ grpclb_shortname = shortname(shortname_prefix, 'grpclb_server', i)
+ grpclb_spec = grpclb_jobspec(balancer_config['transport_sec'],
+ balancer_config['short_stream'],
+ backend_addrs, grpclb_shortname)
+ grpclb_job = dockerjob.DockerJob(grpclb_spec)
+ server_jobs[grpclb_shortname] = grpclb_job
+ grpclb_ips.append(grpclb_job.ip_address())
+ # Start DNS server
+ dns_server_shortname = shortname(shortname_prefix, 'dns_server', 0)
+ dns_server_spec = dns_server_in_docker_jobspec(
+ grpclb_ips, fallback_ips, dns_server_shortname,
+ scenario_config['cause_no_error_no_data_for_balancer_a_record'])
+ dns_server_job = dockerjob.DockerJob(dns_server_spec)
+ server_jobs[dns_server_shortname] = dns_server_job
+ # Get the IP address of the docker container running the DNS server.
+ # The DNS server is running on port 53 of that IP address. Note we will
+ # point the DNS resolvers of grpc clients under test to our controlled
+ # DNS server by effectively modifying the /etc/resolve.conf "nameserver"
+ # lists of their docker containers.
+ dns_server_ip = dns_server_job.ip_address()
+ wait_until_dns_server_is_up(dns_server_ip)
+ # Run clients
+ jobs = []
+ for lang_name in languages:
+ # Skip languages that are known to not currently
+ # work for this test.
+ if not args.no_skips and lang_name in scenario_config.get(
+ 'skip_langs', []):
+ jobset.message('IDLE',
+ 'Skipping scenario: %s for language: %s\n' %
+ (scenario_config['name'], lang_name))
+ continue
+ lang = _LANGUAGES[lang_name]
+ test_job = lb_client_interop_jobspec(
+ lang,
+ dns_server_ip,
+ docker_image=docker_images.get(lang.safename),
+ transport_security=scenario_config['transport_sec'])
+ jobs.append(test_job)
+ jobset.message('IDLE', 'Jobs to run: \n%s\n' % '\n'.join(
+ str(job) for job in jobs))
+ num_failures, resultset = jobset.run(
+ jobs, newline_on_success=True, maxjobs=args.jobs)
+ report_utils.render_junit_xml_report(resultset, 'sponge_log.xml')
+ if num_failures:
+ suppress_server_logs = False
+ jobset.message(
+ 'FAILED',
+ 'Scenario: %s. Some tests failed' % scenario_config['name'],
+ do_newline=True)
+ else:
+ jobset.message(
+ 'SUCCESS',
+ 'Scenario: %s. All tests passed' % scenario_config['name'],
+ do_newline=True)
+ return num_failures
+ finally:
+ # Check if servers are still running.
+ for server, job in server_jobs.items():
+ if not job.is_running():
+ print('Server "%s" has exited prematurely.' % server)
+ suppress_failure = suppress_server_logs and not args.verbose
+ dockerjob.finish_jobs(
+ [j for j in six.itervalues(server_jobs)],
+ suppress_failure=suppress_failure)
+
+
+num_failures = 0
+with open(args.scenarios_file, 'r') as scenarios_input:
+ all_scenarios = json.loads(scenarios_input.read())
+ for scenario in all_scenarios:
+ if args.scenario_name:
+ if args.scenario_name != scenario['name']:
+ jobset.message('IDLE',
+ 'Skipping scenario: %s' % scenario['name'])
+ continue
+ num_failures += run_one_scenario(scenario)
+if num_failures == 0:
+ sys.exit(0)
+else:
+ sys.exit(1)
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 22055d58e8..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 = [
@@ -688,6 +688,10 @@ def write_cmdlog_maybe(cmdlog, filename):
if cmdlog:
with open(filename, 'w') as logfile:
logfile.write('#!/bin/bash\n')
+ logfile.write('# DO NOT MODIFY\n')
+ logfile.write(
+ '# This file is generated by run_interop_tests.py/create_testcases.sh\n'
+ )
logfile.writelines("%s\n" % line for line in cmdlog)
print('Command log written to file %s' % filename)
@@ -776,13 +780,15 @@ def cloud_to_prod_jobspec(language,
'--test_case=%s' % test_case
]
if transport_security == 'tls':
- transport_security_options += ['--use_tls=true']
- elif transport_security == 'google_default_credentials' and language == 'c++':
- transport_security_options += [
+ transport_security_options = ['--use_tls=true']
+ elif transport_security == 'google_default_credentials' and str(
+ language) in ['c++', 'go', 'java', 'javaokhttp']:
+ transport_security_options = [
'--custom_credentials_type=google_default_credentials'
]
else:
- print('Invalid transport security option.')
+ print('Invalid transport security option %s in cloud_to_prod_jobspec.' %
+ transport_security)
sys.exit(1)
cmdargs = cmdargs + transport_security_options
environ = dict(language.cloud_to_prod_env(), **language.global_env())
@@ -817,8 +823,9 @@ def cloud_to_prod_jobspec(language,
cmdline=cmdline,
cwd=cwd,
environ=environ,
- shortname='%s:%s:%s:%s' % (suite_name, language, server_host_nickname,
- test_case),
+ shortname='%s:%s:%s:%s:%s' %
+ (suite_name, language, server_host_nickname, test_case,
+ transport_security),
timeout_seconds=_TEST_TIMEOUT,
flake_retries=4 if args.allow_flakes else 0,
timeout_retries=2 if args.allow_flakes else 0,
@@ -848,7 +855,8 @@ def cloud_to_cloud_jobspec(language,
elif transport_security == 'insecure':
interop_only_options += ['--use_tls=false']
else:
- print('Invalid transport security option.')
+ print('Invalid transport security option %s in cloud_to_cloud_jobspec.'
+ % transport_security)
sys.exit(1)
client_test_case = test_case
@@ -903,8 +911,8 @@ def cloud_to_cloud_jobspec(language,
cmdline=cmdline,
cwd=cwd,
environ=environ,
- shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
- test_case),
+ shortname='cloud_to_cloud:%s:%s_server:%s:%s' %
+ (language, server_name, test_case, transport_security),
timeout_seconds=_TEST_TIMEOUT,
flake_retries=4 if args.allow_flakes else 0,
timeout_retries=2 if args.allow_flakes else 0,
@@ -929,7 +937,8 @@ def server_jobspec(language,
elif transport_security == 'insecure':
server_cmd += ['--use_tls=false']
else:
- print('Invalid transport security option.')
+ print('Invalid transport security option %s in server_jobspec.' %
+ transport_security)
sys.exit(1)
cmdline = bash_cmdline(language.server_cmd(server_cmd))
environ = language.global_env()
@@ -1152,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='',
@@ -1242,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',
@@ -1306,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,
@@ -1318,7 +1332,9 @@ try:
service_account_key_file,
transport_security='tls')
jobs.append(tls_test_job)
- if language == 'c++':
+ if str(language) in [
+ 'c++', 'go', 'java', 'javaokhttp'
+ ]:
google_default_creds_test_job = cloud_to_prod_jobspec(
language,
test_case,
@@ -1370,7 +1386,9 @@ try:
service_account_key_file,
transport_security='tls')
jobs.append(tls_test_job)
- if language == 'c++':
+ if str(language) in [
+ 'go'
+ ]: # Add more languages to the list to turn on tests.
google_default_creds_test_job = cloud_to_prod_jobspec(
language,
test_case,
@@ -1378,6 +1396,7 @@ try:
prod_servers[server_host_nickname],
docker_image=docker_images.get(
str(language)),
+ auth=True,
manual_cmd_log=client_manual_cmd_log,
service_account_key_file=args.
service_account_key_file,
@@ -1494,7 +1513,7 @@ try:
maxjobs=args.jobs,
skip_jobs=args.manual_run)
if args.bq_result_table and resultset:
- upload_interop_results_to_bq(resultset, args.bq_result_table, args)
+ upload_interop_results_to_bq(resultset, args.bq_result_table)
if num_failures:
jobset.message('FAILED', 'Some tests failed', do_newline=True)
else:
@@ -1503,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:
@@ -1519,9 +1535,6 @@ try:
sys.exit(1)
else:
sys.exit(0)
-except Exception as e:
- print('exception occurred:')
- traceback.print_exc(file=sys.stdout)
finally:
# Check if servers are still running.
for server, job in server_jobs.items():
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index 04e706fa5b..c6e67eaf56 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -41,6 +41,11 @@ os.chdir(_ROOT)
_REMOTE_HOST_USERNAME = 'jenkins'
+_SCENARIO_TIMEOUT = 3 * 60
+_WORKER_TIMEOUT = 3 * 60
+_NETPERF_TIMEOUT = 60
+_QUIT_WORKER_TIMEOUT = 2 * 60
+
class QpsWorkerJob:
"""Encapsulates a qps worker server job."""
@@ -85,15 +90,14 @@ def create_qpsworker_job(language,
cmdline = perf_cmd + ['-o', '%s-perf.data' % perf_file_base_name
] + cmdline
- worker_timeout = 3 * 60
+ worker_timeout = _WORKER_TIMEOUT
if remote_host:
user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
ssh_cmd = ['ssh']
cmdline = ['timeout', '%s' % (worker_timeout + 30)] + cmdline
ssh_cmd.extend([
str(user_at_host),
- 'cd ~/performance_workspace/grpc/ && python tools/run_tests/start_port_server.py && %s'
- % ' '.join(cmdline)
+ 'cd ~/performance_workspace/grpc/ && %s' % ' '.join(cmdline)
])
cmdline = ssh_cmd
@@ -132,7 +136,7 @@ def create_scenario_jobspec(scenario_json,
return jobset.JobSpec(
cmdline=[cmd],
shortname='qps_json_driver.%s' % scenario_json['name'],
- timeout_seconds=12 * 60,
+ timeout_seconds=_SCENARIO_TIMEOUT,
shell=True,
verbose_success=True)
@@ -140,7 +144,7 @@ def create_scenario_jobspec(scenario_json,
def create_quit_jobspec(workers, remote_host=None):
"""Runs quit using QPS driver."""
# setting QPS_WORKERS env variable here makes sure it works with SSH too.
- cmd = 'QPS_WORKERS="%s" bins/opt/qps_json_driver --quit' % ','.join(
+ cmd = 'QPS_WORKERS="%s" cmake/build/qps_json_driver --quit' % ','.join(
w.host_and_port for w in workers)
if remote_host:
user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
@@ -150,7 +154,7 @@ def create_quit_jobspec(workers, remote_host=None):
return jobset.JobSpec(
cmdline=[cmd],
shortname='qps_json_driver.quit',
- timeout_seconds=3 * 60,
+ timeout_seconds=_QUIT_WORKER_TIMEOUT,
shell=True,
verbose_success=True)
@@ -182,7 +186,7 @@ def create_netperf_jobspec(server_host='localhost',
return jobset.JobSpec(
cmdline=[cmd],
shortname='netperf',
- timeout_seconds=60,
+ timeout_seconds=_NETPERF_TIMEOUT,
shell=True,
verbose_success=True)
@@ -270,6 +274,12 @@ def build_on_remote_hosts(hosts,
'CONFIG': 'opt'},
timeout_seconds=build_timeout))
if build_local:
+ # start port server locally
+ build_jobs.append(
+ jobset.JobSpec(
+ cmdline=['python', 'tools/run_tests/start_port_server.py'],
+ shortname='local_start_port_server',
+ timeout_seconds=2 * 60))
# Build locally as well
build_jobs.append(
jobset.JobSpec(
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index e04b13b24c..a1f2aaab2f 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -61,7 +61,7 @@ _FORCE_ENVIRON_FOR_WRAPPERS = {
}
_POLLING_STRATEGIES = {
- 'linux': ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv'],
+ 'linux': ['epollex', 'epoll1', 'poll', 'poll-cv'],
'mac': ['poll'],
}
@@ -759,12 +759,16 @@ class PythonLanguage(object):
self.python_manager_name(), _docker_arch_suffix(self.args.arch))
def python_manager_name(self):
- if self.args.compiler in ['python3.5', 'python3.6']:
- return 'pyenv'
+ if self.args.compiler in [
+ 'python2.7', 'python3.5', 'python3.6', 'python3.7'
+ ]:
+ return 'stretch_' + self.args.compiler[len('python'):]
elif self.args.compiler == 'python_alpine':
return 'alpine'
- else:
+ elif self.args.compiler == 'python3.4':
return 'jessie'
+ else:
+ return 'stretch_3.7'
def _get_pythons(self, args):
if args.arch == 'x86':
@@ -825,6 +829,12 @@ class PythonLanguage(object):
minor='6',
bits=bits,
config_vars=config_vars)
+ python37_config = _python_config_generator(
+ name='py37',
+ major='3',
+ minor='7',
+ bits=bits,
+ config_vars=config_vars)
pypy27_config = _pypy_config_generator(
name='pypy', major='2', config_vars=config_vars)
pypy32_config = _pypy_config_generator(
@@ -836,7 +846,7 @@ class PythonLanguage(object):
else:
return (
python27_config,
- python34_config,
+ python37_config,
)
elif args.compiler == 'python2.7':
return (python27_config,)
@@ -846,6 +856,8 @@ class PythonLanguage(object):
return (python35_config,)
elif args.compiler == 'python3.6':
return (python36_config,)
+ elif args.compiler == 'python3.7':
+ return (python37_config,)
elif args.compiler == 'pypy':
return (pypy27_config,)
elif args.compiler == 'pypy3':
@@ -858,6 +870,7 @@ class PythonLanguage(object):
python34_config,
python35_config,
python36_config,
+ python37_config,
)
else:
raise Exception('Compiler %s not supported.' % args.compiler)
@@ -922,20 +935,13 @@ class CSharpLanguage(object):
self.config = config
self.args = args
if self.platform == 'windows':
- _check_compiler(self.args.compiler, ['coreclr', 'default'])
+ _check_compiler(self.args.compiler, ['default', 'coreclr'])
_check_arch(self.args.arch, ['default'])
self._cmake_arch_option = 'x64'
- self._make_options = []
else:
_check_compiler(self.args.compiler, ['default', 'coreclr'])
self._docker_distro = 'jessie'
- if self.platform == 'mac':
- # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
- self._make_options = ['EMBED_OPENSSL=true']
- else:
- self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
-
def test_specs(self):
with open('src/csharp/tests.json') as f:
tests_by_assembly = json.load(f)
@@ -1010,7 +1016,7 @@ class CSharpLanguage(object):
return ['grpc_csharp_ext']
def make_options(self):
- return self._make_options
+ return []
def build_steps(self):
if self.platform == 'windows':
@@ -1028,7 +1034,9 @@ class CSharpLanguage(object):
if self.platform == 'windows':
return 'cmake/build/%s/Makefile' % self._cmake_arch_option
else:
- return 'Makefile'
+ # no need to set x86 specific flags as run_tests.py
+ # currently forbids x86 C# builds on both Linux and MacOS.
+ return 'cmake/build/Makefile'
def dockerfile_dir(self):
return 'tools/dockerfile/test/csharp_%s_%s' % (
@@ -1365,9 +1373,9 @@ argp.add_argument(
choices=[
'default', 'gcc4.4', 'gcc4.6', 'gcc4.8', 'gcc4.9', 'gcc5.3', 'gcc7.2',
'gcc_musl', 'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7', 'clang7.0',
- 'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3',
- 'python_alpine', 'all_the_cpythons', 'electron1.3', 'electron1.6',
- 'coreclr', 'cmake', 'cmake_vs2015', 'cmake_vs2017'
+ 'python2.7', 'python3.4', 'python3.5', 'python3.6', 'python3.7', 'pypy',
+ 'pypy3', 'python_alpine', 'all_the_cpythons', 'electron1.3',
+ 'electron1.6', 'coreclr', 'cmake', 'cmake_vs2015', 'cmake_vs2017'
],
default='default',
help=
@@ -1430,7 +1438,7 @@ argp.add_argument(
default=None,
type=str,
help='Only use the specified comma-delimited list of polling engines. '
- 'Example: --force_use_pollers epollsig,poll '
+ 'Example: --force_use_pollers epoll1,poll '
' (This flag has no effect if --force_default_poller flag is also used)')
argp.add_argument(
'--max_time', default=-1, type=int, help='Maximum test runtime in seconds')
@@ -1506,12 +1514,12 @@ 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
if 'gcov' in args.config:
- for bad in ['grpc-node', 'objc', 'sanity']:
+ for bad in ['csharp', 'grpc-node', 'objc', 'sanity']:
if bad in lang_list:
lang_list.remove(bad)
@@ -1713,9 +1721,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
@@ -1821,8 +1829,16 @@ def _build_and_run(check_cancelled,
for antagonist in antagonists:
antagonist.kill()
if args.bq_result_table and resultset:
- upload_results_to_bq(resultset, args.bq_result_table, args,
- platform_string())
+ upload_extra_fields = {
+ 'compiler': args.compiler,
+ 'config': args.config,
+ 'iomgr_platform': args.iomgr_platform,
+ 'language': args.language[
+ 0], # args.language is a list but will always have one element when uploading to BQ is enabled.
+ 'platform': platform_string()
+ }
+ upload_results_to_bq(resultset, args.bq_result_table,
+ upload_extra_fields)
if xml_report and resultset:
report_utils.render_junit_xml_report(
resultset, xml_report, suite_name=args.report_suite_name)
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 0af9e0cbbe..d93add00cd 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -43,9 +43,6 @@ _OBJC_RUNTESTS_TIMEOUT = 90 * 60
# Number of jobs assigned to each run_tests.py instance
_DEFAULT_INNER_JOBS = 2
-# report suffix is important for reports to get picked up by internal CI
-_REPORT_SUFFIX = 'sponge_log.xml'
-
def _safe_report_name(name):
"""Reports with '+' in target name won't show correctly in ResultStore"""
@@ -53,13 +50,16 @@ def _safe_report_name(name):
def _report_filename(name):
- """Generates report file name"""
- return 'report_%s_%s' % (_safe_report_name(name), _REPORT_SUFFIX)
+ """Generates report file name with directory structure that leads to better presentation by internal CI"""
+ # 'sponge_log.xml' suffix must be there for results to get recognized by kokoro.
+ return '%s/%s' % (_safe_report_name(name), 'sponge_log.xml')
-def _report_filename_internal_ci(name):
- """Generates report file name that leads to better presentation by internal CI"""
- return '%s/%s' % (_safe_report_name(name), _REPORT_SUFFIX)
+def _report_logfilename(name):
+ """Generates log file name that corresponds to name generated by _report_filename"""
+ # 'sponge_log.log' suffix must be there for log to get recognized as "target log"
+ # for the corresponding 'sponge_log.xml' report.
+ return '%s/%s' % (_safe_report_name(name), 'sponge_log.log')
def _docker_jobspec(name,
@@ -80,7 +80,8 @@ def _docker_jobspec(name,
] + runtests_args,
environ=runtests_envs,
shortname='run_tests_%s' % name,
- timeout_seconds=timeout_seconds)
+ timeout_seconds=timeout_seconds,
+ logfilename=_report_logfilename(name))
return test_job
@@ -107,7 +108,8 @@ def _workspace_jobspec(name,
] + runtests_args,
environ=env,
shortname='run_tests_%s' % name,
- timeout_seconds=timeout_seconds)
+ timeout_seconds=timeout_seconds,
+ logfilename=_report_logfilename(name))
return test_job
@@ -507,8 +509,9 @@ if __name__ == "__main__":
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 Kokoro.')
argp.add_argument(
'--bq_result_table',
default='',
@@ -517,9 +520,6 @@ if __name__ == "__main__":
help='Upload test results to a specified BQ table.')
args = argp.parse_args()
- if args.internal_ci:
- _report_filename = _report_filename_internal_ci # override the function
-
extra_args = []
if args.build_only:
extra_args.append('--build_only')
@@ -574,11 +574,8 @@ if __name__ == "__main__":
print('Will run these tests:')
for job in jobs:
- if args.dry_run:
- print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
- else:
- print(' %s' % job.shortname)
- print
+ print(' %s: "%s"' % (job.shortname, ' '.join(job.cmdline)))
+ print('')
if args.dry_run:
print('--dry_run was used, exiting')
diff --git a/tools/run_tests/sanity/check_qps_scenario_changes.py b/tools/run_tests/sanity/check_qps_scenario_changes.py
new file mode 100755
index 0000000000..635fee6a60
--- /dev/null
+++ b/tools/run_tests/sanity/check_qps_scenario_changes.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# 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.
+
+import os
+import sys
+import subprocess
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../../test/cpp/qps'))
+subprocess.call(['./json_run_localhost_scenario_gen.py'])
+subprocess.call(['./qps_json_driver_scenario_gen.py'])
+
+output = subprocess.check_output(['git', 'status', '--porcelain'])
+qps_json_driver_bzl = 'test/cpp/qps/qps_json_driver_scenarios.bzl'
+json_run_localhost_bzl = 'test/cpp/qps/json_run_localhost_scenarios.bzl'
+
+if qps_json_driver_bzl in output or json_run_localhost_bzl in output:
+ print('qps benchmark scenarios have been updated, please commit '
+ 'test/cpp/qps/qps_json_driver_scenarios.bzl and/or '
+ 'test/cpp/qps/json_run_localhost_scenarios.bzl')
+ sys.exit(1)
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 2c7c140716..8ea53dfec5 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -30,7 +30,7 @@ cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8 third_party/benchmark (v1.2.0)
73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty (remotes/origin/wide-14-g73594cd)
b29b21a81b32ec273f118f589f46d56ad3332420 third_party/boringssl (remotes/origin/chromium-stable)
- 8149b351bf797bd80e063787886b7618f508e451 third_party/boringssl-with-bazel (version_for_cocoapods_10.0-434-g8149b351)
+ afc30d43eef92979b05776ec0963c9cede5fb80f third_party/boringssl-with-bazel (fips-20180716-116-gafc30d43e)
3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0)
30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0-5-g30dbc81)
ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
diff --git a/tools/run_tests/sanity/core_banned_functions.py b/tools/run_tests/sanity/core_banned_functions.py
index 8afd826453..549ae14f5a 100755
--- a/tools/run_tests/sanity/core_banned_functions.py
+++ b/tools/run_tests/sanity/core_banned_functions.py
@@ -24,7 +24,8 @@ os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
# map of banned function signature to whitelist
BANNED_EXCEPT = {
'grpc_resource_quota_ref(': ['src/core/lib/iomgr/resource_quota.cc'],
- 'grpc_resource_quota_unref(': ['src/core/lib/iomgr/resource_quota.cc'],
+ 'grpc_resource_quota_unref(':
+ ['src/core/lib/iomgr/resource_quota.cc', 'src/core/lib/surface/server.cc'],
'grpc_slice_buffer_destroy(': ['src/core/lib/slice/slice_buffer.cc'],
'grpc_slice_buffer_reset_and_unref(':
['src/core/lib/slice/slice_buffer.cc'],
@@ -38,6 +39,7 @@ BANNED_EXCEPT = {
'grpc_wsa_error(': ['src/core/lib/iomgr/error.cc'],
'grpc_log_if_error(': ['src/core/lib/iomgr/error.cc'],
'grpc_slice_malloc(': ['src/core/lib/slice/slice.cc'],
+ 'grpc_call_cancel_internal(': ['src/core/lib/surface/call.cc'],
'grpc_closure_create(': ['src/core/lib/iomgr/closure.cc'],
'grpc_closure_init(': ['src/core/lib/iomgr/closure.cc'],
'grpc_closure_sched(': ['src/core/lib/iomgr/closure.cc'],
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index fd9b34a198..1913edd425 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -3,6 +3,7 @@
- script: tools/run_tests/sanity/check_bazel_workspace.py
- script: tools/run_tests/sanity/check_cache_mk.sh
- script: tools/run_tests/sanity/check_owners.sh
+- script: tools/run_tests/sanity/check_qps_scenario_changes.py
- script: tools/run_tests/sanity/check_shellcheck.sh
- script: tools/run_tests/sanity/check_submodules.sh
- script: tools/run_tests/sanity/check_test_filtering.py