Merge github.com:grpc/grpc into we-are-one

pull/3423/head
Craig Tiller 9 years ago
commit 10ee2747a9
  1. 14
      BUILD
  2. 40
      Makefile
  3. 110
      build.yaml
  4. 9
      gRPC.podspec
  5. 21
      include/grpc++/security/credentials.h
  6. 40
      include/grpc/grpc_security.h
  7. 12
      src/core/channel/http_client_filter.c
  8. 3
      src/core/channel/http_server_filter.c
  9. 554
      src/core/client_config/lb_policies/round_robin.c
  10. 46
      src/core/client_config/lb_policies/round_robin.h
  11. 26
      src/core/client_config/resolvers/sockaddr_resolver.c
  12. 29
      src/core/httpcli/httpcli_security_connector.c
  13. 7
      src/core/iomgr/tcp_server.h
  14. 28
      src/core/iomgr/tcp_server_posix.c
  15. 26
      src/core/iomgr/tcp_server_windows.c
  16. 36
      src/core/security/client_auth_filter.c
  17. 94
      src/core/security/credentials.c
  18. 9
      src/core/security/credentials.h
  19. 207
      src/core/security/handshake.c
  20. 25
      src/core/security/handshake.h
  21. 94
      src/core/security/security_connector.c
  22. 22
      src/core/security/security_connector.h
  23. 14
      src/core/security/server_secure_chttp2.c
  24. 16
      src/core/surface/channel_connectivity.c
  25. 2
      src/core/surface/init.c
  26. 17
      src/core/surface/secure_channel_create.c
  27. 60
      src/cpp/client/secure_credentials.cc
  28. 19
      src/cpp/client/secure_credentials.h
  29. 705
      test/core/client_config/lb_policies_test.c
  30. 115
      test/core/security/credentials_test.c
  31. 109
      test/cpp/end2end/end2end_test.cc
  32. 6
      test/cpp/interop/client.cc
  33. 16
      test/cpp/interop/interop_client.cc
  34. 1
      test/cpp/interop/interop_client.h
  35. 6
      tools/doxygen/Doxyfile.core.internal
  36. 81
      tools/jenkins/build_docker_and_run_tests.sh
  37. 7
      tools/jenkins/docker_run_tests.sh
  38. 40
      tools/jenkins/run_jenkins.sh
  39. 4
      tools/run_tests/port_server.py
  40. 50
      tools/run_tests/run_tests.py
  41. 26
      tools/run_tests/sources_and_headers.json
  42. 18
      tools/run_tests/tests.json
  43. 27
      vsprojects/buildtests_c.sln
  44. 9
      vsprojects/vcxproj/grpc/grpc.vcxproj
  45. 18
      vsprojects/vcxproj/grpc/grpc.vcxproj.filters
  46. 3
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
  47. 6
      vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
  48. 172
      vsprojects/vcxproj/test/lb_policies_test/lb_policies_test.vcxproj
  49. 21
      vsprojects/vcxproj/test/lb_policies_test/lb_policies_test.vcxproj.filters

14
BUILD

@ -134,10 +134,10 @@ cc_library(
"src/core/security/auth_filters.h", "src/core/security/auth_filters.h",
"src/core/security/base64.h", "src/core/security/base64.h",
"src/core/security/credentials.h", "src/core/security/credentials.h",
"src/core/security/handshake.h",
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/jwt_verifier.h", "src/core/security/jwt_verifier.h",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.h",
"src/core/security/security_connector.h", "src/core/security/security_connector.h",
"src/core/security/security_context.h", "src/core/security/security_context.h",
"src/core/tsi/fake_transport_security.h", "src/core/tsi/fake_transport_security.h",
@ -157,6 +157,7 @@ cc_library(
"src/core/client_config/client_config.h", "src/core/client_config/client_config.h",
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.h", "src/core/client_config/lb_policy_factory.h",
"src/core/client_config/lb_policy_registry.h", "src/core/client_config/lb_policy_registry.h",
@ -261,10 +262,10 @@ cc_library(
"src/core/security/credentials_posix.c", "src/core/security/credentials_posix.c",
"src/core/security/credentials_win32.c", "src/core/security/credentials_win32.c",
"src/core/security/google_default_credentials.c", "src/core/security/google_default_credentials.c",
"src/core/security/handshake.c",
"src/core/security/json_token.c", "src/core/security/json_token.c",
"src/core/security/jwt_verifier.c", "src/core/security/jwt_verifier.c",
"src/core/security/secure_endpoint.c", "src/core/security/secure_endpoint.c",
"src/core/security/secure_transport_setup.c",
"src/core/security/security_connector.c", "src/core/security/security_connector.c",
"src/core/security/security_context.c", "src/core/security/security_context.c",
"src/core/security/server_auth_filter.c", "src/core/security/server_auth_filter.c",
@ -287,6 +288,7 @@ cc_library(
"src/core/client_config/client_config.c", "src/core/client_config/client_config.c",
"src/core/client_config/connector.c", "src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c", "src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c", "src/core/client_config/lb_policy.c",
"src/core/client_config/lb_policy_factory.c", "src/core/client_config/lb_policy_factory.c",
"src/core/client_config/lb_policy_registry.c", "src/core/client_config/lb_policy_registry.c",
@ -436,6 +438,7 @@ cc_library(
"src/core/client_config/client_config.h", "src/core/client_config/client_config.h",
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.h", "src/core/client_config/lb_policy_factory.h",
"src/core/client_config/lb_policy_registry.h", "src/core/client_config/lb_policy_registry.h",
@ -546,6 +549,7 @@ cc_library(
"src/core/client_config/client_config.c", "src/core/client_config/client_config.c",
"src/core/client_config/connector.c", "src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c", "src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c", "src/core/client_config/lb_policy.c",
"src/core/client_config/lb_policy_factory.c", "src/core/client_config/lb_policy_factory.c",
"src/core/client_config/lb_policy_registry.c", "src/core/client_config/lb_policy_registry.c",
@ -1040,10 +1044,10 @@ objc_library(
"src/core/security/credentials_posix.c", "src/core/security/credentials_posix.c",
"src/core/security/credentials_win32.c", "src/core/security/credentials_win32.c",
"src/core/security/google_default_credentials.c", "src/core/security/google_default_credentials.c",
"src/core/security/handshake.c",
"src/core/security/json_token.c", "src/core/security/json_token.c",
"src/core/security/jwt_verifier.c", "src/core/security/jwt_verifier.c",
"src/core/security/secure_endpoint.c", "src/core/security/secure_endpoint.c",
"src/core/security/secure_transport_setup.c",
"src/core/security/security_connector.c", "src/core/security/security_connector.c",
"src/core/security/security_context.c", "src/core/security/security_context.c",
"src/core/security/server_auth_filter.c", "src/core/security/server_auth_filter.c",
@ -1066,6 +1070,7 @@ objc_library(
"src/core/client_config/client_config.c", "src/core/client_config/client_config.c",
"src/core/client_config/connector.c", "src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c", "src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policy.c", "src/core/client_config/lb_policy.c",
"src/core/client_config/lb_policy_factory.c", "src/core/client_config/lb_policy_factory.c",
"src/core/client_config/lb_policy_registry.c", "src/core/client_config/lb_policy_registry.c",
@ -1189,10 +1194,10 @@ objc_library(
"src/core/security/auth_filters.h", "src/core/security/auth_filters.h",
"src/core/security/base64.h", "src/core/security/base64.h",
"src/core/security/credentials.h", "src/core/security/credentials.h",
"src/core/security/handshake.h",
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/jwt_verifier.h", "src/core/security/jwt_verifier.h",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.h",
"src/core/security/security_connector.h", "src/core/security/security_connector.h",
"src/core/security/security_context.h", "src/core/security/security_context.h",
"src/core/tsi/fake_transport_security.h", "src/core/tsi/fake_transport_security.h",
@ -1212,6 +1217,7 @@ objc_library(
"src/core/client_config/client_config.h", "src/core/client_config/client_config.h",
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.h", "src/core/client_config/lb_policy_factory.h",
"src/core/client_config/lb_policy_registry.h", "src/core/client_config/lb_policy_registry.h",

File diff suppressed because one or more lines are too long

@ -45,58 +45,59 @@ filegroups:
src/core/channel/client_channel.h, src/core/channel/compress_filter.h, src/core/channel/connected_channel.h, src/core/channel/client_channel.h, src/core/channel/compress_filter.h, src/core/channel/connected_channel.h,
src/core/channel/context.h, src/core/channel/http_client_filter.h, src/core/channel/http_server_filter.h, src/core/channel/context.h, src/core/channel/http_client_filter.h, src/core/channel/http_server_filter.h,
src/core/channel/noop_filter.h, src/core/client_config/client_config.h, src/core/client_config/connector.h, src/core/channel/noop_filter.h, src/core/client_config/client_config.h, src/core/client_config/connector.h,
src/core/client_config/lb_policies/pick_first.h, src/core/client_config/lb_policy.h, src/core/client_config/lb_policies/pick_first.h, src/core/client_config/lb_policies/round_robin.h,
src/core/client_config/lb_policy_factory.h, src/core/client_config/lb_policy_registry.h, src/core/client_config/lb_policy.h, src/core/client_config/lb_policy_factory.h,
src/core/client_config/resolver.h, src/core/client_config/resolver_factory.h, src/core/client_config/lb_policy_registry.h, src/core/client_config/resolver.h,
src/core/client_config/resolver_registry.h, src/core/client_config/resolvers/dns_resolver.h, src/core/client_config/resolver_factory.h, src/core/client_config/resolver_registry.h,
src/core/client_config/resolvers/sockaddr_resolver.h, src/core/client_config/subchannel.h, src/core/client_config/resolvers/dns_resolver.h, src/core/client_config/resolvers/sockaddr_resolver.h,
src/core/client_config/subchannel_factory.h, src/core/client_config/subchannel_factory_decorators/add_channel_arg.h, src/core/client_config/subchannel.h, src/core/client_config/subchannel_factory.h,
src/core/client_config/subchannel_factory_decorators/merge_channel_args.h, src/core/client_config/uri_parser.h, src/core/client_config/subchannel_factory_decorators/add_channel_arg.h, src/core/client_config/subchannel_factory_decorators/merge_channel_args.h,
src/core/compression/message_compress.h, src/core/debug/trace.h, src/core/httpcli/format_request.h, src/core/client_config/uri_parser.h, src/core/compression/message_compress.h,
src/core/httpcli/httpcli.h, src/core/httpcli/parser.h, src/core/iomgr/alarm.h, src/core/debug/trace.h, src/core/httpcli/format_request.h, src/core/httpcli/httpcli.h,
src/core/iomgr/alarm_heap.h, src/core/iomgr/alarm_internal.h, src/core/iomgr/endpoint.h, src/core/httpcli/parser.h, src/core/iomgr/alarm.h, src/core/iomgr/alarm_heap.h,
src/core/iomgr/endpoint_pair.h, src/core/iomgr/fd_posix.h, src/core/iomgr/iocp_windows.h, src/core/iomgr/alarm_internal.h, src/core/iomgr/endpoint.h, src/core/iomgr/endpoint_pair.h,
src/core/iomgr/iomgr.h, src/core/iomgr/iomgr_internal.h, src/core/iomgr/iomgr_posix.h, src/core/iomgr/fd_posix.h, src/core/iomgr/iocp_windows.h, src/core/iomgr/iomgr.h,
src/core/iomgr/pollset.h, src/core/iomgr/pollset_posix.h, src/core/iomgr/pollset_set.h, src/core/iomgr/iomgr_internal.h, src/core/iomgr/iomgr_posix.h, src/core/iomgr/pollset.h,
src/core/iomgr/pollset_set_posix.h, src/core/iomgr/pollset_set_windows.h, src/core/iomgr/pollset_windows.h, src/core/iomgr/pollset_posix.h, src/core/iomgr/pollset_set.h, src/core/iomgr/pollset_set_posix.h,
src/core/iomgr/resolve_address.h, src/core/iomgr/sockaddr.h, src/core/iomgr/sockaddr_posix.h, src/core/iomgr/pollset_set_windows.h, src/core/iomgr/pollset_windows.h, src/core/iomgr/resolve_address.h,
src/core/iomgr/sockaddr_utils.h, src/core/iomgr/sockaddr_win32.h, src/core/iomgr/socket_utils_posix.h, src/core/iomgr/sockaddr.h, src/core/iomgr/sockaddr_posix.h, src/core/iomgr/sockaddr_utils.h,
src/core/iomgr/socket_windows.h, src/core/iomgr/tcp_client.h, src/core/iomgr/tcp_posix.h, src/core/iomgr/sockaddr_win32.h, src/core/iomgr/socket_utils_posix.h, src/core/iomgr/socket_windows.h,
src/core/iomgr/tcp_server.h, src/core/iomgr/tcp_windows.h, src/core/iomgr/time_averaged_stats.h, src/core/iomgr/tcp_client.h, src/core/iomgr/tcp_posix.h, src/core/iomgr/tcp_server.h,
src/core/iomgr/udp_server.h, src/core/iomgr/wakeup_fd_pipe.h, src/core/iomgr/wakeup_fd_posix.h, src/core/iomgr/tcp_windows.h, src/core/iomgr/time_averaged_stats.h, src/core/iomgr/udp_server.h,
src/core/iomgr/workqueue.h, src/core/iomgr/workqueue_posix.h, src/core/iomgr/workqueue_windows.h, src/core/iomgr/wakeup_fd_pipe.h, src/core/iomgr/wakeup_fd_posix.h, src/core/iomgr/workqueue.h,
src/core/json/json.h, src/core/json/json_common.h, src/core/json/json_reader.h, src/core/iomgr/workqueue_posix.h, src/core/iomgr/workqueue_windows.h, src/core/json/json.h,
src/core/json/json_writer.h, src/core/profiling/timers.h, src/core/statistics/census_interface.h, src/core/json/json_common.h, src/core/json/json_reader.h, src/core/json/json_writer.h,
src/core/statistics/census_rpc_stats.h, src/core/surface/byte_buffer_queue.h, src/core/profiling/timers.h, src/core/statistics/census_interface.h, src/core/statistics/census_rpc_stats.h,
src/core/surface/call.h, src/core/surface/channel.h, src/core/surface/completion_queue.h, src/core/surface/byte_buffer_queue.h, src/core/surface/call.h, src/core/surface/channel.h,
src/core/surface/event_string.h, src/core/surface/init.h, src/core/surface/server.h, src/core/surface/completion_queue.h, src/core/surface/event_string.h, src/core/surface/init.h,
src/core/surface/surface_trace.h, src/core/transport/chttp2/alpn.h, src/core/transport/chttp2/bin_encoder.h, src/core/surface/server.h, src/core/surface/surface_trace.h, src/core/transport/chttp2/alpn.h,
src/core/transport/chttp2/frame.h, src/core/transport/chttp2/frame_data.h, src/core/transport/chttp2/frame_goaway.h, src/core/transport/chttp2/bin_encoder.h, src/core/transport/chttp2/frame.h, src/core/transport/chttp2/frame_data.h,
src/core/transport/chttp2/frame_ping.h, src/core/transport/chttp2/frame_rst_stream.h, src/core/transport/chttp2/frame_goaway.h, src/core/transport/chttp2/frame_ping.h,
src/core/transport/chttp2/frame_settings.h, src/core/transport/chttp2/frame_window_update.h, src/core/transport/chttp2/frame_rst_stream.h, src/core/transport/chttp2/frame_settings.h,
src/core/transport/chttp2/hpack_parser.h, src/core/transport/chttp2/hpack_table.h, src/core/transport/chttp2/frame_window_update.h, src/core/transport/chttp2/hpack_parser.h,
src/core/transport/chttp2/http2_errors.h, src/core/transport/chttp2/huffsyms.h, src/core/transport/chttp2/hpack_table.h, src/core/transport/chttp2/http2_errors.h,
src/core/transport/chttp2/incoming_metadata.h, src/core/transport/chttp2/internal.h, src/core/transport/chttp2/huffsyms.h, src/core/transport/chttp2/incoming_metadata.h,
src/core/transport/chttp2/status_conversion.h, src/core/transport/chttp2/stream_encoder.h, src/core/transport/chttp2/internal.h, src/core/transport/chttp2/status_conversion.h,
src/core/transport/chttp2/stream_map.h, src/core/transport/chttp2/timeout_encoding.h, src/core/transport/chttp2/stream_encoder.h, src/core/transport/chttp2/stream_map.h,
src/core/transport/chttp2/varint.h, src/core/transport/chttp2_transport.h, src/core/transport/connectivity_state.h, src/core/transport/chttp2/timeout_encoding.h, src/core/transport/chttp2/varint.h,
src/core/transport/chttp2_transport.h, src/core/transport/connectivity_state.h,
src/core/transport/metadata.h, src/core/transport/stream_op.h, src/core/transport/transport.h, src/core/transport/metadata.h, src/core/transport/stream_op.h, src/core/transport/transport.h,
src/core/transport/transport_impl.h] src/core/transport/transport_impl.h]
src: [src/core/census/grpc_context.c, src/core/census/grpc_filter.c, src/core/channel/channel_args.c, src: [src/core/census/grpc_context.c, src/core/census/grpc_filter.c, src/core/channel/channel_args.c,
src/core/channel/channel_stack.c, src/core/channel/client_channel.c, src/core/channel/compress_filter.c, src/core/channel/channel_stack.c, src/core/channel/client_channel.c, src/core/channel/compress_filter.c,
src/core/channel/connected_channel.c, src/core/channel/http_client_filter.c, src/core/channel/http_server_filter.c, src/core/channel/connected_channel.c, src/core/channel/http_client_filter.c, src/core/channel/http_server_filter.c,
src/core/channel/noop_filter.c, src/core/client_config/client_config.c, src/core/client_config/connector.c, src/core/channel/noop_filter.c, src/core/client_config/client_config.c, src/core/client_config/connector.c,
src/core/client_config/lb_policies/pick_first.c, src/core/client_config/lb_policy.c, src/core/client_config/lb_policies/pick_first.c, src/core/client_config/lb_policies/round_robin.c,
src/core/client_config/lb_policy_factory.c, src/core/client_config/lb_policy_registry.c, src/core/client_config/lb_policy.c, src/core/client_config/lb_policy_factory.c,
src/core/client_config/resolver.c, src/core/client_config/resolver_factory.c, src/core/client_config/lb_policy_registry.c, src/core/client_config/resolver.c,
src/core/client_config/resolver_registry.c, src/core/client_config/resolvers/dns_resolver.c, src/core/client_config/resolver_factory.c, src/core/client_config/resolver_registry.c,
src/core/client_config/resolvers/sockaddr_resolver.c, src/core/client_config/subchannel.c, src/core/client_config/resolvers/dns_resolver.c, src/core/client_config/resolvers/sockaddr_resolver.c,
src/core/client_config/subchannel_factory.c, src/core/client_config/subchannel_factory_decorators/add_channel_arg.c, src/core/client_config/subchannel.c, src/core/client_config/subchannel_factory.c,
src/core/client_config/subchannel_factory_decorators/merge_channel_args.c, src/core/client_config/uri_parser.c, src/core/client_config/subchannel_factory_decorators/add_channel_arg.c, src/core/client_config/subchannel_factory_decorators/merge_channel_args.c,
src/core/compression/algorithm.c, src/core/compression/message_compress.c, src/core/debug/trace.c, src/core/client_config/uri_parser.c, src/core/compression/algorithm.c, src/core/compression/message_compress.c,
src/core/httpcli/format_request.c, src/core/httpcli/httpcli.c, src/core/httpcli/parser.c, src/core/debug/trace.c, src/core/httpcli/format_request.c, src/core/httpcli/httpcli.c,
src/core/iomgr/alarm.c, src/core/iomgr/alarm_heap.c, src/core/iomgr/endpoint.c, src/core/httpcli/parser.c, src/core/iomgr/alarm.c, src/core/iomgr/alarm_heap.c,
src/core/iomgr/endpoint_pair_posix.c, src/core/iomgr/endpoint_pair_windows.c, src/core/iomgr/endpoint.c, src/core/iomgr/endpoint_pair_posix.c, src/core/iomgr/endpoint_pair_windows.c,
src/core/iomgr/fd_posix.c, src/core/iomgr/iocp_windows.c, src/core/iomgr/iomgr.c, src/core/iomgr/fd_posix.c, src/core/iomgr/iocp_windows.c, src/core/iomgr/iomgr.c,
src/core/iomgr/iomgr_posix.c, src/core/iomgr/iomgr_windows.c, src/core/iomgr/pollset_multipoller_with_epoll.c, src/core/iomgr/iomgr_posix.c, src/core/iomgr/iomgr_windows.c, src/core/iomgr/pollset_multipoller_with_epoll.c,
src/core/iomgr/pollset_multipoller_with_poll_posix.c, src/core/iomgr/pollset_posix.c, src/core/iomgr/pollset_multipoller_with_poll_posix.c, src/core/iomgr/pollset_posix.c,
@ -180,15 +181,15 @@ libs:
language: c language: c
public_headers: [include/grpc/grpc_security.h] public_headers: [include/grpc/grpc_security.h]
headers: [src/core/security/auth_filters.h, src/core/security/base64.h, src/core/security/credentials.h, headers: [src/core/security/auth_filters.h, src/core/security/base64.h, src/core/security/credentials.h,
src/core/security/json_token.h, src/core/security/jwt_verifier.h, src/core/security/secure_endpoint.h, src/core/security/handshake.h, src/core/security/json_token.h, src/core/security/jwt_verifier.h,
src/core/security/secure_transport_setup.h, src/core/security/security_connector.h, src/core/security/secure_endpoint.h, src/core/security/security_connector.h, src/core/security/security_context.h,
src/core/security/security_context.h, src/core/tsi/fake_transport_security.h, src/core/tsi/fake_transport_security.h, src/core/tsi/ssl_transport_security.h,
src/core/tsi/ssl_transport_security.h, src/core/tsi/transport_security.h, src/core/tsi/transport_security_interface.h] src/core/tsi/transport_security.h, src/core/tsi/transport_security_interface.h]
src: [src/core/httpcli/httpcli_security_connector.c, src/core/security/base64.c, src: [src/core/httpcli/httpcli_security_connector.c, src/core/security/base64.c,
src/core/security/client_auth_filter.c, src/core/security/credentials.c, src/core/security/credentials_metadata.c, src/core/security/client_auth_filter.c, src/core/security/credentials.c, src/core/security/credentials_metadata.c,
src/core/security/credentials_posix.c, src/core/security/credentials_win32.c, src/core/security/credentials_posix.c, src/core/security/credentials_win32.c,
src/core/security/google_default_credentials.c, src/core/security/json_token.c, src/core/security/google_default_credentials.c, src/core/security/handshake.c,
src/core/security/jwt_verifier.c, src/core/security/secure_endpoint.c, src/core/security/secure_transport_setup.c, src/core/security/json_token.c, src/core/security/jwt_verifier.c, src/core/security/secure_endpoint.c,
src/core/security/security_connector.c, src/core/security/security_context.c, src/core/security/security_connector.c, src/core/security/security_context.c,
src/core/security/server_auth_filter.c, src/core/security/server_secure_chttp2.c, src/core/security/server_auth_filter.c, src/core/security/server_secure_chttp2.c,
src/core/surface/init_secure.c, src/core/surface/secure_channel_create.c, src/core/tsi/fake_transport_security.c, src/core/surface/init_secure.c, src/core/surface/secure_channel_create.c, src/core/tsi/fake_transport_security.c,
@ -639,6 +640,11 @@ targets:
language: c language: c
src: [test/core/surface/lame_client_test.c] src: [test/core/surface/lame_client_test.c]
deps: [grpc_test_util, grpc, gpr_test_util, gpr] deps: [grpc_test_util, grpc, gpr_test_util, gpr]
- name: lb_policies_test
build: test
language: c
src: [test/core/client_config/lb_policies_test.c]
deps: [grpc_test_util, grpc, gpr_test_util, gpr]
- name: low_level_ping_pong_benchmark - name: low_level_ping_pong_benchmark
build: benchmark build: benchmark
language: c language: c

@ -136,10 +136,10 @@ Pod::Spec.new do |s|
'src/core/security/auth_filters.h', 'src/core/security/auth_filters.h',
'src/core/security/base64.h', 'src/core/security/base64.h',
'src/core/security/credentials.h', 'src/core/security/credentials.h',
'src/core/security/handshake.h',
'src/core/security/json_token.h', 'src/core/security/json_token.h',
'src/core/security/jwt_verifier.h', 'src/core/security/jwt_verifier.h',
'src/core/security/secure_endpoint.h', 'src/core/security/secure_endpoint.h',
'src/core/security/secure_transport_setup.h',
'src/core/security/security_connector.h', 'src/core/security/security_connector.h',
'src/core/security/security_context.h', 'src/core/security/security_context.h',
'src/core/tsi/fake_transport_security.h', 'src/core/tsi/fake_transport_security.h',
@ -159,6 +159,7 @@ Pod::Spec.new do |s|
'src/core/client_config/client_config.h', 'src/core/client_config/client_config.h',
'src/core/client_config/connector.h', 'src/core/client_config/connector.h',
'src/core/client_config/lb_policies/pick_first.h', 'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policies/round_robin.h',
'src/core/client_config/lb_policy.h', 'src/core/client_config/lb_policy.h',
'src/core/client_config/lb_policy_factory.h', 'src/core/client_config/lb_policy_factory.h',
'src/core/client_config/lb_policy_registry.h', 'src/core/client_config/lb_policy_registry.h',
@ -270,10 +271,10 @@ Pod::Spec.new do |s|
'src/core/security/credentials_posix.c', 'src/core/security/credentials_posix.c',
'src/core/security/credentials_win32.c', 'src/core/security/credentials_win32.c',
'src/core/security/google_default_credentials.c', 'src/core/security/google_default_credentials.c',
'src/core/security/handshake.c',
'src/core/security/json_token.c', 'src/core/security/json_token.c',
'src/core/security/jwt_verifier.c', 'src/core/security/jwt_verifier.c',
'src/core/security/secure_endpoint.c', 'src/core/security/secure_endpoint.c',
'src/core/security/secure_transport_setup.c',
'src/core/security/security_connector.c', 'src/core/security/security_connector.c',
'src/core/security/security_context.c', 'src/core/security/security_context.c',
'src/core/security/server_auth_filter.c', 'src/core/security/server_auth_filter.c',
@ -296,6 +297,7 @@ Pod::Spec.new do |s|
'src/core/client_config/client_config.c', 'src/core/client_config/client_config.c',
'src/core/client_config/connector.c', 'src/core/client_config/connector.c',
'src/core/client_config/lb_policies/pick_first.c', 'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policies/round_robin.c',
'src/core/client_config/lb_policy.c', 'src/core/client_config/lb_policy.c',
'src/core/client_config/lb_policy_factory.c', 'src/core/client_config/lb_policy_factory.c',
'src/core/client_config/lb_policy_registry.c', 'src/core/client_config/lb_policy_registry.c',
@ -419,10 +421,10 @@ Pod::Spec.new do |s|
'src/core/security/auth_filters.h', 'src/core/security/auth_filters.h',
'src/core/security/base64.h', 'src/core/security/base64.h',
'src/core/security/credentials.h', 'src/core/security/credentials.h',
'src/core/security/handshake.h',
'src/core/security/json_token.h', 'src/core/security/json_token.h',
'src/core/security/jwt_verifier.h', 'src/core/security/jwt_verifier.h',
'src/core/security/secure_endpoint.h', 'src/core/security/secure_endpoint.h',
'src/core/security/secure_transport_setup.h',
'src/core/security/security_connector.h', 'src/core/security/security_connector.h',
'src/core/security/security_context.h', 'src/core/security/security_context.h',
'src/core/tsi/fake_transport_security.h', 'src/core/tsi/fake_transport_security.h',
@ -442,6 +444,7 @@ Pod::Spec.new do |s|
'src/core/client_config/client_config.h', 'src/core/client_config/client_config.h',
'src/core/client_config/connector.h', 'src/core/client_config/connector.h',
'src/core/client_config/lb_policies/pick_first.h', 'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policies/round_robin.h',
'src/core/client_config/lb_policy.h', 'src/core/client_config/lb_policy.h',
'src/core/client_config/lb_policy_factory.h', 'src/core/client_config/lb_policy_factory.h',
'src/core/client_config/lb_policy_registry.h', 'src/core/client_config/lb_policy_registry.h',

@ -34,10 +34,13 @@
#ifndef GRPCXX_CREDENTIALS_H #ifndef GRPCXX_CREDENTIALS_H
#define GRPCXX_CREDENTIALS_H #define GRPCXX_CREDENTIALS_H
#include <map>
#include <memory> #include <memory>
#include <grpc++/impl/grpc_library.h> #include <grpc++/impl/grpc_library.h>
#include <grpc++/support/config.h> #include <grpc++/support/config.h>
#include <grpc++/support/status.h>
#include <grpc++/support/string_ref.h>
namespace grpc { namespace grpc {
class ChannelArguments; class ChannelArguments;
@ -165,6 +168,24 @@ std::shared_ptr<Credentials> CompositeCredentials(
/// Credentials for an unencrypted, unauthenticated channel /// Credentials for an unencrypted, unauthenticated channel
std::shared_ptr<Credentials> InsecureCredentials(); std::shared_ptr<Credentials> InsecureCredentials();
// User defined metadata credentials.
class MetadataCredentialsPlugin {
public:
virtual ~MetadataCredentialsPlugin() {}
// If this method returns true, the Process function will be scheduled in
// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
// Gets the auth metatada produced by this plugin.
virtual Status GetMetadata(
grpc::string_ref service_url,
std::multimap<grpc::string, grpc::string_ref>* metadata) = 0;
};
std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
} // namespace grpc } // namespace grpc
#endif // GRPCXX_CREDENTIALS_H #endif // GRPCXX_CREDENTIALS_H

@ -131,6 +131,46 @@ grpc_credentials *grpc_google_iam_credentials_create(
const char *authorization_token, const char *authority_selector, const char *authorization_token, const char *authority_selector,
void *reserved); void *reserved);
/* Callback function to be called by the metadata credentials plugin
implementation when the metadata is ready.
- user_data is the opaque pointer that was passed in the get_metadata method
of the grpc_metadata_credentials_plugin (see below).
- creds_md is an array of credentials metadata produced by the plugin. It
may be set to NULL in case of an error.
- num_creds_md is the number of items in the creds_md array.
- status must be GRPC_STATUS_OK in case of success or another specific error
code otherwise.
- error_details contains details about the error if any. In case of success
it should be NULL and will be otherwise ignored. */
typedef void (*grpc_credentials_plugin_metadata_cb)(
void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
grpc_status_code status, const char *error_details);
/* grpc_metadata_credentials plugin is an API user provided structure used to
create grpc_credentials objects that can be set on a channel (composed) or
a call. See grpc_credentials_metadata_create_from_plugin below.
The grpc client stack will call the get_metadata method of the plugin for
every call in scope for the credentials created from it. */
typedef struct {
/* The implementation of this method has to be non-blocking.
- service_url is the fully qualified URL that the client stack is
connecting to.
- cb is the callback that needs to be called when the metadata is ready.
- user_data needs to be passed as the first parameter of the callback. */
void (*get_metadata)(void *state, const char *service_url,
grpc_credentials_plugin_metadata_cb cb, void *user_data);
/* Destroys the plugin state. */
void (*destroy)(void *state);
/* State that will be set as the first parameter of the methods above. */
void *state;
} grpc_metadata_credentials_plugin;
/* Creates a credentials object from a plugin. */
grpc_credentials *grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void *reserved);
/* --- Secure channel creation. --- */ /* --- Secure channel creation. --- */
/* Creates a secure channel using the passed-in credentials. */ /* Creates a secure channel using the passed-in credentials. */

@ -70,10 +70,10 @@ typedef struct channel_data {
typedef struct { typedef struct {
grpc_call_element *elem; grpc_call_element *elem;
grpc_call_list *call_list; grpc_call_list *call_list;
} client_filter_args; } client_recv_filter_args;
static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) { static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
client_filter_args *a = user_data; client_recv_filter_args *a = user_data;
grpc_call_element *elem = a->elem; grpc_call_element *elem = a->elem;
channel_data *channeld = elem->channel_data; channel_data *channeld = elem->channel_data;
if (md == channeld->status) { if (md == channeld->status) {
@ -81,6 +81,8 @@ static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) {
} else if (md->key == channeld->status->key) { } else if (md->key == channeld->status->key) {
grpc_call_element_send_cancel(elem, a->call_list); grpc_call_element_send_cancel(elem, a->call_list);
return NULL; return NULL;
} else if (md->key == channeld->content_type->key) {
return NULL;
} }
return md; return md;
} }
@ -94,12 +96,12 @@ static void hc_on_recv(void *user_data, int success,
grpc_stream_op *ops = calld->recv_ops->ops; grpc_stream_op *ops = calld->recv_ops->ops;
for (i = 0; i < nops; i++) { for (i = 0; i < nops; i++) {
grpc_stream_op *op = &ops[i]; grpc_stream_op *op = &ops[i];
client_filter_args a; client_recv_filter_args a;
if (op->type != GRPC_OP_METADATA) continue; if (op->type != GRPC_OP_METADATA) continue;
calld->got_initial_metadata = 1; calld->got_initial_metadata = 1;
a.elem = elem; a.elem = elem;
a.call_list = call_list; a.call_list = call_list;
grpc_metadata_batch_filter(&op->data.metadata, client_filter, &a); grpc_metadata_batch_filter(&op->data.metadata, client_recv_filter, &a);
} }
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success, call_list); calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success, call_list);
} }

@ -117,8 +117,7 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
return NULL; return NULL;
} else if (md->key == channeld->te_trailers->key || } else if (md->key == channeld->te_trailers->key ||
md->key == channeld->method_post->key || md->key == channeld->method_post->key ||
md->key == channeld->http_scheme->key || md->key == channeld->http_scheme->key) {
md->key == channeld->content_type->key) {
gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
/* swallow it and error everything out. */ /* swallow it and error everything out. */

@ -0,0 +1,554 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/lb_policies/round_robin.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include "src/core/transport/connectivity_state.h"
int grpc_lb_round_robin_trace = 0;
/** List of entities waiting for a pick.
*
* Once a pick is available, \a target is updated and \a on_complete called. */
typedef struct pending_pick {
struct pending_pick *next;
grpc_pollset *pollset;
grpc_subchannel **target;
grpc_closure *on_complete;
} pending_pick;
/** List of subchannels in a connectivity READY state */
typedef struct ready_list {
grpc_subchannel *subchannel;
struct ready_list *next;
struct ready_list *prev;
} ready_list;
typedef struct {
size_t subchannel_idx; /**< Index over p->subchannels */
void *p; /**< round_robin_lb_policy instance */
} connectivity_changed_cb_arg;
typedef struct {
/** base policy: must be first */
grpc_lb_policy base;
/** all our subchannels */
grpc_subchannel **subchannels;
size_t num_subchannels;
/** Callbacks, one per subchannel being watched, to be called when their
* respective connectivity changes */
grpc_closure *connectivity_changed_cbs;
connectivity_changed_cb_arg *cb_args;
/** mutex protecting remaining members */
gpr_mu mu;
/** have we started picking? */
int started_picking;
/** are we shutting down? */
int shutdown;
/** Connectivity state of the subchannels being watched */
grpc_connectivity_state *subchannel_connectivity;
/** List of picks that are waiting on connectivity */
pending_pick *pending_picks;
/** our connectivity state tracker */
grpc_connectivity_state_tracker state_tracker;
/** (Dummy) root of the doubly linked list containing READY subchannels */
ready_list ready_list;
/** Last pick from the ready list. */
ready_list *ready_list_last_pick;
/** Subchannel index to ready_list node.
*
* Kept in order to remove nodes from the ready list associated with a
* subchannel */
ready_list **subchannel_index_to_readylist_node;
} round_robin_lb_policy;
/** Returns the next subchannel from the connected list or NULL if the list is
* empty.
*
* Note that this function does *not* advance p->ready_list_last_pick. Use \a
* advance_last_picked_locked() for that. */
static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) {
ready_list *selected;
selected = p->ready_list_last_pick->next;
while (selected != NULL) {
if (selected == &p->ready_list) {
GPR_ASSERT(selected->subchannel == NULL);
/* skip dummy root */
selected = selected->next;
} else {
GPR_ASSERT(selected->subchannel != NULL);
return selected;
}
}
return NULL;
}
/** Advance the \a ready_list picking head. */
static void advance_last_picked_locked(round_robin_lb_policy *p) {
if (p->ready_list_last_pick->next != NULL) { /* non-empty list */
p->ready_list_last_pick = p->ready_list_last_pick->next;
if (p->ready_list_last_pick == &p->ready_list) {
/* skip dummy root */
p->ready_list_last_pick = p->ready_list_last_pick->next;
}
} else { /* should be an empty list */
GPR_ASSERT(p->ready_list_last_pick == &p->ready_list);
}
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)",
p->ready_list_last_pick, p->ready_list_last_pick->subchannel);
}
}
/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
* csc to the list of ready subchannels. */
static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
grpc_subchannel *csc) {
ready_list *new_elem = gpr_malloc(sizeof(ready_list));
new_elem->subchannel = csc;
if (p->ready_list.prev == NULL) {
/* first element */
new_elem->next = &p->ready_list;
new_elem->prev = &p->ready_list;
p->ready_list.next = new_elem;
p->ready_list.prev = new_elem;
} else {
new_elem->next = &p->ready_list;
new_elem->prev = p->ready_list.prev;
p->ready_list.prev->next = new_elem;
p->ready_list.prev = new_elem;
}
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, csc);
}
return new_elem;
}
/** Removes \a node from the list of connected subchannels */
static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
ready_list *node) {
if (node == NULL) {
return;
}
if (node == p->ready_list_last_pick) {
/* If removing the lastly picked node, reset the last pick pointer to the
* dummy root of the list */
p->ready_list_last_pick = &p->ready_list;
}
/* removing last item */
if (node->next == &p->ready_list && node->prev == &p->ready_list) {
GPR_ASSERT(p->ready_list.next == node);
GPR_ASSERT(p->ready_list.prev == node);
p->ready_list.next = NULL;
p->ready_list.prev = NULL;
} else {
node->prev->next = node->next;
node->next->prev = node->prev;
}
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node,
node->subchannel);
}
node->next = NULL;
node->prev = NULL;
node->subchannel = NULL;
gpr_free(node);
}
static void del_interested_parties_locked(round_robin_lb_policy *p,
const size_t subchannel_idx,
grpc_call_list *call_list) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(p->subchannels[subchannel_idx],
pp->pollset, call_list);
}
}
void rr_destroy(grpc_lb_policy *pol, grpc_call_list *call_list) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
size_t i;
ready_list *elem;
for (i = 0; i < p->num_subchannels; i++) {
del_interested_parties_locked(p, i, call_list);
}
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "round_robin", call_list);
}
gpr_free(p->connectivity_changed_cbs);
gpr_free(p->subchannel_connectivity);
grpc_connectivity_state_destroy(&p->state_tracker, call_list);
gpr_free(p->subchannels);
gpr_mu_destroy(&p->mu);
elem = p->ready_list.next;
while (elem != NULL && elem != &p->ready_list) {
ready_list *tmp;
tmp = elem->next;
elem->next = NULL;
elem->prev = NULL;
elem->subchannel = NULL;
gpr_free(elem);
elem = tmp;
}
gpr_free(p->subchannel_index_to_readylist_node);
gpr_free(p->cb_args);
gpr_free(p);
}
void rr_shutdown(grpc_lb_policy *pol, grpc_call_list *call_list) {
size_t i;
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
for (i = 0; i < p->num_subchannels; i++) {
del_interested_parties_locked(p, i, call_list);
}
p->shutdown = 1;
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_call_list_add(call_list, pp->on_complete, 0);
gpr_free(pp);
}
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_FATAL_FAILURE,
"shutdown", call_list);
gpr_mu_unlock(&p->mu);
}
static void start_picking(round_robin_lb_policy *p, grpc_call_list *call_list) {
size_t i;
p->started_picking = 1;
for (i = 0; i < p->num_subchannels; i++) {
p->subchannel_connectivity[i] = GRPC_CHANNEL_IDLE;
grpc_subchannel_notify_on_state_change(
p->subchannels[i], &p->subchannel_connectivity[i],
&p->connectivity_changed_cbs[i], call_list);
GRPC_LB_POLICY_REF(&p->base, "round_robin_connectivity");
}
}
void rr_exit_idle(grpc_lb_policy *pol, grpc_call_list *call_list) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
gpr_mu_lock(&p->mu);
if (!p->started_picking) {
start_picking(p, call_list);
}
gpr_mu_unlock(&p->mu);
}
void rr_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
grpc_closure *on_complete, grpc_call_list *call_list) {
size_t i;
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
ready_list *selected;
gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu);
*target = selected->subchannel;
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[RR PICK] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected);
}
/* only advance the last picked pointer if the selection was used */
advance_last_picked_locked(p);
on_complete->cb(on_complete->cb_arg, 1, call_list);
} else {
if (!p->started_picking) {
start_picking(p, call_list);
}
for (i = 0; i < p->num_subchannels; i++) {
grpc_subchannel_add_interested_party(p->subchannels[i], pollset,
call_list);
}
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
pp->pollset = pollset;
pp->target = target;
pp->on_complete = on_complete;
p->pending_picks = pp;
gpr_mu_unlock(&p->mu);
}
}
static void rr_connectivity_changed(void *arg, int iomgr_success,
grpc_call_list *call_list) {
connectivity_changed_cb_arg *cb_arg = arg;
round_robin_lb_policy *p = cb_arg->p;
/* index over p->subchannels of this cb's subchannel */
const size_t this_idx = cb_arg->subchannel_idx;
pending_pick *pp;
ready_list *selected;
int unref = 0;
/* connectivity state of this cb's subchannel */
grpc_connectivity_state *this_connectivity;
gpr_mu_lock(&p->mu);
this_connectivity = &p->subchannel_connectivity[this_idx];
if (p->shutdown) {
unref = 1;
} else {
switch (*this_connectivity) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
"connecting_ready", call_list);
/* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */
p->subchannel_index_to_readylist_node[this_idx] =
add_connected_sc_locked(p, p->subchannels[this_idx]);
/* at this point we know there's at least one suitable subchannel. Go
* ahead and pick one and notify the pending suitors in
* p->pending_picks. This preemtively replicates rr_pick()'s actions. */
selected = peek_next_connected_locked(p);
if (p->pending_picks != NULL) {
/* if the selected subchannel is going to be used for the pending
* picks, update the last picked pointer */
advance_last_picked_locked(p);
}
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = selected->subchannel;
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected);
}
grpc_subchannel_del_interested_party(selected->subchannel,
pp->pollset, call_list);
grpc_call_list_add(call_list, pp->on_complete, 1);
gpr_free(pp);
}
grpc_subchannel_notify_on_state_change(
p->subchannels[this_idx], this_connectivity,
&p->connectivity_changed_cbs[this_idx], call_list);
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(&p->state_tracker, *this_connectivity,
"connecting_changed", call_list);
grpc_subchannel_notify_on_state_change(
p->subchannels[this_idx], this_connectivity,
&p->connectivity_changed_cbs[this_idx], call_list);
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
del_interested_parties_locked(p, this_idx, call_list);
/* renew state notification */
grpc_subchannel_notify_on_state_change(
p->subchannels[this_idx], this_connectivity,
&p->connectivity_changed_cbs[this_idx], call_list);
/* remove from ready list if still present */
if (p->subchannel_index_to_readylist_node[this_idx] != NULL) {
remove_disconnected_sc_locked(
p, p->subchannel_index_to_readylist_node[this_idx]);
p->subchannel_index_to_readylist_node[this_idx] = NULL;
}
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure", call_list);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(p, this_idx, call_list);
if (p->subchannel_index_to_readylist_node[this_idx] != NULL) {
remove_disconnected_sc_locked(
p, p->subchannel_index_to_readylist_node[this_idx]);
p->subchannel_index_to_readylist_node[this_idx] = NULL;
}
GPR_SWAP(grpc_subchannel *, p->subchannels[this_idx],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "round_robin",
call_list);
if (p->num_subchannels == 0) {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE,
"no_more_channels", call_list);
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_call_list_add(call_list, pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
} else {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"subchannel_failed", call_list);
}
} /* switch */
} /* !unref */
gpr_mu_unlock(&p->mu);
if (unref) {
GRPC_LB_POLICY_UNREF(&p->base, "round_robin_connectivity", call_list);
}
}
static void rr_broadcast(grpc_lb_policy *pol, grpc_transport_op *op,
grpc_call_list *call_list) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
size_t i;
size_t n;
grpc_subchannel **subchannels;
gpr_mu_lock(&p->mu);
n = p->num_subchannels;
subchannels = gpr_malloc(n * sizeof(*subchannels));
for (i = 0; i < n; i++) {
subchannels[i] = p->subchannels[i];
GRPC_SUBCHANNEL_REF(subchannels[i], "rr_broadcast");
}
gpr_mu_unlock(&p->mu);
for (i = 0; i < n; i++) {
grpc_subchannel_process_transport_op(subchannels[i], op, call_list);
GRPC_SUBCHANNEL_UNREF(subchannels[i], "rr_broadcast", call_list);
}
gpr_free(subchannels);
}
static grpc_connectivity_state rr_check_connectivity(
grpc_lb_policy *pol, grpc_call_list *call_list) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
grpc_connectivity_state st;
gpr_mu_lock(&p->mu);
st = grpc_connectivity_state_check(&p->state_tracker);
gpr_mu_unlock(&p->mu);
return st;
}
static void rr_notify_on_state_change(grpc_lb_policy *pol,
grpc_connectivity_state *current,
grpc_closure *notify,
grpc_call_list *call_list) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
gpr_mu_lock(&p->mu);
grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current,
notify, call_list);
gpr_mu_unlock(&p->mu);
}
static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
rr_destroy,
rr_shutdown,
rr_pick,
rr_exit_idle,
rr_broadcast,
rr_check_connectivity,
rr_notify_on_state_change};
static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
size_t i;
round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
GPR_ASSERT(args->num_subchannels > 0);
memset(p, 0, sizeof(*p));
grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
p->subchannels =
gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
p->num_subchannels = args->num_subchannels;
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"round_robin");
memcpy(p->subchannels, args->subchannels,
sizeof(grpc_subchannel *) * args->num_subchannels);
gpr_mu_init(&p->mu);
p->connectivity_changed_cbs =
gpr_malloc(sizeof(grpc_closure) * args->num_subchannels);
p->subchannel_connectivity =
gpr_malloc(sizeof(grpc_connectivity_state) * args->num_subchannels);
p->cb_args =
gpr_malloc(sizeof(connectivity_changed_cb_arg) * args->num_subchannels);
for (i = 0; i < args->num_subchannels; i++) {
p->cb_args[i].subchannel_idx = i;
p->cb_args[i].p = p;
grpc_closure_init(&p->connectivity_changed_cbs[i], rr_connectivity_changed,
&p->cb_args[i]);
}
/* The (dummy node) root of the ready list */
p->ready_list.subchannel = NULL;
p->ready_list.prev = NULL;
p->ready_list.next = NULL;
p->ready_list_last_pick = &p->ready_list;
p->subchannel_index_to_readylist_node =
gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
memset(p->subchannel_index_to_readylist_node, 0,
sizeof(grpc_subchannel *) * args->num_subchannels);
return &p->base;
}
static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
round_robin_factory_ref, round_robin_factory_unref, create_round_robin,
"round_robin"};
static grpc_lb_policy_factory round_robin_lb_policy_factory = {
&round_robin_factory_vtable};
grpc_lb_policy_factory *grpc_round_robin_lb_factory_create() {
return &round_robin_lb_policy_factory;
}

@ -0,0 +1,46 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_ROUND_ROBIN_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_ROUND_ROBIN_H
#include "src/core/client_config/lb_policy.h"
extern int grpc_lb_round_robin_trace;
#include "src/core/client_config/lb_policy_factory.h"
/** Returns a load balancing factory for the round robin policy */
grpc_lb_policy_factory *grpc_round_robin_lb_factory_create();
#endif

@ -284,7 +284,7 @@ done:
static void do_nothing(void *ignored) {} static void do_nothing(void *ignored) {}
static grpc_resolver *sockaddr_create( static grpc_resolver *sockaddr_create(
grpc_resolver_args *args, const char *lb_policy_name, grpc_resolver_args *args, const char *default_lb_policy_name,
int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) { int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) {
size_t i; size_t i;
int errors_found = 0; /* GPR_FALSE */ int errors_found = 0; /* GPR_FALSE */
@ -293,13 +293,34 @@ static grpc_resolver *sockaddr_create(
gpr_slice_buffer path_parts; gpr_slice_buffer path_parts;
if (0 != strcmp(args->uri->authority, "")) { if (0 != strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported"); gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
args->uri->scheme);
return NULL; return NULL;
} }
r = gpr_malloc(sizeof(sockaddr_resolver)); r = gpr_malloc(sizeof(sockaddr_resolver));
memset(r, 0, sizeof(*r)); memset(r, 0, sizeof(*r));
r->lb_policy_name = NULL;
if (0 != strcmp(args->uri->query, "")) {
gpr_slice query_slice;
gpr_slice_buffer query_parts;
query_slice =
gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing);
gpr_slice_buffer_init(&query_parts);
gpr_slice_split(query_slice, "=", &query_parts);
GPR_ASSERT(query_parts.count == 2);
if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) {
r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII);
}
gpr_slice_buffer_destroy(&query_parts);
gpr_slice_unref(query_slice);
}
if (r->lb_policy_name == NULL) {
r->lb_policy_name = gpr_strdup(default_lb_policy_name);
}
path_slice = path_slice =
gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing); gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
gpr_slice_buffer_init(&path_parts); gpr_slice_buffer_init(&path_parts);
@ -332,7 +353,6 @@ static grpc_resolver *sockaddr_create(
grpc_resolver_init(&r->base, &sockaddr_resolver_vtable); grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
r->subchannel_factory = args->subchannel_factory; r->subchannel_factory = args->subchannel_factory;
grpc_subchannel_factory_ref(r->subchannel_factory); grpc_subchannel_factory_ref(r->subchannel_factory);
r->lb_policy_name = gpr_strdup(lb_policy_name);
return &r->base; return &r->base;
} }

@ -35,7 +35,7 @@
#include <string.h> #include <string.h>
#include "src/core/security/secure_transport_setup.h" #include "src/core/security/handshake.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
@ -58,20 +58,29 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
gpr_free(sc); gpr_free(sc);
} }
static grpc_security_status httpcli_ssl_create_handshaker( static void httpcli_ssl_do_handshake(grpc_security_connector *sc,
grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_httpcli_ssl_channel_security_connector *c = grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc; (grpc_httpcli_ssl_channel_security_connector *)sc;
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR; tsi_handshaker *handshaker;
if (c->handshaker_factory == NULL) {
cb(user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL, call_list);
return;
}
result = tsi_ssl_handshaker_factory_create_handshaker( result = tsi_ssl_handshaker_factory_create_handshaker(
c->handshaker_factory, c->secure_peer_name, handshaker); c->handshaker_factory, c->secure_peer_name, &handshaker);
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.", gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
return GRPC_SECURITY_ERROR; cb(user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL, call_list);
} else {
grpc_do_security_handshake(handshaker, sc, nonsecure_endpoint, cb,
user_data, call_list);
} }
return GRPC_SECURITY_OK;
} }
static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc, static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc,
@ -94,7 +103,7 @@ static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc,
} }
static grpc_security_connector_vtable httpcli_ssl_vtable = { static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer}; httpcli_ssl_destroy, httpcli_ssl_do_handshake, httpcli_ssl_check_peer};
static grpc_security_status httpcli_ssl_channel_security_connector_create( static grpc_security_status httpcli_ssl_channel_security_connector_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size, const unsigned char *pem_root_certs, size_t pem_root_certs_size,
@ -172,8 +181,8 @@ static void ssl_handshake(void *arg, grpc_endpoint *tcp, const char *host,
GPR_ASSERT(httpcli_ssl_channel_security_connector_create( GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
pem_root_certs, pem_root_certs_size, host, &sc) == pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK); GRPC_SECURITY_OK);
grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done, c, grpc_security_connector_do_handshake(
call_list); &sc->base, tcp, on_secure_transport_setup_done, c, call_list);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
} }

@ -39,7 +39,7 @@
/* Forward decl of grpc_tcp_server */ /* Forward decl of grpc_tcp_server */
typedef struct grpc_tcp_server grpc_tcp_server; typedef struct grpc_tcp_server grpc_tcp_server;
/* New server callback: tcp is the newly connected tcp connection */ /* Called for newly connected TCP connections. */
typedef void (*grpc_tcp_server_cb)(void *arg, grpc_endpoint *ep, typedef void (*grpc_tcp_server_cb)(void *arg, grpc_endpoint *ep,
grpc_call_list *call_list); grpc_call_list *call_list);
@ -48,8 +48,9 @@ grpc_tcp_server *grpc_tcp_server_create(void);
/* Start listening to bound ports */ /* Start listening to bound ports */
void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset **pollsets, void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset **pollsets,
size_t pollset_count, grpc_tcp_server_cb cb, size_t pollset_count,
void *cb_arg, grpc_call_list *call_list); grpc_tcp_server_cb on_accept_cb, void *cb_arg,
grpc_call_list *call_list);
/* Add a port to the server, returning port number on success, or negative /* Add a port to the server, returning port number on success, or negative
on failure. on failure.

@ -98,8 +98,9 @@ static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
/* the overall server */ /* the overall server */
struct grpc_tcp_server { struct grpc_tcp_server {
grpc_tcp_server_cb cb; /* Called whenever accept() succeeds on a server port. */
void *cb_arg; grpc_tcp_server_cb on_accept_cb;
void *on_accept_cb_arg;
gpr_mu mu; gpr_mu mu;
@ -131,8 +132,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
s->active_ports = 0; s->active_ports = 0;
s->destroyed_ports = 0; s->destroyed_ports = 0;
s->shutdown = 0; s->shutdown = 0;
s->cb = NULL; s->on_accept_cb = NULL;
s->cb_arg = NULL; s->on_accept_cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->nports = 0; s->nports = 0;
s->port_capacity = INIT_PORT_CAP; s->port_capacity = INIT_PORT_CAP;
@ -345,8 +346,8 @@ static void on_read(void *arg, int success, grpc_call_list *call_list) {
for (i = 0; i < sp->server->pollset_count; i++) { for (i = 0; i < sp->server->pollset_count; i++) {
grpc_pollset_add_fd(sp->server->pollsets[i], fdobj, call_list); grpc_pollset_add_fd(sp->server->pollsets[i], fdobj, call_list);
} }
sp->server->cb( sp->server->on_accept_cb(
sp->server->cb_arg, sp->server->on_accept_cb_arg,
grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str), grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
call_list); call_list);
@ -378,7 +379,7 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1); grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str); gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb && "must add ports before starting server"); GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
/* append it to the list under a lock */ /* append it to the list under a lock */
if (s->nports == s->port_capacity) { if (s->nports == s->port_capacity) {
s->port_capacity *= 2; s->port_capacity *= 2;
@ -485,15 +486,16 @@ int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index) {
} }
void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollsets, void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollsets,
size_t pollset_count, grpc_tcp_server_cb cb, size_t pollset_count,
void *cb_arg, grpc_call_list *call_list) { grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg, grpc_call_list *call_list) {
size_t i, j; size_t i, j;
GPR_ASSERT(cb); GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb); GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0); GPR_ASSERT(s->active_ports == 0);
s->cb = cb; s->on_accept_cb = on_accept_cb;
s->cb_arg = cb_arg; s->on_accept_cb_arg = on_accept_cb_arg;
s->pollsets = pollsets; s->pollsets = pollsets;
s->pollset_count = pollset_count; s->pollset_count = pollset_count;
for (i = 0; i < s->nports; i++) { for (i = 0; i < s->nports; i++) {

@ -71,8 +71,9 @@ typedef struct server_port {
/* the overall server */ /* the overall server */
struct grpc_tcp_server { struct grpc_tcp_server {
grpc_tcp_server_cb cb; /* Called whenever accept() succeeds on a server port. */
void *cb_arg; grpc_tcp_server_cb on_accept_cb;
void *on_accept_cb_arg;
gpr_mu mu; gpr_mu mu;
@ -95,8 +96,8 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server)); grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
gpr_mu_init(&s->mu); gpr_mu_init(&s->mu);
s->active_ports = 0; s->active_ports = 0;
s->cb = NULL; s->on_accept_cb = NULL;
s->cb_arg = NULL; s->on_accept_cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP); s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->nports = 0; s->nports = 0;
s->port_capacity = INIT_PORT_CAP; s->port_capacity = INIT_PORT_CAP;
@ -344,7 +345,7 @@ static void on_accept(void *arg, int from_iocp) {
/* The only time we should call our callback, is where we successfully /* The only time we should call our callback, is where we successfully
managed to accept a connection, and created an endpoint. */ managed to accept a connection, and created an endpoint. */
if (ep) sp->server->cb(sp->server->cb_arg, ep); if (ep) sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep);
/* As we were notified from the IOCP of one and exactly one accept, /* As we were notified from the IOCP of one and exactly one accept,
the former socked we created has now either been destroy or assigned the former socked we created has now either been destroy or assigned
to the new connection. We need to create a new one for the next to the new connection. We need to create a new one for the next
@ -380,7 +381,7 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
port = prepare_socket(sock, addr, addr_len); port = prepare_socket(sock, addr, addr_len);
if (port >= 0) { if (port >= 0) {
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb && "must add ports before starting server"); GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
/* append it to the list under a lock */ /* append it to the list under a lock */
if (s->nports == s->port_capacity) { if (s->nports == s->port_capacity) {
s->port_capacity *= 2; s->port_capacity *= 2;
@ -462,15 +463,16 @@ SOCKET grpc_tcp_server_get_socket(grpc_tcp_server *s, unsigned index) {
} }
void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset, void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
size_t pollset_count, grpc_tcp_server_cb cb, size_t pollset_count,
void *cb_arg) { grpc_tcp_server_cb on_accept_cb,
void *on_accept_cb_arg) {
size_t i; size_t i;
GPR_ASSERT(cb); GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->cb); GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0); GPR_ASSERT(s->active_ports == 0);
s->cb = cb; s->on_accept_cb = on_accept_cb;
s->cb_arg = cb_arg; s->on_accept_cb_arg = on_accept_cb_arg;
for (i = 0; i < s->nports; i++) { for (i = 0; i < s->nports; i++) {
start_accept(s->ports + i); start_accept(s->ports + i);
s->active_ports++; s->active_ports++;

@ -63,6 +63,7 @@ typedef struct {
int sent_initial_metadata; int sent_initial_metadata;
gpr_uint8 security_context_set; gpr_uint8 security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
char *service_url;
} call_data; } call_data;
/* We can have a per-channel credentials. */ /* We can have a per-channel credentials. */
@ -75,6 +76,13 @@ typedef struct {
grpc_mdstr *status_key; grpc_mdstr *status_key;
} channel_data; } channel_data;
static void reset_service_url(call_data *calld) {
if (calld->service_url != NULL) {
gpr_free(calld->service_url);
calld->service_url = NULL;
}
}
static void bubble_up_error(grpc_call_element *elem, grpc_status_code status, static void bubble_up_error(grpc_call_element *elem, grpc_status_code status,
const char *error_msg, grpc_call_list *call_list) { const char *error_msg, grpc_call_list *call_list) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
@ -94,6 +102,7 @@ static void on_credentials_metadata(void *user_data,
grpc_transport_stream_op *op = &calld->op; grpc_transport_stream_op *op = &calld->op;
grpc_metadata_batch *mdb; grpc_metadata_batch *mdb;
size_t i; size_t i;
reset_service_url(calld);
if (status != GRPC_CREDENTIALS_OK) { if (status != GRPC_CREDENTIALS_OK) {
bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED, bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED,
"Credentials failed to get metadata.", call_list); "Credentials failed to get metadata.", call_list);
@ -112,8 +121,7 @@ static void on_credentials_metadata(void *user_data,
grpc_call_next_op(elem, op, call_list); grpc_call_next_op(elem, op, call_list);
} }
static char *build_service_url(const char *url_scheme, call_data *calld) { void build_service_url(const char *url_scheme, call_data *calld) {
char *service_url;
char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
char *last_slash = strrchr(service, '/'); char *last_slash = strrchr(service, '/');
if (last_slash == NULL) { if (last_slash == NULL) {
@ -126,10 +134,10 @@ static char *build_service_url(const char *url_scheme, call_data *calld) {
*last_slash = '\0'; *last_slash = '\0';
} }
if (url_scheme == NULL) url_scheme = ""; if (url_scheme == NULL) url_scheme = "";
gpr_asprintf(&service_url, "%s://%s%s", url_scheme, reset_service_url(calld);
gpr_asprintf(&calld->service_url, "%s://%s%s", url_scheme,
grpc_mdstr_as_c_string(calld->host), service); grpc_mdstr_as_c_string(calld->host), service);
gpr_free(service); gpr_free(service);
return service_url;
} }
static void send_security_metadata(grpc_call_element *elem, static void send_security_metadata(grpc_call_element *elem,
@ -139,7 +147,6 @@ static void send_security_metadata(grpc_call_element *elem,
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_client_security_context *ctx = grpc_client_security_context *ctx =
(grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
char *service_url = NULL;
grpc_credentials *channel_creds = grpc_credentials *channel_creds =
chand->security_connector->request_metadata_creds; chand->security_connector->request_metadata_creds;
int channel_creds_has_md = int channel_creds_has_md =
@ -168,14 +175,12 @@ static void send_security_metadata(grpc_call_element *elem,
grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds); grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds);
} }
service_url = build_service_url(chand->security_connector->base.url_scheme, calld);
build_service_url(chand->security_connector->base.url_scheme, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */ calld->op = *op; /* Copy op (originates from the caller's stack). */
GPR_ASSERT(calld->pollset); GPR_ASSERT(calld->pollset);
grpc_credentials_get_request_metadata(calld->creds, calld->pollset, grpc_credentials_get_request_metadata(
service_url, on_credentials_metadata, calld->creds, calld->pollset, calld->service_url, on_credentials_metadata,
elem, call_list); elem, call_list);
gpr_free(service_url);
} }
static void on_host_checked(void *user_data, grpc_security_status status, static void on_host_checked(void *user_data, grpc_security_status status,
@ -283,13 +288,7 @@ static void init_call_elem(grpc_call_element *elem,
grpc_transport_stream_op *initial_op, grpc_transport_stream_op *initial_op,
grpc_call_list *call_list) { grpc_call_list *call_list) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
calld->creds = NULL; memset(calld, 0, sizeof(*calld));
calld->host = NULL;
calld->method = NULL;
calld->pollset = NULL;
calld->sent_initial_metadata = 0;
calld->security_context_set = 0;
GPR_ASSERT(!initial_op || !initial_op->send_ops); GPR_ASSERT(!initial_op || !initial_op->send_ops);
} }
@ -304,6 +303,7 @@ static void destroy_call_elem(grpc_call_element *elem,
if (calld->method != NULL) { if (calld->method != NULL) {
GRPC_MDSTR_UNREF(calld->method); GRPC_MDSTR_UNREF(calld->method);
} }
reset_service_url(calld);
} }
/* Constructor for channel_data */ /* Constructor for channel_data */

@ -1197,3 +1197,97 @@ grpc_credentials *grpc_google_iam_credentials_create(
c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
return &c->base; return &c->base;
} }
/* -- Plugin credentials. -- */
typedef struct {
void *user_data;
grpc_credentials_metadata_cb cb;
} grpc_metadata_plugin_request;
static void plugin_destruct(grpc_credentials *creds) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
c->plugin.destroy(c->plugin.state);
}
}
static int plugin_has_request_metadata(const grpc_credentials *creds) {
return 1;
}
static int plugin_has_request_metadata_only(const grpc_credentials *creds) {
return 1;
}
static void plugin_md_request_metadata_ready(void *request,
const grpc_metadata *md,
size_t num_md,
grpc_status_code status,
const char *error_details) {
/* called from application code */
grpc_call_list call_list = GRPC_CALL_LIST_INIT;
grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
if (status != GRPC_STATUS_OK) {
if (error_details != NULL) {
gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s",
error_details);
}
r->cb(r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR, &call_list);
} else {
size_t i;
grpc_credentials_md *md_array = NULL;
if (num_md > 0) {
md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
for (i = 0; i < num_md; i++) {
md_array[i].key = gpr_slice_from_copied_string(md[i].key);
md_array[i].value =
gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
}
}
r->cb(r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK, &call_list);
if (md_array != NULL) {
for (i = 0; i < num_md; i++) {
gpr_slice_unref(md_array[i].key);
gpr_slice_unref(md_array[i].value);
}
gpr_free(md_array);
}
}
gpr_free(r);
}
static void plugin_get_request_metadata(grpc_credentials *creds,
grpc_pollset *pollset,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
if (c->plugin.get_metadata != NULL) {
grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
memset(request, 0, sizeof(*request));
request->user_data = user_data;
request->cb = cb;
c->plugin.get_metadata(c->plugin.state, service_url,
plugin_md_request_metadata_ready, request);
} else {
cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK, call_list);
}
}
static grpc_credentials_vtable plugin_vtable = {
plugin_destruct, plugin_has_request_metadata,
plugin_has_request_metadata_only, plugin_get_request_metadata, NULL};
grpc_credentials *grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void *reserved) {
grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(*c));
c->base.type = GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN;
c->base.vtable = &plugin_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->plugin = plugin;
return &c->base;
}

@ -56,6 +56,7 @@ typedef enum {
#define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
#define GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
#define GRPC_CREDENTIALS_TYPE_JWT "Jwt" #define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
#define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_IAM "Iam"
#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite"
@ -325,4 +326,12 @@ typedef struct {
grpc_credentials *connector_creds; grpc_credentials *connector_creds;
} grpc_composite_credentials; } grpc_composite_credentials;
/* -- Plugin credentials. -- */
typedef struct {
grpc_credentials base;
grpc_metadata_credentials_plugin plugin;
grpc_credentials_md_store *plugin_md;
} grpc_plugin_credentials;
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */ #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */

@ -31,7 +31,7 @@
* *
*/ */
#include "src/core/security/secure_transport_setup.h" #include "src/core/security/handshake.h"
#include <string.h> #include <string.h>
@ -52,11 +52,11 @@ typedef struct {
gpr_slice_buffer left_overs; gpr_slice_buffer left_overs;
gpr_slice_buffer incoming; gpr_slice_buffer incoming;
gpr_slice_buffer outgoing; gpr_slice_buffer outgoing;
grpc_secure_transport_setup_done_cb cb; grpc_security_handshake_done_cb cb;
void *user_data; void *user_data;
grpc_closure on_handshake_data_sent_to_peer; grpc_closure on_handshake_data_sent_to_peer;
grpc_closure on_handshake_data_received_from_peer; grpc_closure on_handshake_data_received_from_peer;
} grpc_secure_transport_setup; } grpc_security_handshake;
static void on_handshake_data_received_from_peer(void *setup, int success, static void on_handshake_data_received_from_peer(void *setup, int success,
grpc_call_list *call_list); grpc_call_list *call_list);
@ -64,119 +64,117 @@ static void on_handshake_data_received_from_peer(void *setup, int success,
static void on_handshake_data_sent_to_peer(void *setup, int success, static void on_handshake_data_sent_to_peer(void *setup, int success,
grpc_call_list *call_list); grpc_call_list *call_list);
static void secure_transport_setup_done(grpc_secure_transport_setup *s, static void security_handshake_done(grpc_security_handshake *h, int is_success,
int is_success, grpc_call_list *call_list) {
grpc_call_list *call_list) {
if (is_success) { if (is_success) {
s->cb(s->user_data, GRPC_SECURITY_OK, s->wrapped_endpoint, h->cb(h->user_data, GRPC_SECURITY_OK, h->wrapped_endpoint,
s->secure_endpoint, call_list); h->secure_endpoint, call_list);
} else { } else {
if (s->secure_endpoint != NULL) { if (h->secure_endpoint != NULL) {
grpc_endpoint_shutdown(s->secure_endpoint, call_list); grpc_endpoint_shutdown(h->secure_endpoint, call_list);
grpc_endpoint_destroy(s->secure_endpoint, call_list); grpc_endpoint_destroy(h->secure_endpoint, call_list);
} else { } else {
grpc_endpoint_destroy(s->wrapped_endpoint, call_list); grpc_endpoint_destroy(h->wrapped_endpoint, call_list);
} }
s->cb(s->user_data, GRPC_SECURITY_ERROR, s->wrapped_endpoint, NULL, h->cb(h->user_data, GRPC_SECURITY_ERROR, h->wrapped_endpoint, NULL,
call_list); call_list);
} }
if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker); if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
gpr_slice_buffer_destroy(&s->left_overs); gpr_slice_buffer_destroy(&h->left_overs);
gpr_slice_buffer_destroy(&s->outgoing); gpr_slice_buffer_destroy(&h->outgoing);
gpr_slice_buffer_destroy(&s->incoming); gpr_slice_buffer_destroy(&h->incoming);
GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup"); GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
gpr_free(s); gpr_free(h);
} }
static void on_peer_checked(void *user_data, grpc_security_status status, static void on_peer_checked(void *user_data, grpc_security_status status,
grpc_call_list *call_list) { grpc_call_list *call_list) {
grpc_secure_transport_setup *s = user_data; grpc_security_handshake *h = user_data;
tsi_frame_protector *protector; tsi_frame_protector *protector;
tsi_result result; tsi_result result;
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Error checking peer."); gpr_log(GPR_ERROR, "Error checking peer.");
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
result = result =
tsi_handshaker_create_frame_protector(s->handshaker, NULL, &protector); tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.", gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
s->secure_endpoint = h->secure_endpoint =
grpc_secure_endpoint_create(protector, s->wrapped_endpoint, grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
s->left_overs.slices, s->left_overs.count); h->left_overs.slices, h->left_overs.count);
s->left_overs.count = 0; h->left_overs.count = 0;
s->left_overs.length = 0; h->left_overs.length = 0;
secure_transport_setup_done(s, 1, call_list); security_handshake_done(h, 1, call_list);
return; return;
} }
static void check_peer(grpc_secure_transport_setup *s, static void check_peer(grpc_security_handshake *h, grpc_call_list *call_list) {
grpc_call_list *call_list) {
grpc_security_status peer_status; grpc_security_status peer_status;
tsi_peer peer; tsi_peer peer;
tsi_result result = tsi_handshaker_extract_peer(s->handshaker, &peer); tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Peer extraction failed with error %s", gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
tsi_result_to_string(result)); tsi_result_to_string(result));
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
peer_status = grpc_security_connector_check_peer(s->connector, peer, peer_status = grpc_security_connector_check_peer(h->connector, peer,
on_peer_checked, s); on_peer_checked, h);
if (peer_status == GRPC_SECURITY_ERROR) { if (peer_status == GRPC_SECURITY_ERROR) {
gpr_log(GPR_ERROR, "Peer check failed."); gpr_log(GPR_ERROR, "Peer check failed.");
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} else if (peer_status == GRPC_SECURITY_OK) { } else if (peer_status == GRPC_SECURITY_OK) {
on_peer_checked(s, peer_status, call_list); on_peer_checked(h, peer_status, call_list);
} }
} }
static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s, static void send_handshake_bytes_to_peer(grpc_security_handshake *h,
grpc_call_list *call_list) { grpc_call_list *call_list) {
size_t offset = 0; size_t offset = 0;
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
gpr_slice to_send; gpr_slice to_send;
do { do {
size_t to_send_size = s->handshake_buffer_size - offset; size_t to_send_size = h->handshake_buffer_size - offset;
result = tsi_handshaker_get_bytes_to_send_to_peer( result = tsi_handshaker_get_bytes_to_send_to_peer(
s->handshaker, s->handshake_buffer + offset, &to_send_size); h->handshaker, h->handshake_buffer + offset, &to_send_size);
offset += to_send_size; offset += to_send_size;
if (result == TSI_INCOMPLETE_DATA) { if (result == TSI_INCOMPLETE_DATA) {
s->handshake_buffer_size *= 2; h->handshake_buffer_size *= 2;
s->handshake_buffer = h->handshake_buffer =
gpr_realloc(s->handshake_buffer, s->handshake_buffer_size); gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
} }
} while (result == TSI_INCOMPLETE_DATA); } while (result == TSI_INCOMPLETE_DATA);
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshake failed with error %s", gpr_log(GPR_ERROR, "Handshake failed with error %s",
tsi_result_to_string(result)); tsi_result_to_string(result));
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
to_send = to_send =
gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset); gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
gpr_slice_buffer_reset_and_unref(&s->outgoing); gpr_slice_buffer_reset_and_unref(&h->outgoing);
gpr_slice_buffer_add(&s->outgoing, to_send); gpr_slice_buffer_add(&h->outgoing, to_send);
/* TODO(klempner,jboeuf): This should probably use the client setup /* TODO(klempner,jboeuf): This should probably use the client setup
deadline */ deadline */
grpc_endpoint_write(s->wrapped_endpoint, &s->outgoing, grpc_endpoint_write(h->wrapped_endpoint, &h->outgoing,
&s->on_handshake_data_sent_to_peer, call_list); &h->on_handshake_data_sent_to_peer, call_list);
} }
static void on_handshake_data_received_from_peer(void *setup, int success, static void on_handshake_data_received_from_peer(void *handshake, int success,
grpc_call_list *call_list) { grpc_call_list *call_list) {
grpc_secure_transport_setup *s = setup; grpc_security_handshake *h = handshake;
size_t consumed_slice_size = 0; size_t consumed_slice_size = 0;
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
size_t i; size_t i;
@ -185,26 +183,26 @@ static void on_handshake_data_received_from_peer(void *setup, int success,
if (!success) { if (!success) {
gpr_log(GPR_ERROR, "Read failed."); gpr_log(GPR_ERROR, "Read failed.");
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
for (i = 0; i < s->incoming.count; i++) { for (i = 0; i < h->incoming.count; i++) {
consumed_slice_size = GPR_SLICE_LENGTH(s->incoming.slices[i]); consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]);
result = tsi_handshaker_process_bytes_from_peer( result = tsi_handshaker_process_bytes_from_peer(
s->handshaker, GPR_SLICE_START_PTR(s->incoming.slices[i]), h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]),
&consumed_slice_size); &consumed_slice_size);
if (!tsi_handshaker_is_in_progress(s->handshaker)) break; if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
} }
if (tsi_handshaker_is_in_progress(s->handshaker)) { if (tsi_handshaker_is_in_progress(h->handshaker)) {
/* We may need more data. */ /* We may need more data. */
if (result == TSI_INCOMPLETE_DATA) { if (result == TSI_INCOMPLETE_DATA) {
grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, grpc_endpoint_read(h->wrapped_endpoint, &h->incoming,
&s->on_handshake_data_received_from_peer, call_list); &h->on_handshake_data_received_from_peer, call_list);
return; return;
} else { } else {
send_handshake_bytes_to_peer(s, call_list); send_handshake_bytes_to_peer(h, call_list);
return; return;
} }
} }
@ -212,80 +210,77 @@ static void on_handshake_data_received_from_peer(void *setup, int success,
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshake failed with error %s", gpr_log(GPR_ERROR, "Handshake failed with error %s",
tsi_result_to_string(result)); tsi_result_to_string(result));
secure_transport_setup_done(s, 0, call_list); security_handshake_done(h, 0, call_list);
return; return;
} }
/* Handshake is done and successful this point. */ /* Handshake is done and successful this point. */
has_left_overs_in_current_slice = has_left_overs_in_current_slice =
(consumed_slice_size < GPR_SLICE_LENGTH(s->incoming.slices[i])); (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i]));
num_left_overs = num_left_overs =
(has_left_overs_in_current_slice ? 1 : 0) + s->incoming.count - i - 1; (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
if (num_left_overs == 0) { if (num_left_overs == 0) {
check_peer(s, call_list); check_peer(h, call_list);
return; return;
} }
/* Put the leftovers in our buffer (ownership transfered). */ /* Put the leftovers in our buffer (ownership transfered). */
if (has_left_overs_in_current_slice) { if (has_left_overs_in_current_slice) {
gpr_slice_buffer_add( gpr_slice_buffer_add(
&s->left_overs, &h->left_overs,
gpr_slice_split_tail(&s->incoming.slices[i], consumed_slice_size)); gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
gpr_slice_unref( gpr_slice_unref(
s->incoming.slices[i]); /* split_tail above increments refcount. */ h->incoming.slices[i]); /* split_tail above increments refcount. */
} }
gpr_slice_buffer_addn( gpr_slice_buffer_addn(
&s->left_overs, &s->incoming.slices[i + 1], &h->left_overs, &h->incoming.slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice); num_left_overs - (size_t)has_left_overs_in_current_slice);
check_peer(s, call_list); check_peer(h, call_list);
} }
/* If setup is NULL, the setup is done. */ /* If handshake is NULL, the handshake is done. */
static void on_handshake_data_sent_to_peer(void *setup, int success, static void on_handshake_data_sent_to_peer(void *handshake, int success,
grpc_call_list *call_list) { grpc_call_list *call_list) {
grpc_secure_transport_setup *s = setup; grpc_security_handshake *h = handshake;
/* Make sure that write is OK. */ /* Make sure that write is OK. */
if (!success) { if (!success) {
gpr_log(GPR_ERROR, "Write failed."); gpr_log(GPR_ERROR, "Write failed.");
if (setup != NULL) secure_transport_setup_done(s, 0, call_list); if (handshake != NULL) security_handshake_done(h, 0, call_list);
return; return;
} }
/* We may be done. */ /* We may be done. */
if (tsi_handshaker_is_in_progress(s->handshaker)) { if (tsi_handshaker_is_in_progress(h->handshaker)) {
grpc_endpoint_read(s->wrapped_endpoint, &s->incoming, /* TODO(klempner,jboeuf): This should probably use the client setup
&s->on_handshake_data_received_from_peer, call_list); deadline */
grpc_endpoint_read(h->wrapped_endpoint, &h->incoming,
&h->on_handshake_data_received_from_peer, call_list);
} else { } else {
check_peer(s, call_list); check_peer(h, call_list);
} }
} }
void grpc_setup_secure_transport(grpc_security_connector *connector, void grpc_do_security_handshake(tsi_handshaker *handshaker,
grpc_endpoint *nonsecure_endpoint, grpc_security_connector *connector,
grpc_secure_transport_setup_done_cb cb, grpc_endpoint *nonsecure_endpoint,
void *user_data, grpc_call_list *call_list) { grpc_security_handshake_done_cb cb,
grpc_security_status result = GRPC_SECURITY_OK; void *user_data, grpc_call_list *call_list) {
grpc_secure_transport_setup *s = grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
gpr_malloc(sizeof(grpc_secure_transport_setup)); memset(h, 0, sizeof(grpc_security_handshake));
memset(s, 0, sizeof(grpc_secure_transport_setup)); h->handshaker = handshaker;
result = grpc_security_connector_create_handshaker(connector, &s->handshaker); h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
if (result != GRPC_SECURITY_OK) { h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
secure_transport_setup_done(s, 0, call_list); h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
return; h->wrapped_endpoint = nonsecure_endpoint;
} h->user_data = user_data;
s->connector = h->cb = cb;
GRPC_SECURITY_CONNECTOR_REF(connector, "secure_transport_setup"); grpc_closure_init(&h->on_handshake_data_sent_to_peer,
s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; on_handshake_data_sent_to_peer, h);
s->handshake_buffer = gpr_malloc(s->handshake_buffer_size); grpc_closure_init(&h->on_handshake_data_received_from_peer,
s->wrapped_endpoint = nonsecure_endpoint; on_handshake_data_received_from_peer, h);
s->user_data = user_data; gpr_slice_buffer_init(&h->left_overs);
s->cb = cb; gpr_slice_buffer_init(&h->outgoing);
grpc_closure_init(&s->on_handshake_data_sent_to_peer, gpr_slice_buffer_init(&h->incoming);
on_handshake_data_sent_to_peer, s); send_handshake_bytes_to_peer(h, call_list);
grpc_closure_init(&s->on_handshake_data_received_from_peer,
on_handshake_data_received_from_peer, s);
gpr_slice_buffer_init(&s->left_overs);
gpr_slice_buffer_init(&s->outgoing);
gpr_slice_buffer_init(&s->incoming);
send_handshake_bytes_to_peer(s, call_list);
} }

@ -31,24 +31,17 @@
* *
*/ */
#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #ifndef GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H
#define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #define GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/security/security_connector.h" #include "src/core/security/security_connector.h"
/* --- Secure transport setup --- */ /* Calls the callback upon completion. Takes owership of handshaker. */
void grpc_do_security_handshake(tsi_handshaker *handshaker,
grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data, grpc_call_list *call_list);
/* Ownership of the secure_endpoint is transfered. */ #endif /* GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H */
typedef void (*grpc_secure_transport_setup_done_cb)(
void *user_data, grpc_security_status status,
grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint,
grpc_call_list *call_list);
/* Calls the callback upon completion. */
void grpc_setup_secure_transport(grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint,
grpc_secure_transport_setup_done_cb cb,
void *user_data, grpc_call_list *call_list);
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */

@ -36,6 +36,7 @@
#include <string.h> #include <string.h>
#include "src/core/security/credentials.h" #include "src/core/security/credentials.h"
#include "src/core/security/handshake.h"
#include "src/core/security/secure_endpoint.h" #include "src/core/security/secure_endpoint.h"
#include "src/core/security/security_context.h" #include "src/core/security/security_context.h"
#include "src/core/support/env.h" #include "src/core/support/env.h"
@ -101,10 +102,16 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
return NULL; return NULL;
} }
grpc_security_status grpc_security_connector_create_handshaker( void grpc_security_connector_do_handshake(grpc_security_connector *sc,
grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_endpoint *nonsecure_endpoint,
if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR; grpc_security_handshake_done_cb cb,
return sc->vtable->create_handshaker(sc, handshaker); void *user_data,
grpc_call_list *call_list) {
if (sc == NULL || nonsecure_endpoint == NULL) {
cb(user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL, call_list);
} else {
sc->vtable->do_handshake(sc, nonsecure_endpoint, cb, user_data, call_list);
}
} }
grpc_security_status grpc_security_connector_check_peer( grpc_security_status grpc_security_connector_check_peer(
@ -225,18 +232,6 @@ static void fake_server_destroy(grpc_security_connector *sc) {
gpr_free(sc); gpr_free(sc);
} }
static grpc_security_status fake_channel_create_handshaker(
grpc_security_connector *sc, tsi_handshaker **handshaker) {
*handshaker = tsi_create_fake_handshaker(1);
return GRPC_SECURITY_OK;
}
static grpc_security_status fake_server_create_handshaker(
grpc_security_connector *sc, tsi_handshaker **handshaker) {
*handshaker = tsi_create_fake_handshaker(0);
return GRPC_SECURITY_OK;
}
static grpc_security_status fake_check_peer(grpc_security_connector *sc, static grpc_security_status fake_check_peer(grpc_security_connector *sc,
tsi_peer peer, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
@ -286,11 +281,29 @@ static grpc_security_status fake_channel_check_call_host(
} }
} }
static void fake_channel_do_handshake(grpc_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_do_security_handshake(tsi_create_fake_handshaker(1), sc,
nonsecure_endpoint, cb, user_data, call_list);
}
static void fake_server_do_handshake(grpc_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_do_security_handshake(tsi_create_fake_handshaker(0), sc,
nonsecure_endpoint, cb, user_data, call_list);
}
static grpc_security_connector_vtable fake_channel_vtable = { static grpc_security_connector_vtable fake_channel_vtable = {
fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer}; fake_channel_destroy, fake_channel_do_handshake, fake_check_peer};
static grpc_security_connector_vtable fake_server_vtable = { static grpc_security_connector_vtable fake_server_vtable = {
fake_server_destroy, fake_server_create_handshaker, fake_check_peer}; fake_server_destroy, fake_server_do_handshake, fake_check_peer};
grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_credentials *request_metadata_creds, int call_host_check_is_async) { grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
@ -372,22 +385,43 @@ static grpc_security_status ssl_create_handshaker(
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }
static grpc_security_status ssl_channel_create_handshaker( static void ssl_channel_do_handshake(grpc_security_connector *sc,
grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_ssl_channel_security_connector *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 1, tsi_handshaker *handshaker;
c->overridden_target_name != NULL grpc_security_status status = ssl_create_handshaker(
? c->overridden_target_name c->handshaker_factory, 1,
: c->target_name, c->overridden_target_name != NULL ? c->overridden_target_name
handshaker); : c->target_name,
&handshaker);
if (status != GRPC_SECURITY_OK) {
cb(user_data, status, nonsecure_endpoint, NULL, call_list);
} else {
grpc_do_security_handshake(handshaker, sc, nonsecure_endpoint, cb,
user_data, call_list);
}
} }
static grpc_security_status ssl_server_create_handshaker( static void ssl_server_do_handshake(grpc_security_connector *sc,
grpc_security_connector *sc, tsi_handshaker **handshaker) { grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list) {
grpc_ssl_server_security_connector *c = grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc; (grpc_ssl_server_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); tsi_handshaker *handshaker;
grpc_security_status status =
ssl_create_handshaker(c->handshaker_factory, 0, NULL, &handshaker);
if (status != GRPC_SECURITY_OK) {
cb(user_data, status, nonsecure_endpoint, NULL, call_list);
} else {
grpc_do_security_handshake(handshaker, sc, nonsecure_endpoint, cb,
user_data, call_list);
}
} }
static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
@ -512,10 +546,10 @@ static grpc_security_status ssl_channel_check_call_host(
} }
static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_channel_vtable = {
ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer}; ssl_channel_destroy, ssl_channel_do_handshake, ssl_channel_check_peer};
static grpc_security_connector_vtable ssl_server_vtable = { static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer}; ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer};
static gpr_slice default_pem_root_certs; static gpr_slice default_pem_root_certs;

@ -64,10 +64,19 @@ typedef void (*grpc_security_check_cb)(void *user_data,
grpc_security_status status, grpc_security_status status,
grpc_call_list *call_list); grpc_call_list *call_list);
/* Ownership of the secure_endpoint is transfered. */
typedef void (*grpc_security_handshake_done_cb)(void *user_data,
grpc_security_status status,
grpc_endpoint *wrapped_endpoint,
grpc_endpoint *secure_endpoint,
grpc_call_list *call_list);
typedef struct { typedef struct {
void (*destroy)(grpc_security_connector *sc); void (*destroy)(grpc_security_connector *sc);
grpc_security_status (*create_handshaker)(grpc_security_connector *sc, void (*do_handshake)(grpc_security_connector *sc,
tsi_handshaker **handshaker); grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, void *user_data,
grpc_call_list *call_list);
grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer, grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
void *user_data); void *user_data);
@ -101,9 +110,12 @@ grpc_security_connector *grpc_security_connector_ref(
void grpc_security_connector_unref(grpc_security_connector *policy); void grpc_security_connector_unref(grpc_security_connector *policy);
#endif #endif
/* Handshake creation. */ /* Handshake. */
grpc_security_status grpc_security_connector_create_handshaker( void grpc_security_connector_do_handshake(grpc_security_connector *connector,
grpc_security_connector *sc, tsi_handshaker **handshaker); grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data,
grpc_call_list *call_list);
/* Check the peer. /* Check the peer.
Implementations can choose to check the peer either synchronously or Implementations can choose to check the peer either synchronously or

@ -44,7 +44,6 @@
#include "src/core/security/credentials.h" #include "src/core/security/credentials.h"
#include "src/core/security/security_connector.h" #include "src/core/security/security_connector.h"
#include "src/core/security/security_context.h" #include "src/core/security/security_context.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/surface/server.h" #include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h" #include "src/core/transport/chttp2_transport.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
@ -126,11 +125,10 @@ static int remove_tcp_from_list_locked(grpc_server_secure_state *state,
return -1; return -1;
} }
static void on_secure_transport_setup_done(void *statep, static void on_secure_handshake_done(void *statep, grpc_security_status status,
grpc_security_status status, grpc_endpoint *wrapped_endpoint,
grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint,
grpc_endpoint *secure_endpoint, grpc_call_list *call_list) {
grpc_call_list *call_list) {
grpc_server_secure_state *state = statep; grpc_server_secure_state *state = statep;
grpc_transport *transport; grpc_transport *transport;
grpc_mdctx *mdctx; grpc_mdctx *mdctx;
@ -170,8 +168,8 @@ static void on_accept(void *statep, grpc_endpoint *tcp,
node->next = state->handshaking_tcp_endpoints; node->next = state->handshaking_tcp_endpoints;
state->handshaking_tcp_endpoints = node; state->handshaking_tcp_endpoints = node;
gpr_mu_unlock(&state->mu); gpr_mu_unlock(&state->mu);
grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done, grpc_security_connector_do_handshake(state->sc, tcp, on_secure_handshake_done,
state, call_list); state, call_list);
} }
/* Server callback: start listening on our ports */ /* Server callback: start listening on our ports */

@ -71,6 +71,7 @@ typedef struct {
gpr_mu mu; gpr_mu mu;
callback_phase phase; callback_phase phase;
int success; int success;
int removed;
grpc_closure on_complete; grpc_closure on_complete;
grpc_alarm alarm; grpc_alarm alarm;
grpc_connectivity_state state; grpc_connectivity_state state;
@ -81,10 +82,6 @@ typedef struct {
} state_watcher; } state_watcher;
static void delete_state_watcher(state_watcher *w, grpc_call_list *call_list) { static void delete_state_watcher(state_watcher *w, grpc_call_list *call_list) {
grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(w->channel));
grpc_client_channel_del_interested_party(client_channel_elem,
grpc_cq_pollset(w->cq), call_list);
GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity", call_list); GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity", call_list);
gpr_mu_destroy(&w->mu); gpr_mu_destroy(&w->mu);
gpr_free(w); gpr_free(w);
@ -118,7 +115,17 @@ static void finished_completion(void *pw, grpc_cq_completion *ignored,
static void partly_done(state_watcher *w, int due_to_completion, static void partly_done(state_watcher *w, int due_to_completion,
grpc_call_list *call_list) { grpc_call_list *call_list) {
int delete = 0; int delete = 0;
grpc_channel_element *client_channel_elem = NULL;
gpr_mu_lock(&w->mu);
if (w->removed == 0) {
w->removed = 1;
client_channel_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(w->channel));
grpc_client_channel_del_interested_party(client_channel_elem,
grpc_cq_pollset(w->cq), call_list);
}
gpr_mu_unlock(&w->mu);
if (due_to_completion) { if (due_to_completion) {
gpr_mu_lock(&w->mu); gpr_mu_lock(&w->mu);
w->success = 1; w->success = 1;
@ -174,6 +181,7 @@ void grpc_channel_watch_connectivity_state(
w->phase = WAITING; w->phase = WAITING;
w->state = last_observed_state; w->state = last_observed_state;
w->success = 0; w->success = 0;
w->removed = 0;
w->cq = cq; w->cq = cq;
w->tag = tag; w->tag = tag;
w->channel = channel; w->channel = channel;

@ -42,6 +42,7 @@
#include "src/core/channel/channel_stack.h" #include "src/core/channel/channel_stack.h"
#include "src/core/client_config/lb_policy_registry.h" #include "src/core/client_config/lb_policy_registry.h"
#include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/client_config/lb_policies/pick_first.h"
#include "src/core/client_config/lb_policies/round_robin.h"
#include "src/core/client_config/resolver_registry.h" #include "src/core/client_config/resolver_registry.h"
#include "src/core/client_config/resolvers/dns_resolver.h" #include "src/core/client_config/resolvers/dns_resolver.h"
#include "src/core/client_config/resolvers/sockaddr_resolver.h" #include "src/core/client_config/resolvers/sockaddr_resolver.h"
@ -89,6 +90,7 @@ void grpc_init(void) {
gpr_time_init(); gpr_time_init();
grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create()); grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_pick_first_lb_factory_create()); grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
grpc_resolver_registry_init("dns:///"); grpc_resolver_registry_init("dns:///");
grpc_register_resolver_type(grpc_dns_resolver_factory_create()); grpc_register_resolver_type(grpc_dns_resolver_factory_create());
grpc_register_resolver_type(grpc_ipv4_resolver_factory_create()); grpc_register_resolver_type(grpc_ipv4_resolver_factory_create());

@ -47,7 +47,6 @@
#include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_client.h"
#include "src/core/security/auth_filters.h" #include "src/core/security/auth_filters.h"
#include "src/core/security/credentials.h" #include "src/core/security/credentials.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/surface/channel.h" #include "src/core/surface/channel.h"
#include "src/core/transport/chttp2_transport.h" #include "src/core/transport/chttp2_transport.h"
#include "src/core/tsi/transport_security_interface.h" #include "src/core/tsi/transport_security_interface.h"
@ -84,11 +83,10 @@ static void connector_unref(grpc_connector *con, grpc_call_list *call_list) {
} }
} }
static void on_secure_transport_setup_done(void *arg, static void on_secure_handshake_done(void *arg, grpc_security_status status,
grpc_security_status status, grpc_endpoint *wrapped_endpoint,
grpc_endpoint *wrapped_endpoint, grpc_endpoint *secure_endpoint,
grpc_endpoint *secure_endpoint, grpc_call_list *call_list) {
grpc_call_list *call_list) {
connector *c = arg; connector *c = arg;
grpc_closure *notify; grpc_closure *notify;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
@ -97,7 +95,7 @@ static void on_secure_transport_setup_done(void *arg,
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
} else if (status != GRPC_SECURITY_OK) { } else if (status != GRPC_SECURITY_OK) {
GPR_ASSERT(c->connecting_endpoint == wrapped_endpoint); GPR_ASSERT(c->connecting_endpoint == wrapped_endpoint);
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
c->connecting_endpoint = NULL; c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
@ -128,8 +126,9 @@ static void connected(void *arg, int success, grpc_call_list *call_list) {
GPR_ASSERT(c->connecting_endpoint == NULL); GPR_ASSERT(c->connecting_endpoint == NULL);
c->connecting_endpoint = tcp; c->connecting_endpoint = tcp;
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
grpc_setup_secure_transport(&c->security_connector->base, tcp, grpc_security_connector_do_handshake(&c->security_connector->base, tcp,
on_secure_transport_setup_done, c, call_list); on_secure_handshake_done, c,
call_list);
} else { } else {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
notify = c->notify; notify = c->notify;

@ -144,4 +144,64 @@ std::shared_ptr<Credentials> CompositeCredentials(
return nullptr; return nullptr;
} }
void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
if (wrapper == nullptr) return;
MetadataCredentialsPluginWrapper* w =
reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
delete w;
}
void MetadataCredentialsPluginWrapper::GetMetadata(
void* wrapper, const char* service_url,
grpc_credentials_plugin_metadata_cb cb, void* user_data) {
GPR_ASSERT(wrapper != nullptr);
MetadataCredentialsPluginWrapper* w =
reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
if (w->plugin_ == nullptr) {
cb(user_data, NULL, 0, GRPC_STATUS_OK, NULL);
return;
}
if (w->plugin_->IsBlocking()) {
w->thread_pool_->Add(
std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w,
service_url, cb, user_data));
} else {
w->InvokePlugin(service_url, cb, user_data);
}
}
void MetadataCredentialsPluginWrapper::InvokePlugin(
const char* service_url, grpc_credentials_plugin_metadata_cb cb,
void* user_data) {
std::multimap<grpc::string, grpc::string_ref> metadata;
Status status = plugin_->GetMetadata(service_url, &metadata);
std::vector<grpc_metadata> md;
for (auto it = metadata.begin(); it != metadata.end(); ++it) {
md.push_back({it->first.c_str(),
it->second.data(),
it->second.size(),
0,
{{nullptr, nullptr, nullptr, nullptr}}});
}
cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
static_cast<grpc_status_code>(status.error_code()),
status.error_message().c_str());
}
MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
std::unique_ptr<MetadataCredentialsPlugin> plugin)
: thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}
std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
GrpcLibrary init; // To call grpc_init().
MetadataCredentialsPluginWrapper* wrapper =
new MetadataCredentialsPluginWrapper(std::move(plugin));
grpc_metadata_credentials_plugin c_plugin = {
MetadataCredentialsPluginWrapper::GetMetadata,
MetadataCredentialsPluginWrapper::Destroy, wrapper};
return WrapCredentials(
grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
}
} // namespace grpc } // namespace grpc

@ -39,6 +39,8 @@
#include <grpc++/support/config.h> #include <grpc++/support/config.h>
#include <grpc++/security/credentials.h> #include <grpc++/security/credentials.h>
#include "src/cpp/server/thread_pool_interface.h"
namespace grpc { namespace grpc {
class SecureCredentials GRPC_FINAL : public Credentials { class SecureCredentials GRPC_FINAL : public Credentials {
@ -56,6 +58,23 @@ class SecureCredentials GRPC_FINAL : public Credentials {
grpc_credentials* const c_creds_; grpc_credentials* const c_creds_;
}; };
class MetadataCredentialsPluginWrapper GRPC_FINAL {
public:
static void Destroy(void* wrapper);
static void GetMetadata(void* wrapper, const char* service_url,
grpc_credentials_plugin_metadata_cb cb,
void* user_data);
explicit MetadataCredentialsPluginWrapper(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
private:
void InvokePlugin(const char* service_url,
grpc_credentials_plugin_metadata_cb cb, void* user_data);
std::unique_ptr<ThreadPoolInterface> thread_pool_;
std::unique_ptr<MetadataCredentialsPlugin> plugin_;
};
} // namespace grpc } // namespace grpc
#endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H #endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H

@ -0,0 +1,705 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdarg.h>
#include <string.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc/support/string_util.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/surface/channel.h"
#include "src/core/channel/client_channel.h"
#include "src/core/support/string.h"
#include "src/core/surface/server.h"
#include "test/core/util/test_config.h"
#include "test/core/util/port.h"
#include "test/core/end2end/cq_verifier.h"
typedef struct servers_fixture {
size_t num_servers;
grpc_server **servers;
grpc_call **server_calls;
grpc_completion_queue *cq;
char **servers_hostports;
grpc_metadata_array *request_metadata_recv;
} servers_fixture;
typedef void (*verifier_fn)(const servers_fixture *, grpc_channel *,
const int *, const size_t);
typedef struct test_spec {
size_t num_iters;
size_t num_servers;
int **kill_at;
int **revive_at;
const char *description;
verifier_fn verifier;
} test_spec;
static void test_spec_reset(test_spec *spec) {
size_t i, j;
for (i = 0; i < spec->num_iters; i++) {
for (j = 0; j < spec->num_servers; j++) {
spec->kill_at[i][j] = 0;
spec->revive_at[i][j] = 0;
}
}
}
static test_spec *test_spec_create(size_t num_iters, size_t num_servers) {
test_spec *spec;
size_t i;
spec = gpr_malloc(sizeof(test_spec));
spec->num_iters = num_iters;
spec->num_servers = num_servers;
spec->kill_at = gpr_malloc(sizeof(int *) * num_iters);
spec->revive_at = gpr_malloc(sizeof(int *) * num_iters);
for (i = 0; i < num_iters; i++) {
spec->kill_at[i] = gpr_malloc(sizeof(int) * num_servers);
spec->revive_at[i] = gpr_malloc(sizeof(int) * num_servers);
}
test_spec_reset(spec);
return spec;
}
static void test_spec_destroy(test_spec *spec) {
size_t i;
for (i = 0; i < spec->num_iters; i++) {
gpr_free(spec->kill_at[i]);
gpr_free(spec->revive_at[i]);
}
gpr_free(spec->kill_at);
gpr_free(spec->revive_at);
gpr_free(spec);
}
static void *tag(gpr_intptr t) { return (void *)t; }
static gpr_timespec n_seconds_time(int n) {
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
}
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, n_seconds_time(5), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void kill_server(const servers_fixture *f, size_t i) {
gpr_log(GPR_INFO, "KILLING SERVER %d", i);
GPR_ASSERT(f->servers[i] != NULL);
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
GPR_ASSERT(grpc_completion_queue_pluck(
f->cq, tag(10000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]);
f->servers[i] = NULL;
}
static void revive_server(const servers_fixture *f, size_t i) {
int got_port;
gpr_log(GPR_INFO, "RAISE AGAIN SERVER %d", i);
GPR_ASSERT(f->servers[i] == NULL);
f->servers[i] = grpc_server_create(NULL, NULL);
grpc_server_register_completion_queue(f->servers[i], f->cq, NULL);
GPR_ASSERT((got_port = grpc_server_add_insecure_http2_port(
f->servers[i], f->servers_hostports[i])) > 0);
grpc_server_start(f->servers[i]);
}
static servers_fixture *setup_servers(const char *server_host,
const size_t num_servers) {
servers_fixture *f = gpr_malloc(sizeof(servers_fixture));
int *ports;
int got_port;
size_t i;
f->num_servers = num_servers;
f->server_calls = gpr_malloc(sizeof(grpc_call *) * num_servers);
f->request_metadata_recv =
gpr_malloc(sizeof(grpc_metadata_array) * num_servers);
/* Create servers. */
ports = gpr_malloc(sizeof(int *) * num_servers);
f->servers = gpr_malloc(sizeof(grpc_server *) * num_servers);
f->servers_hostports = gpr_malloc(sizeof(char *) * num_servers);
f->cq = grpc_completion_queue_create(NULL);
for (i = 0; i < num_servers; i++) {
ports[i] = grpc_pick_unused_port_or_die();
gpr_join_host_port(&f->servers_hostports[i], server_host, ports[i]);
f->servers[i] = grpc_server_create(NULL, NULL);
grpc_server_register_completion_queue(f->servers[i], f->cq, NULL);
GPR_ASSERT((got_port = grpc_server_add_insecure_http2_port(
f->servers[i], f->servers_hostports[i])) > 0);
GPR_ASSERT(ports[i] == got_port);
grpc_server_start(f->servers[i]);
}
gpr_free(ports);
return f;
}
static void teardown_servers(servers_fixture *f) {
size_t i;
/* Destroy server. */
for (i = 0; i < f->num_servers; i++) {
if (f->servers[i] == NULL) continue;
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
GPR_ASSERT(grpc_completion_queue_pluck(
f->cq, tag(10000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]);
}
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
gpr_free(f->servers);
for (i = 0; i < f->num_servers; i++) {
gpr_free(f->servers_hostports[i]);
}
gpr_free(f->servers_hostports);
gpr_free(f->request_metadata_recv);
gpr_free(f->server_calls);
gpr_free(f);
}
/** Returns connection sequence (server indices), which must be freed */
int *perform_request(servers_fixture *f, grpc_channel *client,
const test_spec *spec) {
grpc_call *c;
int s_idx;
int *s_valid;
gpr_timespec deadline;
grpc_op ops[6];
grpc_op *op;
grpc_status_code status;
char *details;
size_t details_capacity;
int was_cancelled;
grpc_call_details *call_details;
size_t i, iter_num;
grpc_event ev;
int read_tag;
int *connection_sequence;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
s_valid = gpr_malloc(sizeof(int) * f->num_servers);
call_details = gpr_malloc(sizeof(grpc_call_details) * f->num_servers);
connection_sequence = gpr_malloc(sizeof(int) * spec->num_iters);
/* Send a trivial request. */
deadline = n_seconds_time(60);
for (iter_num = 0; iter_num < spec->num_iters; iter_num++) {
cq_verifier *cqv = cq_verifier_create(f->cq);
details = NULL;
details_capacity = 0;
was_cancelled = 2;
for (i = 0; i < f->num_servers; i++) {
if (spec->kill_at[iter_num][i] != 0) {
kill_server(f, i);
} else if (spec->revive_at[iter_num][i] != 0) {
/* killing takes precedence */
revive_server(f, i);
}
}
connection_sequence[iter_num] = -1;
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
for (i = 0; i < f->num_servers; i++) {
grpc_call_details_init(&call_details[i]);
}
memset(s_valid, 0, f->num_servers * sizeof(int));
c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
"/foo", "foo.test.google.fr", deadline, NULL);
GPR_ASSERT(c);
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->data.recv_status_on_client.status_details_capacity = &details_capacity;
op->flags = 0;
op->reserved = NULL;
op++;
GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL));
/* "listen" on all servers */
for (i = 0; i < f->num_servers; i++) {
grpc_metadata_array_init(&f->request_metadata_recv[i]);
if (f->servers[i] != NULL) {
GPR_ASSERT(GRPC_CALL_OK ==
grpc_server_request_call(f->servers[i], &f->server_calls[i],
&call_details[i],
&f->request_metadata_recv[i], f->cq,
f->cq, tag(1000 + (int)i)));
}
}
s_idx = -1;
while ((ev = grpc_completion_queue_next(
f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL))
.type != GRPC_QUEUE_TIMEOUT) {
read_tag = ((int)(gpr_intptr)ev.tag);
gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d",
ev.success, ev.type, read_tag, iter_num);
if (ev.success && read_tag >= 1000) {
GPR_ASSERT(s_idx == -1); /* only one server must reply */
/* only server notifications for non-shutdown events */
s_idx = read_tag - 1000;
s_valid[s_idx] = 1;
connection_sequence[iter_num] = s_idx;
}
}
if (s_idx >= 0) {
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
op->data.send_status_from_server.status_details = "xyz";
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = NULL;
op++;
GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(f->server_calls[s_idx],
ops, (size_t)(op - ops),
tag(102), NULL));
cq_expect_completion(cqv, tag(102), 1);
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
GPR_ASSERT(0 == strcmp(details, "xyz"));
GPR_ASSERT(0 == strcmp(call_details[s_idx].method, "/foo"));
GPR_ASSERT(0 == strcmp(call_details[s_idx].host, "foo.test.google.fr"));
GPR_ASSERT(was_cancelled == 1);
}
for (i = 0; i < f->num_servers; i++) {
if (s_valid[i] != 0) {
grpc_call_destroy(f->server_calls[i]);
}
grpc_metadata_array_destroy(&f->request_metadata_recv[i]);
}
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
cq_verifier_destroy(cqv);
grpc_call_destroy(c);
for (i = 0; i < f->num_servers; i++) {
grpc_call_details_destroy(&call_details[i]);
}
gpr_free(details);
}
gpr_free(call_details);
gpr_free(s_valid);
return connection_sequence;
}
static void assert_channel_connectivity(
grpc_channel *ch, size_t num_accepted_conn_states,
grpc_connectivity_state accepted_conn_state, ...) {
size_t i;
grpc_channel_stack *client_stack;
grpc_channel_element *client_channel_filter;
grpc_connectivity_state actual_conn_state;
grpc_call_list call_list = GRPC_CALL_LIST_INIT;
va_list ap;
client_stack = grpc_channel_get_channel_stack(ch);
client_channel_filter = grpc_channel_stack_last_element(client_stack);
actual_conn_state = grpc_client_channel_check_connectivity_state(
client_channel_filter, 0 /* don't try to connect */, &call_list);
grpc_call_list_run(&call_list);
va_start(ap, accepted_conn_state);
for (i = 0; i < num_accepted_conn_states; i++) {
if (actual_conn_state == accepted_conn_state) {
break;
}
accepted_conn_state = va_arg(ap, grpc_connectivity_state);
}
va_end(ap);
if (i == num_accepted_conn_states) {
char **accepted_strs =
gpr_malloc(sizeof(char *) * num_accepted_conn_states);
char *accepted_str_joined;
va_start(ap, accepted_conn_state);
for (i = 0; i < num_accepted_conn_states; i++) {
GPR_ASSERT(gpr_asprintf(&accepted_strs[i], "%d", accepted_conn_state) >
0);
accepted_conn_state = va_arg(ap, grpc_connectivity_state);
}
va_end(ap);
accepted_str_joined = gpr_strjoin_sep((const char **)accepted_strs,
num_accepted_conn_states, ", ", NULL);
gpr_log(
GPR_ERROR,
"Channel connectivity assertion failed: expected <one of [%s]>, got %d",
accepted_str_joined, actual_conn_state);
for (i = 0; i < num_accepted_conn_states; i++) {
gpr_free(accepted_strs[i]);
}
gpr_free(accepted_strs);
gpr_free(accepted_str_joined);
abort();
}
}
void run_spec(const test_spec *spec) {
grpc_channel *client;
char *client_hostport;
char *servers_hostports_str;
int *actual_connection_sequence;
servers_fixture *f = setup_servers("127.0.0.1", spec->num_servers);
/* Create client. */
servers_hostports_str = gpr_strjoin_sep((const char **)f->servers_hostports,
f->num_servers, ",", NULL);
gpr_asprintf(&client_hostport, "ipv4:%s?lb_policy=round_robin",
servers_hostports_str);
client = grpc_insecure_channel_create(client_hostport, NULL, NULL);
gpr_log(GPR_INFO, "Testing '%s' with servers=%s client=%s", spec->description,
servers_hostports_str, client_hostport);
actual_connection_sequence = perform_request(f, client, spec);
spec->verifier(f, client, actual_connection_sequence, spec->num_iters);
gpr_free(client_hostport);
gpr_free(servers_hostports_str);
gpr_free(actual_connection_sequence);
grpc_channel_destroy(client);
teardown_servers(f);
}
static void print_failed_expectations(const int *expected_connection_sequence,
const int *actual_connection_sequence,
const size_t expected_seq_length,
const size_t num_iters) {
size_t i;
for (i = 0; i < num_iters; i++) {
gpr_log(GPR_ERROR, "FAILURE: Iter, expected, actual:%d (%d, %d)", i,
expected_connection_sequence[i % expected_seq_length],
actual_connection_sequence[i]);
}
}
static void verify_vanilla_round_robin(const servers_fixture *f,
grpc_channel *client,
const int *actual_connection_sequence,
const size_t num_iters) {
int *expected_connection_sequence;
size_t i;
const size_t expected_seq_length = f->num_servers;
/* verify conn. seq. expectation */
/* get the first sequence of "num_servers" elements */
expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
memcpy(expected_connection_sequence, actual_connection_sequence,
sizeof(int) * expected_seq_length);
for (i = 0; i < num_iters; i++) {
const int actual = actual_connection_sequence[i];
const int expected = expected_connection_sequence[i % expected_seq_length];
if (actual != expected) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d", expected,
actual, i);
print_failed_expectations(expected_connection_sequence,
actual_connection_sequence, expected_seq_length,
num_iters);
abort();
}
}
assert_channel_connectivity(client, 1, GRPC_CHANNEL_READY);
gpr_free(expected_connection_sequence);
}
/* At the start of the second iteration, all but the first and last servers (as
* given in "f") are killed */
static void verify_vanishing_floor_round_robin(
const servers_fixture *f, grpc_channel *client,
const int *actual_connection_sequence, const size_t num_iters) {
int *expected_connection_sequence;
const size_t expected_seq_length = 2;
size_t i;
/* verify conn. seq. expectation */
/* copy the first full sequence (without -1s) */
expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
memcpy(expected_connection_sequence, actual_connection_sequence + 2,
expected_seq_length * sizeof(int));
/* first three elements of the sequence should be [<1st>, -1] */
if (actual_connection_sequence[0] != expected_connection_sequence[0]) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d",
expected_connection_sequence[0], actual_connection_sequence[0], 0);
print_failed_expectations(expected_connection_sequence,
actual_connection_sequence, expected_seq_length,
1u);
abort();
}
GPR_ASSERT(actual_connection_sequence[1] == -1);
for (i = 2; i < num_iters; i++) {
const int actual = actual_connection_sequence[i];
const int expected = expected_connection_sequence[i % expected_seq_length];
if (actual != expected) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d", expected,
actual, i);
print_failed_expectations(expected_connection_sequence,
actual_connection_sequence, expected_seq_length,
num_iters);
abort();
}
}
gpr_free(expected_connection_sequence);
}
static void verify_total_carnage_round_robin(
const servers_fixture *f, grpc_channel *client,
const int *actual_connection_sequence, const size_t num_iters) {
size_t i;
for (i = 0; i < num_iters; i++) {
const int actual = actual_connection_sequence[i];
const int expected = -1;
if (actual != expected) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d", expected,
actual, i);
abort();
}
}
/* even though we know all the servers are dead, the client is still trying
* retrying, believing it's in a transient failure situation */
assert_channel_connectivity(client, 2, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_CHANNEL_CONNECTING);
}
static void verify_partial_carnage_round_robin(
const servers_fixture *f, grpc_channel *client,
const int *actual_connection_sequence, const size_t num_iters) {
int *expected_connection_sequence;
size_t i;
const size_t expected_seq_length = f->num_servers;
/* verify conn. seq. expectation */
/* get the first sequence of "num_servers" elements */
expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
memcpy(expected_connection_sequence, actual_connection_sequence,
sizeof(int) * expected_seq_length);
for (i = 0; i < num_iters / 2; i++) {
const int actual = actual_connection_sequence[i];
const int expected = expected_connection_sequence[i % expected_seq_length];
if (actual != expected) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d", expected,
actual, i);
print_failed_expectations(expected_connection_sequence,
actual_connection_sequence, expected_seq_length,
num_iters);
abort();
}
}
/* second half of the iterations go without response */
for (; i < num_iters; i++) {
GPR_ASSERT(actual_connection_sequence[i] == -1);
}
/* even though we know all the servers are dead, the client is still trying
* retrying, believing it's in a transient failure situation */
assert_channel_connectivity(client, 2, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_CHANNEL_CONNECTING);
gpr_free(expected_connection_sequence);
}
static void verify_rebirth_round_robin(const servers_fixture *f,
grpc_channel *client,
const int *actual_connection_sequence,
const size_t num_iters) {
int *expected_connection_sequence;
size_t i;
const size_t expected_seq_length = f->num_servers;
/* verify conn. seq. expectation */
/* get the first sequence of "num_servers" elements */
expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
memcpy(expected_connection_sequence, actual_connection_sequence + 4,
sizeof(int) * expected_seq_length);
/* first iteration succeeds */
GPR_ASSERT(actual_connection_sequence[0] != -1);
/* back up on the third (or maybe fourth) iteration */
i = 3;
if (actual_connection_sequence[i] == -1) {
i = 4;
}
for (; i < num_iters; i++) {
const int actual = actual_connection_sequence[i];
const int expected = expected_connection_sequence[i % expected_seq_length];
if (actual != expected) {
gpr_log(GPR_ERROR, "FAILURE: expected %d, actual %d at iter %d", expected,
actual, i);
print_failed_expectations(expected_connection_sequence,
actual_connection_sequence, expected_seq_length,
num_iters);
abort();
}
}
/* things are fine once the servers are brought back up */
assert_channel_connectivity(client, 1, GRPC_CHANNEL_READY);
gpr_free(expected_connection_sequence);
}
int main(int argc, char **argv) {
test_spec *spec;
size_t i;
const size_t NUM_ITERS = 10;
const size_t NUM_SERVERS = 4;
grpc_test_init(argc, argv);
grpc_init();
/* everything is fine, all servers stay up the whole time and life's peachy */
spec = test_spec_create(NUM_ITERS, NUM_SERVERS);
spec->verifier = verify_vanilla_round_robin;
spec->description = "test_all_server_up";
run_spec(spec);
/* Kill all servers first thing in the morning */
test_spec_reset(spec);
spec->verifier = verify_total_carnage_round_robin;
spec->description = "test_kill_all_server";
for (i = 0; i < NUM_SERVERS; i++) {
spec->kill_at[0][i] = 1;
}
run_spec(spec);
/* at the start of the 2nd iteration, kill all but the first and last servers.
* This should knock down the server bound to be selected next */
test_spec_reset(spec);
spec->verifier = verify_vanishing_floor_round_robin;
spec->description = "test_kill_all_server_at_2nd_iteration";
for (i = 1; i < NUM_SERVERS - 1; i++) {
spec->kill_at[1][i] = 1;
}
run_spec(spec);
/* Midway, kill all servers. */
test_spec_reset(spec);
spec->verifier = verify_partial_carnage_round_robin;
spec->description = "test_kill_all_server_midway";
for (i = 0; i < NUM_SERVERS; i++) {
spec->kill_at[spec->num_iters / 2][i] = 1;
}
run_spec(spec);
/* After first iteration, kill all servers. On the third one, bring them all
* back up. */
test_spec_reset(spec);
spec->verifier = verify_rebirth_round_robin;
spec->description = "test_kill_all_server_after_1st_resurrect_at_3rd";
for (i = 0; i < NUM_SERVERS; i++) {
spec->kill_at[1][i] = 1;
spec->revive_at[3][i] = 1;
}
run_spec(spec);
test_spec_destroy(spec);
grpc_shutdown();
return 0;
}

@ -875,6 +875,119 @@ static void test_google_default_creds_access_token(void) {
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
} }
typedef enum {
PLUGIN_INITIAL_STATE,
PLUGIN_GET_METADATA_CALLED_STATE,
PLUGIN_DESTROY_CALLED_STATE
} plugin_state;
typedef struct {
const char *key;
const char *value;
} plugin_metadata;
static const plugin_metadata plugin_md[] = {{"foo", "bar"}, {"hi", "there"}};
static void plugin_get_metadata_success(void *state, const char *service_url,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
size_t i;
grpc_metadata md[GPR_ARRAY_SIZE(plugin_md)];
plugin_state *s = (plugin_state *)state;
GPR_ASSERT(strcmp(service_url, test_service_url) == 0);
*s = PLUGIN_GET_METADATA_CALLED_STATE;
for (i = 0; i < GPR_ARRAY_SIZE(plugin_md); i++) {
memset(&md[i], 0, sizeof(grpc_metadata));
md[i].key = plugin_md[i].key;
md[i].value = plugin_md[i].value;
md[i].value_length = strlen(plugin_md[i].value);
}
cb(user_data, md, GPR_ARRAY_SIZE(md), GRPC_STATUS_OK, NULL);
}
static void plugin_get_metadata_failure(void *state, const char *service_url,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
plugin_state *s = (plugin_state *)state;
GPR_ASSERT(strcmp(service_url, test_service_url) == 0);
*s = PLUGIN_GET_METADATA_CALLED_STATE;
cb(user_data, NULL, 0, GRPC_STATUS_UNAUTHENTICATED,
"Could not get metadata for plugin.");
}
static void on_plugin_metadata_received_success(void *user_data,
grpc_credentials_md *md_elems,
size_t num_md,
grpc_credentials_status status,
grpc_call_list *call_list) {
size_t i = 0;
GPR_ASSERT(user_data == NULL);
GPR_ASSERT(md_elems != NULL);
GPR_ASSERT(num_md == GPR_ARRAY_SIZE(plugin_md));
for (i = 0; i < num_md; i++) {
GPR_ASSERT(gpr_slice_str_cmp(md_elems[i].key, plugin_md[i].key) == 0);
GPR_ASSERT(gpr_slice_str_cmp(md_elems[i].value, plugin_md[i].value) == 0);
}
}
static void on_plugin_metadata_received_failure(void *user_data,
grpc_credentials_md *md_elems,
size_t num_md,
grpc_credentials_status status,
grpc_call_list *call_list) {
GPR_ASSERT(user_data == NULL);
GPR_ASSERT(md_elems == NULL);
GPR_ASSERT(num_md == 0);
GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
}
static void plugin_destroy(void *state) {
plugin_state *s = (plugin_state *)state;
*s = PLUGIN_DESTROY_CALLED_STATE;
}
static void test_metadata_plugin_success(void) {
grpc_credentials *creds;
plugin_state state = PLUGIN_INITIAL_STATE;
grpc_metadata_credentials_plugin plugin;
grpc_call_list call_list = GRPC_CALL_LIST_INIT;
plugin.state = &state;
plugin.get_metadata = plugin_get_metadata_success;
plugin.destroy = plugin_destroy;
creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
on_plugin_metadata_received_success,
NULL, &call_list);
GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
grpc_credentials_release(creds);
GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
grpc_call_list_run(&call_list);
}
static void test_metadata_plugin_failure(void) {
grpc_credentials *creds;
plugin_state state = PLUGIN_INITIAL_STATE;
grpc_metadata_credentials_plugin plugin;
grpc_call_list call_list = GRPC_CALL_LIST_INIT;
plugin.state = &state;
plugin.get_metadata = plugin_get_metadata_failure;
plugin.destroy = plugin_destroy;
creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
on_plugin_metadata_received_failure,
NULL, &call_list);
GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
grpc_credentials_release(creds);
GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
grpc_call_list_run(&call_list);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_empty_md_store(); test_empty_md_store();
@ -902,5 +1015,7 @@ int main(int argc, char **argv) {
test_jwt_creds_signing_failure(); test_jwt_creds_signing_failure();
test_google_default_creds_auth_key(); test_google_default_creds_auth_key();
test_google_default_creds_access_token(); test_google_default_creds_access_token();
test_metadata_plugin_success();
test_metadata_plugin_failure();
return 0; return 0;
} }

@ -108,6 +108,39 @@ bool CheckIsLocalhost(const grpc::string& addr) {
addr.substr(0, kIpv6.size()) == kIpv6; addr.substr(0, kIpv6.size()) == kIpv6;
} }
class TestMetadataCredentialsPlugin : public MetadataCredentialsPlugin {
public:
static const char kMetadataKey[];
TestMetadataCredentialsPlugin(grpc::string_ref metadata_value,
bool is_blocking, bool is_successful)
: metadata_value_(metadata_value.data(), metadata_value.length()),
is_blocking_(is_blocking),
is_successful_(is_successful) {}
bool IsBlocking() const GRPC_OVERRIDE { return is_blocking_; }
Status GetMetadata(grpc::string_ref service_url,
std::multimap<grpc::string, grpc::string_ref>* metadata)
GRPC_OVERRIDE {
EXPECT_GT(service_url.length(), 0UL);
EXPECT_TRUE(metadata != nullptr);
if (is_successful_) {
metadata->insert(std::make_pair(kMetadataKey, metadata_value_));
return Status::OK;
} else {
return Status(StatusCode::NOT_FOUND, "Could not find plugin metadata.");
}
}
private:
grpc::string metadata_value_;
bool is_blocking_;
bool is_successful_;
};
const char TestMetadataCredentialsPlugin::kMetadataKey[] = "TestPluginMetadata";
class TestAuthMetadataProcessor : public AuthMetadataProcessor { class TestAuthMetadataProcessor : public AuthMetadataProcessor {
public: public:
static const char kGoodGuy[]; static const char kGoodGuy[];
@ -115,10 +148,15 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
TestAuthMetadataProcessor(bool is_blocking) : is_blocking_(is_blocking) {} TestAuthMetadataProcessor(bool is_blocking) : is_blocking_(is_blocking) {}
std::shared_ptr<Credentials> GetCompatibleClientCreds() { std::shared_ptr<Credentials> GetCompatibleClientCreds() {
return AccessTokenCredentials(kGoodGuy); return MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin(kGoodGuy, is_blocking_, true)));
} }
std::shared_ptr<Credentials> GetIncompatibleClientCreds() { std::shared_ptr<Credentials> GetIncompatibleClientCreds() {
return AccessTokenCredentials("Mr Hyde"); return MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin("Mr Hyde", is_blocking_, true)));
} }
// Interface implementation // Interface implementation
@ -130,10 +168,11 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
EXPECT_TRUE(consumed_auth_metadata != nullptr); EXPECT_TRUE(consumed_auth_metadata != nullptr);
EXPECT_TRUE(context != nullptr); EXPECT_TRUE(context != nullptr);
EXPECT_TRUE(response_metadata != nullptr); EXPECT_TRUE(response_metadata != nullptr);
auto auth_md = auth_metadata.find(GRPC_AUTHORIZATION_METADATA_KEY); auto auth_md =
auth_metadata.find(TestMetadataCredentialsPlugin::kMetadataKey);
EXPECT_NE(auth_md, auth_metadata.end()); EXPECT_NE(auth_md, auth_metadata.end());
string_ref auth_md_value = auth_md->second; string_ref auth_md_value = auth_md->second;
if (auth_md_value.ends_with(kGoodGuy)) { if (auth_md_value == kGoodGuy) {
context->AddProperty(kIdentityPropName, kGoodGuy); context->AddProperty(kIdentityPropName, kGoodGuy);
context->SetPeerIdentityPropertyName(kIdentityPropName); context->SetPeerIdentityPropertyName(kIdentityPropName);
consumed_auth_metadata->insert( consumed_auth_metadata->insert(
@ -147,7 +186,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
} }
} }
protected: private:
static const char kIdentityPropName[]; static const char kIdentityPropName[];
bool is_blocking_; bool is_blocking_;
}; };
@ -876,7 +915,24 @@ TEST_F(End2endTest, OverridePerCallCredentials) {
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
} }
TEST_F(End2endTest, NonBlockingAuthMetadataProcessorSuccess) { TEST_F(End2endTest, NonBlockingAuthMetadataPluginFailure) {
ResetStub(false);
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_credentials(
MetadataCredentialsFromPlugin(std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin(
"Does not matter, will fail anyway (see 3rd param)", false,
false))));
request.set_message("Hello");
Status s = stub_->Echo(&context, request, &response);
EXPECT_FALSE(s.ok());
EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
}
TEST_F(End2endTest, NonBlockingAuthMetadataPluginAndProcessorSuccess) {
auto* processor = new TestAuthMetadataProcessor(false); auto* processor = new TestAuthMetadataProcessor(false);
StartServer(std::shared_ptr<AuthMetadataProcessor>(processor)); StartServer(std::shared_ptr<AuthMetadataProcessor>(processor));
ResetStub(false); ResetStub(false);
@ -899,7 +955,7 @@ TEST_F(End2endTest, NonBlockingAuthMetadataProcessorSuccess) {
grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy)); grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy));
} }
TEST_F(End2endTest, NonBlockingAuthMetadataProcessorFailure) { TEST_F(End2endTest, NonBlockingAuthMetadataPluginAndProcessorFailure) {
auto* processor = new TestAuthMetadataProcessor(false); auto* processor = new TestAuthMetadataProcessor(false);
StartServer(std::shared_ptr<AuthMetadataProcessor>(processor)); StartServer(std::shared_ptr<AuthMetadataProcessor>(processor));
ResetStub(false); ResetStub(false);
@ -914,7 +970,24 @@ TEST_F(End2endTest, NonBlockingAuthMetadataProcessorFailure) {
EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
} }
TEST_F(End2endTest, BlockingAuthMetadataProcessorSuccess) { TEST_F(End2endTest, BlockingAuthMetadataPluginFailure) {
ResetStub(false);
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_credentials(
MetadataCredentialsFromPlugin(std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin(
"Does not matter, will fail anyway (see 3rd param)", true,
false))));
request.set_message("Hello");
Status s = stub_->Echo(&context, request, &response);
EXPECT_FALSE(s.ok());
EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
}
TEST_F(End2endTest, BlockingAuthMetadataPluginAndProcessorSuccess) {
auto* processor = new TestAuthMetadataProcessor(true); auto* processor = new TestAuthMetadataProcessor(true);
StartServer(std::shared_ptr<AuthMetadataProcessor>(processor)); StartServer(std::shared_ptr<AuthMetadataProcessor>(processor));
ResetStub(false); ResetStub(false);
@ -937,7 +1010,7 @@ TEST_F(End2endTest, BlockingAuthMetadataProcessorSuccess) {
grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy)); grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy));
} }
TEST_F(End2endTest, BlockingAuthMetadataProcessorFailure) { TEST_F(End2endTest, BlockingAuthMetadataPluginAndProcessorFailure) {
auto* processor = new TestAuthMetadataProcessor(true); auto* processor = new TestAuthMetadataProcessor(true);
StartServer(std::shared_ptr<AuthMetadataProcessor>(processor)); StartServer(std::shared_ptr<AuthMetadataProcessor>(processor));
ResetStub(false); ResetStub(false);
@ -1076,6 +1149,24 @@ TEST_F(End2endTest, ChannelState) {
EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false)); EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false));
} }
// Takes 10s.
TEST_F(End2endTest, ChannelStateTimeout) {
int port = grpc_pick_unused_port_or_die();
std::ostringstream server_address;
server_address << "127.0.0.1:" << port;
// Channel to non-existing server
auto channel = CreateChannel(server_address.str(), InsecureCredentials());
// Start IDLE
EXPECT_EQ(GRPC_CHANNEL_IDLE, channel->GetState(true));
auto state = GRPC_CHANNEL_IDLE;
for (int i = 0; i < 10; i++) {
channel->WaitForStateChange(
state, std::chrono::system_clock::now() + std::chrono::seconds(1));
state = channel->GetState(false);
}
}
// Talking to a non-existing service. // Talking to a non-existing service.
TEST_F(End2endTest, NonExistingService) { TEST_F(End2endTest, NonExistingService) {
ResetChannel(); ResetChannel();

@ -68,6 +68,7 @@ DEFINE_string(test_case, "large_unary",
"cancel_after_begin : cancel stream after starting it; " "cancel_after_begin : cancel stream after starting it; "
"cancel_after_first_response: cancel on first response; " "cancel_after_first_response: cancel on first response; "
"timeout_on_sleeping_server: deadline exceeds on stream; " "timeout_on_sleeping_server: deadline exceeds on stream; "
"empty_stream : bi-di stream with no request/response; "
"compute_engine_creds: large_unary with compute engine auth; " "compute_engine_creds: large_unary with compute engine auth; "
"jwt_token_creds: large_unary with JWT token auth; " "jwt_token_creds: large_unary with JWT token auth; "
"oauth2_auth_token: raw oauth2 access token auth; " "oauth2_auth_token: raw oauth2 access token auth; "
@ -113,6 +114,8 @@ int main(int argc, char** argv) {
client.DoCancelAfterFirstResponse(); client.DoCancelAfterFirstResponse();
} else if (FLAGS_test_case == "timeout_on_sleeping_server") { } else if (FLAGS_test_case == "timeout_on_sleeping_server") {
client.DoTimeoutOnSleepingServer(); client.DoTimeoutOnSleepingServer();
} else if (FLAGS_test_case == "empty_stream") {
client.DoEmptyStream();
} else if (FLAGS_test_case == "compute_engine_creds") { } else if (FLAGS_test_case == "compute_engine_creds") {
client.DoComputeEngineCreds(FLAGS_default_service_account, client.DoComputeEngineCreds(FLAGS_default_service_account,
FLAGS_oauth_scope); FLAGS_oauth_scope);
@ -137,6 +140,7 @@ int main(int argc, char** argv) {
client.DoCancelAfterBegin(); client.DoCancelAfterBegin();
client.DoCancelAfterFirstResponse(); client.DoCancelAfterFirstResponse();
client.DoTimeoutOnSleepingServer(); client.DoTimeoutOnSleepingServer();
client.DoEmptyStream();
client.DoStatusWithMessage(); client.DoStatusWithMessage();
// service_account_creds and jwt_token_creds can only run with ssl. // service_account_creds and jwt_token_creds can only run with ssl.
if (FLAGS_enable_ssl) { if (FLAGS_enable_ssl) {
@ -153,7 +157,7 @@ int main(int argc, char** argv) {
"Unsupported test case %s. Valid options are all|empty_unary|" "Unsupported test case %s. Valid options are all|empty_unary|"
"large_unary|large_compressed_unary|client_streaming|server_streaming|" "large_unary|large_compressed_unary|client_streaming|server_streaming|"
"server_compressed_streaming|half_duplex|ping_pong|cancel_after_begin|" "server_compressed_streaming|half_duplex|ping_pong|cancel_after_begin|"
"cancel_after_first_response|timeout_on_sleeping_server|" "cancel_after_first_response|timeout_on_sleeping_server|empty_stream|"
"compute_engine_creds|jwt_token_creds|oauth2_auth_token|per_rpc_creds", "compute_engine_creds|jwt_token_creds|oauth2_auth_token|per_rpc_creds",
FLAGS_test_case.c_str()); FLAGS_test_case.c_str());
ret = 1; ret = 1;

@ -554,6 +554,22 @@ void InteropClient::DoTimeoutOnSleepingServer() {
gpr_log(GPR_INFO, "Pingpong streaming timeout done."); gpr_log(GPR_INFO, "Pingpong streaming timeout done.");
} }
void InteropClient::DoEmptyStream() {
gpr_log(GPR_INFO, "Starting empty_stream.");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
ClientContext context;
std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
StreamingOutputCallResponse>>
stream(stub->FullDuplexCall(&context));
stream->WritesDone();
StreamingOutputCallResponse response;
GPR_ASSERT(stream->Read(&response) == false);
Status s = stream->Finish();
AssertOkOrPrintErrorStatus(s);
gpr_log(GPR_INFO, "empty_stream done.");
}
void InteropClient::DoStatusWithMessage() { void InteropClient::DoStatusWithMessage() {
gpr_log(GPR_INFO, "Sending RPC with a request for status code 2 and message"); gpr_log(GPR_INFO, "Sending RPC with a request for status code 2 and message");
std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_)); std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

@ -62,6 +62,7 @@ class InteropClient {
void DoCancelAfterBegin(); void DoCancelAfterBegin();
void DoCancelAfterFirstResponse(); void DoCancelAfterFirstResponse();
void DoTimeoutOnSleepingServer(); void DoTimeoutOnSleepingServer();
void DoEmptyStream();
void DoStatusWithMessage(); void DoStatusWithMessage();
// Auth tests. // Auth tests.
// username is a string containing the user email // username is a string containing the user email

@ -770,10 +770,10 @@ include/grpc/census.h \
src/core/security/auth_filters.h \ src/core/security/auth_filters.h \
src/core/security/base64.h \ src/core/security/base64.h \
src/core/security/credentials.h \ src/core/security/credentials.h \
src/core/security/handshake.h \
src/core/security/json_token.h \ src/core/security/json_token.h \
src/core/security/jwt_verifier.h \ src/core/security/jwt_verifier.h \
src/core/security/secure_endpoint.h \ src/core/security/secure_endpoint.h \
src/core/security/secure_transport_setup.h \
src/core/security/security_connector.h \ src/core/security/security_connector.h \
src/core/security/security_context.h \ src/core/security/security_context.h \
src/core/tsi/fake_transport_security.h \ src/core/tsi/fake_transport_security.h \
@ -793,6 +793,7 @@ src/core/channel/noop_filter.h \
src/core/client_config/client_config.h \ src/core/client_config/client_config.h \
src/core/client_config/connector.h \ src/core/client_config/connector.h \
src/core/client_config/lb_policies/pick_first.h \ src/core/client_config/lb_policies/pick_first.h \
src/core/client_config/lb_policies/round_robin.h \
src/core/client_config/lb_policy.h \ src/core/client_config/lb_policy.h \
src/core/client_config/lb_policy_factory.h \ src/core/client_config/lb_policy_factory.h \
src/core/client_config/lb_policy_registry.h \ src/core/client_config/lb_policy_registry.h \
@ -897,10 +898,10 @@ src/core/security/credentials_metadata.c \
src/core/security/credentials_posix.c \ src/core/security/credentials_posix.c \
src/core/security/credentials_win32.c \ src/core/security/credentials_win32.c \
src/core/security/google_default_credentials.c \ src/core/security/google_default_credentials.c \
src/core/security/handshake.c \
src/core/security/json_token.c \ src/core/security/json_token.c \
src/core/security/jwt_verifier.c \ src/core/security/jwt_verifier.c \
src/core/security/secure_endpoint.c \ src/core/security/secure_endpoint.c \
src/core/security/secure_transport_setup.c \
src/core/security/security_connector.c \ src/core/security/security_connector.c \
src/core/security/security_context.c \ src/core/security/security_context.c \
src/core/security/server_auth_filter.c \ src/core/security/server_auth_filter.c \
@ -923,6 +924,7 @@ src/core/channel/noop_filter.c \
src/core/client_config/client_config.c \ src/core/client_config/client_config.c \
src/core/client_config/connector.c \ src/core/client_config/connector.c \
src/core/client_config/lb_policies/pick_first.c \ src/core/client_config/lb_policies/pick_first.c \
src/core/client_config/lb_policies/round_robin.c \
src/core/client_config/lb_policy.c \ src/core/client_config/lb_policy.c \
src/core/client_config/lb_policy_factory.c \ src/core/client_config/lb_policy_factory.c \
src/core/client_config/lb_policy_registry.c \ src/core/client_config/lb_policy_registry.c \

@ -0,0 +1,81 @@
#!/bin/bash
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# This script is invoked by run_tests.py to accommodate "test under docker"
# scenario. You should never need to call this script on your own.
set -ex
cd `dirname $0`/../..
git_root=`pwd`
cd -
mkdir -p /tmp/ccache
# Create a local branch so the child Docker script won't complain
git branch -f jenkins-docker
# Use image name based on Dockerfile checksum
DOCKER_IMAGE_NAME=grpc_jenkins_slave${docker_suffix}_`sha1sum tools/jenkins/grpc_jenkins_slave/Dockerfile | cut -f1 -d\ `
# Make sure docker image has been built. Should be instantaneous if so.
docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave$docker_suffix
# Make sure the CID file is gone.
rm -f docker.cid
# Run tests inside docker
docker run \
-e "RUN_TESTS_COMMAND=$RUN_TESTS_COMMAND" \
-e "config=$config" \
-e "arch=$arch" \
-e CCACHE_DIR=/tmp/ccache \
-i $TTY_FLAG \
-v "$git_root:/var/local/jenkins/grpc" \
-v /tmp/ccache:/tmp/ccache \
-w /var/local/git/grpc \
--cidfile=docker.cid \
$DOCKER_IMAGE_NAME \
bash -l /var/local/jenkins/grpc/tools/jenkins/docker_run_tests.sh || DOCKER_FAILED="true"
DOCKER_CID=`cat docker.cid`
if [ "$XML_REPORT" != "" ]
then
docker cp "$DOCKER_CID:/var/local/git/grpc/$XML_REPORT" $git_root
fi
# remove the container, possibly killing it first
docker rm -f $DOCKER_CID || true
if [ "$DOCKER_FAILED" != "" ] && [ "$XML_REPORT" == "" ]
then
exit 1
fi

@ -28,18 +28,17 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# #
# This script is invoked by run_jekins.sh when piggy-backing into docker. # This script is invoked by build_docker_and_run_tests.py inside a docker
# container. You should never need to call this script on your own.
set -e set -e
export CONFIG=$config export CONFIG=$config
export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5 export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5
export CPPFLAGS=-I/tmp/prebuilt/include
mkdir -p /var/local/git mkdir -p /var/local/git
git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
cd /var/local/git/grpc
nvm use 0.12 nvm use 0.12
rvm use ruby-2.1 rvm use ruby-2.1
setarch $arch tools/run_tests/run_tests.py -t -c $config -l $language -x report.xml $RUN_TESTS_COMMAND

@ -56,46 +56,8 @@ if [ "$platform" == "linux" ]
then then
echo "building $language on Linux" echo "building $language on Linux"
cd `dirname $0`/../.. ./tools/run_tests/run_tests.py --use_docker -t -l $language -c $config -x report.xml || true
git_root=`pwd`
cd -
mkdir -p /tmp/ccache
# Use image name based on Dockerfile checksum
DOCKER_IMAGE_NAME=grpc_jenkins_slave$docker_suffix_`sha1sum tools/jenkins/grpc_jenkins_slave/Dockerfile | cut -f1 -d\ `
# Make sure docker image has been built. Should be instantaneous if so.
docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave$docker_suffix
# Create a local branch so the child Docker script won't complain
git branch jenkins-docker
# Make sure the CID file is gone.
rm -f docker.cid
# Run tests inside docker
docker run \
-e "config=$config" \
-e "language=$language" \
-e "arch=$arch" \
-e CCACHE_DIR=/tmp/ccache \
-i \
-v "$git_root:/var/local/jenkins/grpc" \
-v /tmp/ccache:/tmp/ccache \
--cidfile=docker.cid \
$DOCKER_IMAGE_NAME \
bash -l /var/local/jenkins/grpc/tools/jenkins/docker_run_jenkins.sh || DOCKER_FAILED="true"
DOCKER_CID=`cat docker.cid`
# forcefully kill the instance if it's still running, otherwise
# continue
# (failure to kill something that's already dead => things are dead)
docker kill $DOCKER_CID || true
docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
# TODO(ctiller): why?
sleep 4
docker rm $DOCKER_CID || true
elif [ "$platform" == "interop" ] elif [ "$platform" == "interop" ]
then then
python tools/run_tests/run_interops.py --language=$language python tools/run_tests/run_interops.py --language=$language

@ -37,7 +37,6 @@ import os
import socket import socket
import sys import sys
import time import time
import yaml
argp = argparse.ArgumentParser(description='Server for httpcli_test') argp = argparse.ArgumentParser(description='Server for httpcli_test')
argp.add_argument('-p', '--port', default=12345, type=int) argp.add_argument('-p', '--port', default=12345, type=int)
@ -118,6 +117,9 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(_MY_VERSION) self.wfile.write(_MY_VERSION)
elif self.path == '/dump': elif self.path == '/dump':
# yaml module is not installed on Macs and Windows machines by default
# so we import it lazily (/dump action is only used for debugging)
import yaml
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'text/plain') self.send_header('Content-Type', 'text/plain')
self.end_headers() self.end_headers()

@ -397,12 +397,6 @@ _WINDOWS_CONFIG = {
'opt': 'Release', 'opt': 'Release',
} }
# parse command line
argp = argparse.ArgumentParser(description='Run grpc tests.')
argp.add_argument('-c', '--config',
choices=['all'] + sorted(_CONFIGS.keys()),
nargs='+',
default=_DEFAULT)
def runs_per_test_type(arg_str): def runs_per_test_type(arg_str):
"""Auxilary function to parse the "runs_per_test" flag. """Auxilary function to parse the "runs_per_test" flag.
@ -423,6 +417,13 @@ def runs_per_test_type(arg_str):
except: except:
msg = "'{}' isn't a positive integer or 'inf'".format(arg_str) msg = "'{}' isn't a positive integer or 'inf'".format(arg_str)
raise argparse.ArgumentTypeError(msg) raise argparse.ArgumentTypeError(msg)
# parse command line
argp = argparse.ArgumentParser(description='Run grpc tests.')
argp.add_argument('-c', '--config',
choices=['all'] + sorted(_CONFIGS.keys()),
nargs='+',
default=_DEFAULT)
argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type, argp.add_argument('-n', '--runs_per_test', default=1, type=runs_per_test_type,
help='A positive integer or "inf". If "inf", all tests will run in an ' help='A positive integer or "inf". If "inf", all tests will run in an '
'infinite loop. Especially useful in combination with "-f"') 'infinite loop. Especially useful in combination with "-f"')
@ -449,11 +450,48 @@ argp.add_argument('-S', '--stop_on_failure',
default=False, default=False,
action='store_const', action='store_const',
const=True) const=True)
argp.add_argument('--use_docker',
default=False,
action='store_const',
const=True,
help="Run all the tests under docker. That provides " +
"additional isolation and prevents the need to installs " +
"language specific prerequisites. Only available on Linux.")
argp.add_argument('-a', '--antagonists', default=0, type=int) argp.add_argument('-a', '--antagonists', default=0, type=int)
argp.add_argument('-x', '--xml_report', default=None, type=str, argp.add_argument('-x', '--xml_report', default=None, type=str,
help='Generates a JUnit-compatible XML report') help='Generates a JUnit-compatible XML report')
args = argp.parse_args() args = argp.parse_args()
if args.use_docker:
if not args.travis:
print 'Seen --use_docker flag, will run tests under docker.'
print
print 'IMPORTANT: The changes you are testing need to be locally committed'
print 'because only the committed changes in the current branch will be'
print 'copied to the docker environment.'
time.sleep(5)
child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
run_tests_cmd = 'tools/run_tests/run_tests.py %s' % " ".join(child_argv[1:])
# TODO(jtattermusch): revisit if we need special handling for arch here
# set arch command prefix in case we are working with different arch.
arch_env = os.getenv('arch')
if arch_env:
run_test_cmd = 'arch %s %s' % (arch_env, run_test_cmd)
env = os.environ.copy()
env['RUN_TESTS_COMMAND'] = run_tests_cmd
if args.xml_report:
env['XML_REPORT'] = args.xml_report
if not args.travis:
env['TTY_FLAG'] = '-t' # enables Ctrl-C when not on Jenkins.
subprocess.check_call(['tools/jenkins/build_docker_and_run_tests.sh'],
shell=True,
env=env)
sys.exit(0)
# grab config # grab config
run_configs = set(_CONFIGS[cfg] run_configs = set(_CONFIGS[cfg]
for cfg in itertools.chain.from_iterable( for cfg in itertools.chain.from_iterable(

@ -760,6 +760,20 @@
"test/core/surface/lame_client_test.c" "test/core/surface/lame_client_test.c"
] ]
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "lb_policies_test",
"src": [
"test/core/client_config/lb_policies_test.c"
]
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -12275,6 +12289,7 @@
"src/core/client_config/client_config.h", "src/core/client_config/client_config.h",
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.h", "src/core/client_config/lb_policy_factory.h",
"src/core/client_config/lb_policy_registry.h", "src/core/client_config/lb_policy_registry.h",
@ -12335,10 +12350,10 @@
"src/core/security/auth_filters.h", "src/core/security/auth_filters.h",
"src/core/security/base64.h", "src/core/security/base64.h",
"src/core/security/credentials.h", "src/core/security/credentials.h",
"src/core/security/handshake.h",
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/jwt_verifier.h", "src/core/security/jwt_verifier.h",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.h",
"src/core/security/security_connector.h", "src/core/security/security_connector.h",
"src/core/security/security_context.h", "src/core/security/security_context.h",
"src/core/statistics/census_interface.h", "src/core/statistics/census_interface.h",
@ -12425,6 +12440,8 @@
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.c", "src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.c", "src/core/client_config/lb_policy.c",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.c", "src/core/client_config/lb_policy_factory.c",
@ -12555,14 +12572,14 @@
"src/core/security/credentials_posix.c", "src/core/security/credentials_posix.c",
"src/core/security/credentials_win32.c", "src/core/security/credentials_win32.c",
"src/core/security/google_default_credentials.c", "src/core/security/google_default_credentials.c",
"src/core/security/handshake.c",
"src/core/security/handshake.h",
"src/core/security/json_token.c", "src/core/security/json_token.c",
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/jwt_verifier.c", "src/core/security/jwt_verifier.c",
"src/core/security/jwt_verifier.h", "src/core/security/jwt_verifier.h",
"src/core/security/secure_endpoint.c", "src/core/security/secure_endpoint.c",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.c",
"src/core/security/secure_transport_setup.h",
"src/core/security/security_connector.c", "src/core/security/security_connector.c",
"src/core/security/security_connector.h", "src/core/security/security_connector.h",
"src/core/security/security_context.c", "src/core/security/security_context.c",
@ -12769,6 +12786,7 @@
"src/core/client_config/client_config.h", "src/core/client_config/client_config.h",
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.h", "src/core/client_config/lb_policy_factory.h",
"src/core/client_config/lb_policy_registry.h", "src/core/client_config/lb_policy_registry.h",
@ -12905,6 +12923,8 @@
"src/core/client_config/connector.h", "src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.c", "src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policies/pick_first.h", "src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policies/round_robin.c",
"src/core/client_config/lb_policies/round_robin.h",
"src/core/client_config/lb_policy.c", "src/core/client_config/lb_policy.c",
"src/core/client_config/lb_policy.h", "src/core/client_config/lb_policy.h",
"src/core/client_config/lb_policy_factory.c", "src/core/client_config/lb_policy_factory.c",

@ -851,6 +851,24 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "lb_policies_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",

@ -1085,6 +1085,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lame_client_test", "vcxproj
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lb_policies_test", "vcxproj\test\lb_policies_test\lb_policies_test.vcxproj", "{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}"
ProjectSection(myProperties) = preProject
lib = "False"
EndProjectSection
ProjectSection(ProjectDependencies) = postProject
{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vcxproj\test\message_compress_test\message_compress_test.vcxproj", "{07170557-CCB0-D23C-8018-C2909D115DF9}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vcxproj\test\message_compress_test\message_compress_test.vcxproj", "{07170557-CCB0-D23C-8018-C2909D115DF9}"
ProjectSection(myProperties) = preProject ProjectSection(myProperties) = preProject
lib = "False" lib = "False"
@ -9565,6 +9576,22 @@ Global
{6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|Win32.Build.0 = Release|Win32 {6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|Win32.Build.0 = Release|Win32
{6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|x64.ActiveCfg = Release|x64 {6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|x64.ActiveCfg = Release|x64
{6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|x64.Build.0 = Release|x64 {6E60B394-E17D-658A-6648-A2E6E183226F}.Release-DLL|x64.Build.0 = Release|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug|Win32.ActiveCfg = Debug|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug|x64.ActiveCfg = Debug|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release|Win32.ActiveCfg = Release|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release|x64.ActiveCfg = Release|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug|Win32.Build.0 = Debug|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug|x64.Build.0 = Debug|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release|Win32.Build.0 = Release|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release|x64.Build.0 = Release|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug-DLL|Win32.Build.0 = Debug|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug-DLL|x64.ActiveCfg = Debug|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Debug-DLL|x64.Build.0 = Debug|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release-DLL|Win32.ActiveCfg = Release|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release-DLL|Win32.Build.0 = Release|Win32
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release-DLL|x64.ActiveCfg = Release|x64
{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}.Release-DLL|x64.Build.0 = Release|x64
{07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|Win32.ActiveCfg = Debug|Win32 {07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|Win32.ActiveCfg = Debug|Win32
{07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|x64.ActiveCfg = Debug|x64 {07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|x64.ActiveCfg = Debug|x64
{07170557-CCB0-D23C-8018-C2909D115DF9}.Release|Win32.ActiveCfg = Release|Win32 {07170557-CCB0-D23C-8018-C2909D115DF9}.Release|Win32.ActiveCfg = Release|Win32

@ -232,10 +232,10 @@
<ClInclude Include="..\..\..\src\core\security\auth_filters.h" /> <ClInclude Include="..\..\..\src\core\security\auth_filters.h" />
<ClInclude Include="..\..\..\src\core\security\base64.h" /> <ClInclude Include="..\..\..\src\core\security\base64.h" />
<ClInclude Include="..\..\..\src\core\security\credentials.h" /> <ClInclude Include="..\..\..\src\core\security\credentials.h" />
<ClInclude Include="..\..\..\src\core\security\handshake.h" />
<ClInclude Include="..\..\..\src\core\security\json_token.h" /> <ClInclude Include="..\..\..\src\core\security\json_token.h" />
<ClInclude Include="..\..\..\src\core\security\jwt_verifier.h" /> <ClInclude Include="..\..\..\src\core\security\jwt_verifier.h" />
<ClInclude Include="..\..\..\src\core\security\secure_endpoint.h" /> <ClInclude Include="..\..\..\src\core\security\secure_endpoint.h" />
<ClInclude Include="..\..\..\src\core\security\secure_transport_setup.h" />
<ClInclude Include="..\..\..\src\core\security\security_connector.h" /> <ClInclude Include="..\..\..\src\core\security\security_connector.h" />
<ClInclude Include="..\..\..\src\core\security\security_context.h" /> <ClInclude Include="..\..\..\src\core\security\security_context.h" />
<ClInclude Include="..\..\..\src\core\tsi\fake_transport_security.h" /> <ClInclude Include="..\..\..\src\core\tsi\fake_transport_security.h" />
@ -255,6 +255,7 @@
<ClInclude Include="..\..\..\src\core\client_config\client_config.h" /> <ClInclude Include="..\..\..\src\core\client_config\client_config.h" />
<ClInclude Include="..\..\..\src\core\client_config\connector.h" /> <ClInclude Include="..\..\..\src\core\client_config\connector.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\round_robin.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy_factory.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy_factory.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy_registry.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy_registry.h" />
@ -369,14 +370,14 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\google_default_credentials.c"> <ClCompile Include="..\..\..\src\core\security\google_default_credentials.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\handshake.c">
</ClCompile>
<ClCompile Include="..\..\..\src\core\security\json_token.c"> <ClCompile Include="..\..\..\src\core\security\json_token.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\jwt_verifier.c"> <ClCompile Include="..\..\..\src\core\security\jwt_verifier.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\secure_endpoint.c"> <ClCompile Include="..\..\..\src\core\security\secure_endpoint.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\secure_transport_setup.c">
</ClCompile>
<ClCompile Include="..\..\..\src\core\security\security_connector.c"> <ClCompile Include="..\..\..\src\core\security\security_connector.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\security_context.c"> <ClCompile Include="..\..\..\src\core\security\security_context.c">
@ -421,6 +422,8 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\round_robin.c">
</ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy_factory.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy_factory.c">

@ -25,6 +25,9 @@
<ClCompile Include="..\..\..\src\core\security\google_default_credentials.c"> <ClCompile Include="..\..\..\src\core\security\google_default_credentials.c">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\handshake.c">
<Filter>src\core\security</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\core\security\json_token.c"> <ClCompile Include="..\..\..\src\core\security\json_token.c">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClCompile> </ClCompile>
@ -34,9 +37,6 @@
<ClCompile Include="..\..\..\src\core\security\secure_endpoint.c"> <ClCompile Include="..\..\..\src\core\security\secure_endpoint.c">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\security\secure_transport_setup.c">
<Filter>src\core\security</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\core\security\security_connector.c"> <ClCompile Include="..\..\..\src\core\security\security_connector.c">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClCompile> </ClCompile>
@ -103,6 +103,9 @@
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c">
<Filter>src\core\client_config\lb_policies</Filter> <Filter>src\core\client_config\lb_policies</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\round_robin.c">
<Filter>src\core\client_config\lb_policies</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy.c">
<Filter>src\core\client_config</Filter> <Filter>src\core\client_config</Filter>
</ClCompile> </ClCompile>
@ -470,6 +473,9 @@
<ClInclude Include="..\..\..\src\core\security\credentials.h"> <ClInclude Include="..\..\..\src\core\security\credentials.h">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\core\security\handshake.h">
<Filter>src\core\security</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\core\security\json_token.h"> <ClInclude Include="..\..\..\src\core\security\json_token.h">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClInclude> </ClInclude>
@ -479,9 +485,6 @@
<ClInclude Include="..\..\..\src\core\security\secure_endpoint.h"> <ClInclude Include="..\..\..\src\core\security\secure_endpoint.h">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\core\security\secure_transport_setup.h">
<Filter>src\core\security</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\core\security\security_connector.h"> <ClInclude Include="..\..\..\src\core\security\security_connector.h">
<Filter>src\core\security</Filter> <Filter>src\core\security</Filter>
</ClInclude> </ClInclude>
@ -539,6 +542,9 @@
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h"> <ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h">
<Filter>src\core\client_config\lb_policies</Filter> <Filter>src\core\client_config\lb_policies</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\round_robin.h">
<Filter>src\core\client_config\lb_policies</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\core\client_config\lb_policy.h"> <ClInclude Include="..\..\..\src\core\client_config\lb_policy.h">
<Filter>src\core\client_config</Filter> <Filter>src\core\client_config</Filter>
</ClInclude> </ClInclude>

@ -234,6 +234,7 @@
<ClInclude Include="..\..\..\src\core\client_config\client_config.h" /> <ClInclude Include="..\..\..\src\core\client_config\client_config.h" />
<ClInclude Include="..\..\..\src\core\client_config\connector.h" /> <ClInclude Include="..\..\..\src\core\client_config\connector.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\round_robin.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy_factory.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy_factory.h" />
<ClInclude Include="..\..\..\src\core\client_config\lb_policy_registry.h" /> <ClInclude Include="..\..\..\src\core\client_config\lb_policy_registry.h" />
@ -360,6 +361,8 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\round_robin.c">
</ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy.c">
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy_factory.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy_factory.c">

@ -43,6 +43,9 @@
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policies\pick_first.c">
<Filter>src\core\client_config\lb_policies</Filter> <Filter>src\core\client_config\lb_policies</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policies\round_robin.c">
<Filter>src\core\client_config\lb_policies</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\core\client_config\lb_policy.c"> <ClCompile Include="..\..\..\src\core\client_config\lb_policy.c">
<Filter>src\core\client_config</Filter> <Filter>src\core\client_config</Filter>
</ClCompile> </ClCompile>
@ -437,6 +440,9 @@
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h"> <ClInclude Include="..\..\..\src\core\client_config\lb_policies\pick_first.h">
<Filter>src\core\client_config\lb_policies</Filter> <Filter>src\core\client_config\lb_policies</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\src\core\client_config\lb_policies\round_robin.h">
<Filter>src\core\client_config\lb_policies</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\core\client_config\lb_policy.h"> <ClInclude Include="..\..\..\src\core\client_config\lb_policy.h">
<Filter>src\core\client_config</Filter> <Filter>src\core\client_config</Filter>
</ClInclude> </ClInclude>

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\1.0.2.3.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{62D58A08-3B5E-D6A8-ABBB-77995AA0A8C6}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
<PlatformToolset>v100</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\..\..\vsprojects\global.props" />
<Import Project="..\..\..\..\vsprojects\openssl.props" />
<Import Project="..\..\..\..\vsprojects\winsock.props" />
<Import Project="..\..\..\..\vsprojects\zlib.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<TargetName>lb_policies_test</TargetName>
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<TargetName>lb_policies_test</TargetName>
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\test\core\client_config\lb_policies_test.c">
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
<Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
<Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
<Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
<Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets')" />
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets')" />
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets')" />
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props')" />
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets')" />
</Target>
</Project>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="..\..\..\..\test\core\client_config\lb_policies_test.c">
<Filter>test\core\client_config</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="test">
<UniqueIdentifier>{58736598-65ad-bf09-4484-a4de1bb9b51f}</UniqueIdentifier>
</Filter>
<Filter Include="test\core">
<UniqueIdentifier>{6e194f4b-ceb1-0e6b-e77a-8149b0411d99}</UniqueIdentifier>
</Filter>
<Filter Include="test\core\client_config">
<UniqueIdentifier>{f948fe8f-47f8-fcce-2740-6c390af3c30b}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
Loading…
Cancel
Save