Merge branch 'buffer_pools_for_realsies' of github.com:ctiller/grpc into buffer_pools_for_realsies

reviewable/pr8239/r2
Craig Tiller 8 years ago
commit 5a2a9eaa34
  1. 16
      BUILD
  2. 6
      CMakeLists.txt
  3. 63
      Makefile
  4. 2
      binding.gyp
  5. 4
      build.yaml
  6. 2
      config.m4
  7. 6
      gRPC-Core.podspec
  8. 4
      grpc.gemspec
  9. 6
      include/grpc++/resource_quota.h
  10. 6
      include/grpc/impl/codegen/grpc_types.h
  11. 4
      package.xml
  12. 4
      src/core/ext/census/grpc_filter.c
  13. 193
      src/core/ext/client_config/client_channel.c
  14. 296
      src/core/ext/client_config/method_config.c
  15. 116
      src/core/ext/client_config/method_config.h
  16. 9
      src/core/ext/client_config/resolver_result.h
  17. 4
      src/core/ext/client_config/subchannel.c
  18. 3
      src/core/ext/client_config/subchannel.h
  19. 5
      src/core/ext/lb_policy/grpclb/grpclb.c
  20. 1
      src/core/ext/lb_policy/pick_first/pick_first.c
  21. 1
      src/core/ext/lb_policy/round_robin/round_robin.c
  22. 6
      src/core/ext/resolver/sockaddr/sockaddr_resolver.c
  23. 4
      src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
  24. 12
      src/core/lib/channel/channel_args.c
  25. 4
      src/core/lib/channel/channel_args.h
  26. 4
      src/core/lib/channel/channel_stack.c
  27. 4
      src/core/lib/channel/channel_stack.h
  28. 76
      src/core/lib/channel/deadline_filter.c
  29. 33
      src/core/lib/channel/deadline_filter.h
  30. 2
      src/core/lib/channel/handshaker.c
  31. 60
      src/core/lib/channel/message_size_filter.c
  32. 2
      src/core/lib/iomgr/endpoint.h
  33. 3
      src/core/lib/iomgr/endpoint_pair.h
  34. 3
      src/core/lib/iomgr/endpoint_pair_posix.c
  35. 9
      src/core/lib/iomgr/ev_poll_posix.c
  36. 131
      src/core/lib/iomgr/resource_quota.c
  37. 6
      src/core/lib/iomgr/resource_quota.h
  38. 2
      src/core/lib/iomgr/tcp_client_posix.h
  39. 17
      src/core/lib/iomgr/timer.h
  40. 6
      src/core/lib/security/credentials/jwt/jwt_verifier.c
  41. 7
      src/core/lib/security/credentials/oauth2/oauth2_credentials.c
  42. 3
      src/core/lib/security/transport/secure_endpoint.c
  43. 13
      src/core/lib/surface/call.c
  44. 142
      src/core/lib/transport/mdstr_hash_table.c
  45. 83
      src/core/lib/transport/mdstr_hash_table.h
  46. 3
      src/cpp/common/channel_arguments.cc
  47. 2
      src/cpp/server/server_builder.cc
  48. 33
      src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
  49. 2
      src/csharp/Grpc.Core/Server.cs
  50. 12
      src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
  51. 2
      src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme
  52. 18
      src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
  53. 2
      src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme
  54. 25
      src/objective-c/examples/SwiftSample/ViewController.swift
  55. 2
      src/objective-c/tests/Info.plist
  56. 16
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  57. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme
  58. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
  59. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme
  60. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme
  61. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme
  62. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme
  63. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme
  64. 2
      src/python/grpcio/grpc_core_dependencies.py
  65. 12
      src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
  66. 4
      src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
  67. 3
      test/core/bad_client/bad_client.c
  68. 4
      test/core/channel/channel_stack_test.c
  69. 31
      test/core/end2end/connection_refused_test.c
  70. 3
      test/core/end2end/end2end_tests.h
  71. 51
      test/core/end2end/fake_resolver.c
  72. 6
      test/core/end2end/fixtures/h2_census.c
  73. 4
      test/core/end2end/fixtures/h2_compress.c
  74. 128
      test/core/end2end/fixtures/h2_fake_resolver.c
  75. 4
      test/core/end2end/fixtures/h2_fakesec.c
  76. 5
      test/core/end2end/fixtures/h2_fd.c
  77. 4
      test/core/end2end/fixtures/h2_full+pipe.c
  78. 4
      test/core/end2end/fixtures/h2_full+trace.c
  79. 4
      test/core/end2end/fixtures/h2_full.c
  80. 4
      test/core/end2end/fixtures/h2_http_proxy.c
  81. 4
      test/core/end2end/fixtures/h2_load_reporting.c
  82. 4
      test/core/end2end/fixtures/h2_oauth2.c
  83. 4
      test/core/end2end/fixtures/h2_proxy.c
  84. 4
      test/core/end2end/fixtures/h2_sockpair+trace.c
  85. 4
      test/core/end2end/fixtures/h2_sockpair.c
  86. 4
      test/core/end2end/fixtures/h2_sockpair_1byte.c
  87. 4
      test/core/end2end/fixtures/h2_ssl.c
  88. 70
      test/core/end2end/fixtures/h2_ssl_cert.c
  89. 4
      test/core/end2end/fixtures/h2_ssl_proxy.c
  90. 4
      test/core/end2end/fixtures/h2_uds.c
  91. 3
      test/core/end2end/fuzzers/client_fuzzer.c
  92. 3
      test/core/end2end/fuzzers/server_fuzzer.c
  93. 3
      test/core/end2end/gen_build_yaml.py
  94. 2
      test/core/end2end/tests/bad_hostname.c
  95. 2
      test/core/end2end/tests/binary_metadata.c
  96. 2
      test/core/end2end/tests/call_creds.c
  97. 41
      test/core/end2end/tests/cancel_after_accept.c
  98. 2
      test/core/end2end/tests/cancel_after_client_done.c
  99. 2
      test/core/end2end/tests/cancel_after_invoke.c
  100. 2
      test/core/end2end/tests/cancel_before_invoke.c
  101. Some files were not shown because too many files have changed in this diff Show More

16
BUILD

@ -241,6 +241,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@ -300,6 +301,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
"src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@ -412,6 +414,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@ -481,6 +484,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
"src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@ -645,6 +649,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@ -681,6 +686,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
"src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@ -801,6 +807,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@ -844,6 +851,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
"src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@ -1004,6 +1012,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@ -1039,6 +1048,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
"src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@ -1152,6 +1162,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@ -1195,6 +1206,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
"src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@ -1920,6 +1932,7 @@ objc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
"src/core/lib/transport/mdstr_hash_table.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@ -1989,6 +2002,7 @@ objc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
"src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@ -2132,6 +2146,7 @@ objc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/mdstr_hash_table.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@ -2191,6 +2206,7 @@ objc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
"src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",

@ -377,6 +377,7 @@ add_library(grpc
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@ -446,6 +447,7 @@ add_library(grpc
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c
@ -637,6 +639,7 @@ add_library(grpc_cronet
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@ -680,6 +683,7 @@ add_library(grpc_cronet
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c
@ -869,6 +873,7 @@ add_library(grpc_unsecure
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
src/core/lib/transport/mdstr_hash_table.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@ -912,6 +917,7 @@ add_library(grpc_unsecure
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c

@ -1134,6 +1134,7 @@ bad_ssl_cert_server: $(BINDIR)/$(CONFIG)/bad_ssl_cert_server
bad_ssl_cert_test: $(BINDIR)/$(CONFIG)/bad_ssl_cert_test
h2_census_test: $(BINDIR)/$(CONFIG)/h2_census_test
h2_compress_test: $(BINDIR)/$(CONFIG)/h2_compress_test
h2_fake_resolver_test: $(BINDIR)/$(CONFIG)/h2_fake_resolver_test
h2_fakesec_test: $(BINDIR)/$(CONFIG)/h2_fakesec_test
h2_fd_test: $(BINDIR)/$(CONFIG)/h2_fd_test
h2_full_test: $(BINDIR)/$(CONFIG)/h2_full_test
@ -1152,6 +1153,7 @@ h2_ssl_proxy_test: $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test
h2_uds_test: $(BINDIR)/$(CONFIG)/h2_uds_test
h2_census_nosec_test: $(BINDIR)/$(CONFIG)/h2_census_nosec_test
h2_compress_nosec_test: $(BINDIR)/$(CONFIG)/h2_compress_nosec_test
h2_fake_resolver_nosec_test: $(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test
h2_fd_nosec_test: $(BINDIR)/$(CONFIG)/h2_fd_nosec_test
h2_full_nosec_test: $(BINDIR)/$(CONFIG)/h2_full_nosec_test
h2_full+pipe_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test
@ -1360,6 +1362,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/bad_ssl_cert_test \
$(BINDIR)/$(CONFIG)/h2_census_test \
$(BINDIR)/$(CONFIG)/h2_compress_test \
$(BINDIR)/$(CONFIG)/h2_fake_resolver_test \
$(BINDIR)/$(CONFIG)/h2_fakesec_test \
$(BINDIR)/$(CONFIG)/h2_fd_test \
$(BINDIR)/$(CONFIG)/h2_full_test \
@ -1378,6 +1381,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_uds_test \
$(BINDIR)/$(CONFIG)/h2_census_nosec_test \
$(BINDIR)/$(CONFIG)/h2_compress_nosec_test \
$(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test \
$(BINDIR)/$(CONFIG)/h2_fd_nosec_test \
$(BINDIR)/$(CONFIG)/h2_full_nosec_test \
$(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test \
@ -2634,6 +2638,7 @@ LIBGRPC_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@ -2703,6 +2708,7 @@ LIBGRPC_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
@ -2912,6 +2918,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@ -2955,6 +2962,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
@ -3180,6 +3188,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@ -3375,6 +3384,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@ -3418,6 +3428,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
@ -14608,6 +14619,38 @@ endif
endif
H2_FAKE_RESOLVER_TEST_SRC = \
test/core/end2end/fixtures/h2_fake_resolver.c \
H2_FAKE_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FAKE_RESOLVER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_fake_resolver_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_fake_resolver_test: $(H2_FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(H2_FAKE_RESOLVER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_fake_resolver_test
endif
$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fake_resolver.o: $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_h2_fake_resolver_test: $(H2_FAKE_RESOLVER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(H2_FAKE_RESOLVER_TEST_OBJS:.o=.dep)
endif
endif
H2_FAKESEC_TEST_SRC = \
test/core/end2end/fixtures/h2_fakesec.c \
@ -15160,6 +15203,26 @@ ifneq ($(NO_DEPS),true)
endif
H2_FAKE_RESOLVER_NOSEC_TEST_SRC = \
test/core/end2end/fixtures/h2_fake_resolver.c \
H2_FAKE_RESOLVER_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FAKE_RESOLVER_NOSEC_TEST_SRC))))
$(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test: $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_fake_resolver_nosec_test
$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fake_resolver.o: $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_h2_fake_resolver_nosec_test: $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS:.o=.dep)
ifneq ($(NO_DEPS),true)
-include $(H2_FAKE_RESOLVER_NOSEC_TEST_OBJS:.o=.dep)
endif
H2_FD_NOSEC_TEST_SRC = \
test/core/end2end/fixtures/h2_fd.c \

@ -652,6 +652,7 @@
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@ -721,6 +722,7 @@
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',

@ -245,6 +245,7 @@ filegroups:
- src/core/lib/surface/server.h
- src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/mdstr_hash_table.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/static_metadata.h
@ -339,6 +340,7 @@ filegroups:
- src/core/lib/surface/version.c
- src/core/lib/transport/byte_stream.c
- src/core/lib/transport/connectivity_state.c
- src/core/lib/transport/mdstr_hash_table.c
- src/core/lib/transport/metadata.c
- src/core/lib/transport/metadata_batch.c
- src/core/lib/transport/static_metadata.c
@ -359,6 +361,7 @@ filegroups:
- src/core/ext/client_config/lb_policy.h
- src/core/ext/client_config/lb_policy_factory.h
- src/core/ext/client_config/lb_policy_registry.h
- src/core/ext/client_config/method_config.h
- src/core/ext/client_config/parse_address.h
- src/core/ext/client_config/resolver.h
- src/core/ext/client_config/resolver_factory.h
@ -379,6 +382,7 @@ filegroups:
- src/core/ext/client_config/lb_policy.c
- src/core/ext/client_config/lb_policy_factory.c
- src/core/ext/client_config/lb_policy_registry.c
- src/core/ext/client_config/method_config.c
- src/core/ext/client_config/parse_address.c
- src/core/ext/client_config/resolver.c
- src/core/ext/client_config/resolver_factory.c

@ -171,6 +171,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
src/core/lib/transport/mdstr_hash_table.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@ -240,6 +241,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \

@ -328,6 +328,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/mdstr_hash_table.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/static_metadata.h',
@ -387,6 +388,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.h',
'src/core/ext/client_config/lb_policy_factory.h',
'src/core/ext/client_config/lb_policy_registry.h',
'src/core/ext/client_config/method_config.h',
'src/core/ext/client_config/parse_address.h',
'src/core/ext/client_config/resolver.h',
'src/core/ext/client_config/resolver_factory.h',
@ -503,6 +505,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@ -572,6 +575,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',
@ -704,6 +708,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/mdstr_hash_table.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/static_metadata.h',
@ -763,6 +768,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.h',
'src/core/ext/client_config/lb_policy_factory.h',
'src/core/ext/client_config/lb_policy_registry.h',
'src/core/ext/client_config/method_config.h',
'src/core/ext/client_config/parse_address.h',
'src/core/ext/client_config/resolver.h',
'src/core/ext/client_config/resolver_factory.h',

@ -248,6 +248,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/server.h )
s.files += %w( src/core/lib/transport/byte_stream.h )
s.files += %w( src/core/lib/transport/connectivity_state.h )
s.files += %w( src/core/lib/transport/mdstr_hash_table.h )
s.files += %w( src/core/lib/transport/metadata.h )
s.files += %w( src/core/lib/transport/metadata_batch.h )
s.files += %w( src/core/lib/transport/static_metadata.h )
@ -307,6 +308,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/lb_policy.h )
s.files += %w( src/core/ext/client_config/lb_policy_factory.h )
s.files += %w( src/core/ext/client_config/lb_policy_registry.h )
s.files += %w( src/core/ext/client_config/method_config.h )
s.files += %w( src/core/ext/client_config/parse_address.h )
s.files += %w( src/core/ext/client_config/resolver.h )
s.files += %w( src/core/ext/client_config/resolver_factory.h )
@ -423,6 +425,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/version.c )
s.files += %w( src/core/lib/transport/byte_stream.c )
s.files += %w( src/core/lib/transport/connectivity_state.c )
s.files += %w( src/core/lib/transport/mdstr_hash_table.c )
s.files += %w( src/core/lib/transport/metadata.c )
s.files += %w( src/core/lib/transport/metadata_batch.c )
s.files += %w( src/core/lib/transport/static_metadata.c )
@ -492,6 +495,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/lb_policy.c )
s.files += %w( src/core/ext/client_config/lb_policy_factory.c )
s.files += %w( src/core/ext/client_config/lb_policy_registry.c )
s.files += %w( src/core/ext/client_config/method_config.c )
s.files += %w( src/core/ext/client_config/parse_address.c )
s.files += %w( src/core/ext/client_config/resolver.c )
s.files += %w( src/core/ext/client_config/resolver_factory.c )

@ -31,8 +31,8 @@
*
*/
#ifndef GRPCXX_BUFFER_POOL_H
#define GRPCXX_BUFFER_POOL_H
#ifndef GRPCXX_RESOURCE_QUOTA_H
#define GRPCXX_RESOURCE_QUOTA_H
struct grpc_resource_quota;
@ -67,4 +67,4 @@ class ResourceQuota GRPC_FINAL {
} // namespace grpc
#endif
#endif // GRPCXX_RESOURCE_QUOTA_H

@ -202,9 +202,11 @@ typedef struct {
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
/** If non-zero, a pointer to a buffer pool (use grpc_resource_quota_arg_vtable
to
fetch an appropriate pointer arg vtable */
to fetch an appropriate pointer arg vtable */
#define GRPC_ARG_BUFFER_POOL "grpc.resource_quota"
/** Service config data, to be passed to subchannels.
Not intended for external use. */
#define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a

@ -255,6 +255,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/server.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/byte_stream.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/mdstr_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
@ -314,6 +315,7 @@
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/method_config.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.h" role="src" />
@ -430,6 +432,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/version.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/byte_stream.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/mdstr_hash_table.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
@ -499,6 +502,7 @@
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_registry.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/method_config.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/parse_address.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.c" role="src" />

@ -133,7 +133,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx,
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
memset(d, 0, sizeof(*d));
d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
d->start_ts = args->start_time;
return GRPC_ERROR_NONE;
}
@ -152,7 +152,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx,
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
memset(d, 0, sizeof(*d));
d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
d->start_ts = args->start_time;
/* TODO(hongyu): call census_tracing_start_op here. */
grpc_closure_init(&d->finish_recv, server_on_done_recv, elem);
return GRPC_ERROR_NONE;

@ -43,6 +43,7 @@
#include <grpc/support/useful.h>
#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/method_config.h"
#include "src/core/ext/client_config/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
@ -53,6 +54,9 @@
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
/* Client channel implementation */
@ -68,12 +72,13 @@ typedef struct client_channel_channel_data {
/** client channel factory */
grpc_client_channel_factory *client_channel_factory;
/** mutex protecting client configuration, including all
variables below in this data structure */
/** mutex protecting all variables below in this data structure */
gpr_mu mu;
/** currently active load balancer - guarded by mu */
/** currently active load balancer */
grpc_lb_policy *lb_policy;
/** incoming resolver result - set by resolver.next(), guarded by mu */
/** method config table */
grpc_method_config_table *method_config_table;
/** incoming resolver result - set by resolver.next() */
grpc_resolver_result *resolver_result;
/** a list of closures that are all waiting for config to come in */
grpc_closure_list waiting_for_config_closures;
@ -172,6 +177,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_method_config_table *method_config_table = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
@ -220,6 +226,13 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
const grpc_arg *channel_arg = grpc_channel_args_find(
lb_policy_args.additional_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
method_config_table = grpc_method_config_table_ref(
(grpc_method_config_table *)channel_arg->value.pointer.p);
}
grpc_resolver_result_unref(exec_ctx, chand->resolver_result);
chand->resolver_result = NULL;
}
@ -232,6 +245,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&chand->mu);
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
if (chand->method_config_table != NULL) {
grpc_method_config_table_unref(chand->method_config_table);
}
chand->method_config_table = method_config_table;
if (lb_policy != NULL) {
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL);
@ -392,6 +409,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
}
if (chand->method_config_table != NULL) {
grpc_method_config_table_unref(chand->method_config_table);
}
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
grpc_pollset_set_destroy(chand->interested_parties);
gpr_mu_destroy(&chand->mu);
@ -424,7 +444,16 @@ typedef struct client_channel_call_data {
// stack and each has its own mutex. If/when we have time, find a way
// to avoid this without breaking the grpc_deadline_state abstraction.
grpc_deadline_state deadline_state;
grpc_mdstr *path; // Request path.
gpr_timespec call_start_time;
gpr_timespec deadline;
enum {
WAIT_FOR_READY_UNSET,
WAIT_FOR_READY_FALSE,
WAIT_FOR_READY_TRUE
} wait_for_ready_from_service_config;
grpc_closure read_service_config;
grpc_error *cancel_error;
@ -532,10 +561,11 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_ERROR_CREATE_REFERENCING(
"Cancelled before creating subchannel", &error, 1));
} else {
/* Create call on subchannel. */
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *new_error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline,
&subchannel_call);
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
calld->deadline, &subchannel_call);
if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL;
@ -584,11 +614,15 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg,
/* cancelled, do nothing */
} else if (error != GRPC_ERROR_NONE) {
grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL);
} else if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
cpa->initial_metadata_flags,
cpa->connected_subchannel, cpa->on_ready,
GRPC_ERROR_NONE)) {
grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
} else {
call_data *calld = cpa->elem->call_data;
gpr_mu_lock(&calld->mu);
if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
cpa->initial_metadata_flags, cpa->connected_subchannel,
cpa->on_ready, GRPC_ERROR_NONE)) {
grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
}
gpr_mu_unlock(&calld->mu);
}
gpr_free(cpa);
}
@ -631,18 +665,33 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
GPR_ASSERT(error == GRPC_ERROR_NONE);
if (chand->lb_policy != NULL) {
grpc_lb_policy *lb_policy = chand->lb_policy;
int r;
GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel");
gpr_mu_unlock(&chand->mu);
// If the application explicitly set wait_for_ready, use that.
// Otherwise, if the service config specified a value for this
// method, use that.
const bool wait_for_ready_set_from_api =
initial_metadata_flags &
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
const bool wait_for_ready_set_from_service_config =
calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET;
if (!wait_for_ready_set_from_api &&
wait_for_ready_set_from_service_config) {
if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) {
initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
} else {
initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
}
}
// TODO(dgq): make this deadline configurable somehow.
const grpc_lb_policy_pick_args inputs = {
initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem,
gpr_inf_future(GPR_CLOCK_MONOTONIC)};
r = grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, connected_subchannel,
NULL, on_ready);
const bool result = grpc_lb_policy_pick(
exec_ctx, lb_policy, &inputs, connected_subchannel, NULL, on_ready);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel");
GPR_TIMER_END("pick_subchannel", 0);
return r;
return result;
}
if (chand->resolver != NULL && !chand->started_resolving) {
chand->started_resolving = true;
@ -768,8 +817,8 @@ retry:
calld->connected_subchannel != NULL) {
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline,
&subchannel_call);
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
calld->deadline, &subchannel_call);
if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
@ -786,13 +835,69 @@ retry:
GPR_TIMER_END("cc_start_transport_stream_op", 0);
}
// Gets data from the service config. Invoked when the resolver returns
// its initial result.
static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = arg;
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
// If this is an error, there's no point in looking at the service config.
if (error == GRPC_ERROR_NONE) {
// Get the method config table from channel data.
gpr_mu_lock(&chand->mu);
grpc_method_config_table *method_config_table = NULL;
if (chand->method_config_table != NULL) {
method_config_table =
grpc_method_config_table_ref(chand->method_config_table);
}
gpr_mu_unlock(&chand->mu);
// If the method config table was present, use it.
if (method_config_table != NULL) {
const grpc_method_config *method_config =
grpc_method_config_table_get_method_config(method_config_table,
calld->path);
if (method_config != NULL) {
const gpr_timespec *per_method_timeout =
grpc_method_config_get_timeout(method_config);
const bool *wait_for_ready =
grpc_method_config_get_wait_for_ready(method_config);
if (per_method_timeout != NULL || wait_for_ready != NULL) {
gpr_mu_lock(&calld->mu);
if (per_method_timeout != NULL) {
gpr_timespec per_method_deadline =
gpr_time_add(calld->call_start_time, *per_method_timeout);
if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
calld->deadline = per_method_deadline;
// Reset deadline timer.
grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
}
}
if (wait_for_ready != NULL) {
calld->wait_for_ready_from_service_config =
*wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE;
}
gpr_mu_unlock(&calld->mu);
}
}
grpc_method_config_table_unref(method_config_table);
}
}
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config");
}
/* Constructor for call_data */
static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_call_element_args *args) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
grpc_deadline_state_init(exec_ctx, elem, args);
calld->deadline = args->deadline;
// Initialize data members.
grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
calld->path = GRPC_MDSTR_REF(args->path);
calld->call_start_time = args->start_time;
calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET;
calld->cancel_error = GRPC_ERROR_NONE;
gpr_atm_rel_store(&calld->subchannel_call, 0);
gpr_mu_init(&calld->mu);
@ -803,6 +908,55 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
calld->owning_call = args->call_stack;
calld->pollent = NULL;
// If the resolver has already returned results, then we can access
// the service config parameters immediately. Otherwise, we need to
// defer that work until the resolver returns an initial result.
// TODO(roth): This code is almost but not quite identical to the code
// in read_service_config() above. It would be nice to find a way to
// combine them, to avoid having to maintain it twice.
gpr_mu_lock(&chand->mu);
if (chand->lb_policy != NULL) {
// We already have a resolver result, so check for service config.
if (chand->method_config_table != NULL) {
grpc_method_config_table *method_config_table =
grpc_method_config_table_ref(chand->method_config_table);
gpr_mu_unlock(&chand->mu);
grpc_method_config *method_config =
grpc_method_config_table_get_method_config(method_config_table,
args->path);
if (method_config != NULL) {
const gpr_timespec *per_method_timeout =
grpc_method_config_get_timeout(method_config);
if (per_method_timeout != NULL) {
gpr_timespec per_method_deadline =
gpr_time_add(calld->call_start_time, *per_method_timeout);
calld->deadline = gpr_time_min(calld->deadline, per_method_deadline);
}
const bool *wait_for_ready =
grpc_method_config_get_wait_for_ready(method_config);
if (wait_for_ready != NULL) {
calld->wait_for_ready_from_service_config =
*wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE;
}
}
grpc_method_config_table_unref(method_config_table);
} else {
gpr_mu_unlock(&chand->mu);
}
} else {
// We don't yet have a resolver result, so register a callback to
// get the service config data once the resolver returns.
// Take a reference to the call stack to be owned by the callback.
GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config");
grpc_closure_init(&calld->read_service_config, read_service_config, elem);
grpc_closure_list_append(&chand->waiting_for_config_closures,
&calld->read_service_config, GRPC_ERROR_NONE);
gpr_mu_unlock(&chand->mu);
}
// Start the deadline timer with the current deadline value. If we
// do not yet have service config data, then the timer may be reset
// later.
grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
return GRPC_ERROR_NONE;
}
@ -813,6 +967,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
void *and_free_memory) {
call_data *calld = elem->call_data;
grpc_deadline_state_destroy(exec_ctx, elem);
GRPC_MDSTR_UNREF(calld->path);
GRPC_ERROR_UNREF(calld->cancel_error);
grpc_subchannel_call *call = GET_CALL(calld);
if (call != NULL && call != CANCELLED_CALL) {

@ -0,0 +1,296 @@
//
// 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/ext/client_config/method_config.h"
#include <string.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/transport/mdstr_hash_table.h"
#include "src/core/lib/transport/metadata.h"
//
// grpc_method_config
//
// bool vtable
static void* bool_copy(void* valuep) {
bool value = *(bool*)valuep;
bool* new_value = gpr_malloc(sizeof(bool));
*new_value = value;
return new_value;
}
static int bool_cmp(void* v1, void* v2) {
bool b1 = *(bool*)v1;
bool b2 = *(bool*)v2;
if (!b1 && b2) return -1;
if (b1 && !b2) return 1;
return 0;
}
static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy,
bool_cmp};
// timespec vtable
static void* timespec_copy(void* valuep) {
gpr_timespec value = *(gpr_timespec*)valuep;
gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
*new_value = value;
return new_value;
}
static int timespec_cmp(void* v1, void* v2) {
return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
}
static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy,
timespec_cmp};
// int32 vtable
static void* int32_copy(void* valuep) {
int32_t value = *(int32_t*)valuep;
int32_t* new_value = gpr_malloc(sizeof(int32_t));
*new_value = value;
return new_value;
}
static int int32_cmp(void* v1, void* v2) {
int32_t i1 = *(int32_t*)v1;
int32_t i2 = *(int32_t*)v2;
if (i1 < i2) return -1;
if (i1 > i2) return 1;
return 0;
}
static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy,
int32_cmp};
// Hash table keys.
#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
"grpc.max_request_message_bytes" // int32
#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
"grpc.max_response_message_bytes" // int32
struct grpc_method_config {
grpc_mdstr_hash_table* table;
grpc_mdstr* wait_for_ready_key;
grpc_mdstr* timeout_key;
grpc_mdstr* max_request_message_bytes_key;
grpc_mdstr* max_response_message_bytes_key;
};
grpc_method_config* grpc_method_config_create(
bool* wait_for_ready, gpr_timespec* timeout,
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
memset(method_config, 0, sizeof(grpc_method_config));
method_config->wait_for_ready_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
method_config->timeout_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
method_config->max_request_message_bytes_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
method_config->max_response_message_bytes_key =
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
grpc_mdstr_hash_table_entry entries[4];
size_t num_entries = 0;
if (wait_for_ready != NULL) {
entries[num_entries].key = method_config->wait_for_ready_key;
entries[num_entries].value = wait_for_ready;
entries[num_entries].vtable = &bool_vtable;
++num_entries;
}
if (timeout != NULL) {
entries[num_entries].key = method_config->timeout_key;
entries[num_entries].value = timeout;
entries[num_entries].vtable = &timespec_vtable;
++num_entries;
}
if (max_request_message_bytes != NULL) {
entries[num_entries].key = method_config->max_request_message_bytes_key;
entries[num_entries].value = max_request_message_bytes;
entries[num_entries].vtable = &int32_vtable;
++num_entries;
}
if (max_response_message_bytes != NULL) {
entries[num_entries].key = method_config->max_response_message_bytes_key;
entries[num_entries].value = max_response_message_bytes;
entries[num_entries].vtable = &int32_vtable;
++num_entries;
}
method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
return method_config;
}
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
grpc_mdstr_hash_table_ref(method_config->table);
return method_config;
}
void grpc_method_config_unref(grpc_method_config* method_config) {
if (grpc_mdstr_hash_table_unref(method_config->table)) {
GRPC_MDSTR_UNREF(method_config->wait_for_ready_key);
GRPC_MDSTR_UNREF(method_config->timeout_key);
GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key);
GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key);
gpr_free(method_config);
}
}
int grpc_method_config_cmp(const grpc_method_config* method_config1,
const grpc_method_config* method_config2) {
return grpc_mdstr_hash_table_cmp(method_config1->table,
method_config2->table);
}
const bool* grpc_method_config_get_wait_for_ready(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(method_config->table,
method_config->wait_for_ready_key);
}
const gpr_timespec* grpc_method_config_get_timeout(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(method_config->table,
method_config->timeout_key);
}
const int32_t* grpc_method_config_get_max_request_message_bytes(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(
method_config->table, method_config->max_request_message_bytes_key);
}
const int32_t* grpc_method_config_get_max_response_message_bytes(
const grpc_method_config* method_config) {
return grpc_mdstr_hash_table_get(
method_config->table, method_config->max_response_message_bytes_key);
}
//
// grpc_method_config_table
//
static void method_config_unref(void* valuep) {
grpc_method_config_unref(valuep);
}
static void* method_config_ref(void* valuep) {
return grpc_method_config_ref(valuep);
}
static int method_config_cmp(void* valuep1, void* valuep2) {
return grpc_method_config_cmp(valuep1, valuep2);
}
static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
method_config_unref, method_config_ref, method_config_cmp};
grpc_method_config_table* grpc_method_config_table_create(
size_t num_entries, grpc_method_config_table_entry* entries) {
grpc_mdstr_hash_table_entry* hash_table_entries =
gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
for (size_t i = 0; i < num_entries; ++i) {
hash_table_entries[i].key = entries[i].method_name;
hash_table_entries[i].value = entries[i].method_config;
hash_table_entries[i].vtable = &method_config_table_vtable;
}
grpc_method_config_table* method_config_table =
grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
gpr_free(hash_table_entries);
return method_config_table;
}
grpc_method_config_table* grpc_method_config_table_ref(
grpc_method_config_table* table) {
return grpc_mdstr_hash_table_ref(table);
}
void grpc_method_config_table_unref(grpc_method_config_table* table) {
grpc_mdstr_hash_table_unref(table);
}
int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
const grpc_method_config_table* table2) {
return grpc_mdstr_hash_table_cmp(table1, table2);
}
grpc_method_config* grpc_method_config_table_get_method_config(
const grpc_method_config_table* table, const grpc_mdstr* path) {
grpc_method_config* method_config = grpc_mdstr_hash_table_get(table, path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (method_config == NULL) {
const char* path_str = grpc_mdstr_as_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = (size_t)(sep - path_str);
char* buf = gpr_malloc(len + 2); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
gpr_free(buf);
method_config = grpc_mdstr_hash_table_get(table, wildcard_path);
GRPC_MDSTR_UNREF(wildcard_path);
}
return method_config;
}
static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
static void destroy_arg(void* p) { grpc_method_config_table_unref(p); }
static int cmp_arg(void* p1, void* p2) {
return grpc_method_config_table_cmp(p1, p2);
}
static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
grpc_arg grpc_method_config_table_create_channel_arg(
grpc_method_config_table* table) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_ARG_SERVICE_CONFIG;
arg.value.pointer.p = table;
arg.value.pointer.vtable = &arg_vtable;
return arg;
}

@ -0,0 +1,116 @@
//
// Copyright 2016, 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_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H
#define GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H
#include <stdbool.h>
#include <grpc/impl/codegen/gpr_types.h>
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/transport/mdstr_hash_table.h"
#include "src/core/lib/transport/metadata.h"
/// Per-method configuration.
typedef struct grpc_method_config grpc_method_config;
/// Creates a grpc_method_config with the specified parameters.
/// Any parameter may be NULL to indicate that the value is unset.
///
/// \a wait_for_ready indicates whether the client should wait until the
/// request deadline for the channel to become ready, even if there is a
/// temporary failure before the deadline while attempting to connect.
///
/// \a timeout indicates the timeout for calls.
///
/// \a max_request_message_bytes and \a max_response_message_bytes
/// indicate the maximum sizes of the request (checked when sending) and
/// response (checked when receiving) messages.
grpc_method_config* grpc_method_config_create(
bool* wait_for_ready, gpr_timespec* timeout,
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
void grpc_method_config_unref(grpc_method_config* method_config);
/// Compares two grpc_method_configs.
/// The sort order is stable but undefined.
int grpc_method_config_cmp(const grpc_method_config* method_config1,
const grpc_method_config* method_config2);
/// These methods return NULL if the requested field is unset.
/// The caller does NOT take ownership of the result.
const bool* grpc_method_config_get_wait_for_ready(
const grpc_method_config* method_config);
const gpr_timespec* grpc_method_config_get_timeout(
const grpc_method_config* method_config);
const int32_t* grpc_method_config_get_max_request_message_bytes(
const grpc_method_config* method_config);
const int32_t* grpc_method_config_get_max_response_message_bytes(
const grpc_method_config* method_config);
/// A table of method configs.
typedef grpc_mdstr_hash_table grpc_method_config_table;
typedef struct grpc_method_config_table_entry {
/// The name is of one of the following forms:
/// service/method -- specifies exact service and method name
/// service/* -- matches all methods for the specified service
grpc_mdstr* method_name;
grpc_method_config* method_config;
} grpc_method_config_table_entry;
/// Takes new references to all keys and values in \a entries.
grpc_method_config_table* grpc_method_config_table_create(
size_t num_entries, grpc_method_config_table_entry* entries);
grpc_method_config_table* grpc_method_config_table_ref(
grpc_method_config_table* table);
void grpc_method_config_table_unref(grpc_method_config_table* table);
/// Compares two grpc_method_config_tables.
/// The sort order is stable but undefined.
int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
const grpc_method_config_table* table2);
/// Gets the method config for the specified \a path, which should be of
/// the form "/service/method".
/// Returns NULL if the method has no config.
/// Caller does NOT own a reference to the result.
grpc_method_config* grpc_method_config_table_get_method_config(
const grpc_method_config_table* table, const grpc_mdstr* path);
/// Returns a channel arg containing \a table.
grpc_arg grpc_method_config_table_create_channel_arg(
grpc_method_config_table* table);
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H */

@ -52,22 +52,17 @@ typedef struct grpc_resolver_result grpc_resolver_result;
grpc_resolver_result* grpc_resolver_result_create(
const char* server_name, grpc_lb_addresses* addresses,
const char* lb_policy_name, grpc_channel_args* lb_policy_args);
void grpc_resolver_result_ref(grpc_resolver_result* result);
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx,
grpc_resolver_result* result);
/// Caller does NOT take ownership of result.
/// Accessors. Caller does NOT take ownership of results.
const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result);
/// Caller does NOT take ownership of result.
grpc_lb_addresses* grpc_resolver_result_get_addresses(
grpc_resolver_result* result);
/// Caller does NOT take ownership of result.
const char* grpc_resolver_result_get_lb_policy_name(
grpc_resolver_result* result);
/// Caller does NOT take ownership of result.
grpc_channel_args* grpc_resolver_result_get_lb_policy_args(
grpc_resolver_result* result);

@ -704,7 +704,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
grpc_polling_entity *pollent, gpr_timespec deadline,
grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
*call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
@ -712,7 +712,7 @@ grpc_error *grpc_connected_subchannel_create_call(
(*call)->connection = con; // Ref is added below.
grpc_error *error =
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call,
NULL, NULL, deadline, callstk);
NULL, NULL, path, deadline, callstk);
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);

@ -38,6 +38,7 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
/** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */
@ -110,7 +111,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call */
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
grpc_polling_entity *pollent, gpr_timespec deadline,
grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
grpc_subchannel_call **subchannel_call);
/** process a transport level op */

@ -113,6 +113,7 @@
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/lb_policy/grpclb/grpclb.h"
#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"
@ -270,6 +271,7 @@ typedef struct glb_lb_policy {
/** who the client is trying to communicate with */
const char *server_name;
grpc_client_channel_factory *cc_factory;
grpc_channel_args *args;
/** deadline for the LB's call */
gpr_timespec deadline;
@ -457,6 +459,7 @@ static grpc_lb_policy *create_rr_locked(
args.server_name = glb_policy->server_name;
args.client_channel_factory = glb_policy->cc_factory;
args.addresses = process_serverlist(serverlist);
args.additional_args = glb_policy->args;
grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
@ -584,6 +587,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
* Create a client channel over them to communicate with a LB service */
glb_policy->server_name = gpr_strdup(args->server_name);
glb_policy->cc_factory = args->client_channel_factory;
glb_policy->args = grpc_channel_args_copy(args->additional_args);
GPR_ASSERT(glb_policy->cc_factory != NULL);
/* construct a target from the addresses in args, given in the form
@ -650,6 +654,7 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
GPR_ASSERT(glb_policy->pending_picks == NULL);
GPR_ASSERT(glb_policy->pending_pings == NULL);
gpr_free((void *)glb_policy->server_name);
grpc_channel_args_destroy(glb_policy->args);
grpc_channel_destroy(glb_policy->lb_channel);
glb_policy->lb_channel = NULL;
grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker);

@ -466,6 +466,7 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
sc_args.addr =
(struct sockaddr *)(&args->addresses->addresses[i].address.addr);
sc_args.addr_len = args->addresses->addresses[i].address.len;
sc_args.args = args->additional_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);

@ -629,6 +629,7 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
sc_args.addr =
(struct sockaddr *)(&args->addresses->addresses[i].address.addr);
sc_args.addr_len = args->addresses->addresses[i].address.len;
sc_args.args = args->additional_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);

@ -33,6 +33,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
@ -42,6 +43,7 @@
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/support/string.h"
@ -119,7 +121,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
*r->target_result = grpc_resolver_result_create(
r->target_name,
grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */),
NULL /* lb_policy_name */, NULL);
NULL /* lb_policy_name */, NULL /* lb_policy_args */);
grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
@ -128,8 +130,8 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
sockaddr_resolver *r = (sockaddr_resolver *)gr;
gpr_mu_destroy(&r->mu);
grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r->target_name);
grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r);
}

@ -57,8 +57,8 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
char *name;
gpr_asprintf(&name, "fd:%d", fd);
grpc_resource_quota *resource_quota =
grpc_resource_quota_from_channel_args(grpc_server_get_channel_args(server));
grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args(
grpc_server_get_channel_args(server));
grpc_endpoint *server_endpoint =
grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);

@ -272,6 +272,18 @@ int grpc_channel_args_compare(const grpc_channel_args *a,
return 0;
}
const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
const char *name) {
if (args != NULL) {
for (size_t i = 0; i < args->num_args; ++i) {
if (strcmp(args->args[i].key, name) == 0) {
return &args->args[i];
}
}
}
return NULL;
}
int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) {
if (arg->type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);

@ -89,6 +89,10 @@ uint32_t grpc_channel_args_compression_algorithm_get_states(
int grpc_channel_args_compare(const grpc_channel_args *a,
const grpc_channel_args *b);
/** Returns the value of argument \a name from \a args, or NULL if not found. */
const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
const char *name);
typedef struct grpc_integer_options {
int default_value; // Return this if value is outside of expected bounds.
int min_value;

@ -162,7 +162,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
gpr_timespec deadline, grpc_call_stack *call_stack) {
grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
grpc_call_element_args args;
size_t count = channel_stack->count;
@ -179,10 +179,12 @@ grpc_error *grpc_call_stack_init(
/* init per-filter data */
grpc_error *first_error = GRPC_ERROR_NONE;
args.start_time = gpr_now(GPR_CLOCK_MONOTONIC);
for (i = 0; i < count; i++) {
args.call_stack = call_stack;
args.server_transport_data = transport_server_data;
args.context = context;
args.path = path;
args.deadline = deadline;
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;

@ -74,6 +74,8 @@ typedef struct {
grpc_call_stack *call_stack;
const void *server_transport_data;
grpc_call_context_element *context;
grpc_mdstr *path;
gpr_timespec start_time;
gpr_timespec deadline;
} grpc_call_element_args;
@ -225,7 +227,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
gpr_timespec deadline, grpc_call_stack *call_stack);
grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack);
/* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */
void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,

@ -64,30 +64,49 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg,
}
// Starts the deadline timer.
static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
gpr_timespec deadline) {
static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
gpr_timespec deadline) {
grpc_deadline_state* deadline_state = elem->call_data;
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
// Note: We do not start the timer if there is already a timer
// pending. This should be okay, because this is only called from two
// functions exported by this module: grpc_deadline_state_start(), which
// starts the initial timer, and grpc_deadline_state_reset(), which
// cancels any pre-existing timer before starting a new one. In
// particular, we want to ensure that if grpc_deadline_state_start()
// winds up trying to start the timer after grpc_deadline_state_reset()
// has already done so, we ignore the value from the former.
if (!deadline_state->timer_pending &&
gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
// Take a reference to the call stack, to be owned by the timer.
GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
gpr_mu_lock(&deadline_state->timer_mu);
deadline_state->timer_pending = true;
grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback,
elem, gpr_now(GPR_CLOCK_MONOTONIC));
gpr_mu_unlock(&deadline_state->timer_mu);
}
}
static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
gpr_timespec deadline) {
grpc_deadline_state* deadline_state = elem->call_data;
gpr_mu_lock(&deadline_state->timer_mu);
start_timer_if_needed_locked(exec_ctx, elem, deadline);
gpr_mu_unlock(&deadline_state->timer_mu);
}
// Cancels the deadline timer.
static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx,
grpc_deadline_state* deadline_state) {
gpr_mu_lock(&deadline_state->timer_mu);
static void cancel_timer_if_needed_locked(grpc_exec_ctx* exec_ctx,
grpc_deadline_state* deadline_state) {
if (deadline_state->timer_pending) {
grpc_timer_cancel(exec_ctx, &deadline_state->timer);
deadline_state->timer_pending = false;
}
}
static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx,
grpc_deadline_state* deadline_state) {
gpr_mu_lock(&deadline_state->timer_mu);
cancel_timer_if_needed_locked(exec_ctx, deadline_state);
gpr_mu_unlock(&deadline_state->timer_mu);
}
@ -108,6 +127,21 @@ static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
op->on_complete = &deadline_state->on_complete;
}
void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
grpc_call_stack* call_stack) {
grpc_deadline_state* deadline_state = elem->call_data;
memset(deadline_state, 0, sizeof(*deadline_state));
deadline_state->call_stack = call_stack;
gpr_mu_init(&deadline_state->timer_mu);
}
void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem) {
grpc_deadline_state* deadline_state = elem->call_data;
cancel_timer_if_needed(exec_ctx, deadline_state);
gpr_mu_destroy(&deadline_state->timer_mu);
}
// Callback and associated state for starting the timer after call stack
// initialization has been completed.
struct start_timer_after_init_state {
@ -122,16 +156,11 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
gpr_free(state);
}
void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
grpc_call_element_args* args) {
grpc_deadline_state* deadline_state = elem->call_data;
memset(deadline_state, 0, sizeof(*deadline_state));
deadline_state->call_stack = args->call_stack;
gpr_mu_init(&deadline_state->timer_mu);
void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
gpr_timespec deadline) {
// Deadline will always be infinite on servers, so the timer will only be
// set on clients with a finite deadline.
const gpr_timespec deadline =
gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
// When the deadline passes, we indicate the failure by sending down
// an op with cancel_error set. However, we can't send down any ops
@ -148,11 +177,13 @@ void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
}
}
void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem) {
void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
gpr_timespec new_deadline) {
grpc_deadline_state* deadline_state = elem->call_data;
cancel_timer_if_needed(exec_ctx, deadline_state);
gpr_mu_destroy(&deadline_state->timer_mu);
gpr_mu_lock(&deadline_state->timer_mu);
cancel_timer_if_needed_locked(exec_ctx, deadline_state);
start_timer_if_needed_locked(exec_ctx, elem, new_deadline);
gpr_mu_unlock(&deadline_state->timer_mu);
}
void grpc_deadline_state_client_start_transport_stream_op(
@ -209,7 +240,8 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element_args* args) {
// Note: size of call data is different between client and server.
memset(elem->call_data, 0, elem->filter->sizeof_call_data);
grpc_deadline_state_init(exec_ctx, elem, args);
grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
grpc_deadline_state_start(exec_ctx, elem, args->deadline);
return GRPC_ERROR_NONE;
}

@ -54,18 +54,37 @@ typedef struct grpc_deadline_state {
grpc_closure* next_on_complete;
} grpc_deadline_state;
// To be used in a filter's init_call_elem(), destroy_call_elem(), and
// start_transport_stream_op() methods to enforce call deadlines.
//
// REQUIRES: The first field in elem->call_data is a grpc_deadline_state.
// NOTE: All of these functions require that the first field in
// elem->call_data is a grpc_deadline_state.
//
// For grpc_deadline_state_client_start_transport_stream_op(), it is the
// caller's responsibility to chain to the next filter if necessary
// after the function returns.
void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
grpc_call_element_args* args);
grpc_call_stack* call_stack);
void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem);
// Starts the timer with the specified deadline.
// Should be called from the filter's init_call_elem() method.
void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
gpr_timespec deadline);
// Cancels the existing timer and starts a new one with new_deadline.
//
// Note: It is generally safe to call this with an earlier deadline
// value than the current one, but not the reverse. No checks are done
// to ensure that the timer callback is not invoked while it is in the
// process of being reset, which means that attempting to increase the
// deadline may result in the timer being called twice.
void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
gpr_timespec new_deadline);
// To be called from the client-side filter's start_transport_stream_op()
// method. Ensures that the deadline timer is cancelled when the call
// is completed.
//
// Note: It is the caller's responsibility to chain to the next filter if
// necessary after this function returns.
void grpc_deadline_state_client_start_transport_stream_op(
grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
grpc_transport_stream_op* op);

@ -183,7 +183,7 @@ void grpc_handshake_manager_do_handshake(
gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data) {
grpc_channel_args* args_copy = grpc_channel_args_copy(args);
gpr_slice_buffer* read_buffer = malloc(sizeof(*read_buffer));
gpr_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer));
gpr_slice_buffer_init(read_buffer);
if (mgr->count == 0) {
// No handshakers registered, so we just immediately call the done

@ -38,6 +38,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_config/method_config.h"
#include "src/core/lib/channel/channel_args.h"
#define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited.
@ -45,6 +46,8 @@
#define DEFAULT_MAX_RECV_MESSAGE_LENGTH (4 * 1024 * 1024)
typedef struct call_data {
int max_send_size;
int max_recv_size;
// Receive closures are chained: we inject this closure as the
// recv_message_ready up-call on transport_stream_op, and remember to
// call our next_recv_message_ready member after handling it.
@ -58,6 +61,8 @@ typedef struct call_data {
typedef struct channel_data {
int max_send_size;
int max_recv_size;
// Method config table.
grpc_method_config_table* method_config_table;
} channel_data;
// Callback invoked when we receive a message. Here we check the max
@ -66,13 +71,12 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data,
grpc_error* error) {
grpc_call_element* elem = user_data;
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
if (*calld->recv_message != NULL && chand->max_recv_size >= 0 &&
(*calld->recv_message)->length > (size_t)chand->max_recv_size) {
if (*calld->recv_message != NULL && calld->max_recv_size >= 0 &&
(*calld->recv_message)->length > (size_t)calld->max_recv_size) {
char* message_string;
gpr_asprintf(&message_string,
"Received message larger than max (%u vs. %d)",
(*calld->recv_message)->length, chand->max_recv_size);
(*calld->recv_message)->length, calld->max_recv_size);
grpc_error* new_error = grpc_error_set_int(
GRPC_ERROR_CREATE(message_string), GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_INVALID_ARGUMENT);
@ -93,13 +97,12 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
// Check max send message size.
if (op->send_message != NULL && chand->max_send_size >= 0 &&
op->send_message->length > (size_t)chand->max_send_size) {
if (op->send_message != NULL && calld->max_send_size >= 0 &&
op->send_message->length > (size_t)calld->max_send_size) {
char* message_string;
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
op->send_message->length, chand->max_send_size);
op->send_message->length, calld->max_send_size);
gpr_slice message = gpr_slice_from_copied_string(message_string);
gpr_free(message_string);
grpc_call_element_send_close_with_message(
@ -119,9 +122,37 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
grpc_call_element_args* args) {
channel_data* chand = elem->channel_data;
call_data* calld = elem->call_data;
calld->next_recv_message_ready = NULL;
grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem);
// Get max sizes from channel data, then merge in per-method config values.
// Note: Per-method config is only available on the client, so we
// apply the max request size to the send limit and the max response
// size to the receive limit.
calld->max_send_size = chand->max_send_size;
calld->max_recv_size = chand->max_recv_size;
if (chand->method_config_table != NULL) {
grpc_method_config* method_config =
grpc_method_config_table_get_method_config(chand->method_config_table,
args->path);
if (method_config != NULL) {
const int32_t* max_request_message_bytes =
grpc_method_config_get_max_request_message_bytes(method_config);
if (max_request_message_bytes != NULL &&
(*max_request_message_bytes < calld->max_send_size ||
calld->max_send_size < 0)) {
calld->max_send_size = *max_request_message_bytes;
}
const int32_t* max_response_message_bytes =
grpc_method_config_get_max_response_message_bytes(method_config);
if (max_response_message_bytes != NULL &&
(*max_response_message_bytes < calld->max_recv_size ||
calld->max_recv_size < 0)) {
calld->max_recv_size = *max_response_message_bytes;
}
}
}
return GRPC_ERROR_NONE;
}
@ -155,11 +186,22 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
}
}
// Get method config table from channel args.
const grpc_arg* channel_arg =
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
chand->method_config_table = grpc_method_config_table_ref(
(grpc_method_config_table*)channel_arg->value.pointer.p);
}
}
// Destructor for channel_data.
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_element* elem) {}
grpc_channel_element* elem) {
channel_data* chand = elem->channel_data;
grpc_method_config_table_unref(chand->method_config_table);
}
const grpc_channel_filter grpc_message_size_filter = {
start_transport_stream_op,

@ -37,9 +37,9 @@
#include <grpc/support/slice.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resource_quota.h"
/* An endpoint caps a streaming channel between two communicating processes.
Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */

@ -42,6 +42,7 @@ typedef struct {
} grpc_endpoint_pair;
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota, size_t read_slice_size);
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size);
#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */

@ -63,7 +63,8 @@ static void create_sockets(int sv[2]) {
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
const char *name, grpc_resource_quota *resource_quota, size_t read_slice_size) {
const char *name, grpc_resource_quota *resource_quota,
size_t read_slice_size) {
int sv[2];
grpc_endpoint_pair p;
char *final_name;

@ -985,8 +985,15 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (errno != EINTR) {
work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
}
for (i = 2; i < pfd_count; i++) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
if (watchers[i].fd == NULL) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
} else {
// Wake up all the file descriptors, if we have an invalid one
// we can identify it on the next pollset_work()
fd_end_poll(exec_ctx, &watchers[i], 1, 1, pollset);
}
}
} else if (r == 0) {
for (i = 2; i < pfd_count; i++) {

@ -73,12 +73,14 @@ struct grpc_resource_quota {
* list management
*/
static void bulist_add_tail(grpc_resource_user *resource_user, grpc_bulist list) {
static void bulist_add_tail(grpc_resource_user *resource_user,
grpc_bulist list) {
grpc_resource_quota *resource_quota = resource_user->resource_quota;
grpc_resource_user **root = &resource_quota->roots[list];
if (*root == NULL) {
*root = resource_user;
resource_user->links[list].next = resource_user->links[list].prev = resource_user;
resource_user->links[list].next = resource_user->links[list].prev =
resource_user;
} else {
resource_user->links[list].next = *root;
resource_user->links[list].prev = (*root)->links[list].prev;
@ -87,12 +89,14 @@ static void bulist_add_tail(grpc_resource_user *resource_user, grpc_bulist list)
}
}
static void bulist_add_head(grpc_resource_user *resource_user, grpc_bulist list) {
static void bulist_add_head(grpc_resource_user *resource_user,
grpc_bulist list) {
grpc_resource_quota *resource_quota = resource_user->resource_quota;
grpc_resource_user **root = &resource_quota->roots[list];
if (*root == NULL) {
*root = resource_user;
resource_user->links[list].next = resource_user->links[list].prev = resource_user;
resource_user->links[list].next = resource_user->links[list].prev =
resource_user;
} else {
resource_user->links[list].next = (*root)->links[list].next;
resource_user->links[list].prev = *root;
@ -102,12 +106,13 @@ static void bulist_add_head(grpc_resource_user *resource_user, grpc_bulist list)
}
}
static bool bulist_empty(grpc_resource_quota *resource_quota, grpc_bulist list) {
static bool bulist_empty(grpc_resource_quota *resource_quota,
grpc_bulist list) {
return resource_quota->roots[list] == NULL;
}
static grpc_resource_user *bulist_pop(grpc_resource_quota *resource_quota,
grpc_bulist list) {
grpc_bulist list) {
grpc_resource_user **root = &resource_quota->roots[list];
grpc_resource_user *resource_user = *root;
if (resource_user == NULL) {
@ -145,10 +150,12 @@ static void bulist_remove(grpc_resource_user *resource_user, grpc_bulist list) {
* buffer pool state machine
*/
static bool bpalloc(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota);
static bool bpscavenge(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota);
static bool bpreclaim(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota,
bool destructive);
static bool bpalloc(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota);
static bool bpscavenge(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota);
static bool bpreclaim(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota, bool destructive);
static void bpstep(grpc_exec_ctx *exec_ctx, void *bp, grpc_error *error) {
grpc_resource_quota *resource_quota = bp;
@ -168,12 +175,13 @@ static void bpstep_sched(grpc_exec_ctx *exec_ctx,
resource_quota->step_scheduled = true;
grpc_resource_quota_internal_ref(resource_quota);
grpc_combiner_execute_finally(exec_ctx, resource_quota->combiner,
&resource_quota->bpstep_closure, GRPC_ERROR_NONE,
false);
&resource_quota->bpstep_closure,
GRPC_ERROR_NONE, false);
}
/* returns true if all allocations are completed */
static bool bpalloc(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) {
static bool bpalloc(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota) {
grpc_resource_user *resource_user;
while ((resource_user =
bulist_pop(resource_quota, GRPC_BULIST_AWAITING_ALLOCATION))) {
@ -207,7 +215,8 @@ static bool bpalloc(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota
}
/* returns true if any memory could be reclaimed from buffers */
static bool bpscavenge(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) {
static bool bpscavenge(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota) {
grpc_resource_user *resource_user;
while ((resource_user =
bulist_pop(resource_quota, GRPC_BULIST_NON_EMPTY_FREE_POOL))) {
@ -232,16 +241,17 @@ static bool bpscavenge(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_qu
}
/* returns true if reclaimation is proceeding */
static bool bpreclaim(grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota,
bool destructive) {
static bool bpreclaim(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota, bool destructive) {
if (resource_quota->reclaiming) return true;
grpc_bulist list = destructive ? GRPC_BULIST_RECLAIMER_DESTRUCTIVE
: GRPC_BULIST_RECLAIMER_BENIGN;
grpc_resource_user *resource_user = bulist_pop(resource_quota, list);
if (resource_user == NULL) return false;
if (grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, "BP %s %s: initiate %s reclaimation", resource_quota->name,
resource_user->name, destructive ? "destructive" : "benign");
gpr_log(GPR_DEBUG, "BP %s %s: initiate %s reclaimation",
resource_quota->name, resource_user->name,
destructive ? "destructive" : "benign");
}
resource_quota->reclaiming = true;
grpc_resource_quota_internal_ref(resource_quota);
@ -284,7 +294,8 @@ static void bu_slice_unref(void *p) {
}
}
static gpr_slice bu_slice_create(grpc_resource_user *resource_user, size_t size) {
static gpr_slice bu_slice_create(grpc_resource_user *resource_user,
size_t size) {
bu_slice_refcount *rc = gpr_malloc(sizeof(bu_slice_refcount) + size);
rc->base.ref = bu_slice_ref;
rc->base.unref = bu_slice_unref;
@ -304,7 +315,8 @@ static gpr_slice bu_slice_create(grpc_resource_user *resource_user, size_t size)
static void bu_allocate(grpc_exec_ctx *exec_ctx, void *bu, grpc_error *error) {
grpc_resource_user *resource_user = bu;
if (bulist_empty(resource_user->resource_quota, GRPC_BULIST_AWAITING_ALLOCATION)) {
if (bulist_empty(resource_user->resource_quota,
GRPC_BULIST_AWAITING_ALLOCATION)) {
bpstep_sched(exec_ctx, resource_user->resource_quota);
}
bulist_add_tail(resource_user, GRPC_BULIST_AWAITING_ALLOCATION);
@ -315,7 +327,8 @@ static void bu_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *bu,
grpc_resource_user *resource_user = bu;
if (!bulist_empty(resource_user->resource_quota,
GRPC_BULIST_AWAITING_ALLOCATION) &&
bulist_empty(resource_user->resource_quota, GRPC_BULIST_NON_EMPTY_FREE_POOL)) {
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_NON_EMPTY_FREE_POOL)) {
bpstep_sched(exec_ctx, resource_user->resource_quota);
}
bulist_add_tail(resource_user, GRPC_BULIST_NON_EMPTY_FREE_POOL);
@ -326,8 +339,10 @@ static void bu_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *bu,
grpc_resource_user *resource_user = bu;
if (!bulist_empty(resource_user->resource_quota,
GRPC_BULIST_AWAITING_ALLOCATION) &&
bulist_empty(resource_user->resource_quota, GRPC_BULIST_NON_EMPTY_FREE_POOL) &&
bulist_empty(resource_user->resource_quota, GRPC_BULIST_RECLAIMER_BENIGN)) {
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_NON_EMPTY_FREE_POOL) &&
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_RECLAIMER_BENIGN)) {
bpstep_sched(exec_ctx, resource_user->resource_quota);
}
bulist_add_tail(resource_user, GRPC_BULIST_RECLAIMER_BENIGN);
@ -338,8 +353,10 @@ static void bu_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *bu,
grpc_resource_user *resource_user = bu;
if (!bulist_empty(resource_user->resource_quota,
GRPC_BULIST_AWAITING_ALLOCATION) &&
bulist_empty(resource_user->resource_quota, GRPC_BULIST_NON_EMPTY_FREE_POOL) &&
bulist_empty(resource_user->resource_quota, GRPC_BULIST_RECLAIMER_BENIGN) &&
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_NON_EMPTY_FREE_POOL) &&
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_RECLAIMER_BENIGN) &&
bulist_empty(resource_user->resource_quota,
GRPC_BULIST_RECLAIMER_DESTRUCTIVE)) {
bpstep_sched(exec_ctx, resource_user->resource_quota);
@ -371,9 +388,9 @@ static void bu_allocated_slices(grpc_exec_ctx *exec_ctx, void *ts,
grpc_resource_user_slice_allocator *slice_allocator = ts;
if (error == GRPC_ERROR_NONE) {
for (size_t i = 0; i < slice_allocator->count; i++) {
gpr_slice_buffer_add_indexed(slice_allocator->dest,
bu_slice_create(slice_allocator->resource_user,
slice_allocator->length));
gpr_slice_buffer_add_indexed(
slice_allocator->dest, bu_slice_create(slice_allocator->resource_user,
slice_allocator->length));
}
}
grpc_closure_run(exec_ctx, &slice_allocator->on_done, GRPC_ERROR_REF(error));
@ -393,7 +410,8 @@ static void bp_resize(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
if (delta < 0 && a->resource_quota->free_pool < 0) {
bpstep_sched(exec_ctx, a->resource_quota);
} else if (delta > 0 &&
!bulist_empty(a->resource_quota, GRPC_BULIST_AWAITING_ALLOCATION)) {
!bulist_empty(a->resource_quota,
GRPC_BULIST_AWAITING_ALLOCATION)) {
bpstep_sched(exec_ctx, a->resource_quota);
}
grpc_resource_quota_internal_unref(exec_ctx, a->resource_quota);
@ -436,7 +454,7 @@ grpc_resource_quota *grpc_resource_quota_create(const char *name) {
}
void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota) {
grpc_resource_quota *resource_quota) {
if (gpr_unref(&resource_quota->refs)) {
grpc_combiner_destroy(exec_ctx, resource_quota->combiner);
gpr_free(resource_quota->name);
@ -450,7 +468,8 @@ void grpc_resource_quota_unref(grpc_resource_quota *resource_quota) {
grpc_exec_ctx_finish(&exec_ctx);
}
grpc_resource_quota *grpc_resource_quota_internal_ref(grpc_resource_quota *resource_quota) {
grpc_resource_quota *grpc_resource_quota_internal_ref(
grpc_resource_quota *resource_quota) {
gpr_ref(&resource_quota->refs);
return resource_quota;
}
@ -459,7 +478,8 @@ void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) {
grpc_resource_quota_internal_ref(resource_quota);
}
void grpc_resource_quota_resize(grpc_resource_quota *resource_quota, size_t size) {
void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
size_t size) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
bp_resize_args *a = gpr_malloc(sizeof(*a));
a->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
@ -508,16 +528,20 @@ const grpc_arg_pointer_vtable *grpc_resource_quota_arg_vtable(void) {
*/
void grpc_resource_user_init(grpc_resource_user *resource_user,
grpc_resource_quota *resource_quota, const char *name) {
resource_user->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
grpc_closure_init(&resource_user->allocate_closure, &bu_allocate, resource_user);
grpc_resource_quota *resource_quota,
const char *name) {
resource_user->resource_quota =
grpc_resource_quota_internal_ref(resource_quota);
grpc_closure_init(&resource_user->allocate_closure, &bu_allocate,
resource_user);
grpc_closure_init(&resource_user->add_to_free_pool_closure,
&bu_add_to_free_pool, resource_user);
grpc_closure_init(&resource_user->post_reclaimer_closure[0],
&bu_post_benign_reclaimer, resource_user);
grpc_closure_init(&resource_user->post_reclaimer_closure[1],
&bu_post_destructive_reclaimer, resource_user);
grpc_closure_init(&resource_user->destroy_closure, &bu_destroy, resource_user);
grpc_closure_init(&resource_user->destroy_closure, &bu_destroy,
resource_user);
gpr_mu_init(&resource_user->mu);
resource_user->allocated = 0;
resource_user->free_pool = 0;
@ -542,8 +566,8 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
}
void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user,
grpc_closure *on_done) {
grpc_resource_user *resource_user,
grpc_closure *on_done) {
gpr_mu_lock(&resource_user->mu);
GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->on_done_destroy_closure) ==
0);
@ -558,7 +582,7 @@ void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
}
void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user) {
grpc_resource_user *resource_user) {
#ifndef NDEBUG
gpr_free(resource_user->asan_canary);
#endif
@ -568,8 +592,8 @@ void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
}
void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user, size_t size,
grpc_closure *optional_on_done) {
grpc_resource_user *resource_user, size_t size,
grpc_closure *optional_on_done) {
gpr_mu_lock(&resource_user->mu);
grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
&resource_user->on_done_destroy_closure);
@ -609,7 +633,7 @@ void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
}
void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user, size_t size) {
grpc_resource_user *resource_user, size_t size) {
gpr_mu_lock(&resource_user->mu);
GPR_ASSERT(resource_user->allocated >= (int64_t)size);
bool was_zero_or_negative = resource_user->free_pool <= 0;
@ -640,8 +664,9 @@ void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
}
void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user,
bool destructive, grpc_closure *closure) {
grpc_resource_user *resource_user,
bool destructive,
grpc_closure *closure) {
if (gpr_atm_acq_load(&resource_user->on_done_destroy_closure) == 0) {
GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
resource_user->reclaimers[destructive] = closure;
@ -654,14 +679,15 @@ void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
}
void grpc_resource_user_finish_reclaimation(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user) {
grpc_resource_user *resource_user) {
if (grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, "BP %s %s: reclaimation complete",
resource_user->resource_quota->name, resource_user->name);
}
grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
&resource_user->resource_quota->bpreclaimation_done_closure,
GRPC_ERROR_NONE, false);
grpc_combiner_execute(
exec_ctx, resource_user->resource_quota->combiner,
&resource_user->resource_quota->bpreclaimation_done_closure,
GRPC_ERROR_NONE, false);
}
void grpc_resource_user_slice_allocator_init(
@ -674,11 +700,12 @@ void grpc_resource_user_slice_allocator_init(
}
void grpc_resource_user_alloc_slices(
grpc_exec_ctx *exec_ctx, grpc_resource_user_slice_allocator *slice_allocator,
size_t length, size_t count, gpr_slice_buffer *dest) {
grpc_exec_ctx *exec_ctx,
grpc_resource_user_slice_allocator *slice_allocator, size_t length,
size_t count, gpr_slice_buffer *dest) {
slice_allocator->length = length;
slice_allocator->count = count;
slice_allocator->dest = dest;
grpc_resource_user_alloc(exec_ctx, slice_allocator->resource_user, count * length,
&slice_allocator->on_allocated);
grpc_resource_user_alloc(exec_ctx, slice_allocator->resource_user,
count * length, &slice_allocator->on_allocated);
}

@ -31,8 +31,8 @@
*
*/
#ifndef GRPC_CORE_LIB_IOMGR_BUFFER_POOL_H
#define GRPC_CORE_LIB_IOMGR_BUFFER_POOL_H
#ifndef GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
#define GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
#include <grpc/grpc.h>
@ -128,4 +128,4 @@ void grpc_resource_user_alloc_slices(
grpc_resource_user_slice_allocator *slice_allocator, size_t length,
size_t count, gpr_slice_buffer *dest);
#endif /* GRPC_CORE_LIB_IOMGR_BUFFER_POOL_H */
#endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */

@ -42,4 +42,4 @@ grpc_endpoint *grpc_tcp_client_create_from_fd(
grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args,
const char *addr_str);
#endif
#endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H */

@ -49,11 +49,11 @@ typedef struct grpc_timer {
} grpc_timer;
/* Initialize *timer. When expired or canceled, timer_cb will be called with
*timer_cb_arg and status to indicate if it expired (SUCCESS) or was
canceled (CANCELLED). timer_cb is guaranteed to be called exactly once,
and application code should check the status to determine how it was
invoked. The application callback is also responsible for maintaining
information about when to free up any user-level state. */
*timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or
was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called
exactly once, and application code should check the error to determine
how it was invoked. The application callback is also responsible for
maintaining information about when to free up any user-level state. */
void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
void *timer_cb_arg, gpr_timespec now);
@ -74,8 +74,8 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
In all of these cases, the cancellation is still considered successful.
They are essentially distinguished in that the timer_cb will be run
exactly once from either the cancellation (with status CANCELLED)
or from the activation (with status SUCCESS)
exactly once from either the cancellation (with error GRPC_ERROR_CANCELLED)
or from the activation (with error GRPC_ERROR_NONE).
Note carefully that the callback function MAY occur in the same callstack
as grpc_timer_cancel. It's expected that most timers will be cancelled (their
@ -83,14 +83,13 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
that cancellation costs as little as possible. Making callbacks run inline
matches this aim.
Requires: cancel() must happen after add() on a given timer */
Requires: cancel() must happen after init() on a given timer */
void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer);
/* iomgr internal api for dealing with timers */
/* Check for timers to be run, and run them.
Return true if timer callbacks were executed.
Drops drop_mu if it is non-null before executing callbacks.
If next is non-null, TRY to update *next with the next running timer
IF that timer occurs before *next current value.
*next is never guaranteed to be updated on any given execution; however,

@ -660,7 +660,8 @@ static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
/* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
channel. This would allow us to cancel an authentication query when under
extreme memory pressure. */
grpc_resource_quota *resource_quota = grpc_resource_quota_create("jwt_verifier");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("jwt_verifier");
grpc_httpcli_get(
exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
@ -772,7 +773,8 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
/* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
channel. This would allow us to cancel an authentication query when under
extreme memory pressure. */
grpc_resource_quota *resource_quota = grpc_resource_quota_create("jwt_verifier");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("jwt_verifier");
grpc_httpcli_get(
exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),

@ -310,7 +310,8 @@ static void compute_engine_fetch_oauth2(
/* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
channel. This would allow us to cancel an authentication query when under
extreme memory pressure. */
grpc_resource_quota *resource_quota = grpc_resource_quota_create("oauth2_credentials");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("oauth2_credentials");
grpc_httpcli_get(exec_ctx, httpcli_context, pollent, resource_quota, &request,
deadline, grpc_closure_create(response_cb, metadata_req),
&metadata_req->response);
@ -367,8 +368,8 @@ static void refresh_token_fetch_oauth2(
extreme memory pressure. */
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("oauth2_credentials_refresh");
grpc_httpcli_post(exec_ctx, httpcli_context, pollent, resource_quota, &request,
body, strlen(body), deadline,
grpc_httpcli_post(exec_ctx, httpcli_context, pollent, resource_quota,
&request, body, strlen(body), deadline,
grpc_closure_create(response_cb, metadata_req),
&metadata_req->response);
grpc_resource_quota_internal_unref(exec_ctx, resource_quota);

@ -370,7 +370,8 @@ static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
return grpc_endpoint_get_workqueue(ep->wrapped_ep);
}
static grpc_resource_user *endpoint_get_resource_user(grpc_endpoint *secure_ep) {
static grpc_resource_user *endpoint_get_resource_user(
grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
return grpc_endpoint_get_resource_user(ep->wrapped_ep);
}

@ -241,11 +241,15 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
grpc_mdstr *path = NULL;
if (call->is_client) {
GPR_ASSERT(args->add_initial_metadata_count <
MAX_SEND_EXTRA_METADATA_COUNT);
for (i = 0; i < args->add_initial_metadata_count; i++) {
call->send_extra_metadata[i].md = args->add_initial_metadata[i];
if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) {
path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value);
}
}
call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
} else {
@ -306,9 +310,10 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args,
GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
/* initial refcount dropped by grpc_call_destroy */
grpc_error *error = grpc_call_stack_init(
&exec_ctx, channel_stack, 1, destroy_call, call, call->context,
args->server_transport_data, send_deadline, CALL_STACK_FROM_CALL(call));
grpc_error *error =
grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
call->context, args->server_transport_data, path,
send_deadline, CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) {
grpc_status_code status;
const char *error_str;
@ -332,6 +337,8 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args,
&exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
if (path != NULL) GRPC_MDSTR_UNREF(path);
grpc_exec_ctx_finish(&exec_ctx);
GPR_TIMER_END("grpc_call_create", 0);
return error;

@ -0,0 +1,142 @@
//
// Copyright 2016, 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/lib/transport/mdstr_hash_table.h"
#include <stdbool.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/transport/metadata.h"
struct grpc_mdstr_hash_table {
gpr_refcount refs;
size_t num_entries;
grpc_mdstr_hash_table_entry* entries;
};
// Helper function for insert and get operations that performs quadratic
// probing (https://en.wikipedia.org/wiki/Quadratic_probing).
static size_t grpc_mdstr_hash_table_find_index(
const grpc_mdstr_hash_table* table, const grpc_mdstr* key,
bool find_empty) {
for (size_t i = 0; i < table->num_entries; ++i) {
const size_t idx = (key->hash + i * i) % table->num_entries;
if (table->entries[idx].key == NULL)
return find_empty ? idx : table->num_entries;
if (table->entries[idx].key == key) return idx;
}
return table->num_entries; // Not found.
}
static void grpc_mdstr_hash_table_add(
grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value,
const grpc_mdstr_hash_table_vtable* vtable) {
GPR_ASSERT(value != NULL);
const size_t idx =
grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */);
GPR_ASSERT(idx != table->num_entries); // Table should never be full.
grpc_mdstr_hash_table_entry* entry = &table->entries[idx];
entry->key = GRPC_MDSTR_REF(key);
entry->value = vtable->copy_value(value);
entry->vtable = vtable;
}
grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
size_t num_entries, grpc_mdstr_hash_table_entry* entries) {
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table));
memset(table, 0, sizeof(*table));
gpr_ref_init(&table->refs, 1);
// Quadratic probing gets best performance when the table is no more
// than half full.
table->num_entries = num_entries * 2;
const size_t entry_size =
sizeof(grpc_mdstr_hash_table_entry) * table->num_entries;
table->entries = gpr_malloc(entry_size);
memset(table->entries, 0, entry_size);
for (size_t i = 0; i < num_entries; ++i) {
grpc_mdstr_hash_table_entry* entry = &entries[i];
grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable);
}
return table;
}
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) {
if (table != NULL) gpr_ref(&table->refs);
return table;
}
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
if (table != NULL && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->num_entries; ++i) {
grpc_mdstr_hash_table_entry* entry = &table->entries[i];
if (entry->key != NULL) {
GRPC_MDSTR_UNREF(entry->key);
entry->vtable->destroy_value(entry->value);
}
}
gpr_free(table->entries);
gpr_free(table);
return 1;
}
return 0;
}
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* key) {
const size_t idx =
grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */);
if (idx == table->num_entries) return NULL; // Not found.
return table->entries[idx].value;
}
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
const grpc_mdstr_hash_table* table2) {
// Compare by num_entries.
if (table1->num_entries < table2->num_entries) return -1;
if (table1->num_entries > table2->num_entries) return 1;
for (size_t i = 0; i < table1->num_entries; ++i) {
grpc_mdstr_hash_table_entry* e1 = &table1->entries[i];
grpc_mdstr_hash_table_entry* e2 = &table2->entries[i];
// Compare keys by hash value.
if (e1->key->hash < e2->key->hash) return -1;
if (e1->key->hash > e2->key->hash) return 1;
// Compare by vtable (pointer equality).
if (e1->vtable < e2->vtable) return -1;
if (e1->vtable > e2->vtable) return 1;
// Compare values via vtable.
const int value_result = e1->vtable->compare_value(e1->value, e2->value);
if (value_result != 0) return value_result;
}
return 0;
}

@ -0,0 +1,83 @@
/*
* Copyright 2016, 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_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H
#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H
#include "src/core/lib/transport/metadata.h"
/** Hash table implementation.
*
* This implementation uses open addressing
* (https://en.wikipedia.org/wiki/Open_addressing) with quadratic
* probing (https://en.wikipedia.org/wiki/Quadratic_probing).
*
* The keys are \a grpc_mdstr objects. The values are arbitrary pointers
* with a common vtable.
*
* Hash tables are intentionally immutable, to avoid the need for locking.
*/
typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table;
typedef struct grpc_mdstr_hash_table_vtable {
void (*destroy_value)(void* value);
void* (*copy_value)(void* value);
int (*compare_value)(void* value1, void* value2);
} grpc_mdstr_hash_table_vtable;
typedef struct grpc_mdstr_hash_table_entry {
grpc_mdstr* key;
void* value; /* Must not be NULL. */
const grpc_mdstr_hash_table_vtable* vtable;
} grpc_mdstr_hash_table_entry;
/** Creates a new hash table of containing \a entries, which is an array
of length \a num_entries.
Creates its own copy of all keys and values from \a entries. */
grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
size_t num_entries, grpc_mdstr_hash_table_entry* entries);
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table);
/** Returns 1 when \a table is destroyed. */
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* key);
/** Compares two hash tables.
The sort order is stable but undefined. */
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
const grpc_mdstr_hash_table* table2);
#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */

@ -114,7 +114,8 @@ void ChannelArguments::SetUserAgentPrefix(
}
}
void ChannelArguments::SetResourceQuota(const grpc::ResourceQuota& resource_quota) {
void ChannelArguments::SetResourceQuota(
const grpc::ResourceQuota& resource_quota) {
SetPointerWithVtable(GRPC_ARG_BUFFER_POOL, resource_quota.c_resource_quota(),
grpc_resource_quota_arg_vtable());
}

@ -33,8 +33,8 @@
#include <grpc++/server_builder.h>
#include <grpc++/resource_quota.h>
#include <grpc++/impl/service_type.h>
#include <grpc++/resource_quota.h>
#include <grpc++/server.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>

@ -277,20 +277,31 @@ namespace Grpc.Core.Internal
}
}
internal class NoSuchMethodCallHandler : IServerCallHandler
internal class UnimplementedMethodCallHandler : IServerCallHandler
{
public static readonly NoSuchMethodCallHandler Instance = new NoSuchMethodCallHandler();
public static readonly UnimplementedMethodCallHandler Instance = new UnimplementedMethodCallHandler();
public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
DuplexStreamingServerCallHandler<byte[], byte[]> callHandlerImpl;
public UnimplementedMethodCallHandler()
{
// We don't care about the payload type here.
var asyncCall = new AsyncCallServer<byte[], byte[]>(
(payload) => payload, (payload) => payload, newRpc.Server);
asyncCall.Initialize(newRpc.Call, cq);
var finishedTask = asyncCall.ServerSideCallAsync();
await asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty, null).ConfigureAwait(false);
await finishedTask.ConfigureAwait(false);
var marshaller = new Marshaller<byte[]>((payload) => payload, (payload) => payload);
var method = new Method<byte[], byte[]>(MethodType.DuplexStreaming, "", "", marshaller, marshaller);
this.callHandlerImpl = new DuplexStreamingServerCallHandler<byte[], byte[]>(method, new DuplexStreamingServerMethod<byte[], byte[]>(UnimplementedMethod));
}
/// <summary>
/// Handler used for unimplemented method.
/// </summary>
private Task UnimplementedMethod(IAsyncStreamReader<byte[]> requestStream, IServerStreamWriter<byte[]> responseStream, ServerCallContext ctx)
{
ctx.Status = new Status(StatusCode.Unimplemented, "");
return Task.FromResult<object>(null);
}
public Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq)
{
return callHandlerImpl.HandleCall(newRpc, cq);
}
}

@ -317,7 +317,7 @@ namespace Grpc.Core
IServerCallHandler callHandler;
if (!callHandlers.TryGetValue(newRpc.Method, out callHandler))
{
callHandler = NoSuchMethodCallHandler.Instance;
callHandler = UnimplementedMethodCallHandler.Instance;
}
await callHandler.HandleCall(newRpc, cq).ConfigureAwait(false);
}

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
@ -129,7 +129,7 @@
6369A2621A9322E20015FC5C /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
6369A2691A9322E20015FC5C = {
@ -138,7 +138,7 @@
};
};
buildConfigurationList = 6369A2651A9322E20015FC5C /* Build configuration list for PBXProject "Sample" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 8.0";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
@ -253,8 +253,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -263,6 +265,7 @@
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@ -296,8 +299,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -305,6 +310,7 @@
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
@ -123,16 +123,17 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0730;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
633BFFC11B950B210007E424 = {
CreatedOnToolsVersion = 6.4;
LastSwiftMigration = 0800;
};
};
};
buildConfigurationList = 633BFFBD1B950B210007E424 /* Build configuration list for PBXProject "SwiftSample" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 8.0";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
@ -246,8 +247,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -292,8 +295,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -312,6 +317,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@ -327,6 +333,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 3.0;
USER_HEADER_SEARCH_PATHS = "";
};
name = Debug;
@ -341,6 +348,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 3.0;
USER_HEADER_SEARCH_PATHS = "";
};
name = Release;
@ -355,7 +363,7 @@
633BFFE01B950B210007E424 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */ = {
isa = XCConfigurationList;
@ -364,7 +372,7 @@
633BFFE31B950B210007E424 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -51,7 +51,7 @@ class ViewController: UIViewController {
// Example gRPC call using a generated proto client library:
let service = RMTTestService(host: RemoteHost)
service.unaryCallWithRequest(request) { response, error in
service.unaryCall(with: request) { response, error in
if let response = response {
NSLog("1. Finished successfully with response:\n\(response)")
} else {
@ -63,40 +63,39 @@ class ViewController: UIViewController {
// Same but manipulating headers:
var RPC : GRPCProtoCall! // Needed to convince Swift to capture by reference (__block)
RPC = service.RPCToUnaryCallWithRequest(request) { response, error in
RPC = service.rpcToUnaryCall(with: request) { response, error in
if let response = response {
NSLog("2. Finished successfully with response:\n\(response)")
} else {
NSLog("2. Finished with error: \(error!)")
}
NSLog("2. Response headers: \(RPC.responseHeaders)")
NSLog("2. Response trailers: \(RPC.responseTrailers)")
NSLog("2. Response headers: \(RPC.responseHeaders!)")
NSLog("2. Response trailers: \(RPC.responseTrailers!)")
}
// TODO(jcanizales): Revert to using subscript syntax once XCode 8 is released.
RPC.requestHeaders.setObject("My value", forKey: "My-Header")
RPC.requestHeaders["My-Header"] = "My value";
RPC.start()
// Same example call using the generic gRPC client library:
let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")
let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")!
let requestsWriter = GRXWriter(value: request.data())
let call = GRPCCall(host: RemoteHost, path: method.HTTPPath, requestsWriter: requestsWriter)
let call = GRPCCall(host: RemoteHost, path: method.httpPath, requestsWriter: requestsWriter)!
call.requestHeaders.setObject("My value", forKey: "My-Header")
call.requestHeaders["My-Header"] = "My value";
call.startWithWriteable(GRXWriteable { response, error in
if let response = response as? NSData {
call.start(with: GRXWriteable { response, error in
if let response = response as? Data {
NSLog("3. Received response:\n\(try! RMTSimpleResponse(data: response))")
} else {
NSLog("3. Finished with error: \(error!)")
}
NSLog("3. Response headers: \(call.responseHeaders)")
NSLog("3. Response trailers: \(call.responseTrailers)")
NSLog("3. Response headers: \(call.responseHeaders!)")
NSLog("3. Response trailers: \(call.responseTrailers!)")
})
}
}

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
@ -535,7 +535,7 @@
635697BF1B14FC11007A7283 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0630;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
5E8A5DA31D3840B4000F8BC4 = {
@ -565,7 +565,7 @@
};
};
buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 8.0";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
@ -1151,8 +1151,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
@ -1205,6 +1207,7 @@
);
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Cronet;
@ -1362,6 +1365,7 @@
);
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@ -1376,6 +1380,7 @@
);
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@ -1393,13 +1398,16 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -1436,8 +1444,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

@ -165,6 +165,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@ -234,6 +235,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',

@ -34,8 +34,6 @@ import time
import unittest
import grpc
from grpc import _channel
from grpc import _server
from tests.unit.framework.common import test_constants
from tests.unit import _thread_pool
@ -78,7 +76,7 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_lonely_channel_connectivity(self):
callback = _Callback()
channel = _channel.Channel('localhost:12345', (), None)
channel = grpc.insecure_channel('localhost:12345')
channel.subscribe(callback.update, try_to_connect=False)
first_connectivities = callback.block_until_connectivities_satisfy(bool)
channel.subscribe(callback.update, try_to_connect=True)
@ -105,13 +103,13 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_immediately_connectable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
server = _server.Server(thread_pool, (), ())
server = grpc.server(thread_pool)
port = server.add_insecure_port('[::]:0')
server.start()
first_callback = _Callback()
second_callback = _Callback()
channel = _channel.Channel('localhost:{}'.format(port), (), None)
channel = grpc.insecure_channel('localhost:{}'.format(port))
channel.subscribe(first_callback.update, try_to_connect=False)
first_connectivities = first_callback.block_until_connectivities_satisfy(
bool)
@ -146,12 +144,12 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_reachable_then_unreachable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
server = _server.Server(thread_pool, (), ())
server = grpc.server(thread_pool)
port = server.add_insecure_port('[::]:0')
server.start()
callback = _Callback()
channel = _channel.Channel('localhost:{}'.format(port), (), None)
channel = grpc.insecure_channel('localhost:{}'.format(port))
channel.subscribe(callback.update, try_to_connect=True)
callback.block_until_connectivities_satisfy(_ready_in_connectivities)
# Now take down the server and confirm that channel readiness is repudiated.

@ -33,8 +33,6 @@ import threading
import unittest
import grpc
from grpc import _channel
from grpc import _server
from tests.unit.framework.common import test_constants
from tests.unit import _thread_pool
@ -79,7 +77,7 @@ class ChannelReadyFutureTest(unittest.TestCase):
def test_immediately_connectable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
server = _server.Server(thread_pool, (), ())
server = grpc.server(thread_pool)
port = server.add_insecure_port('[::]:0')
server.start()
channel = grpc.insecure_channel('localhost:{}'.format(port))

@ -114,7 +114,8 @@ void grpc_run_bad_client_test(
grpc_init();
/* Create endpoints */
grpc_resource_quota *resource_quota = grpc_resource_quota_create("bad_client_test");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("bad_client_test");
sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);

@ -118,6 +118,7 @@ static void test_create_channel_stack(void) {
int *channel_data;
int *call_data;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_mdstr *path = grpc_mdstr_from_string("/service/method");
arg.type = GRPC_ARG_INTEGER;
arg.key = "test_key";
@ -136,7 +137,7 @@ static void test_create_channel_stack(void) {
call_stack = gpr_malloc(channel_stack->call_stack_size);
grpc_error *error = grpc_call_stack_init(
&exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL,
&exec_ctx, channel_stack, 1, free_call, call_stack, NULL, NULL, path,
gpr_inf_future(GPR_CLOCK_MONOTONIC), call_stack);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(call_stack->count == 1);
@ -154,6 +155,7 @@ static void test_create_channel_stack(void) {
GRPC_CHANNEL_STACK_UNREF(&exec_ctx, channel_stack, "done");
grpc_exec_ctx_finish(&exec_ctx);
GRPC_MDSTR_UNREF(path);
}
int main(int argc, char **argv) {

@ -37,14 +37,16 @@
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/fake_resolver.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
static void *tag(intptr_t i) { return (void *)i; }
static void run_test(bool wait_for_ready) {
static void run_test(bool wait_for_ready, bool use_service_config) {
grpc_channel *chan;
grpc_call *call;
gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2);
@ -57,8 +59,10 @@ static void run_test(bool wait_for_ready) {
char *details = NULL;
size_t details_capacity = 0;
gpr_log(GPR_INFO, "TEST: wait_for_ready=%d", wait_for_ready);
gpr_log(GPR_INFO, "TEST: wait_for_ready=%d use_service_config=%d",
wait_for_ready, use_service_config);
grpc_fake_resolver_init();
grpc_init();
grpc_metadata_array_init(&trailing_metadata_recv);
@ -69,11 +73,21 @@ static void run_test(bool wait_for_ready) {
/* create a call, channel to a port which will refuse connection */
int port = grpc_pick_unused_port_or_die();
char *addr;
gpr_join_host_port(&addr, "localhost", port);
gpr_join_host_port(&addr, "127.0.0.1", port);
if (use_service_config) {
GPR_ASSERT(wait_for_ready);
char *server_uri;
gpr_asprintf(&server_uri,
"test:%s?method_name=/service/method&wait_for_ready=1", addr);
gpr_free(addr);
addr = server_uri;
}
gpr_log(GPR_INFO, "server: %s", addr);
chan = grpc_insecure_channel_create(addr, NULL, NULL);
call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
"/Foo", "nonexistant", deadline, NULL);
"/service/method", "nonexistant", deadline,
NULL);
gpr_free(addr);
@ -81,7 +95,9 @@ static void run_test(bool wait_for_ready) {
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = wait_for_ready ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0;
op->flags = (wait_for_ready && !use_service_config)
? GRPC_INITIAL_METADATA_WAIT_FOR_READY
: 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
@ -122,7 +138,8 @@ static void run_test(bool wait_for_ready) {
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
run_test(false);
run_test(true);
run_test(false /* wait_for_ready */, false /* use_service_config */);
run_test(true /* wait_for_ready */, false /* use_service_config */);
run_test(true /* wait_for_ready */, true /* use_service_config */);
return 0;
}

@ -43,6 +43,7 @@ typedef struct grpc_end2end_test_config grpc_end2end_test_config;
#define FEATURE_MASK_SUPPORTS_HOSTNAME_VERIFICATION 2
#define FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS 4
#define FEATURE_MASK_SUPPORTS_REQUEST_PROXYING 8
#define FEATURE_MASK_SUPPORTS_QUERY_ARGS 16
#define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check"
@ -59,7 +60,7 @@ struct grpc_end2end_test_config {
grpc_end2end_test_fixture (*create_fixture)(grpc_channel_args *client_args,
grpc_channel_args *server_args);
void (*init_client)(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args);
grpc_channel_args *client_args, const char *query_args);
void (*init_server)(grpc_end2end_test_fixture *f,
grpc_channel_args *server_args);
void (*tear_down_data)(grpc_end2end_test_fixture *f);

@ -42,6 +42,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_config/method_config.h"
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
@ -61,6 +62,7 @@ typedef struct {
char* target_name; // the path component of the uri passed in
grpc_lb_addresses* addresses;
char* lb_policy_name;
grpc_method_config_table* method_config_table;
// mutex guarding the rest of the state
gpr_mu mu;
@ -78,6 +80,7 @@ static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
gpr_free(r->target_name);
grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r->lb_policy_name);
grpc_method_config_table_unref(r->method_config_table);
gpr_free(r);
}
@ -97,10 +100,16 @@ static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx,
fake_resolver* r) {
if (r->next_completion != NULL && !r->published) {
r->published = true;
grpc_channel_args* lb_policy_args = NULL;
if (r->method_config_table != NULL) {
const grpc_arg arg =
grpc_method_config_table_create_channel_arg(r->method_config_table);
lb_policy_args = grpc_channel_args_copy_and_add(NULL /* src */, &arg, 1);
}
*r->target_result = grpc_resolver_result_create(
r->target_name,
grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */),
r->lb_policy_name, NULL /* lb_policy_args */);
r->lb_policy_name, lb_policy_args);
grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
@ -181,6 +190,45 @@ static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
grpc_lb_addresses_destroy(addresses, NULL /* user_data_destroy */);
return NULL;
}
// Construct method config table.
// We only support parameters for a single method.
grpc_method_config_table* method_config_table = NULL;
const char* method_name = grpc_uri_get_query_arg(args->uri, "method_name");
if (method_name != NULL) {
const char* wait_for_ready_str =
grpc_uri_get_query_arg(args->uri, "wait_for_ready");
// Anything other than "0" is interpreted as true.
bool wait_for_ready =
wait_for_ready_str != NULL && strcmp("0", wait_for_ready_str) != 0;
const char* timeout_str =
grpc_uri_get_query_arg(args->uri, "timeout_seconds");
gpr_timespec timeout = {timeout_str == NULL ? 0 : atoi(timeout_str), 0,
GPR_TIMESPAN};
const char* max_request_message_bytes_str =
grpc_uri_get_query_arg(args->uri, "max_request_message_bytes");
int32_t max_request_message_bytes =
max_request_message_bytes_str == NULL
? 0
: atoi(max_request_message_bytes_str);
const char* max_response_message_bytes_str =
grpc_uri_get_query_arg(args->uri, "max_response_message_bytes");
int32_t max_response_message_bytes =
max_response_message_bytes_str == NULL
? 0
: atoi(max_response_message_bytes_str);
grpc_method_config* method_config = grpc_method_config_create(
wait_for_ready_str == NULL ? NULL : &wait_for_ready,
timeout_str == NULL ? NULL : &timeout,
max_request_message_bytes_str == NULL ? NULL
: &max_request_message_bytes,
max_response_message_bytes_str == NULL ? NULL
: &max_response_message_bytes);
grpc_method_config_table_entry entry = {grpc_mdstr_from_string(method_name),
method_config};
method_config_table = grpc_method_config_table_create(1, &entry);
GRPC_MDSTR_UNREF(entry.method_name);
grpc_method_config_unref(method_config);
}
// Instantiate resolver.
fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
memset(r, 0, sizeof(*r));
@ -188,6 +236,7 @@ static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
r->addresses = addresses;
r->lb_policy_name =
gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy"));
r->method_config_table = method_config_table;
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &fake_resolver_vtable);
return &r->base;

@ -79,13 +79,15 @@ static grpc_arg make_census_enable_arg(void) {
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
grpc_arg arg = make_census_enable_arg();
client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1);
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
grpc_channel_args_destroy(client_args);
GPR_ASSERT(f->client);
grpc_channel_args_destroy(client_args);
}
void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,

@ -75,7 +75,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack_compression(
}
void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_compression_fixture_data *ffd = f->fixture_data;
if (ffd->client_args_compression != NULL) {
grpc_channel_args_destroy(ffd->client_args_compression);

@ -0,0 +1,128 @@
//
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "test/core/end2end/end2end_tests.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "src/core/ext/client_config/client_channel.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/http_server_filter.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/server.h"
#include "test/core/end2end/fake_resolver.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
typedef struct fullstack_fixture_data {
char *localaddr;
} fullstack_fixture_data;
static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
grpc_channel_args *client_args, grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
int port = grpc_pick_unused_port_or_die();
fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
memset(&f, 0, sizeof(f));
gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create(NULL);
return f;
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args,
const char *query_args) {
fullstack_fixture_data *ffd = f->fixture_data;
char *server_uri;
gpr_asprintf(&server_uri, "test:%s%s%s", ffd->localaddr,
(query_args == NULL ? "" : "?"),
(query_args == NULL ? "" : query_args));
gpr_log(GPR_INFO, "server_uri: %s", server_uri);
f->client = grpc_insecure_channel_create(server_uri, client_args, NULL);
GPR_ASSERT(f->client);
gpr_free(server_uri);
}
void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *server_args) {
fullstack_fixture_data *ffd = f->fixture_data;
if (f->server) {
grpc_server_destroy(f->server);
}
f->server = grpc_server_create(server_args, NULL);
grpc_server_register_completion_queue(f->server, f->cq, NULL);
GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
grpc_server_start(f->server);
}
void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
fullstack_fixture_data *ffd = f->fixture_data;
gpr_free(ffd->localaddr);
gpr_free(ffd);
}
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_QUERY_ARGS,
chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
};
int main(int argc, char **argv) {
size_t i;
grpc_test_init(argc, argv);
grpc_end2end_tests_pre_init();
grpc_fake_resolver_init();
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
grpc_end2end_tests(argc, argv, configs[i]);
}
grpc_shutdown();
return 0;
}

@ -105,7 +105,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
}
static void chttp2_init_client_fake_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_channel_credentials *fake_ts_creds =
grpc_fake_transport_security_credentials_create();
chttp2_init_client_secure_fullstack(f, client_args, fake_ts_creds);

@ -73,7 +73,10 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
}
static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
sp_fixture_data *sfd = f->fixture_data;

@ -71,7 +71,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
GPR_ASSERT(f->client);

@ -71,7 +71,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
GPR_ASSERT(f->client);

@ -70,7 +70,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
GPR_ASSERT(f->client);

@ -75,7 +75,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
char *proxy_uri;
gpr_asprintf(&proxy_uri, "http://%s",

@ -73,7 +73,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_load_reporting(
}
void chttp2_init_client_load_reporting(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
load_reporting_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
GPR_ASSERT(f->client);

@ -150,7 +150,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
}
static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_channel_credentials *ssl_creds =
grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
grpc_call_credentials *oauth2_creds =

@ -85,7 +85,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(
grpc_end2end_proxy_get_client_target(ffd->proxy), client_args, NULL);

@ -99,7 +99,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
}
static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_endpoint_pair *sfd = f->fixture_data;
grpc_transport *transport;

@ -98,7 +98,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
}
static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_endpoint_pair *sfd = f->fixture_data;
grpc_transport *transport;

@ -98,7 +98,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
}
static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_endpoint_pair *sfd = f->fixture_data;
grpc_transport *transport;

@ -109,7 +109,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
}
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_channel_credentials *ssl_creds =
grpc_ssl_credentials_create(NULL, NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,

@ -154,39 +154,41 @@ SERVER_INIT(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY)
typedef enum { NONE, SELF_SIGNED, SIGNED, BAD_CERT_PAIR } certtype;
#define CLIENT_INIT(cert_type) \
static void CLIENT_INIT_NAME(cert_type)(grpc_end2end_test_fixture * f, \
grpc_channel_args * client_args) { \
grpc_channel_credentials *ssl_creds = NULL; \
grpc_ssl_pem_key_cert_pair self_signed_client_key_cert_pair = { \
test_self_signed_client_key, test_self_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { \
test_signed_client_key, test_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair bad_client_key_cert_pair = { \
test_self_signed_client_key, test_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair *key_cert_pair = NULL; \
switch (cert_type) { \
case SELF_SIGNED: \
key_cert_pair = &self_signed_client_key_cert_pair; \
break; \
case SIGNED: \
key_cert_pair = &signed_client_key_cert_pair; \
break; \
case BAD_CERT_PAIR: \
key_cert_pair = &bad_client_key_cert_pair; \
break; \
default: \
break; \
} \
ssl_creds = \
grpc_ssl_credentials_create(test_root_cert, key_cert_pair, NULL); \
grpc_arg ssl_name_override = {GRPC_ARG_STRING, \
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, \
{"foo.test.google.fr"}}; \
grpc_channel_args *new_client_args = \
grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1); \
chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds); \
grpc_channel_args_destroy(new_client_args); \
#define CLIENT_INIT(cert_type) \
static void CLIENT_INIT_NAME(cert_type)(grpc_end2end_test_fixture * f, \
grpc_channel_args * client_args, \
const char *query_args) { \
GPR_ASSERT(query_args == NULL); \
grpc_channel_credentials *ssl_creds = NULL; \
grpc_ssl_pem_key_cert_pair self_signed_client_key_cert_pair = { \
test_self_signed_client_key, test_self_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { \
test_signed_client_key, test_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair bad_client_key_cert_pair = { \
test_self_signed_client_key, test_signed_client_cert}; \
grpc_ssl_pem_key_cert_pair *key_cert_pair = NULL; \
switch (cert_type) { \
case SELF_SIGNED: \
key_cert_pair = &self_signed_client_key_cert_pair; \
break; \
case SIGNED: \
key_cert_pair = &signed_client_key_cert_pair; \
break; \
case BAD_CERT_PAIR: \
key_cert_pair = &bad_client_key_cert_pair; \
break; \
default: \
break; \
} \
ssl_creds = \
grpc_ssl_credentials_create(test_root_cert, key_cert_pair, NULL); \
grpc_arg ssl_name_override = {GRPC_ARG_STRING, \
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, \
{"foo.test.google.fr"}}; \
grpc_channel_args *new_client_args = \
grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1); \
chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds); \
grpc_channel_args_destroy(new_client_args); \
}
CLIENT_INIT(NONE)
@ -265,7 +267,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
return f;
}

@ -142,7 +142,9 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
}
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
grpc_channel_credentials *ssl_creds =
grpc_ssl_credentials_create(NULL, NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,

@ -76,7 +76,9 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args,
const char *query_args) {
GPR_ASSERT(query_args == NULL);
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
}

@ -58,7 +58,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_init();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_resource_quota *resource_quota = grpc_resource_quota_create("client_fuzzer");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("client_fuzzer");
grpc_endpoint *mock_endpoint =
grpc_mock_endpoint_create(discard_write, resource_quota);
grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);

@ -56,7 +56,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_init();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_resource_quota *resource_quota = grpc_resource_quota_create("server_fuzzer");
grpc_resource_quota *resource_quota =
grpc_resource_quota_create("server_fuzzer");
grpc_endpoint *mock_endpoint =
grpc_mock_endpoint_create(discard_write, resource_quota);
grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);

@ -55,6 +55,7 @@ END2END_FIXTURES = {
'h2_census': default_unsecure_fixture_options,
'h2_load_reporting': default_unsecure_fixture_options,
'h2_fakesec': default_secure_fixture_options._replace(ci_mac=False),
'h2_fake_resolver': default_unsecure_fixture_options,
'h2_fd': fd_unsecure_fixture_options,
'h2_full': default_unsecure_fixture_options,
'h2_full+pipe': default_unsecure_fixture_options._replace(
@ -250,7 +251,7 @@ def main():
{
'name': '%s_test' % f,
'args': [t],
'exclude_configs': [],
'exclude_configs': END2END_FIXTURES[f].exclude_configs,
'platforms': END2END_FIXTURES[f].platforms,
'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac else without(

@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
config.init_server(&f, server_args);
return f;
}

@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
return f;
}

@ -61,7 +61,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(NULL, NULL);
config.init_client(&f, NULL);
config.init_client(&f, NULL, NULL);
if (fail_server_auth_check) {
grpc_arg fail_auth_arg = {
GRPC_ARG_STRING, FAIL_AUTH_CHECK_SERVER_ARG_NAME, {NULL}};

@ -49,12 +49,13 @@ static void *tag(intptr_t t) { return (void *)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char *test_name,
grpc_channel_args *client_args,
grpc_channel_args *server_args) {
grpc_channel_args *server_args,
const char *query_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, query_args);
return f;
}
@ -98,15 +99,15 @@ static void end_test(grpc_end2end_test_fixture *f) {
/* Cancel after accept, no payload */
static void test_cancel_after_accept(grpc_end2end_test_config config,
cancellation_mode mode) {
cancellation_mode mode,
bool use_service_config) {
grpc_op ops[6];
grpc_op *op;
grpc_call *c;
grpc_call *s;
grpc_end2end_test_fixture f =
begin_test(config, "cancel_after_accept", NULL, NULL);
gpr_timespec deadline = five_seconds_time();
cq_verifier *cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = use_service_config
? gpr_inf_future(GPR_CLOCK_MONOTONIC)
: five_seconds_time();
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
@ -125,8 +126,19 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
int was_cancelled = 2;
const char *query_args = NULL;
if (use_service_config) {
query_args =
"method_name=/service/method"
"&timeout_seconds=5";
}
grpc_end2end_test_fixture f =
begin_test(config, "cancel_after_accept", NULL, NULL, query_args);
cq_verifier *cqv = cq_verifier_create(f.cq);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline, NULL);
"/service/method", "foo.test.google.fr",
deadline, NULL);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
@ -230,7 +242,18 @@ void cancel_after_accept(grpc_end2end_test_config config) {
unsigned i;
for (i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); i++) {
test_cancel_after_accept(config, cancellation_modes[i]);
test_cancel_after_accept(config, cancellation_modes[i],
false /* use_service_config */);
}
if (config.feature_mask & FEATURE_MASK_SUPPORTS_QUERY_ARGS) {
for (i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); i++) {
if (cancellation_modes[i].expect_status ==
GRPC_STATUS_DEADLINE_EXCEEDED) {
test_cancel_after_accept(config, cancellation_modes[i],
true /* use_service_config */);
}
}
}
}

@ -54,7 +54,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
return f;
}

@ -55,7 +55,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
gpr_log(GPR_INFO, "%s/%s/%s", test_name, config.name, mode.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
return f;
}

@ -53,7 +53,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
config.init_client(&f, client_args, NULL);
return f;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save