Merge pull request #2 from ctiller/complain-with-both-passion-and-meaning

Fixes for sending status from the server
pull/2492/head
jboeuf 10 years ago
commit 0945420b34
  1. 34
      BUILD
  2. 2
      INSTALL
  3. 4363
      Makefile
  4. 90
      build.json
  5. 1
      composer.json
  6. 77
      doc/connection-backoff-interop-test-description.md
  7. 57
      doc/interop-test-descriptions.md
  8. 25
      gRPC.podspec
  9. 16
      include/grpc++/channel_arguments.h
  10. 15
      include/grpc++/client_context.h
  11. 3
      include/grpc++/completion_queue.h
  12. 2
      include/grpc++/config.h
  13. 6
      include/grpc++/credentials.h
  14. 82
      include/grpc++/dynamic_thread_pool.h
  15. 8
      include/grpc++/fixed_size_thread_pool.h
  16. 2
      include/grpc++/impl/sync_no_cxx11.h
  17. 24
      include/grpc++/server_context.h
  18. 3
      include/grpc++/server_credentials.h
  19. 2
      include/grpc++/thread_pool_interface.h
  20. 43
      include/grpc/census.h
  21. 31
      include/grpc/compression.h
  22. 445
      include/grpc/grpc.h
  23. 21
      include/grpc/grpc_security.h
  24. 6
      include/grpc/support/host_port.h
  25. 12
      include/grpc/support/port_platform.h
  26. 45
      include/grpc/support/time.h
  27. 20
      include/grpc/support/useful.h
  28. 26
      src/compiler/csharp_generator.cc
  29. 5
      src/compiler/objective_c_generator.cc
  30. 5
      src/compiler/objective_c_plugin.cc
  31. 2
      src/compiler/python_generator.cc
  32. 5
      src/core/census/grpc_context.c
  33. 19
      src/core/census/initialize.c
  34. 21
      src/core/census/record_stat.c
  35. 34
      src/core/census/rpc_stat_id.h
  36. 29
      src/core/channel/channel_args.c
  37. 13
      src/core/channel/channel_args.h
  38. 5
      src/core/channel/channel_stack.c
  39. 5
      src/core/channel/channel_stack.h
  40. 204
      src/core/channel/client_channel.c
  41. 14
      src/core/channel/client_channel.h
  42. 328
      src/core/channel/compress_filter.c
  43. 65
      src/core/channel/compress_filter.h
  44. 6
      src/core/channel/connected_channel.c
  45. 77
      src/core/channel/http_client_filter.c
  46. 9
      src/core/channel/http_server_filter.c
  47. 1
      src/core/channel/noop_filter.c
  48. 34
      src/core/client_config/README.md
  49. 192
      src/core/client_config/lb_policies/pick_first.c
  50. 2
      src/core/client_config/lb_policies/pick_first.h
  51. 15
      src/core/client_config/lb_policy.c
  52. 12
      src/core/client_config/lb_policy.h
  53. 299
      src/core/client_config/resolvers/sockaddr_resolver.c
  54. 6
      src/core/client_config/resolvers/sockaddr_resolver.h
  55. 195
      src/core/client_config/resolvers/unix_resolver_posix.c
  56. 131
      src/core/client_config/subchannel.c
  57. 3
      src/core/client_config/subchannel.h
  58. 46
      src/core/compression/algorithm.c
  59. 14
      src/core/iomgr/alarm.c
  60. 8
      src/core/iomgr/endpoint.c
  61. 6
      src/core/iomgr/endpoint.h
  62. 8
      src/core/iomgr/endpoint_pair_posix.c
  63. 6
      src/core/iomgr/endpoint_pair_windows.c
  64. 2
      src/core/iomgr/iocp_windows.c
  65. 27
      src/core/iomgr/iomgr.c
  66. 17
      src/core/iomgr/pollset_multipoller_with_epoll.c
  67. 15
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  68. 53
      src/core/iomgr/pollset_posix.c
  69. 6
      src/core/iomgr/pollset_posix.h
  70. 2
      src/core/iomgr/pollset_set.h
  71. 12
      src/core/iomgr/pollset_set_posix.c
  72. 2
      src/core/iomgr/pollset_windows.c
  73. 33
      src/core/iomgr/sockaddr_utils.c
  74. 2
      src/core/iomgr/sockaddr_utils.h
  75. 47
      src/core/iomgr/tcp_client_posix.c
  76. 7
      src/core/iomgr/tcp_client_windows.c
  77. 35
      src/core/iomgr/tcp_posix.c
  78. 3
      src/core/iomgr/tcp_posix.h
  79. 7
      src/core/iomgr/tcp_server_posix.c
  80. 53
      src/core/iomgr/tcp_server_windows.c
  81. 27
      src/core/iomgr/tcp_windows.c
  82. 2
      src/core/iomgr/tcp_windows.h
  83. 22
      src/core/security/client_auth_filter.c
  84. 46
      src/core/security/credentials.c
  85. 13
      src/core/security/credentials.h
  86. 9
      src/core/security/google_default_credentials.c
  87. 2
      src/core/security/json_token.c
  88. 27
      src/core/security/jwt_verifier.c
  89. 17
      src/core/security/secure_endpoint.c
  90. 7
      src/core/security/security_connector.c
  91. 1
      src/core/security/security_connector.h
  92. 18
      src/core/security/server_auth_filter.c
  93. 5
      src/core/support/cancellable.c
  94. 10
      src/core/support/host_port.c
  95. 43
      src/core/support/stack_lockfree.c
  96. 3
      src/core/support/stack_lockfree.h
  97. 62
      src/core/support/string.c
  98. 11
      src/core/support/string.h
  99. 3
      src/core/support/sync_posix.c
  100. 4
      src/core/support/sync_win32.c
  101. Some files were not shown because too many files have changed in this diff Show More

34
BUILD

@ -149,11 +149,11 @@ cc_library(
"src/core/tsi/ssl_transport_security.h",
"src/core/tsi/transport_security.h",
"src/core/tsi/transport_security_interface.h",
"src/core/census/grpc_context.h",
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/client_channel.h",
"src/core/channel/compress_filter.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
@ -167,7 +167,7 @@ cc_library(
"src/core/client_config/resolver_factory.h",
"src/core/client_config/resolver_registry.h",
"src/core/client_config/resolvers/dns_resolver.h",
"src/core/client_config/resolvers/unix_resolver_posix.h",
"src/core/client_config/resolvers/sockaddr_resolver.h",
"src/core/client_config/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
@ -245,6 +245,7 @@ cc_library(
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/context.h",
"src/core/census/rpc_stat_id.h",
"src/core/httpcli/format_request.c",
"src/core/httpcli/httpcli.c",
"src/core/httpcli/httpcli_security_connector.c",
@ -273,6 +274,7 @@ cc_library(
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/client_channel.c",
"src/core/channel/compress_filter.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
@ -285,7 +287,7 @@ cc_library(
"src/core/client_config/resolver_factory.c",
"src/core/client_config/resolver_registry.c",
"src/core/client_config/resolvers/dns_resolver.c",
"src/core/client_config/resolvers/unix_resolver_posix.c",
"src/core/client_config/resolvers/sockaddr_resolver.c",
"src/core/client_config/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
@ -340,6 +342,7 @@ cc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -379,6 +382,7 @@ cc_library(
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
"src/core/census/initialize.c",
"src/core/census/record_stat.c",
],
hdrs = [
"include/grpc/grpc_security.h",
@ -403,11 +407,11 @@ cc_library(
cc_library(
name = "grpc_unsecure",
srcs = [
"src/core/census/grpc_context.h",
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/client_channel.h",
"src/core/channel/compress_filter.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
@ -421,7 +425,7 @@ cc_library(
"src/core/client_config/resolver_factory.h",
"src/core/client_config/resolver_registry.h",
"src/core/client_config/resolvers/dns_resolver.h",
"src/core/client_config/resolvers/unix_resolver_posix.h",
"src/core/client_config/resolvers/sockaddr_resolver.h",
"src/core/client_config/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
@ -499,11 +503,13 @@ cc_library(
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/context.h",
"src/core/census/rpc_stat_id.h",
"src/core/surface/init_unsecure.c",
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/client_channel.c",
"src/core/channel/compress_filter.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
@ -516,7 +522,7 @@ cc_library(
"src/core/client_config/resolver_factory.c",
"src/core/client_config/resolver_registry.c",
"src/core/client_config/resolvers/dns_resolver.c",
"src/core/client_config/resolvers/unix_resolver_posix.c",
"src/core/client_config/resolvers/sockaddr_resolver.c",
"src/core/client_config/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
@ -571,6 +577,7 @@ cc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -610,6 +617,7 @@ cc_library(
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
"src/core/census/initialize.c",
"src/core/census/record_stat.c",
],
hdrs = [
"include/grpc/byte_buffer.h",
@ -657,6 +665,7 @@ cc_library(
"src/cpp/proto/proto_utils.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc",
"src/cpp/server/fixed_size_thread_pool.cc",
"src/cpp/server/insecure_server_credentials.cc",
"src/cpp/server/server.cc",
@ -682,6 +691,7 @@ cc_library(
"include/grpc++/config_protobuf.h",
"include/grpc++/create_channel.h",
"include/grpc++/credentials.h",
"include/grpc++/dynamic_thread_pool.h",
"include/grpc++/fixed_size_thread_pool.h",
"include/grpc++/generic_stub.h",
"include/grpc++/impl/call.h",
@ -742,6 +752,7 @@ cc_library(
"src/cpp/proto/proto_utils.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc",
"src/cpp/server/fixed_size_thread_pool.cc",
"src/cpp/server/insecure_server_credentials.cc",
"src/cpp/server/server.cc",
@ -767,6 +778,7 @@ cc_library(
"include/grpc++/config_protobuf.h",
"include/grpc++/create_channel.h",
"include/grpc++/credentials.h",
"include/grpc++/dynamic_thread_pool.h",
"include/grpc++/fixed_size_thread_pool.h",
"include/grpc++/generic_stub.h",
"include/grpc++/impl/call.h",
@ -981,6 +993,7 @@ objc_library(
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/client_channel.c",
"src/core/channel/compress_filter.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
@ -993,7 +1006,7 @@ objc_library(
"src/core/client_config/resolver_factory.c",
"src/core/client_config/resolver_registry.c",
"src/core/client_config/resolvers/dns_resolver.c",
"src/core/client_config/resolvers/unix_resolver_posix.c",
"src/core/client_config/resolvers/sockaddr_resolver.c",
"src/core/client_config/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
@ -1048,6 +1061,7 @@ objc_library(
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -1087,6 +1101,7 @@ objc_library(
"src/core/transport/transport_op_string.c",
"src/core/census/context.c",
"src/core/census/initialize.c",
"src/core/census/record_stat.c",
],
hdrs = [
"include/grpc/grpc_security.h",
@ -1113,11 +1128,11 @@ objc_library(
"src/core/tsi/ssl_transport_security.h",
"src/core/tsi/transport_security.h",
"src/core/tsi/transport_security_interface.h",
"src/core/census/grpc_context.h",
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/client_channel.h",
"src/core/channel/compress_filter.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
@ -1131,7 +1146,7 @@ objc_library(
"src/core/client_config/resolver_factory.h",
"src/core/client_config/resolver_registry.h",
"src/core/client_config/resolvers/dns_resolver.h",
"src/core/client_config/resolvers/unix_resolver_posix.h",
"src/core/client_config/resolvers/sockaddr_resolver.h",
"src/core/client_config/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
@ -1209,6 +1224,7 @@ objc_library(
"src/core/transport/transport.h",
"src/core/transport/transport_impl.h",
"src/core/census/context.h",
"src/core/census/rpc_stat_id.h",
],
includes = [
"include",

@ -117,7 +117,7 @@ most Mac installations. Do the "git submodule" command listed above.
Then execute the following for all the needed build dependencies
$ sudo /opt/local/bin/port install autoconf automake libtool gflags cmake
$ mkdir ~/gtest
$ mkdir ~/gtest-svn
$ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
$ mkdir mybuild
$ cd mybuild

4363
Makefile

File diff suppressed because one or more lines are too long

@ -18,11 +18,13 @@
"include/grpc/census.h"
],
"headers": [
"src/core/census/context.h"
"src/core/census/context.h",
"src/core/census/rpc_stat_id.h"
],
"src": [
"src/core/census/context.c",
"src/core/census/initialize.c"
"src/core/census/initialize.c",
"src/core/census/record_stat.c"
]
},
{
@ -41,6 +43,7 @@
"include/grpc++/config_protobuf.h",
"include/grpc++/create_channel.h",
"include/grpc++/credentials.h",
"include/grpc++/dynamic_thread_pool.h",
"include/grpc++/fixed_size_thread_pool.h",
"include/grpc++/generic_stub.h",
"include/grpc++/impl/call.h",
@ -88,6 +91,7 @@
"src/cpp/proto/proto_utils.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc",
"src/cpp/server/fixed_size_thread_pool.cc",
"src/cpp/server/insecure_server_credentials.cc",
"src/cpp/server/server.cc",
@ -110,11 +114,11 @@
"include/grpc/status.h"
],
"headers": [
"src/core/census/grpc_context.h",
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/client_channel.h",
"src/core/channel/compress_filter.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
@ -128,7 +132,7 @@
"src/core/client_config/resolver_factory.h",
"src/core/client_config/resolver_registry.h",
"src/core/client_config/resolvers/dns_resolver.h",
"src/core/client_config/resolvers/unix_resolver_posix.h",
"src/core/client_config/resolvers/sockaddr_resolver.h",
"src/core/client_config/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
@ -211,6 +215,7 @@
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/client_channel.c",
"src/core/channel/compress_filter.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
@ -223,7 +228,7 @@
"src/core/client_config/resolver_factory.c",
"src/core/client_config/resolver_registry.c",
"src/core/client_config/resolvers/dns_resolver.c",
"src/core/client_config/resolvers/unix_resolver_posix.c",
"src/core/client_config/resolvers/sockaddr_resolver.c",
"src/core/client_config/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
@ -278,6 +283,7 @@
"src/core/surface/call_details.c",
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_connectivity.c",
"src/core/surface/channel_create.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
@ -322,6 +328,7 @@
"headers": [
"test/core/end2end/cq_verifier.h",
"test/core/iomgr/endpoint_tests.h",
"test/core/security/oauth2_utils.h",
"test/core/util/grpc_profiler.h",
"test/core/util/parse_hexstring.h",
"test/core/util/port.h",
@ -330,6 +337,7 @@
"src": [
"test/core/end2end/cq_verifier.c",
"test/core/iomgr/endpoint_tests.c",
"test/core/security/oauth2_utils.c",
"test/core/util/grpc_profiler.c",
"test/core/util/parse_hexstring.c",
"test/core/util/port_posix.c",
@ -497,6 +505,7 @@
"gpr"
],
"baselib": true,
"dll": "yes",
"filegroups": [
"grpc_base",
"census"
@ -552,6 +561,7 @@
"gpr"
],
"baselib": true,
"dll": "yes",
"filegroups": [
"grpc_base",
"census"
@ -581,6 +591,7 @@
"grpc"
],
"baselib": true,
"dll": "yes",
"filegroups": [
"grpc++_base"
],
@ -605,7 +616,6 @@
"headers": [
"test/cpp/util/cli_call.h",
"test/cpp/util/create_test_channel.h",
"test/cpp/util/fake_credentials.h",
"test/cpp/util/subprocess.h"
],
"src": [
@ -614,7 +624,6 @@
"test/cpp/util/echo_duplicate.proto",
"test/cpp/util/cli_call.cc",
"test/cpp/util/create_test_channel.cc",
"test/cpp/util/fake_credentials.cc",
"test/cpp/util/subprocess.cc"
],
"deps": [
@ -634,6 +643,7 @@
"grpc_unsecure"
],
"baselib": true,
"dll": "yes",
"filegroups": [
"grpc++_base"
],
@ -822,6 +832,7 @@
"gpr",
"grpc"
],
"dll": "only",
"vs_project_guid": "{D64C6D63-4458-4A88-AB38-35678384A7E4}"
}
],
@ -1787,20 +1798,6 @@
"gpr"
]
},
{
"name": "time_test",
"build": "test",
"language": "c",
"src": [
"test/core/support/time_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "timeout_encoding_test",
"build": "test",
@ -1902,6 +1899,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -1919,6 +1919,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -1977,6 +1980,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2054,6 +2060,21 @@
"gpr"
]
},
{
"name": "dynamic_thread_pool_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/server/dynamic_thread_pool_test.cc"
],
"deps": [
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "end2end_test",
"build": "test",
@ -2200,6 +2221,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2218,6 +2242,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2232,6 +2259,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2336,6 +2366,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2354,6 +2387,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2372,6 +2408,9 @@
"gpr_test_util",
"gpr",
"grpc++_test_config"
],
"platforms": [
"posix"
]
},
{
@ -2423,6 +2462,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2472,6 +2514,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{
@ -2489,6 +2534,9 @@
"grpc",
"gpr_test_util",
"gpr"
],
"platforms": [
"posix"
]
},
{

@ -2,6 +2,7 @@
"name": "grpc/grpc",
"type": "library",
"description": "gRPC library for PHP",
"version": "0.5.1",
"keywords": ["rpc"],
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",

@ -0,0 +1,77 @@
Connection Backoff Interop Test Descriptions
===============================================
This test is to verify the client is reconnecting the server with correct
backoffs as specified in
[the spec](http://github.com/grpc/grpc/blob/master/doc/connection-backoff.md).
The test server has a port (control_port) running a rpc service for controlling
the server and another port (retry_port) to close any incoming tcp connections.
The test has the following flow:
1. The server starts listening on control_port.
2. The client calls Start rpc on server control_port.
3. The server starts listening on retry_port.
4. The client connects to server retry_port and retries with backoff for 540s,
which translates to about 13 retries.
5. The client calls Stop rpc on server control port.
6. The client checks the response to see whether the server thinks the backoffs
are conforming the spec or do its own check on the backoffs in the response.
Client and server use
[test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto).
Each language should implement its own client. The C++ server is shared among
languages.
Client
------
Clients should accept these arguments:
* --server_control_port=PORT
* The server port to connect to for rpc. For example, "8080"
* --server_retry_port=PORT
* The server port to connect to for testing backoffs. For example, "8081"
The client must connect to the control port without TLS. The client should
either assert on the server returned backoff status or check the returned
backoffs on its own.
Procedure of client:
1. Calls Start on server control port with a large deadline or no deadline,
waits for its finish and checks it succeeded.
2. Initiates a channel connection to server retry port, which should perform
reconnections with proper backoffs. A convienent way to achieve this is to
call Start with a deadline of 540s. The rpc should fail with deadline exceeded.
3. Calls Stop on server control port and checks it succeeded.
4. Checks the response to see whether the server thinks the backoffs passed the
test.
5. Optionally, the client can do its own check on the returned backoffs.
Server
------
A C++ server can be used for the test. Other languages do NOT need to implement
a server. To minimize the network delay, the server binary should run on the
same machine or on a nearby machine (in terms of network distance) with the
client binary.
A server implements the ReconnectService to its state. It also opens a
tcp server on the retry_port, which just shuts down all incoming tcp
connections to simulate connection failures. The server will keep a record of
all the reconnection timestamps and return the connection backoffs in the
response in milliseconds. The server also checks the backoffs to see whether
they conform the spec and returns whether the client passes the test.
If the server receives a Start call when another client is being tested, it
finishes the call when the other client is done. If some other host connects
to the server retry_port when a client is being tested, the server will log an
error but likely would think the client fails the test.
The server accepts these arguments:
* --control_port=PORT
* The port to listen on for control rpcs. For example, "8080"
* --retry_port=PORT
* The tcp server port. For example, "8081"

@ -483,18 +483,17 @@ library to obtain the authorization token
* received SimpleResponse.oauth_scope is in `--oauth_scope`
### Metadata (TODO: fix name)
Status: Not yet implementable
### custom_metadata
This test verifies that custom metadata in either binary or ascii format can be
sent in header and trailer.
sent as initial-metadata by the client and as both initial- and trailing-metadata
by the server.
Server features:
* [UnaryCall][]
* [FullDuplexCall][]
* [Compressable Payload][]
* Ability to receive custom metadata from client in header and send custom data
back to client in both header and trailer. (TODO: this is not defined)
* [Echo Metadata][]
Procedure:
1. While sending custom metadata (ascii + binary) in the header, client calls
@ -509,21 +508,29 @@ Procedure:
}
}
```
The client attaches custom metadata with the following keys and values:
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts:
* call was successful
* custom metadata is echoed back in the response header.
* custom metadata is echoed back in the response trailer.
* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata.
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata.
### status_code_and_message
Status: Not yet implementable
### status_code_and_message
This test verifies unary calls succeed in sending messages, and propagates back
status code and message sent along with the messages.
Server features:
* [UnaryCall][]
* [FullDuplexCall][]
* [Echo Status][]
Procedure:
1. Client calls UnaryCall with:
@ -536,6 +543,8 @@ Procedure:
}
}
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts:
* received status code is the same with sent code
@ -543,21 +552,15 @@ Asserts:
### unimplemented_method
Status: Not yet implementable
Status: Ready for implementation. Blocking beta.
This test verifies calling unimplemented RPC method returns unimplemented
status.
This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code.
Procedure:
* Client calls UnimplementedCall with:
* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`):
```
{
response_type: COMPRESSABLE
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
@ -767,6 +770,22 @@ When the client requests COMPRESSABLE payload, the response includes a payload
of the size requested containing all zeros and the payload type is
COMPRESSABLE.
### Echo Status
[Echo Status]: #echo-status
When the client sends a response_status in the request payload, the server closes
the stream with the status code and messsage contained within said response_status.
The server will not process any further messages on the stream sent by the client.
This can be used by clients to verify correct handling of different status codes and
associated status messages end-to-end.
### Echo Metadata
[Echo Metadata]: #echo-metadata
When the client sends metadata with the key `"x-grpc-test-echo-initial"` with its
request, the server sends back exactly this key and the corresponding value back to
the client as part of initial metadata. When the client sends metadata with the key
`"x-grpc-test-echo-trailing-bin"` with its request, the server sends back exactly this
key and the corresponding value back to the client as trailing metadata.
### Observe ResponseParameters.interval_us
[Observe ResponseParameters.interval_us]: #observe-responseparametersinterval_us

@ -36,14 +36,14 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
s.version = '0.6.0'
s.version = '0.7.0'
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io'
s.license = 'New BSD'
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
# s.source = { :git => 'https://github.com/grpc/grpc.git',
# :tag => 'release-0_9_1-objectivec-0.5.1' }
# :tag => 'release-0_10_0-objectivec-0.6.0' }
s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'
@ -151,11 +151,11 @@ Pod::Spec.new do |s|
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_interface.h',
'src/core/census/grpc_context.h',
'src/core/channel/census_filter.h',
'src/core/channel/channel_args.h',
'src/core/channel/channel_stack.h',
'src/core/channel/client_channel.h',
'src/core/channel/compress_filter.h',
'src/core/channel/connected_channel.h',
'src/core/channel/context.h',
'src/core/channel/http_client_filter.h',
@ -169,7 +169,7 @@ Pod::Spec.new do |s|
'src/core/client_config/resolver_factory.h',
'src/core/client_config/resolver_registry.h',
'src/core/client_config/resolvers/dns_resolver.h',
'src/core/client_config/resolvers/unix_resolver_posix.h',
'src/core/client_config/resolvers/sockaddr_resolver.h',
'src/core/client_config/subchannel.h',
'src/core/client_config/subchannel_factory.h',
'src/core/client_config/uri_parser.h',
@ -247,6 +247,7 @@ Pod::Spec.new do |s|
'src/core/transport/transport.h',
'src/core/transport/transport_impl.h',
'src/core/census/context.h',
'src/core/census/rpc_stat_id.h',
'grpc/grpc_security.h',
'grpc/byte_buffer.h',
'grpc/byte_buffer_reader.h',
@ -282,6 +283,7 @@ Pod::Spec.new do |s|
'src/core/channel/channel_args.c',
'src/core/channel/channel_stack.c',
'src/core/channel/client_channel.c',
'src/core/channel/compress_filter.c',
'src/core/channel/connected_channel.c',
'src/core/channel/http_client_filter.c',
'src/core/channel/http_server_filter.c',
@ -294,7 +296,7 @@ Pod::Spec.new do |s|
'src/core/client_config/resolver_factory.c',
'src/core/client_config/resolver_registry.c',
'src/core/client_config/resolvers/dns_resolver.c',
'src/core/client_config/resolvers/unix_resolver_posix.c',
'src/core/client_config/resolvers/sockaddr_resolver.c',
'src/core/client_config/subchannel.c',
'src/core/client_config/subchannel_factory.c',
'src/core/client_config/uri_parser.c',
@ -349,6 +351,7 @@ Pod::Spec.new do |s|
'src/core/surface/call_details.c',
'src/core/surface/call_log_batch.c',
'src/core/surface/channel.c',
'src/core/surface/channel_connectivity.c',
'src/core/surface/channel_create.c',
'src/core/surface/completion_queue.c',
'src/core/surface/event_string.c',
@ -387,7 +390,8 @@ Pod::Spec.new do |s|
'src/core/transport/transport.c',
'src/core/transport/transport_op_string.c',
'src/core/census/context.c',
'src/core/census/initialize.c'
'src/core/census/initialize.c',
'src/core/census/record_stat.c'
ss.private_header_files = 'src/core/support/env.h',
'src/core/support/file.h',
@ -413,11 +417,11 @@ Pod::Spec.new do |s|
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_interface.h',
'src/core/census/grpc_context.h',
'src/core/channel/census_filter.h',
'src/core/channel/channel_args.h',
'src/core/channel/channel_stack.h',
'src/core/channel/client_channel.h',
'src/core/channel/compress_filter.h',
'src/core/channel/connected_channel.h',
'src/core/channel/context.h',
'src/core/channel/http_client_filter.h',
@ -431,7 +435,7 @@ Pod::Spec.new do |s|
'src/core/client_config/resolver_factory.h',
'src/core/client_config/resolver_registry.h',
'src/core/client_config/resolvers/dns_resolver.h',
'src/core/client_config/resolvers/unix_resolver_posix.h',
'src/core/client_config/resolvers/sockaddr_resolver.h',
'src/core/client_config/subchannel.h',
'src/core/client_config/subchannel_factory.h',
'src/core/client_config/uri_parser.h',
@ -508,13 +512,16 @@ Pod::Spec.new do |s|
'src/core/transport/stream_op.h',
'src/core/transport/transport.h',
'src/core/transport/transport_impl.h',
'src/core/census/context.h'
'src/core/census/context.h',
'src/core/census/rpc_stat_id.h'
ss.header_mappings_dir = '.'
ss.requires_arc = false
ss.libraries = 'z'
ss.dependency 'OpenSSL', '~> 1.0.200'
# ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
end
# This is a workaround for Cocoapods Issue #1437.

@ -54,13 +54,21 @@ class ChannelArguments {
ChannelArguments() {}
~ChannelArguments() {}
ChannelArguments(const ChannelArguments& other);
ChannelArguments& operator=(ChannelArguments other) {
Swap(other);
return *this;
}
void Swap(ChannelArguments& other);
// grpc specific channel argument setters
// Set target name override for SSL host name checking.
void SetSslTargetNameOverride(const grpc::string& name);
// TODO(yangg) add flow control options
// Set the compression level for the channel.
void SetCompressionLevel(grpc_compression_level level);
// Set the compression algorithm for the channel.
void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
// Generic channel argument setters. Only for advanced use cases.
void SetInt(const grpc::string& key, int value);
@ -73,10 +81,6 @@ class ChannelArguments {
friend class SecureCredentials;
friend class testing::ChannelArgumentsTest;
// TODO(yangg) implement copy and assign
ChannelArguments(const ChannelArguments&);
ChannelArguments& operator=(const ChannelArguments&);
// Returns empty string when it is not set.
grpc::string GetSslTargetNameOverride() const;

@ -38,6 +38,7 @@
#include <memory>
#include <string>
#include <grpc/compression.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc++/auth_context.h>
@ -109,11 +110,17 @@ class ClientContext {
creds_ = creds;
}
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
void set_compression_algorithm(grpc_compression_algorithm algorithm);
std::shared_ptr<const AuthContext> auth_context() const;
// Get and set census context
void set_census_context(census_context* ccp) { census_context_ = ccp; }
census_context* get_census_context() const { return census_context_; }
void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
struct census_context* census_context() const { return census_context_; }
void TryCancel();
@ -163,10 +170,12 @@ class ClientContext {
grpc::string authority_;
std::shared_ptr<Credentials> creds_;
mutable std::shared_ptr<const AuthContext> auth_context_;
census_context* census_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
std::multimap<grpc::string, grpc::string> recv_initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
grpc_compression_algorithm compression_algorithm_;
};
} // namespace grpc

@ -105,7 +105,8 @@ class CompletionQueue : public GrpcLibrary {
// Returns false if the queue is ready for destruction, true if event
bool Next(void** tag, bool* ok) {
return (AsyncNextInternal(tag, ok, gpr_inf_future) != SHUTDOWN);
return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) !=
SHUTDOWN);
}
// Shutdown has to be called, and the CompletionQueue can only be

@ -79,6 +79,7 @@
#ifdef GRPC_CXX0X_NO_NULLPTR
#include <memory>
namespace grpc {
const class {
public:
template <class T>
@ -98,6 +99,7 @@ const class {
private:
void operator&() const = delete;
} nullptr = {};
}
#endif
#ifndef GRPC_CUSTOM_STRING

@ -106,13 +106,13 @@ std::shared_ptr<Credentials> ServiceAccountCredentials(
const grpc::string& json_key, const grpc::string& scope,
long token_lifetime_seconds);
// Builds JWT credentials.
// Builds Service Account JWT Access credentials.
// json_key is the JSON key string containing the client's private key.
// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
// (JWT) created with this credentials. It should not exceed
// grpc_max_auth_token_lifetime or will be cropped to this value.
std::shared_ptr<Credentials> JWTCredentials(const grpc::string& json_key,
long token_lifetime_seconds);
std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials(
const grpc::string& json_key, long token_lifetime_seconds);
// Builds refresh token credentials.
// json_refresh_token is the JSON string containing the refresh token along

@ -0,0 +1,82 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPCXX_DYNAMIC_THREAD_POOL_H
#define GRPCXX_DYNAMIC_THREAD_POOL_H
#include <grpc++/config.h>
#include <grpc++/impl/sync.h>
#include <grpc++/impl/thd.h>
#include <grpc++/thread_pool_interface.h>
#include <list>
#include <memory>
#include <queue>
namespace grpc {
class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface {
public:
explicit DynamicThreadPool(int reserve_threads);
~DynamicThreadPool();
void Add(const std::function<void()>& callback) GRPC_OVERRIDE;
private:
class DynamicThread {
public:
DynamicThread(DynamicThreadPool *pool);
~DynamicThread();
private:
DynamicThreadPool *pool_;
std::unique_ptr<grpc::thread> thd_;
void ThreadFunc();
};
grpc::mutex mu_;
grpc::condition_variable cv_;
grpc::condition_variable shutdown_cv_;
bool shutdown_;
std::queue<std::function<void()>> callbacks_;
int reserve_threads_;
int nthreads_;
int threads_waiting_;
std::list<DynamicThread*> dead_threads_;
void ThreadFunc();
static void ReapThreads(std::list<DynamicThread*>* tlist);
};
} // namespace grpc
#endif // GRPCXX_DYNAMIC_THREAD_POOL_H

@ -31,8 +31,8 @@
*
*/
#ifndef GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
#ifndef GRPCXX_FIXED_SIZE_THREAD_POOL_H
#define GRPCXX_FIXED_SIZE_THREAD_POOL_H
#include <grpc++/config.h>
@ -50,7 +50,7 @@ class FixedSizeThreadPool GRPC_FINAL : public ThreadPoolInterface {
explicit FixedSizeThreadPool(int num_threads);
~FixedSizeThreadPool();
void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
void Add(const std::function<void()>& callback) GRPC_OVERRIDE;
private:
grpc::mutex mu_;
@ -64,4 +64,4 @@ class FixedSizeThreadPool GRPC_FINAL : public ThreadPoolInterface {
} // namespace grpc
#endif // GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
#endif // GRPCXX_FIXED_SIZE_THREAD_POOL_H

@ -87,7 +87,7 @@ class condition_variable {
~condition_variable() { gpr_cv_destroy(&cv_); }
void wait(lock_guard<mutex> &mu) {
mu.locked = false;
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future);
gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
mu.locked = true;
}
void notify_one() { gpr_cv_signal(&cv_); }

@ -37,6 +37,7 @@
#include <map>
#include <memory>
#include <grpc/compression.h>
#include <grpc/support/time.h>
#include <grpc++/auth_context.h>
#include <grpc++/config.h>
@ -45,6 +46,7 @@
struct gpr_timespec;
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc {
@ -76,6 +78,10 @@ class CallOpBuffer;
class CompletionQueue;
class Server;
namespace testing {
class InteropContextInspector;
} // namespace testing
// Interface of server side rpc context.
class ServerContext {
public:
@ -93,15 +99,28 @@ class ServerContext {
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
bool IsCancelled();
bool IsCancelled() const;
const std::multimap<grpc::string, grpc::string>& client_metadata() {
return client_metadata_;
}
grpc_compression_level compression_level() const {
return compression_level_;
}
void set_compression_level(grpc_compression_level level);
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
void set_compression_algorithm(grpc_compression_algorithm algorithm);
std::shared_ptr<const AuthContext> auth_context() const;
const struct census_context* census_context() const;
private:
friend class ::grpc::testing::InteropContextInspector;
friend class ::grpc::Server;
template <class W, class R>
friend class ::grpc::ServerAsyncReader;
@ -149,6 +168,9 @@ class ServerContext {
std::multimap<grpc::string, grpc::string> client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_;
};
} // namespace grpc

@ -58,12 +58,15 @@ class ServerCredentials {
// Options to create ServerCredentials with SSL
struct SslServerCredentialsOptions {
SslServerCredentialsOptions() : force_client_auth(false) {}
struct PemKeyCertPair {
grpc::string private_key;
grpc::string cert_chain;
};
grpc::string pem_root_certs;
std::vector<PemKeyCertPair> pem_key_cert_pairs;
bool force_client_auth;
};
// Builds SSL ServerCredentials given SSL specific options

@ -44,7 +44,7 @@ class ThreadPoolInterface {
virtual ~ThreadPoolInterface() {}
// Schedule the given callback for execution.
virtual void ScheduleCallback(const std::function<void()>& callback) = 0;
virtual void Add(const std::function<void()>& callback) = 0;
};
ThreadPoolInterface* CreateDefaultThreadPool();

@ -44,26 +44,30 @@
extern "C" {
#endif
/* Identify census functionality that can be enabled via census_initialize(). */
enum census_functions {
CENSUS_NONE = 0, /* Do not enable census. */
CENSUS_TRACING = 1, /* Enable census tracing. */
CENSUS_STATS = 2, /* Enable Census stats collection. */
CENSUS_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_ALL = CENSUS_TRACING | CENSUS_STATS | CENSUS_CPU
/* Identify census features that can be enabled via census_initialize(). */
enum census_features {
CENSUS_FEATURE_NONE = 0, /* Do not enable census. */
CENSUS_FEATURE_TRACING = 1, /* Enable census tracing. */
CENSUS_FEATURE_STATS = 2, /* Enable Census stats collection. */
CENSUS_FEATURE_CPU = 4, /* Enable Census CPU usage collection. */
CENSUS_FEATURE_ALL =
CENSUS_FEATURE_TRACING | CENSUS_FEATURE_STATS | CENSUS_FEATURE_CPU
};
/* Shutdown and startup census subsystem. The 'functions' argument should be
* the OR (|) of census_functions values. If census fails to initialize, then
/** Shutdown and startup census subsystem. The 'features' argument should be
* the OR (|) of census_features values. If census fails to initialize, then
* census_initialize() will return a non-zero value. It is an error to call
* census_initialize() more than once (without an intervening
* census_shutdown()). */
int census_initialize(int functions);
void census_shutdown();
int census_initialize(int features);
void census_shutdown(void);
/* If any census feature has been initialized, this funtion will return a
* non-zero value. */
int census_available();
/** Return the features supported by the current census implementation (not all
* features will be available on all platforms). */
int census_supported(void);
/** Return the census features currently enabled. */
int census_enabled(void);
/* Internally, Census relies on a context, which should be propagated across
* RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.
@ -100,6 +104,17 @@ int census_context_deserialize(const char *buffer, census_context **context);
* future census calls will result in undefined behavior. */
void census_context_destroy(census_context *context);
/* A census statistic to be recorded comprises two parts: an ID for the
* particular statistic and the value to be recorded against it. */
typedef struct {
int id;
double value;
} census_stat;
/* Record new stats against the given context. */
void census_record_stat(census_context *context, census_stat *stats,
size_t nstats);
#ifdef __cplusplus
}
#endif

@ -34,8 +34,12 @@
#ifndef GRPC_COMPRESSION_H
#define GRPC_COMPRESSION_H
#ifdef __cplusplus
extern "C" {
#endif
/** To be used in channel arguments */
#define GRPC_COMPRESSION_LEVEL_ARG "grpc.compression_level"
#define GRPC_COMPRESSION_ALGORITHM_ARG "grpc.compression_algorithm"
/* The various compression algorithms supported by GRPC */
typedef enum {
@ -50,13 +54,34 @@ typedef enum {
GRPC_COMPRESS_LEVEL_NONE = 0,
GRPC_COMPRESS_LEVEL_LOW,
GRPC_COMPRESS_LEVEL_MED,
GRPC_COMPRESS_LEVEL_HIGH
GRPC_COMPRESS_LEVEL_HIGH,
GRPC_COMPRESS_LEVEL_COUNT
} grpc_compression_level;
const char *grpc_compression_algorithm_name(
/** Parses \a name as a grpc_compression_algorithm instance, updating \a
* algorithm. Returns 1 upon success, 0 otherwise. */
int grpc_compression_algorithm_parse(const char *name,
grpc_compression_algorithm *algorithm);
/** Updates \a name with the encoding name corresponding to a valid \a
* algorithm. Returns 1 upon success, 0 otherwise. */
int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
char **name);
/** Returns the compression level corresponding to \a algorithm.
*
* It abort()s for unknown algorithms. */
grpc_compression_level grpc_compression_level_for_algorithm(
grpc_compression_algorithm algorithm);
/** Returns the compression algorithm corresponding to \a level.
*
* It abort()s for unknown levels . */
grpc_compression_algorithm grpc_compression_algorithm_for_level(
grpc_compression_level level);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_COMPRESSION_H */

@ -45,40 +45,49 @@
extern "C" {
#endif
/* Completion Queues enable notification of the completion of asynchronous
actions. */
/*! \mainpage GRPC Core
*
* \section intro_sec The GRPC Core library is a low-level library designed
* to be wrapped by higher level libraries.
*
* The top-level API is provided in grpc.h.
* Security related functionality lives in grpc_security.h.
*/
/** Completion Queues enable notification of the completion of asynchronous
actions. */
typedef struct grpc_completion_queue grpc_completion_queue;
/* The Channel interface allows creation of Call objects. */
/** The Channel interface allows creation of Call objects. */
typedef struct grpc_channel grpc_channel;
/* A server listens to some port and responds to request calls */
/** A server listens to some port and responds to request calls */
typedef struct grpc_server grpc_server;
/* A Call represents an RPC. When created, it is in a configuration state
allowing properties to be set until it is invoked. After invoke, the Call
can have messages written to it and read from it. */
/** A Call represents an RPC. When created, it is in a configuration state
allowing properties to be set until it is invoked. After invoke, the Call
can have messages written to it and read from it. */
typedef struct grpc_call grpc_call;
/* Type specifier for grpc_arg */
/** Type specifier for grpc_arg */
typedef enum {
GRPC_ARG_STRING,
GRPC_ARG_INTEGER,
GRPC_ARG_POINTER
} grpc_arg_type;
/* A single argument... each argument has a key and a value
/** A single argument... each argument has a key and a value
A note on naming keys:
Keys are namespaced into groups, usually grouped by library, and are
keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
A note on naming keys:
Keys are namespaced into groups, usually grouped by library, and are
keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
GRPC core library keys are prefixed by grpc.
GRPC core library keys are prefixed by grpc.
Library authors are strongly encouraged to #define symbolic constants for
their keys so that it's possible to change them in the future. */
Library authors are strongly encouraged to \#define symbolic constants for
their keys so that it's possible to change them in the future. */
typedef struct {
grpc_arg_type type;
char *key;
@ -107,16 +116,22 @@ typedef struct {
} grpc_channel_args;
/* Channel argument keys: */
/* Enable census for tracing and stats collection */
/** Enable census for tracing and stats collection */
#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
/* Maximum number of concurrent incoming streams to allow on a http2
connection */
/** Maximum number of concurrent incoming streams to allow on a http2
connection */
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
/* Maximum message length that the channel can receive */
/** Maximum message length that the channel can receive */
#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
/* Initial sequence number for http2 transports */
/** Initial sequence number for http2 transports */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Primary user agent: goes at the start of the user-agent metadata
sent on each request */
#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
/** Secondary user agent: goes at the end of the user-agent metadata
sent on each request */
#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
/** Connectivity state of a channel. */
typedef enum {
@ -132,59 +147,60 @@ typedef enum {
GRPC_CHANNEL_FATAL_FAILURE
} grpc_connectivity_state;
/* Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
Receiving any other value listed here is an indication of a bug in the
caller. */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
Receiving any other value listed here is an indication of a bug in the
caller. */
typedef enum grpc_call_error {
/* everything went ok */
/** everything went ok */
GRPC_CALL_OK = 0,
/* something failed, we don't know what */
/** something failed, we don't know what */
GRPC_CALL_ERROR,
/* this method is not available on the server */
/** this method is not available on the server */
GRPC_CALL_ERROR_NOT_ON_SERVER,
/* this method is not available on the client */
/** this method is not available on the client */
GRPC_CALL_ERROR_NOT_ON_CLIENT,
/* this method must be called before server_accept */
/** this method must be called before server_accept */
GRPC_CALL_ERROR_ALREADY_ACCEPTED,
/* this method must be called before invoke */
/** this method must be called before invoke */
GRPC_CALL_ERROR_ALREADY_INVOKED,
/* this method must be called after invoke */
/** this method must be called after invoke */
GRPC_CALL_ERROR_NOT_INVOKED,
/* this call is already finished
(writes_done or write_status has already been called) */
/** this call is already finished
(writes_done or write_status has already been called) */
GRPC_CALL_ERROR_ALREADY_FINISHED,
/* there is already an outstanding read/write operation on the call */
/** there is already an outstanding read/write operation on the call */
GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
/* the flags value was illegal for this call */
/** the flags value was illegal for this call */
GRPC_CALL_ERROR_INVALID_FLAGS,
/* invalid metadata was passed to this call */
/** invalid metadata was passed to this call */
GRPC_CALL_ERROR_INVALID_METADATA,
/* completion queue for notification has not been registered with the server
*/
/** completion queue for notification has not been registered with the
server */
GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE
} grpc_call_error;
/* Write Flags: */
/* Hint that the write may be buffered and need not go out on the wire
immediately. GRPC is free to buffer the message until the next non-buffered
write, or until writes_done, but it need not buffer completely or at all. */
/** Hint that the write may be buffered and need not go out on the wire
immediately. GRPC is free to buffer the message until the next non-buffered
write, or until writes_done, but it need not buffer completely or at all. */
#define GRPC_WRITE_BUFFER_HINT (0x00000001u)
/* Force compression to be disabled for a particular write
(start_write/add_metadata). Illegal on invoke/accept. */
/** Force compression to be disabled for a particular write
(start_write/add_metadata). Illegal on invoke/accept. */
#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
/* Mask of all valid flags. */
/** Mask of all valid flags. */
#define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
/* A single metadata element */
/** A single metadata element */
typedef struct grpc_metadata {
const char *key;
const char *value;
size_t value_length;
/* The following fields are reserved for grpc internal use.
There is no need to initialize them, and they will be set to garbage during
calls to grpc. */
/** The following fields are reserved for grpc internal use.
There is no need to initialize them, and they will be set to garbage
during
calls to grpc. */
struct {
void *obfuscated[3];
} internal_data;
@ -235,42 +251,42 @@ void grpc_call_details_init(grpc_call_details *details);
void grpc_call_details_destroy(grpc_call_details *details);
typedef enum {
/* Send initial metadata: one and only one instance MUST be sent for each
call,
unless the call was cancelled - in which case this can be skipped */
/** Send initial metadata: one and only one instance MUST be sent for each
call, unless the call was cancelled - in which case this can be skipped */
GRPC_OP_SEND_INITIAL_METADATA = 0,
/* Send a message: 0 or more of these operations can occur for each call */
/** Send a message: 0 or more of these operations can occur for each call */
GRPC_OP_SEND_MESSAGE,
/* Send a close from the client: one and only one instance MUST be sent from
the client,
unless the call was cancelled - in which case this can be skipped */
/** Send a close from the client: one and only one instance MUST be sent from
the client, unless the call was cancelled - in which case this can be
skipped */
GRPC_OP_SEND_CLOSE_FROM_CLIENT,
/* Send status from the server: one and only one instance MUST be sent from
the server
unless the call was cancelled - in which case this can be skipped */
/** Send status from the server: one and only one instance MUST be sent from
the server unless the call was cancelled - in which case this can be
skipped */
GRPC_OP_SEND_STATUS_FROM_SERVER,
/* Receive initial metadata: one and only one MUST be made on the client, must
not be made on the server */
/** Receive initial metadata: one and only one MUST be made on the client,
must not be made on the server */
GRPC_OP_RECV_INITIAL_METADATA,
/* Receive a message: 0 or more of these operations can occur for each call */
/** Receive a message: 0 or more of these operations can occur for each call
*/
GRPC_OP_RECV_MESSAGE,
/* Receive status on the client: one and only one must be made on the client.
/** Receive status on the client: one and only one must be made on the client.
This operation always succeeds, meaning ops paired with this operation
will also appear to succeed, even though they may not have. In that case
the status will indicate some failure.
*/
the status will indicate some failure. */
GRPC_OP_RECV_STATUS_ON_CLIENT,
/* Receive close on the server: one and only one must be made on the server
*/
/** Receive close on the server: one and only one must be made on the
server */
GRPC_OP_RECV_CLOSE_ON_SERVER
} grpc_op_type;
/* Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
which has
no arguments) */
/** Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
which has no arguments) */
typedef struct grpc_op {
/** Operation type, as defined by grpc_op_type */
grpc_op_type op;
gpr_uint32 flags; /**< Write flags bitset for grpc_begin_messages */
/** Write flags bitset for grpc_begin_messages */
gpr_uint32 flags;
union {
struct {
size_t count;
@ -283,53 +299,51 @@ typedef struct grpc_op {
grpc_status_code status;
const char *status_details;
} send_status_from_server;
/* ownership of the array is with the caller, but ownership of the elements
stays with the call object (ie key, value members are owned by the call
object, recv_initial_metadata->array is owned by the caller).
After the operation completes, call grpc_metadata_array_destroy on this
value, or reuse it in a future op. */
/** ownership of the array is with the caller, but ownership of the elements
stays with the call object (ie key, value members are owned by the call
object, recv_initial_metadata->array is owned by the caller).
After the operation completes, call grpc_metadata_array_destroy on this
value, or reuse it in a future op. */
grpc_metadata_array *recv_initial_metadata;
/* ownership of the byte buffer is moved to the caller; the caller must call
grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
/** ownership of the byte buffer is moved to the caller; the caller must
call
grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
grpc_byte_buffer **recv_message;
struct {
/* ownership of the array is with the caller, but ownership of the
elements
stays with the call object (ie key, value members are owned by the call
object, trailing_metadata->array is owned by the caller).
After the operation completes, call grpc_metadata_array_destroy on this
value, or reuse it in a future op. */
/** ownership of the array is with the caller, but ownership of the
elements stays with the call object (ie key, value members are owned
by the call object, trailing_metadata->array is owned by the caller).
After the operation completes, call grpc_metadata_array_destroy on
this
value, or reuse it in a future op. */
grpc_metadata_array *trailing_metadata;
grpc_status_code *status;
/* status_details is a buffer owned by the application before the op
completes
and after the op has completed. During the operation status_details may
be
reallocated to a size larger than *status_details_capacity, in which
case
*status_details_capacity will be updated with the new array capacity.
Pre-allocating space:
size_t my_capacity = 8;
char *my_details = gpr_malloc(my_capacity);
x.status_details = &my_details;
x.status_details_capacity = &my_capacity;
Not pre-allocating space:
size_t my_capacity = 0;
char *my_details = NULL;
x.status_details = &my_details;
x.status_details_capacity = &my_capacity;
After the call:
gpr_free(my_details); */
/** status_details is a buffer owned by the application before the op
completes and after the op has completed. During the operation
status_details may be reallocated to a size larger than
*status_details_capacity, in which case *status_details_capacity will
be updated with the new array capacity.
Pre-allocating space:
size_t my_capacity = 8;
char *my_details = gpr_malloc(my_capacity);
x.status_details = &my_details;
x.status_details_capacity = &my_capacity;
Not pre-allocating space:
size_t my_capacity = 0;
char *my_details = NULL;
x.status_details = &my_details;
x.status_details_capacity = &my_capacity;
After the call:
gpr_free(my_details); */
char **status_details;
size_t *status_details_capacity;
} recv_status_on_client;
struct {
/* out argument, set to 1 if the call failed in any way (seen as a
cancellation
on the server), or 0 if the call succeeded */
/** out argument, set to 1 if the call failed in any way (seen as a
cancellation on the server), or 0 if the call succeeded */
int *cancelled;
} recv_close_on_server;
} data;
@ -379,62 +393,103 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
gpr_timespec deadline);
/* Begin destruction of a completion queue. Once all possible events are
drained then grpc_completion_queue_next will start to produce
GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call
grpc_completion_queue_destroy.
/** Begin destruction of a completion queue. Once all possible events are
drained then grpc_completion_queue_next will start to produce
GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call
grpc_completion_queue_destroy.
After calling this function applications should ensure that no
NEW work is added to be published on this completion queue. */
After calling this function applications should ensure that no
NEW work is added to be published on this completion queue. */
void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
/* Destroy a completion queue. The caller must ensure that the queue is
drained and no threads are executing grpc_completion_queue_next */
/** Destroy a completion queue. The caller must ensure that the queue is
drained and no threads are executing grpc_completion_queue_next */
void grpc_completion_queue_destroy(grpc_completion_queue *cq);
/* Create a call given a grpc_channel, in order to call 'method'. All
completions are sent to 'completion_queue'. 'method' and 'host' need only
live through the invocation of this function. */
/** Check the connectivity state of a channel. */
grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect);
/** Watch for a change in connectivity state.
Once the channel connectivity state is different from last_observed_state,
tag will be enqueued on cq with success=1.
If deadline expires BEFORE the state is changed, tag will be enqueued on cq
with success=0.
If optional_new_state is non-NULL, it will be set to the newly observed
connectivity state of the channel at the same point as tag is enqueued onto
the completion queue. */
void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
grpc_connectivity_state *optional_new_state, gpr_timespec deadline,
grpc_completion_queue *cq, void *tag);
/** Create a call given a grpc_channel, in order to call 'method'. All
completions are sent to 'completion_queue'. 'method' and 'host' need only
live through the invocation of this function. */
grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_completion_queue *completion_queue,
const char *method, const char *host,
gpr_timespec deadline);
/* Pre-register a method/host pair on a channel. */
/** Pre-register a method/host pair on a channel. */
void *grpc_channel_register_call(grpc_channel *channel, const char *method,
const char *host);
/* Create a call given a handle returned from grpc_channel_register_call */
/** Create a call given a handle returned from grpc_channel_register_call */
grpc_call *grpc_channel_create_registered_call(
grpc_channel *channel, grpc_completion_queue *completion_queue,
void *registered_call_handle, gpr_timespec deadline);
/* Start a batch of operations defined in the array ops; when complete, post a
completion of type 'tag' to the completion queue bound to the call.
The order of ops specified in the batch has no significance.
Only one operation of each type can be active at once in any given
batch. You must call grpc_completion_queue_next or
grpc_completion_queue_pluck on the completion queue associated with 'call'
for work to be performed.
THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
needs to be synchronized. As an optimization, you may synchronize batches
containing just send operations independently from batches containing just
receive operations. */
/** Start a batch of operations defined in the array ops; when complete, post a
completion of type 'tag' to the completion queue bound to the call.
The order of ops specified in the batch has no significance.
Only one operation of each type can be active at once in any given
batch. You must call grpc_completion_queue_next or
grpc_completion_queue_pluck on the completion queue associated with 'call'
for work to be performed.
THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
needs to be synchronized. As an optimization, you may synchronize batches
containing just send operations independently from batches containing just
receive operations. */
grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
size_t nops, void *tag);
/* Create a client channel to 'target'. Additional channel level configuration
MAY be provided by grpc_channel_args, though the expectation is that most
clients will want to simply pass NULL. See grpc_channel_args definition for
more on this. The data in 'args' need only live through the invocation of
this function. */
grpc_channel *grpc_channel_create(const char *target,
const grpc_channel_args *args);
/** Returns a newly allocated string representing the endpoint to which this
call is communicating with. The string is in the uri format accepted by
grpc_channel_create.
The returned string should be disposed of with gpr_free().
WARNING: this value is never authenticated or subject to any security
related code. It must not be used for any authentication related
functionality. Instead, use grpc_auth_context. */
char *grpc_call_get_peer(grpc_call *call);
struct census_context;
/* Set census context for a call; Must be called before first call to
grpc_call_start_batch(). */
void grpc_census_call_set_context(grpc_call *call,
struct census_context *context);
/* Retrieve the calls current census context. */
struct census_context *grpc_census_call_get_context(grpc_call *call);
/** Return a newly allocated string representing the target a channel was
created for. */
char *grpc_channel_get_target(grpc_channel *channel);
/** Create a client channel to 'target'. Additional channel level configuration
MAY be provided by grpc_channel_args, though the expectation is that most
clients will want to simply pass NULL. See grpc_channel_args definition for
more on this. The data in 'args' need only live through the invocation of
this function. */
grpc_channel *grpc_insecure_channel_create(const char *target,
const grpc_channel_args *args);
/* Create a lame client: this client fails every operation attempted on it. */
grpc_channel *grpc_lame_client_channel_create(void);
/** Create a lame client: this client fails every operation attempted on it. */
grpc_channel *grpc_lame_client_channel_create(const char *target);
/* Close and destroy a grpc channel */
/** Close and destroy a grpc channel */
void grpc_channel_destroy(grpc_channel *channel);
/* Error handling for grpc_call
@ -443,49 +498,49 @@ void grpc_channel_destroy(grpc_channel *channel);
If a grpc_call fails, it's guaranteed that no change to the call state
has been made. */
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread.
THREAD-SAFETY grpc_call_cancel and grpc_call_cancel_with_status
are thread-safe, and can be called at any point before grpc_call_destroy
is called.*/
/** Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread.
THREAD-SAFETY grpc_call_cancel and grpc_call_cancel_with_status
are thread-safe, and can be called at any point before grpc_call_destroy
is called.*/
grpc_call_error grpc_call_cancel(grpc_call *call);
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread.
If a status has not been received for the call, set it to the status code
and description passed in.
Importantly, this function does not send status nor description to the
remote endpoint. */
/** Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread.
If a status has not been received for the call, set it to the status code
and description passed in.
Importantly, this function does not send status nor description to the
remote endpoint. */
grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
grpc_status_code status,
const char *description);
/* Destroy a call.
THREAD SAFETY: grpc_call_destroy is thread-compatible */
/** Destroy a call.
THREAD SAFETY: grpc_call_destroy is thread-compatible */
void grpc_call_destroy(grpc_call *call);
/* Request notification of a new call. 'cq_for_notification' must
have been registered to the server via grpc_server_register_completion_queue.
*/
/** Request notification of a new call. 'cq_for_notification' must
have been registered to the server via
grpc_server_register_completion_queue. */
grpc_call_error grpc_server_request_call(
grpc_server *server, grpc_call **call, grpc_call_details *details,
grpc_metadata_array *request_metadata,
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification, void *tag_new);
/* Registers a method in the server.
Methods to this (host, method) pair will not be reported by
grpc_server_request_call, but instead be reported by
grpc_server_request_registered_call when passed the appropriate
registered_method (as returned by this function).
Must be called before grpc_server_start.
Returns NULL on failure. */
/** Registers a method in the server.
Methods to this (host, method) pair will not be reported by
grpc_server_request_call, but instead be reported by
grpc_server_request_registered_call when passed the appropriate
registered_method (as returned by this function).
Must be called before grpc_server_start.
Returns NULL on failure. */
void *grpc_server_register_method(grpc_server *server, const char *method,
const char *host);
/* Request notification of a new pre-registered call. 'cq_for_notification' must
have been registered to the server via grpc_server_register_completion_queue.
*/
/** Request notification of a new pre-registered call. 'cq_for_notification'
must have been registered to the server via
grpc_server_register_completion_queue. */
grpc_call_error grpc_server_request_registered_call(
grpc_server *server, void *registered_method, grpc_call **call,
gpr_timespec *deadline, grpc_metadata_array *request_metadata,
@ -493,45 +548,45 @@ grpc_call_error grpc_server_request_registered_call(
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification, void *tag_new);
/* Create a server. Additional configuration for each incoming channel can
be specified with args. If no additional configuration is needed, args can
be NULL. See grpc_channel_args for more. The data in 'args' need only live
through the invocation of this function. */
/** Create a server. Additional configuration for each incoming channel can
be specified with args. If no additional configuration is needed, args can
be NULL. See grpc_channel_args for more. The data in 'args' need only live
through the invocation of this function. */
grpc_server *grpc_server_create(const grpc_channel_args *args);
/* Register a completion queue with the server. Must be done for any
notification completion queue that is passed to grpc_server_request_*_call
and to grpc_server_shutdown_and_notify. Must be performed prior to
grpc_server_start. */
/** Register a completion queue with the server. Must be done for any
notification completion queue that is passed to grpc_server_request_*_call
and to grpc_server_shutdown_and_notify. Must be performed prior to
grpc_server_start. */
void grpc_server_register_completion_queue(grpc_server *server,
grpc_completion_queue *cq);
/* Add a HTTP2 over plaintext over tcp listener.
Returns bound port number on success, 0 on failure.
REQUIRES: server not started */
/** Add a HTTP2 over plaintext over tcp listener.
Returns bound port number on success, 0 on failure.
REQUIRES: server not started */
int grpc_server_add_http2_port(grpc_server *server, const char *addr);
/* Start a server - tells all listeners to start listening */
/** Start a server - tells all listeners to start listening */
void grpc_server_start(grpc_server *server);
/* Begin shutting down a server.
After completion, no new calls or connections will be admitted.
Existing calls will be allowed to complete.
Send a GRPC_OP_COMPLETE event when there are no more calls being serviced.
Shutdown is idempotent, and all tags will be notified at once if multiple
grpc_server_shutdown_and_notify calls are made. 'cq' must have been
registered to this server via grpc_server_register_completion_queue. */
/** Begin shutting down a server.
After completion, no new calls or connections will be admitted.
Existing calls will be allowed to complete.
Send a GRPC_OP_COMPLETE event when there are no more calls being serviced.
Shutdown is idempotent, and all tags will be notified at once if multiple
grpc_server_shutdown_and_notify calls are made. 'cq' must have been
registered to this server via grpc_server_register_completion_queue. */
void grpc_server_shutdown_and_notify(grpc_server *server,
grpc_completion_queue *cq, void *tag);
/* Cancel all in-progress calls.
Only usable after shutdown. */
/** Cancel all in-progress calls.
Only usable after shutdown. */
void grpc_server_cancel_all_calls(grpc_server *server);
/* Destroy a server.
Shutdown must have completed beforehand (i.e. all tags generated by
grpc_server_shutdown_and_notify must have been received, and at least
one call to grpc_server_shutdown_and_notify must have been made). */
/** Destroy a server.
Shutdown must have completed beforehand (i.e. all tags generated by
grpc_server_shutdown_and_notify must have been received, and at least
one call to grpc_server_shutdown_and_notify must have been made). */
void grpc_server_destroy(grpc_server *server);
/** Enable or disable a tracer.

@ -87,7 +87,7 @@ typedef struct {
directory).
- pem_key_cert_pair is a pointer on the object containing client's private
key and certificate chain. This parameter can be NULL if the client does
not have such a key/cert pair. */
not have such a key/cert pair. */
grpc_credentials *grpc_ssl_credentials_create(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair);
@ -119,8 +119,8 @@ grpc_credentials *grpc_service_account_credentials_create(
- token_lifetime is the lifetime of each Json Web Token (JWT) created with
this credentials. It should not exceed grpc_max_auth_token_lifetime or
will be cropped to this value. */
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime);
grpc_credentials *grpc_service_account_jwt_access_credentials_create(
const char *json_key, gpr_timespec token_lifetime);
/* Creates an Oauth2 Refresh Token credentials object. May return NULL if the
input is invalid.
@ -140,9 +140,6 @@ grpc_credentials *grpc_access_token_credentials_create(
grpc_credentials *grpc_iam_credentials_create(const char *authorization_token,
const char *authority_selector);
/* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void);
/* --- Secure channel creation. --- */
/* The caller of the secure_channel_create functions may override the target
@ -177,14 +174,13 @@ void grpc_server_credentials_release(grpc_server_credentials *creds);
- pem_key_cert_pairs is an array private key / certificate chains of the
server. This parameter cannot be NULL.
- num_key_cert_pairs indicates the number of items in the private_key_files
and cert_chain_files parameters. It should be at least 1. */
and cert_chain_files parameters. It should be at least 1.
- force_client_auth, if set to non-zero will force the client to authenticate
with an SSL cert. Note that this option is ignored if pem_root_certs is
NULL. */
grpc_server_credentials *grpc_ssl_server_credentials_create(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs);
/* Creates a fake server transport security credentials object for testing. */
grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
void);
size_t num_key_cert_pairs, int force_client_auth);
/* --- Server-side secure ports. --- */
@ -204,7 +200,6 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
/* --- Authentication Context. --- */
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type"
#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
#define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
#define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"

@ -52,8 +52,10 @@ int gpr_join_host_port(char **out, const char *host, int port);
/* Given a name in the form "host:port" or "[ho:st]:port", split into hostname
and port number, into newly allocated strings, which must later be
destroyed using gpr_free(). */
void gpr_split_host_port(const char *name, char **host, char **port);
destroyed using gpr_free().
Return 1 on success, 0 on failure. Guarantees *host and *port == NULL on
failure. */
int gpr_split_host_port(const char *name, char **host, char **port);
#ifdef __cplusplus
}

@ -71,6 +71,7 @@
#if !defined(GPR_NO_AUTODETECT_PLATFORM)
#if defined(_WIN64) || defined(WIN64)
#define GPR_PLATFORM_STRING "windows"
#define GPR_WIN32 1
#define GPR_ARCH_64 1
#define GPR_GETPID_IN_PROCESS_H 1
@ -84,6 +85,7 @@
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(_WIN32) || defined(WIN32)
#define GPR_PLATFORM_STRING "windows"
#define GPR_ARCH_32 1
#define GPR_WIN32 1
#define GPR_GETPID_IN_PROCESS_H 1
@ -97,6 +99,7 @@
#endif
#define GPR_WINDOWS_CRASH_HANDLER 1
#elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_PLATFORM_STRING "android"
#define GPR_ANDROID 1
#define GPR_ARCH_32 1
#define GPR_CPU_LINUX 1
@ -117,6 +120,7 @@
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_HAVE_MSG_NOSIGNAL 1
#elif defined(__linux__)
#define GPR_PLATFORM_STRING "linux"
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
@ -173,9 +177,11 @@
#define _BSD_SOURCE
#endif
#if TARGET_OS_IPHONE
#define GPR_PLATFORM_STRING "ios"
#define GPR_CPU_IPHONE 1
#define GPR_PTHREAD_TLS 1
#else /* TARGET_OS_IPHONE */
#define GPR_PLATFORM_STRING "osx"
#define GPR_CPU_POSIX 1
#define GPR_GCC_TLS 1
#endif
@ -201,6 +207,7 @@
#define GPR_ARCH_32 1
#endif /* _LP64 */
#elif defined(__FreeBSD__)
#define GPR_PLATFORM_STRING "freebsd"
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
@ -232,6 +239,11 @@
#endif
#endif /* GPR_NO_AUTODETECT_PLATFORM */
#ifndef GPR_PLATFORM_STRING
#warning "GPR_PLATFORM_STRING not auto-detected"
#define GPR_PLATFORM_STRING "unknown"
#endif
/* For a common case, assume that the platform has a C99-like stdint.h */
#include <stdint.h>

@ -45,15 +45,30 @@
extern "C" {
#endif
/* The clocks we support. */
typedef enum {
/* Monotonic clock. Epoch undefined. Always moves forwards. */
GPR_CLOCK_MONOTONIC = 0,
/* Realtime clock. May jump forwards or backwards. Settable by
the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
GPR_CLOCK_REALTIME,
/* Unmeasurable clock type: no base, created by taking the difference
between two times */
GPR_TIMESPAN
} gpr_clock_type;
typedef struct gpr_timespec {
time_t tv_sec;
int tv_nsec;
/** Against which clock was this time measured? (or GPR_TIMESPAN if
this is a relative time meaure) */
gpr_clock_type clock_type;
} gpr_timespec;
/* Time constants. */
extern const gpr_timespec gpr_time_0; /* The zero time interval. */
extern const gpr_timespec gpr_inf_future; /* The far future */
extern const gpr_timespec gpr_inf_past; /* The far past. */
gpr_timespec gpr_time_0(gpr_clock_type type); /* The zero time interval. */
gpr_timespec gpr_inf_future(gpr_clock_type type); /* The far future */
gpr_timespec gpr_inf_past(gpr_clock_type type); /* The far past. */
#define GPR_MS_PER_SEC 1000
#define GPR_US_PER_SEC 1000000
@ -62,21 +77,15 @@ extern const gpr_timespec gpr_inf_past; /* The far past. */
#define GPR_NS_PER_US 1000
#define GPR_US_PER_MS 1000
/* The clocks we support. */
typedef enum {
/* Monotonic clock. Epoch undefined. Always moves forwards. */
GPR_CLOCK_MONOTONIC = 0,
/* Realtime clock. May jump forwards or backwards. Settable by
the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
GPR_CLOCK_REALTIME
} gpr_clock_type;
/* initialize time subsystem */
void gpr_time_init(void);
/* Return the current time measured from the given clocks epoch. */
gpr_timespec gpr_now(gpr_clock_type clock);
/* Convert a timespec from one clock to another */
gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock);
/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
respectively. */
int gpr_time_cmp(gpr_timespec a, gpr_timespec b);
@ -90,12 +99,12 @@ gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
/* Return a timespec representing a given number of time units. LONG_MIN is
interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future. */
gpr_timespec gpr_time_from_micros(long x);
gpr_timespec gpr_time_from_nanos(long x);
gpr_timespec gpr_time_from_millis(long x);
gpr_timespec gpr_time_from_seconds(long x);
gpr_timespec gpr_time_from_minutes(long x);
gpr_timespec gpr_time_from_hours(long x);
gpr_timespec gpr_time_from_micros(long x, gpr_clock_type clock_type);
gpr_timespec gpr_time_from_nanos(long x, gpr_clock_type clock_type);
gpr_timespec gpr_time_from_millis(long x, gpr_clock_type clock_type);
gpr_timespec gpr_time_from_seconds(long x, gpr_clock_type clock_type);
gpr_timespec gpr_time_from_minutes(long x, gpr_clock_type clock_type);
gpr_timespec gpr_time_from_hours(long x, gpr_clock_type clock_type);
gpr_int32 gpr_time_to_millis(gpr_timespec timespec);

@ -52,4 +52,24 @@
b = x; \
} while (0)
/** Set the \a n-th bit of \a i (a mutable pointer). */
#define GPR_BITSET(i, n) ((*(i)) |= (1u << (n)))
/** Clear the \a n-th bit of \a i (a mutable pointer). */
#define GPR_BITCLEAR(i, n) ((*(i)) &= ~(1u << (n)))
/** Get the \a n-th bit of \a i */
#define GPR_BITGET(i, n) (((i) & (1u << (n))) != 0)
#define GPR_INTERNAL_HEXDIGIT_BITCOUNT(x) \
((x) - (((x) >> 1) & 0x77777777) - (((x) >> 2) & 0x33333333) - \
(((x) >> 3) & 0x11111111))
/** Returns number of bits set in bitset \a i */
#define GPR_BITCOUNT(i) \
(((GPR_INTERNAL_HEXDIGIT_BITCOUNT(i) + \
(GPR_INTERNAL_HEXDIGIT_BITCOUNT(i) >> 4)) & \
0x0f0f0f0f) % \
255)
#endif /* GRPC_SUPPORT_USEFUL_H */

@ -149,7 +149,7 @@ std::string GetMethodRequestParamMaybe(const MethodDescriptor *method) {
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
return "Task<" + GetClassName(method->output_type()) + ">";
return "AsyncUnaryCall<" + GetClassName(method->output_type()) + ">";
case METHODTYPE_CLIENT_STREAMING:
return "AsyncClientStreamingCall<" + GetClassName(method->input_type())
+ ", " + GetClassName(method->output_type()) + ">";
@ -269,7 +269,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
out->Print(
"$response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
@ -280,7 +280,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
method_name += "Async"; // prevent name clash with synchronous method.
}
out->Print(
"$returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
@ -298,11 +298,13 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
out->Print("$returntype$ $methodname$(ServerCallContext context, $request$$response_stream_maybe$);\n",
"methodname", method->name(), "returntype",
GetMethodReturnTypeServer(method), "request",
GetMethodRequestParamServer(method), "response_stream_maybe",
GetMethodResponseStreamMaybe(method));
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
"methodname", method->name(), "returntype",
GetMethodReturnTypeServer(method), "request",
GetMethodRequestParamServer(method), "response_stream_maybe",
GetMethodResponseStreamMaybe(method));
}
out->Outdent();
out->Print("}\n");
@ -332,13 +334,13 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
out->Print(
"public $response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"public $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n",
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n",
"servicenamefield", GetServiceNameFieldName(), "methodfield",
GetMethodFieldName(method));
out->Print("return Calls.BlockingUnaryCall(call, request, cancellationToken);\n");
@ -351,13 +353,13 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
method_name += "Async"; // prevent name clash with synchronous method.
}
out->Print(
"public $returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"public $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n",
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n",
"servicenamefield", GetServiceNameFieldName(), "methodfield",
GetMethodFieldName(method));
switch (GetMethodType(method)) {

@ -67,7 +67,7 @@ void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
printer->Print(vars, "- ($return_type$)$method_name$With");
if (method->client_streaming()) {
printer->Print("RequestsWriter:(id<GRXWriter>)requestWriter");
printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
} else {
printer->Print(vars, "Request:($request_class$ *)request");
}
@ -186,9 +186,6 @@ string GetHeader(const ServiceDescriptor *service) {
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
printer.Print("@protocol GRXWriteable;\n");
printer.Print("@protocol GRXWriter;\n\n");
map<string, string> vars = {{"service_class", ServiceClassName(service)}};
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");

@ -63,7 +63,9 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
// Generate .pbrpc.h
string imports = string("#import \"") + file_name + ".pbobjc.h\"\n\n"
"#import <ProtoRPC/ProtoService.h>\n";
"#import <ProtoRPC/ProtoService.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n"
"#import <RxLibrary/GRXWriter.h>\n";
// TODO(jcanizales): Instead forward-declare the input and output types
// and import the files in the .pbrpc.m
@ -89,7 +91,6 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
string imports = string("#import \"") + file_name + ".pbrpc.h\"\n\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n"
"#import <RxLibrary/GRXWriter+Immediate.h>\n";
string definitions;

@ -249,7 +249,7 @@ bool GetModuleAndMessagePath(const Descriptor* type,
do {
message_path.push_back(path_elem_type);
path_elem_type = path_elem_type->containing_type();
} while (path_elem_type != nullptr);
} while (path_elem_type); // implicit nullptr comparison; don't be explicit
grpc::string file_name = type->file()->name();
static const int proto_suffix_length = strlen(".proto");
if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&

@ -32,14 +32,15 @@
*/
#include <grpc/census.h>
#include "src/core/census/grpc_context.h"
#include <grpc/grpc.h>
#include "src/core/surface/call.h"
static void grpc_census_context_destroy(void *context) {
census_context_destroy((census_context *)context);
}
void grpc_census_call_set_context(grpc_call *call, census_context *context) {
if (!census_available()) {
if (census_enabled() == CENSUS_FEATURE_NONE) {
return;
}
if (context == NULL) {

@ -33,20 +33,25 @@
#include <grpc/census.h>
static int census_fns_enabled = CENSUS_NONE;
static int features_enabled = CENSUS_FEATURE_NONE;
int census_initialize(int functions) {
if (census_fns_enabled != CENSUS_NONE) {
int census_initialize(int features) {
if (features_enabled != CENSUS_FEATURE_NONE) {
return 1;
}
if (functions != CENSUS_NONE) {
if (features != CENSUS_FEATURE_NONE) {
return 1;
} else {
census_fns_enabled = functions;
features_enabled = features;
return 0;
}
}
void census_shutdown() { census_fns_enabled = CENSUS_NONE; }
void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; }
int census_available() { return (census_fns_enabled != CENSUS_NONE); }
int census_supported(void) {
/* TODO(aveitch): improve this as we implement features... */
return CENSUS_FEATURE_NONE;
}
int census_enabled(void) { return features_enabled; }

@ -31,21 +31,8 @@
*
*/
#ifndef GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
#define GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
#include <grpc/census.h>
#include "src/core/census/rpc_stat_id.h"
#include <memory>
namespace grpc {
class Credentials;
class ServerCredentials;
namespace testing {
std::shared_ptr<Credentials> FakeTransportSecurityCredentials();
std::shared_ptr<ServerCredentials> FakeTransportSecurityServerCredentials();
} // namespace testing
} // namespace grpc
#endif // GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H
void census_record_stat(census_context *context, census_stat *stats,
size_t nstats) {}

@ -31,28 +31,16 @@
*
*/
#include <grpc/grpc_security.h>
#include <grpc++/channel_arguments.h>
#include <grpc++/credentials.h>
#include <grpc++/server_credentials.h>
#include "src/cpp/client/channel.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/server/secure_server_credentials.h"
#ifndef CENSUS_RPC_STAT_ID_H
#define CENSUS_RPC_STAT_ID_H
namespace grpc {
namespace testing {
/* Stats ID's used for RPC measurements. */
#define CENSUS_INVALID_STAT_ID 0 /* ID 0 is always invalid */
#define CENSUS_RPC_CLIENT_REQUESTS 1 /* Count of client requests sent. */
#define CENSUS_RPC_SERVER_REQUESTS 2 /* Count of server requests sent. */
#define CENSUS_RPC_CLIENT_ERRORS 3 /* Client error counts. */
#define CENSUS_RPC_SERVER_ERRORS 4 /* Server error counts. */
#define CENSUS_RPC_CLIENT_LATENCY 5 /* Client side request latency. */
#define CENSUS_RPC_SERVER_LATENCY 6 /* Server side request latency. */
std::shared_ptr<Credentials> FakeTransportSecurityCredentials() {
grpc_credentials* c_creds = grpc_fake_transport_security_credentials_create();
return std::shared_ptr<Credentials>(new SecureCredentials(c_creds));
}
std::shared_ptr<ServerCredentials> FakeTransportSecurityServerCredentials() {
grpc_server_credentials* c_creds =
grpc_fake_transport_security_server_credentials_create();
return std::shared_ptr<ServerCredentials>(
new SecureServerCredentials(c_creds));
}
} // namespace testing
} // namespace grpc
#endif /* CENSUS_RPC_STAT_ID_H */

@ -114,7 +114,7 @@ void grpc_channel_args_destroy(grpc_channel_args *a) {
}
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
unsigned i;
size_t i;
if (a == NULL) return 0;
for (i = 0; i < a->num_args; i++) {
if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
@ -124,26 +124,25 @@ int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
return 0;
}
grpc_compression_level grpc_channel_args_get_compression_level(
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args *a) {
size_t i;
if (a) {
for (i = 0; a && i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_LEVEL_ARG, a->args[i].key)) {
return a->args[i].value.integer;
break;
}
if (a == NULL) return 0;
for (i = 0; i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_ALGORITHM_ARG, a->args[i].key)) {
return a->args[i].value.integer;
break;
}
}
return GRPC_COMPRESS_LEVEL_NONE;
return GRPC_COMPRESS_NONE;
}
void grpc_channel_args_set_compression_level(grpc_channel_args **a,
grpc_compression_level level) {
grpc_channel_args *grpc_channel_args_set_compression_algorithm(
grpc_channel_args *a, grpc_compression_algorithm algorithm) {
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = GRPC_COMPRESSION_LEVEL_ARG;
tmp.value.integer = level;
*a = grpc_channel_args_copy_and_add(*a, &tmp, 1);
tmp.key = GRPC_COMPRESSION_ALGORITHM_ARG;
tmp.value.integer = algorithm;
return grpc_channel_args_copy_and_add(a, &tmp, 1);
}

@ -57,13 +57,14 @@ void grpc_channel_args_destroy(grpc_channel_args *a);
* is specified in channel args, otherwise returns 0. */
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
/** Returns the compression level set in \a a. */
grpc_compression_level grpc_channel_args_get_compression_level(
/** Returns the compression algorithm set in \a a. */
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args *a);
/** Sets the compression level in \a a to \a level. Setting it to
* GRPC_COMPRESS_LEVEL_NONE disables compression for the channel. */
void grpc_channel_args_set_compression_level(grpc_channel_args **a,
grpc_compression_level level);
/** Returns a channel arg instance with compression enabled. If \a a is
* non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression
* for the channel. */
grpc_channel_args *grpc_channel_args_set_compression_algorithm(
grpc_channel_args *a, grpc_compression_algorithm algorithm);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */

@ -191,6 +191,11 @@ void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op) {
next_elem->filter->start_transport_stream_op(next_elem, op);
}
char *grpc_call_next_get_peer(grpc_call_element *elem) {
grpc_call_element *next_elem = elem + 1;
return next_elem->filter->get_peer(next_elem);
}
void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op) {
grpc_channel_element *next_elem = elem + 1;
next_elem->filter->start_transport_op(next_elem, op);

@ -104,6 +104,9 @@ typedef struct {
The filter does not need to do any chaining */
void (*destroy_channel_elem)(grpc_channel_element *elem);
/* Implement grpc_call_get_peer() */
char *(*get_peer)(grpc_call_element *elem);
/* The name of this filter */
const char *name;
} grpc_channel_filter;
@ -173,6 +176,8 @@ void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op);
/* Call the next operation (depending on call directionality) in a channel
stack */
void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op);
/* Pass through a request to get_peer to the next child element */
char *grpc_call_next_get_peer(grpc_call_element *elem);
/* Given the top element of a channel stack, get the channel stack itself */
grpc_channel_stack *grpc_channel_stack_from_top_element(

@ -40,7 +40,6 @@
#include "src/core/channel/connected_channel.h"
#include "src/core/surface/channel.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/pollset_set.h"
#include "src/core/support/string.h"
#include "src/core/transport/connectivity_state.h"
#include <grpc/support/alloc.h>
@ -77,8 +76,22 @@ typedef struct {
grpc_iomgr_closure on_config_changed;
/** connectivity state being tracked */
grpc_connectivity_state_tracker state_tracker;
/** when an lb_policy arrives, should we try to exit idle */
int exit_idle_when_lb_policy_arrives;
/** pollset_set of interested parties in a new connection */
grpc_pollset_set pollset_set;
} channel_data;
/** We create one watcher for each new lb_policy that is returned from a resolver,
to watch for state changes from the lb_policy. When a state change is seen, we
update the channel, and create a new watcher */
typedef struct {
channel_data *chand;
grpc_iomgr_closure on_changed;
grpc_connectivity_state state;
grpc_lb_policy *lb_policy;
} lb_policy_connectivity_watcher;
typedef enum {
CALL_CREATED,
CALL_WAITING_FOR_SEND,
@ -132,7 +145,7 @@ static void handle_op_after_cancellation(grpc_call_element *elem,
mdb.list.head = &calld->status;
mdb.list.tail = &calld->details;
mdb.garbage.head = mdb.garbage.tail = NULL;
mdb.deadline = gpr_inf_future;
mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
grpc_sopb_add_metadata(op->recv_ops, mdb);
*op->recv_state = GRPC_STREAM_CLOSED;
op->on_done_recv->cb(op->on_done_recv->cb_arg, 1);
@ -236,21 +249,6 @@ static void picked_target(void *arg, int iomgr_success) {
}
}
static void pick_target(grpc_lb_policy *lb_policy, call_data *calld) {
grpc_metadata_batch *initial_metadata;
grpc_transport_stream_op *op = &calld->waiting_op;
GPR_ASSERT(op->bind_pollset);
GPR_ASSERT(op->send_ops);
GPR_ASSERT(op->send_ops->nops >= 1);
GPR_ASSERT(op->send_ops->ops[0].type == GRPC_OP_METADATA);
initial_metadata = &op->send_ops->ops[0].data.metadata;
grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld);
grpc_lb_policy_pick(lb_policy, op->bind_pollset, initial_metadata,
&calld->picked_channel, &calld->async_setup_task);
}
static grpc_iomgr_closure *merge_into_waiting_op(
grpc_call_element *elem, grpc_transport_stream_op *new_op) {
call_data *calld = elem->call_data;
@ -280,6 +278,26 @@ static grpc_iomgr_closure *merge_into_waiting_op(
return consumed_op;
}
static char *cc_get_peer(grpc_call_element *elem) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_subchannel_call *subchannel_call;
char *result;
gpr_mu_lock(&calld->mu_state);
if (calld->state == CALL_ACTIVE) {
subchannel_call = calld->subchannel_call;
GRPC_SUBCHANNEL_CALL_REF(subchannel_call, "get_peer");
gpr_mu_unlock(&calld->mu_state);
result = grpc_subchannel_call_get_peer(subchannel_call);
GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "get_peer");
return result;
} else {
gpr_mu_unlock(&calld->mu_state);
return grpc_channel_get_target(chand->master);
}
}
static void perform_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op,
int continuation) {
@ -358,12 +376,23 @@ static void perform_transport_stream_op(grpc_call_element *elem,
gpr_mu_lock(&chand->mu_config);
lb_policy = chand->lb_policy;
if (lb_policy) {
grpc_transport_stream_op *op = &calld->waiting_op;
grpc_pollset *bind_pollset = op->bind_pollset;
grpc_metadata_batch *initial_metadata = &op->send_ops->ops[0].data.metadata;
GRPC_LB_POLICY_REF(lb_policy, "pick");
gpr_mu_unlock(&chand->mu_config);
calld->state = CALL_WAITING_FOR_PICK;
GPR_ASSERT(op->bind_pollset);
GPR_ASSERT(op->send_ops);
GPR_ASSERT(op->send_ops->nops >= 1);
GPR_ASSERT(
op->send_ops->ops[0].type == GRPC_OP_METADATA);
gpr_mu_unlock(&calld->mu_state);
pick_target(lb_policy, calld);
grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld);
grpc_lb_policy_pick(lb_policy, bind_pollset, initial_metadata,
&calld->picked_channel, &calld->async_setup_task);
GRPC_LB_POLICY_UNREF(lb_policy, "pick");
} else if (chand->resolver != NULL) {
@ -392,16 +421,53 @@ static void cc_start_transport_stream_op(grpc_call_element *elem,
perform_transport_stream_op(elem, op, 0);
}
static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state);
static void on_lb_policy_state_changed(void *arg, int iomgr_success) {
lb_policy_connectivity_watcher *w = arg;
gpr_mu_lock(&w->chand->mu_config);
/* check if the notification is for a stale policy */
if (w->lb_policy == w->chand->lb_policy) {
grpc_connectivity_state_set(&w->chand->state_tracker, w->state,
"lb_changed");
if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
watch_lb_policy(w->chand, w->lb_policy, w->state);
}
}
gpr_mu_unlock(&w->chand->mu_config);
GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy");
gpr_free(w);
}
static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) {
lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy");
w->chand = chand;
grpc_iomgr_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
w->state = current_state;
w->lb_policy = lb_policy;
grpc_lb_policy_notify_on_state_change(lb_policy, &w->state, &w->on_changed);
}
static void cc_on_config_changed(void *arg, int iomgr_success) {
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_resolver *old_resolver;
grpc_iomgr_closure *wakeup_closures = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
int exit_idle = 0;
if (chand->incoming_configuration != NULL) {
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
GRPC_LB_POLICY_REF(lb_policy, "channel");
if (lb_policy != NULL) {
GRPC_LB_POLICY_REF(lb_policy, "channel");
GRPC_LB_POLICY_REF(lb_policy, "config_change");
state = grpc_lb_policy_check_connectivity(lb_policy);
}
grpc_client_config_unref(chand->incoming_configuration);
}
@ -415,13 +481,12 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
wakeup_closures = chand->waiting_for_config_closures;
chand->waiting_for_config_closures = NULL;
}
gpr_mu_unlock(&chand->mu_config);
if (old_lb_policy) {
GRPC_LB_POLICY_UNREF(old_lb_policy, "channel");
if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
exit_idle = 1;
chand->exit_idle_when_lb_policy_arrives = 0;
}
gpr_mu_lock(&chand->mu_config);
if (iomgr_success && chand->resolver) {
grpc_resolver *resolver = chand->resolver;
GRPC_RESOLVER_REF(resolver, "channel-next");
@ -430,11 +495,16 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(resolver, "channel-next");
grpc_connectivity_state_set(&chand->state_tracker, state,
"new_lb+resolver");
if (lb_policy != NULL) {
watch_lb_policy(chand, lb_policy, state);
}
} else {
old_resolver = chand->resolver;
chand->resolver = NULL;
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
gpr_mu_unlock(&chand->mu_config);
if (old_resolver != NULL) {
grpc_resolver_shutdown(old_resolver);
@ -442,12 +512,24 @@ static void cc_on_config_changed(void *arg, int iomgr_success) {
}
}
if (exit_idle) {
grpc_lb_policy_exit_idle(lb_policy);
GRPC_LB_POLICY_UNREF(lb_policy, "exit_idle");
}
if (old_lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(old_lb_policy, "channel");
}
while (wakeup_closures) {
grpc_iomgr_closure *next = wakeup_closures->next;
grpc_iomgr_add_callback(wakeup_closures);
wakeup_closures->cb(wakeup_closures->cb_arg, 1);
wakeup_closures = next;
}
if (lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(lb_policy, "config_change");
}
GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver");
}
@ -471,20 +553,22 @@ static void cc_start_transport_op(grpc_channel_element *elem,
op->connectivity_state = NULL;
}
if (!is_empty(op, sizeof(*op))) {
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "broadcast");
}
}
if (op->disconnect && chand->resolver != NULL) {
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
destroy_resolver = chand->resolver;
chand->resolver = NULL;
if (chand->lb_policy != NULL) {
grpc_lb_policy_shutdown(chand->lb_policy);
}
}
if (!is_empty(op, sizeof(*op))) {
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "broadcast");
GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
chand->lb_policy = NULL;
}
}
gpr_mu_unlock(&chand->mu_config);
@ -518,7 +602,7 @@ static void init_call_elem(grpc_call_element *elem,
gpr_mu_init(&calld->mu_state);
calld->elem = elem;
calld->state = CALL_CREATED;
calld->deadline = gpr_inf_future;
calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
/* Destructor for call_data */
@ -565,10 +649,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
gpr_mu_init(&chand->mu_config);
chand->mdctx = metadata_context;
chand->master = master;
grpc_pollset_set_init(&chand->pollset_set);
grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed,
chand);
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE);
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel");
}
/* Destructor for channel_data */
@ -582,6 +667,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
if (chand->lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
}
grpc_connectivity_state_destroy(&chand->state_tracker);
grpc_pollset_set_destroy(&chand->pollset_set);
gpr_mu_destroy(&chand->mu_config);
}
@ -594,6 +681,7 @@ const grpc_channel_filter grpc_client_channel_filter = {
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
cc_get_peer,
"client-channel",
};
@ -609,3 +697,47 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element *elem, int try_to_connect) {
channel_data *chand = elem->channel_data;
grpc_connectivity_state out;
gpr_mu_lock(&chand->mu_config);
out = grpc_connectivity_state_check(&chand->state_tracker);
if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
if (chand->lb_policy != NULL) {
grpc_lb_policy_exit_idle(chand->lb_policy);
} else {
chand->exit_idle_when_lb_policy_arrives = 1;
}
}
gpr_mu_unlock(&chand->mu_config);
return out;
}
void grpc_client_channel_watch_connectivity_state(
grpc_channel_element *elem, grpc_connectivity_state *state,
grpc_iomgr_closure *on_complete) {
channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu_config);
grpc_connectivity_state_notify_on_state_change(&chand->state_tracker, state,
on_complete);
gpr_mu_unlock(&chand->mu_config);
}
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
return &chand->pollset_set;
}
void grpc_client_channel_add_interested_party(grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_add_pollset(&chand->pollset_set, pollset);
}
void grpc_client_channel_del_interested_party(grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_del_pollset(&chand->pollset_set, pollset);
}

@ -52,4 +52,18 @@ extern const grpc_channel_filter grpc_client_channel_filter;
void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver *resolver);
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element *elem, int try_to_connect);
void grpc_client_channel_watch_connectivity_state(
grpc_channel_element *elem, grpc_connectivity_state *state,
grpc_iomgr_closure *on_complete);
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem);
void grpc_client_channel_add_interested_party(grpc_channel_element *channel,
grpc_pollset *pollset);
void grpc_client_channel_del_interested_party(grpc_channel_element *channel,
grpc_pollset *pollset);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */

@ -0,0 +1,328 @@
/*
*
* 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 <assert.h>
#include <string.h>
#include <grpc/compression.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
#include "src/core/compression/message_compress.h"
typedef struct call_data {
gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
grpc_linked_mdelem compression_algorithm_storage;
int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */
int written_initial_metadata; /**< Already processed initial md? */
/** Compression algorithm we'll try to use. It may be given by incoming
* metadata, or by the channel's default compression settings. */
grpc_compression_algorithm compression_algorithm;
/** If true, contents of \a compression_algorithm are authoritative */
int has_compression_algorithm;
} call_data;
typedef struct channel_data {
/** Metadata key for the incoming (requested) compression algorithm */
grpc_mdstr *mdstr_request_compression_algorithm_key;
/** Metadata key for the outgoing (used) compression algorithm */
grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
/** Precomputed metadata elements for all available compression algorithms */
grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
} channel_data;
/** Compress \a slices in place using \a algorithm. Returns 1 if compression did
* actually happen, 0 otherwise (for example if the compressed output size was
* larger than the raw input).
*
* Returns 1 if the data was actually compress and 0 otherwise. */
static int compress_send_sb(grpc_compression_algorithm algorithm,
gpr_slice_buffer *slices) {
int did_compress;
gpr_slice_buffer tmp;
gpr_slice_buffer_init(&tmp);
did_compress = grpc_msg_compress(algorithm, slices, &tmp);
if (did_compress) {
gpr_slice_buffer_swap(slices, &tmp);
}
gpr_slice_buffer_destroy(&tmp);
return did_compress;
}
/** For each \a md element from the incoming metadata, filter out the entry for
* "grpc-encoding", using its value to populate the call data's
* compression_algorithm field. */
static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
if (md->key == channeld->mdstr_request_compression_algorithm_key) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
if (!grpc_compression_algorithm_parse(md_c_str,
&calld->compression_algorithm)) {
gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.",
md_c_str);
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
calld->has_compression_algorithm = 1;
return NULL;
}
return md;
}
static int skip_compression(channel_data *channeld, call_data *calld) {
if (calld->has_compression_algorithm) {
if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
return 1;
}
return 0; /* we have an actual call-specific algorithm */
}
/* no per-call compression override */
return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE;
}
/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying
* the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length,
* flags indicating compression is in effect) and replaces \a send_ops with it.
* */
static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
grpc_call_element *elem) {
size_t i;
call_data *calld = elem->call_data;
int new_slices_added = 0; /* GPR_FALSE */
grpc_metadata_batch metadata;
grpc_stream_op_buffer new_send_ops;
grpc_sopb_init(&new_send_ops);
for (i = 0; i < send_ops->nops; i++) {
grpc_stream_op *sop = &send_ops->ops[i];
switch (sop->type) {
case GRPC_OP_BEGIN_MESSAGE:
grpc_sopb_add_begin_message(
&new_send_ops, calld->slices.length,
sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS);
break;
case GRPC_OP_SLICE:
/* Once we reach the slices section of the original buffer, simply add
* all the new (compressed) slices. We obviously want to do this only
* once, hence the "new_slices_added" guard. */
if (!new_slices_added) {
size_t j;
for (j = 0; j < calld->slices.count; ++j) {
grpc_sopb_add_slice(&new_send_ops,
gpr_slice_ref(calld->slices.slices[j]));
}
new_slices_added = 1; /* GPR_TRUE */
}
break;
case GRPC_OP_METADATA:
/* move the metadata to the new buffer. */
grpc_metadata_batch_move(&metadata, &sop->data.metadata);
grpc_sopb_add_metadata(&new_send_ops, metadata);
break;
case GRPC_NO_OP:
break;
}
}
grpc_sopb_swap(send_ops, &new_send_ops);
grpc_sopb_destroy(&new_send_ops);
}
/** Filter's "main" function, called for any incoming grpc_transport_stream_op
* instance that holds a non-zero number of send operations, accesible to this
* function in \a send_ops. */
static void process_send_ops(grpc_call_element *elem,
grpc_stream_op_buffer *send_ops) {
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
size_t i;
int did_compress = 0;
/* In streaming calls, we need to reset the previously accumulated slices */
gpr_slice_buffer_reset_and_unref(&calld->slices);
for (i = 0; i < send_ops->nops; ++i) {
grpc_stream_op *sop = &send_ops->ops[i];
switch (sop->type) {
case GRPC_OP_BEGIN_MESSAGE:
/* buffer up slices until we've processed all the expected ones (as
* given by GRPC_OP_BEGIN_MESSAGE) */
calld->remaining_slice_bytes = sop->data.begin_message.length;
if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) {
calld->has_compression_algorithm = 1; /* GPR_TRUE */
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
break;
case GRPC_OP_METADATA:
if (!calld->written_initial_metadata) {
/* Parse incoming request for compression. If any, it'll be available
* at calld->compression_algorithm */
grpc_metadata_batch_filter(&(sop->data.metadata),
compression_md_filter, elem);
if (!calld->has_compression_algorithm) {
/* If no algorithm was found in the metadata and we aren't
* exceptionally skipping compression, fall back to the channel
* default */
calld->compression_algorithm =
channeld->default_compression_algorithm;
calld->has_compression_algorithm = 1; /* GPR_TRUE */
}
grpc_metadata_batch_add_tail(
&(sop->data.metadata), &calld->compression_algorithm_storage,
GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms
[calld->compression_algorithm]));
calld->written_initial_metadata = 1; /* GPR_TRUE */
}
break;
case GRPC_OP_SLICE:
if (skip_compression(channeld, calld)) continue;
GPR_ASSERT(calld->remaining_slice_bytes > 0);
/* Increase input ref count, gpr_slice_buffer_add takes ownership. */
gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
calld->remaining_slice_bytes -= GPR_SLICE_LENGTH(sop->data.slice);
if (calld->remaining_slice_bytes == 0) {
did_compress =
compress_send_sb(calld->compression_algorithm, &calld->slices);
}
break;
case GRPC_NO_OP:
break;
}
}
/* Modify the send_ops stream_op_buffer depending on whether compression was
* carried out */
if (did_compress) {
finish_compressed_sopb(send_ops, elem);
}
}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void compress_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
if (op->send_ops && op->send_ops->nops > 0) {
process_send_ops(elem, op->send_ops);
}
/* pass control down the stack */
grpc_call_next_op(elem, op);
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_stream_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
/* initialize members */
gpr_slice_buffer_init(&calld->slices);
calld->has_compression_algorithm = 0;
calld->written_initial_metadata = 0; /* GPR_FALSE */
if (initial_op) {
if (initial_op->send_ops && initial_op->send_ops->nops > 0) {
process_send_ops(elem, initial_op->send_ops);
}
}
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
gpr_slice_buffer_destroy(&calld->slices);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
channeld->default_compression_algorithm =
grpc_channel_args_get_compression_algorithm(args);
channeld->mdstr_request_compression_algorithm_key =
grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0);
channeld->mdstr_outgoing_compression_algorithm_key =
grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
char *algorithm_name;
GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
channeld->mdelem_compression_algorithms[algo_idx] =
grpc_mdelem_from_metadata_strings(
mdctx,
GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
grpc_mdstr_from_string(mdctx, algorithm_name, 0));
}
GPR_ASSERT(!is_last);
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key);
GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key);
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT;
++algo_idx) {
GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]);
}
}
const grpc_channel_filter grpc_compress_filter = {
compress_start_transport_stream_op,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
"compress"};

@ -0,0 +1,65 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H
#define GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H
#include "src/core/channel/channel_stack.h"
#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "internal:grpc-encoding-request"
/** Compression filter for outgoing data.
*
* See <grpc/compression.h> for the available compression settings.
*
* Compression settings may come from:
* - Channel configuration, as established at channel creation time.
* - The metadata accompanying the outgoing data to be compressed. This is
* taken as a request only. We may choose not to honor it. The metadata key
* is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY.
*
* Compression can be disabled for concrete messages (for instance in order to
* prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in
* the BEGIN_MESSAGE flags.
*
* The attempted compression mechanism is added to the resulting initial
* metadata under the'grpc-encoding' key.
*
* If compression is actually performed, BEGIN_MESSAGE's flag is modified to
* incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of the
* aforementioned 'grpc-encoding' metadata value, data will pass through
* uncompressed. */
extern const grpc_channel_filter grpc_compress_filter;
#endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */

@ -119,6 +119,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
grpc_transport_destroy(cd->transport);
}
static char *con_get_peer(grpc_call_element *elem) {
channel_data *chand = elem->channel_data;
return grpc_transport_get_peer(chand->transport);
}
const grpc_channel_filter grpc_connected_channel_filter = {
con_start_transport_stream_op,
con_start_transport_op,
@ -128,6 +133,7 @@ const grpc_channel_filter grpc_connected_channel_filter = {
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
con_get_peer,
"connected",
};

@ -32,13 +32,17 @@
#include "src/core/channel/http_client_filter.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/support/string.h"
typedef struct call_data {
grpc_linked_mdelem method;
grpc_linked_mdelem scheme;
grpc_linked_mdelem te_trailers;
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
int sent_initial_metadata;
int got_initial_metadata;
@ -58,6 +62,8 @@ typedef struct channel_data {
grpc_mdelem *scheme;
grpc_mdelem *content_type;
grpc_mdelem *status;
/** complete user agent mdelem */
grpc_mdelem *user_agent;
} channel_data;
/* used to silence 'variable not used' warnings */
@ -92,6 +98,18 @@ static void hc_on_recv(void *user_data, int success) {
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
}
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
channel_data *channeld = elem->channel_data;
/* eat the things we'd like to set ourselves */
if (md->key == channeld->method->key) return NULL;
if (md->key == channeld->scheme->key) return NULL;
if (md->key == channeld->te_trailers->key) return NULL;
if (md->key == channeld->content_type->key) return NULL;
if (md->key == channeld->user_agent->key) return NULL;
return md;
}
static void hc_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
@ -105,6 +123,7 @@ static void hc_mutate_op(grpc_call_element *elem,
grpc_stream_op *op = &ops[i];
if (op->type != GRPC_OP_METADATA) continue;
calld->sent_initial_metadata = 1;
grpc_metadata_batch_filter(&op->data.metadata, client_strip_filter, elem);
/* Send : prefixed headers, which have to be before any application
layer headers. */
grpc_metadata_batch_add_head(&op->data.metadata, &calld->method,
@ -115,6 +134,8 @@ static void hc_mutate_op(grpc_call_element *elem,
GRPC_MDELEM_REF(channeld->te_trailers));
grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type,
GRPC_MDELEM_REF(channeld->content_type));
grpc_metadata_batch_add_tail(&op->data.metadata, &calld->user_agent,
GRPC_MDELEM_REF(channeld->user_agent));
break;
}
}
@ -169,6 +190,55 @@ static const char *scheme_from_args(const grpc_channel_args *args) {
return "http";
}
static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
const grpc_channel_args *args) {
gpr_strvec v;
size_t i;
int is_first = 1;
char *tmp;
grpc_mdstr *result;
gpr_strvec_init(&v);
for (i = 0; args && i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
if (args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
GRPC_ARG_PRIMARY_USER_AGENT_STRING);
} else {
if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
is_first = 0;
gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
}
}
}
gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
grpc_version_string(), GPR_PLATFORM_STRING);
is_first = 0;
gpr_strvec_add(&v, tmp);
for (i = 0; args && i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
if (args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
GRPC_ARG_SECONDARY_USER_AGENT_STRING);
} else {
if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
is_first = 0;
gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
}
}
}
tmp = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v);
result = grpc_mdstr_from_string(mdctx, tmp, 0);
gpr_free(tmp);
return result;
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args, grpc_mdctx *mdctx,
@ -189,6 +259,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
channeld->content_type =
grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
channeld->user_agent = grpc_mdelem_from_metadata_strings(
mdctx, grpc_mdstr_from_string(mdctx, "user-agent", 0),
user_agent_from_args(mdctx, args));
}
/* Destructor for channel data */
@ -201,9 +274,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
GRPC_MDELEM_UNREF(channeld->scheme);
GRPC_MDELEM_UNREF(channeld->content_type);
GRPC_MDELEM_UNREF(channeld->status);
GRPC_MDELEM_UNREF(channeld->user_agent);
}
const grpc_channel_filter grpc_http_client_filter = {
hc_start_transport_op, grpc_channel_next_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "http-client"};
init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer,
"http-client"};

@ -250,9 +250,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
channeld->path_key = grpc_mdstr_from_string(mdctx, ":path");
channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority");
channeld->host_key = grpc_mdstr_from_string(mdctx, "host");
channeld->path_key = grpc_mdstr_from_string(mdctx, ":path", 0);
channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority", 0);
channeld->host_key = grpc_mdstr_from_string(mdctx, "host", 0);
channeld->content_type =
grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
@ -280,4 +280,5 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
const grpc_channel_filter grpc_http_server_filter = {
hs_start_transport_op, grpc_channel_next_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "http-server"};
init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer,
"http-server"};

@ -127,4 +127,5 @@ const grpc_channel_filter grpc_no_op_filter = {noop_start_transport_stream_op,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
"no-op"};

@ -1,7 +1,7 @@
Client Configuration Support for GRPC
=====================================
This library provides high level configuration machinery to construct client
This library provides high level configuration machinery to construct client
channels and load balance between them.
Each grpc_channel is created with a grpc_resolver. It is the resolver's duty
@ -22,32 +22,33 @@ Load Balancing
--------------
Load balancing configuration is provided by a grpc_lb_policy object, stored as
part of grpc_client_config.
part of grpc_client_config.
A load balancing policies primary job is to pick a target server given only the
initial metadata for a request. It does this by providing a grpc_subchannel
The primary job of the load balancing policies is to pick a target server given only the
initial metadata for a request. It does this by providing a grpc_subchannel
object to the owning channel.
Sub-Channels
------------
A sub-channel provides a connection to a server for a client channel. It has a
connectivity state like a regular channel, and so can be connected or
disconnected. This connectivity state can be used to inform load balancing
A sub-channel provides a connection to a server for a client channel. It has a
connectivity state like a regular channel, and so can be connected or
disconnected. This connectivity state can be used to inform load balancing
decisions (for example, by avoiding disconnected backends).
Configured sub-channels are fully setup to participate in the grpc data plane.
Their behavior is specified by a set of grpc channel filters defined at their
construction. To customize this behavior, resolvers build grpc_subchannel_factory
objects, which use the decorator pattern to customize construction arguments for
concrete grpc_subchannel instances.
construction. To customize this behavior, resolvers build
grpc_subchannel_factory objects, which use the decorator pattern to customize
construction arguments for concrete grpc_subchannel instances.
Naming for GRPC
===============
Names in GRPC are represented by a URI.
Names in GRPC are represented by a URI (as defined in
[RFC 3986](https://tools.ietf.org/html/rfc3986)).
The following schemes are currently supported:
@ -55,6 +56,11 @@ dns:///host:port - dns schemes are currently supported so long as authority is
empty (authority based dns resolution is expected in a future
release)
unix:path - the unix scheme is used to create and connect to unix domain
sockets - the authority must be empty, and the path represents
the absolute or relative path to the desired socket
unix:path - the unix scheme is used to create and connect to unix domain
sockets - the authority must be empty, and the path
represents the absolute or relative path to the desired
socket
ipv4:host:port - a pre-resolved ipv4 dotted decimal address/port combination
ipv6:[host]:port - a pre-resolved ipv6 address/port combination

@ -62,6 +62,8 @@ typedef struct {
grpc_subchannel *selected;
/** have we started picking? */
int started_picking;
/** are we shut down? */
int shutdown;
/** which subchannel are we watching? */
size_t checking_subchannel;
/** what is the connectivity of that channel? */
@ -73,12 +75,30 @@ typedef struct {
grpc_connectivity_state_tracker state_tracker;
} pick_first_lb_policy;
static void del_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void add_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
void pf_destroy(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
del_interested_parties_locked(p);
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first");
}
grpc_connectivity_state_destroy(&p->state_tracker);
gpr_free(p->subchannels);
gpr_mu_destroy(&p->mu);
gpr_free(p);
@ -88,12 +108,35 @@ void pf_shutdown(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
del_interested_parties_locked(p);
p->shutdown = 1;
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_iomgr_add_delayed_callback(pp->on_complete, 0);
gpr_free(pp);
}
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_FATAL_FAILURE,
"shutdown");
gpr_mu_unlock(&p->mu);
}
static void start_picking(pick_first_lb_policy *p) {
p->started_picking = 1;
p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE;
GRPC_LB_POLICY_REF(&p->base, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change(p->subchannels[p->checking_subchannel],
&p->checking_connectivity,
&p->connectivity_changed);
}
void pf_exit_idle(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
gpr_mu_lock(&p->mu);
if (!p->started_picking) {
start_picking(p);
}
gpr_mu_unlock(&p->mu);
}
@ -109,13 +152,7 @@ void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
on_complete->cb(on_complete->cb_arg, 1);
} else {
if (!p->started_picking) {
p->started_picking = 1;
p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE;
GRPC_LB_POLICY_REF(pol, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
start_picking(p);
}
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pollset);
@ -129,77 +166,97 @@ void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
}
}
static void del_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void add_interested_parties_locked(pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pp->pollset);
}
}
static void pf_connectivity_changed(void *arg, int iomgr_success) {
pick_first_lb_policy *p = arg;
pending_pick *pp;
int unref = 0;
gpr_mu_lock(&p->mu);
loop:
switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY:
p->selected = p->subchannels[p->checking_subchannel];
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = p->selected;
grpc_subchannel_del_interested_party(p->selected, pp->pollset);
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
del_interested_parties_locked(p);
p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
if (p->shutdown) {
unref = 1;
} else if (p->selected != NULL) {
grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity,
"selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(p);
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first");
if (p->num_subchannels == 0) {
p->selected, &p->checking_connectivity, &p->connectivity_changed);
} else {
unref = 1;
}
} else {
loop:
switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
"connecting_ready");
p->selected = p->subchannels[p->checking_subchannel];
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
*pp->target = p->selected;
grpc_subchannel_del_interested_party(p->selected, pp->pollset);
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
} else {
p->checking_subchannel %= p->num_subchannels;
grpc_subchannel_notify_on_state_change(
p->selected, &p->checking_connectivity, &p->connectivity_changed);
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure");
del_interested_parties_locked(p);
p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
}
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
} else {
goto loop;
}
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(&p->state_tracker, p->checking_connectivity,
"connecting_changed");
grpc_subchannel_notify_on_state_change(
p->subchannels[p->checking_subchannel], &p->checking_connectivity,
&p->connectivity_changed);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(p);
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(p->subchannels[p->num_subchannels], "pick_first");
if (p->num_subchannels == 0) {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE,
"no_more_channels");
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_iomgr_add_delayed_callback(pp->on_complete, 1);
gpr_free(pp);
}
unref = 1;
} else {
grpc_connectivity_state_set(&p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"subchannel_failed");
p->checking_subchannel %= p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(p);
goto loop;
}
}
}
gpr_mu_unlock(&p->mu);
if (unref) {
@ -249,8 +306,13 @@ static void pf_notify_on_state_change(grpc_lb_policy *pol,
}
static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
pf_destroy, pf_shutdown, pf_pick,
pf_broadcast, pf_check_connectivity, pf_notify_on_state_change};
pf_destroy,
pf_shutdown,
pf_pick,
pf_exit_idle,
pf_broadcast,
pf_check_connectivity,
pf_notify_on_state_change};
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
size_t num_subchannels) {
@ -260,6 +322,8 @@ grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_subchannels);
p->num_subchannels = num_subchannels;
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"pick_first");
memcpy(p->subchannels, subchannels,
sizeof(grpc_subchannel *) * num_subchannels);
grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);

@ -36,6 +36,8 @@
#include "src/core/client_config/lb_policy.h"
/** Returns a load balancing policy instance that picks up the first subchannel
* from \a subchannels to succesfully connect */
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
size_t num_subchannels);

@ -77,3 +77,18 @@ void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) {
policy->vtable->broadcast(policy, op);
}
void grpc_lb_policy_exit_idle(grpc_lb_policy *policy) {
policy->vtable->exit_idle(policy);
}
void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy,
grpc_connectivity_state *state,
grpc_iomgr_closure *closure) {
policy->vtable->notify_on_state_change(policy, state, closure);
}
grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_lb_policy *policy) {
return policy->vtable->check_connectivity(policy);
}

@ -59,6 +59,9 @@ struct grpc_lb_policy_vtable {
grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
grpc_iomgr_closure *on_complete);
/** try to enter a READY connectivity state */
void (*exit_idle)(grpc_lb_policy *policy);
/** broadcast a transport op to all subchannels */
void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op);
@ -106,4 +109,13 @@ void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op);
void grpc_lb_policy_exit_idle(grpc_lb_policy *policy);
void grpc_lb_policy_notify_on_state_change(grpc_lb_policy *policy,
grpc_connectivity_state *state,
grpc_iomgr_closure *closure);
grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_lb_policy *policy);
#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */

@ -0,0 +1,299 @@
/*
*
* 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 <grpc/support/port_platform.h>
#include "src/core/client_config/resolvers/sockaddr_resolver.h"
#include <stdio.h>
#include <string.h>
#ifdef GPR_POSIX_SOCKET
#include <sys/un.h>
#endif
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/string_util.h>
#include "src/core/client_config/lb_policies/pick_first.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/support/string.h"
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** refcount */
gpr_refcount refs;
/** subchannel factory */
grpc_subchannel_factory *subchannel_factory;
/** load balancing policy factory */
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels);
/** the address that we've 'resolved' */
struct sockaddr_storage addr;
int addr_len;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** have we published? */
int published;
/** pending next completion, or NULL */
grpc_iomgr_closure *next_completion;
/** target config address for next completion */
grpc_client_config **target_config;
} sockaddr_resolver;
static void sockaddr_destroy(grpc_resolver *r);
static void sockaddr_maybe_finish_next_locked(sockaddr_resolver *r);
static void sockaddr_shutdown(grpc_resolver *r);
static void sockaddr_channel_saw_error(grpc_resolver *r,
struct sockaddr *failing_address,
int failing_address_len);
static void sockaddr_next(grpc_resolver *r, grpc_client_config **target_config,
grpc_iomgr_closure *on_complete);
static const grpc_resolver_vtable sockaddr_resolver_vtable = {
sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error,
sockaddr_next};
static void sockaddr_shutdown(grpc_resolver *resolver) {
sockaddr_resolver *r = (sockaddr_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_config = NULL;
/* TODO(ctiller): add delayed callback */
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
}
gpr_mu_unlock(&r->mu);
}
static void sockaddr_channel_saw_error(grpc_resolver *resolver,
struct sockaddr *sa, int len) {}
static void sockaddr_next(grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_iomgr_closure *on_complete) {
sockaddr_resolver *r = (sockaddr_resolver *)resolver;
gpr_mu_lock(&r->mu);
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_config = target_config;
sockaddr_maybe_finish_next_locked(r);
gpr_mu_unlock(&r->mu);
}
static void sockaddr_maybe_finish_next_locked(sockaddr_resolver *r) {
grpc_client_config *cfg;
grpc_lb_policy *lb_policy;
grpc_subchannel *subchannel;
grpc_subchannel_args args;
if (r->next_completion != NULL && !r->published) {
cfg = grpc_client_config_create();
memset(&args, 0, sizeof(args));
args.addr = (struct sockaddr *)&r->addr;
args.addr_len = r->addr_len;
subchannel =
grpc_subchannel_factory_create_subchannel(r->subchannel_factory, &args);
lb_policy = r->lb_policy_factory(&subchannel, 1);
grpc_client_config_set_lb_policy(cfg, lb_policy);
GRPC_LB_POLICY_UNREF(lb_policy, "unix");
r->published = 1;
*r->target_config = cfg;
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
}
}
static void sockaddr_destroy(grpc_resolver *gr) {
sockaddr_resolver *r = (sockaddr_resolver *)gr;
gpr_mu_destroy(&r->mu);
grpc_subchannel_factory_unref(r->subchannel_factory);
gpr_free(r);
}
#ifdef GPR_POSIX_SOCKET
static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, int *len) {
struct sockaddr_un *un = (struct sockaddr_un *)addr;
un->sun_family = AF_UNIX;
strcpy(un->sun_path, uri->path);
*len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
return 1;
}
#endif
static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, int *len) {
const char *host_port = uri->path;
char *host;
char *port;
int port_num;
int result = 0;
struct sockaddr_in *in = (struct sockaddr_in *)addr;
if (*host_port == '/') ++host_port;
if (!gpr_split_host_port(host_port, &host, &port)) {
return 0;
}
memset(in, 0, sizeof(*in));
*len = sizeof(*in);
in->sin_family = AF_INET;
if (inet_pton(AF_INET, host, &in->sin_addr) == 0) {
gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
goto done;
}
if (port != NULL) {
if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
port_num > 65535) {
gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
goto done;
}
in->sin_port = htons(port_num);
} else {
gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
goto done;
}
result = 1;
done:
gpr_free(host);
gpr_free(port);
return result;
}
static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr, int *len) {
const char *host_port = uri->path;
char *host;
char *port;
int port_num;
int result = 0;
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
if (*host_port == '/') ++host_port;
if (!gpr_split_host_port(host_port, &host, &port)) {
return 0;
}
memset(in6, 0, sizeof(*in6));
*len = sizeof(*in6);
in6->sin6_family = AF_INET6;
if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
goto done;
}
if (port != NULL) {
if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
port_num > 65535) {
gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
goto done;
}
in6->sin6_port = htons(port_num);
} else {
gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
goto done;
}
result = 1;
done:
gpr_free(host);
gpr_free(port);
return result;
}
static grpc_resolver *sockaddr_create(
grpc_uri *uri,
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels),
grpc_subchannel_factory *subchannel_factory,
int parse(grpc_uri *uri, struct sockaddr_storage *dst, int *len)) {
sockaddr_resolver *r;
if (0 != strcmp(uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported");
return NULL;
}
r = gpr_malloc(sizeof(sockaddr_resolver));
memset(r, 0, sizeof(*r));
if (!parse(uri, &r->addr, &r->addr_len)) {
gpr_free(r);
return NULL;
}
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
r->subchannel_factory = subchannel_factory;
r->lb_policy_factory = lb_policy_factory;
grpc_subchannel_factory_ref(subchannel_factory);
return &r->base;
}
/*
* FACTORY
*/
static void sockaddr_factory_ref(grpc_resolver_factory *factory) {}
static void sockaddr_factory_unref(grpc_resolver_factory *factory) {}
#define DECL_FACTORY(name) \
static grpc_resolver *name##_factory_create_resolver( \
grpc_resolver_factory *factory, grpc_uri *uri, \
grpc_subchannel_factory *subchannel_factory) { \
return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \
subchannel_factory, parse_##name); \
} \
static const grpc_resolver_factory_vtable name##_factory_vtable = { \
sockaddr_factory_ref, sockaddr_factory_unref, \
name##_factory_create_resolver}; \
static grpc_resolver_factory name##_resolver_factory = { \
&name##_factory_vtable}; \
grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \
return &name##_resolver_factory; \
}
#ifdef GPR_POSIX_SOCKET
DECL_FACTORY(unix)
#endif
DECL_FACTORY(ipv4)
DECL_FACTORY(ipv6)

@ -38,7 +38,13 @@
#include "src/core/client_config/resolver_factory.h"
grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void);
grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void);
#ifdef GPR_POSIX_SOCKET
/** Create a unix resolver factory */
grpc_resolver_factory *grpc_unix_resolver_factory_create(void);
#endif
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H */

@ -1,195 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/client_config/resolvers/unix_resolver_posix.h"
#include <string.h>
#include <sys/un.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include "src/core/client_config/lb_policies/pick_first.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/support/string.h"
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** refcount */
gpr_refcount refs;
/** subchannel factory */
grpc_subchannel_factory *subchannel_factory;
/** load balancing policy factory */
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels);
/** the address that we've 'resolved' */
struct sockaddr_un addr;
int addr_len;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** have we published? */
int published;
/** pending next completion, or NULL */
grpc_iomgr_closure *next_completion;
/** target config address for next completion */
grpc_client_config **target_config;
} unix_resolver;
static void unix_destroy(grpc_resolver *r);
static void unix_maybe_finish_next_locked(unix_resolver *r);
static void unix_shutdown(grpc_resolver *r);
static void unix_channel_saw_error(grpc_resolver *r,
struct sockaddr *failing_address,
int failing_address_len);
static void unix_next(grpc_resolver *r, grpc_client_config **target_config,
grpc_iomgr_closure *on_complete);
static const grpc_resolver_vtable unix_resolver_vtable = {
unix_destroy, unix_shutdown, unix_channel_saw_error, unix_next};
static void unix_shutdown(grpc_resolver *resolver) {
unix_resolver *r = (unix_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_config = NULL;
/* TODO(ctiller): add delayed callback */
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
}
gpr_mu_unlock(&r->mu);
}
static void unix_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
int len) {}
static void unix_next(grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_iomgr_closure *on_complete) {
unix_resolver *r = (unix_resolver *)resolver;
gpr_mu_lock(&r->mu);
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_config = target_config;
unix_maybe_finish_next_locked(r);
gpr_mu_unlock(&r->mu);
}
static void unix_maybe_finish_next_locked(unix_resolver *r) {
grpc_client_config *cfg;
grpc_lb_policy *lb_policy;
grpc_subchannel *subchannel;
grpc_subchannel_args args;
if (r->next_completion != NULL && !r->published) {
cfg = grpc_client_config_create();
memset(&args, 0, sizeof(args));
args.addr = (struct sockaddr *)&r->addr;
args.addr_len = r->addr_len;
subchannel =
grpc_subchannel_factory_create_subchannel(r->subchannel_factory, &args);
lb_policy = r->lb_policy_factory(&subchannel, 1);
grpc_client_config_set_lb_policy(cfg, lb_policy);
GRPC_LB_POLICY_UNREF(lb_policy, "unix");
r->published = 1;
*r->target_config = cfg;
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
}
}
static void unix_destroy(grpc_resolver *gr) {
unix_resolver *r = (unix_resolver *)gr;
gpr_mu_destroy(&r->mu);
grpc_subchannel_factory_unref(r->subchannel_factory);
gpr_free(r);
}
static grpc_resolver *unix_create(
grpc_uri *uri,
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels),
grpc_subchannel_factory *subchannel_factory) {
unix_resolver *r;
if (0 != strcmp(uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported");
return NULL;
}
r = gpr_malloc(sizeof(unix_resolver));
memset(r, 0, sizeof(*r));
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &unix_resolver_vtable);
r->subchannel_factory = subchannel_factory;
r->lb_policy_factory = lb_policy_factory;
r->addr.sun_family = AF_UNIX;
strcpy(r->addr.sun_path, uri->path);
r->addr_len = strlen(r->addr.sun_path) + sizeof(r->addr.sun_family) + 1;
grpc_subchannel_factory_ref(subchannel_factory);
return &r->base;
}
/*
* FACTORY
*/
static void unix_factory_ref(grpc_resolver_factory *factory) {}
static void unix_factory_unref(grpc_resolver_factory *factory) {}
static grpc_resolver *unix_factory_create_resolver(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory) {
return unix_create(uri, grpc_create_pick_first_lb_policy, subchannel_factory);
}
static const grpc_resolver_factory_vtable unix_factory_vtable = {
unix_factory_ref, unix_factory_unref, unix_factory_create_resolver};
static grpc_resolver_factory unix_resolver_factory = {&unix_factory_vtable};
grpc_resolver_factory *grpc_unix_resolver_factory_create() {
return &unix_resolver_factory;
}
#endif

@ -38,9 +38,17 @@
#include <grpc/support/alloc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/transport/connectivity_state.h"
#include "src/core/surface/channel.h"
#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
typedef struct {
/* all fields protected by subchannel->mu */
@ -94,8 +102,10 @@ struct grpc_subchannel {
grpc_iomgr_closure connected;
/** pollset_set tracking who's interested in a connection
being setup */
grpc_pollset_set pollset_set;
being setup - owned by the master channel (in particular the
client_channel
filter there-in) */
grpc_pollset_set *pollset_set;
/** mutex protecting remaining elements */
gpr_mu mu;
@ -121,6 +131,8 @@ struct grpc_subchannel {
int have_alarm;
/** our alarm */
grpc_alarm alarm;
/** current random value */
gpr_uint32 random;
};
struct grpc_subchannel_call {
@ -132,7 +144,8 @@ struct grpc_subchannel_call {
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1))
static grpc_subchannel_call *create_call(connection *con);
static void connectivity_state_changed_locked(grpc_subchannel *c);
static void connectivity_state_changed_locked(grpc_subchannel *c,
const char *reason);
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c);
static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
static void subchannel_connected(void *subchannel, int iomgr_success);
@ -244,7 +257,6 @@ static void subchannel_destroy(grpc_subchannel *c) {
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
grpc_mdctx_unref(c->mdctx);
grpc_pollset_set_destroy(&c->pollset_set);
grpc_connectivity_state_destroy(&c->state_tracker);
grpc_connector_unref(c->connector);
gpr_free(c);
@ -252,17 +264,23 @@ static void subchannel_destroy(grpc_subchannel *c) {
void grpc_subchannel_add_interested_party(grpc_subchannel *c,
grpc_pollset *pollset) {
grpc_pollset_set_add_pollset(&c->pollset_set, pollset);
grpc_pollset_set_add_pollset(c->pollset_set, pollset);
}
void grpc_subchannel_del_interested_party(grpc_subchannel *c,
grpc_pollset *pollset) {
grpc_pollset_set_del_pollset(&c->pollset_set, pollset);
grpc_pollset_set_del_pollset(c->pollset_set, pollset);
}
static gpr_uint32 random_seed() {
return (gpr_uint32)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC)));
}
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args) {
grpc_subchannel *c = gpr_malloc(sizeof(*c));
grpc_channel_element *parent_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(args->master));
memset(c, 0, sizeof(*c));
c->refs = 1;
c->connector = connector;
@ -277,10 +295,12 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
c->args = grpc_channel_args_copy(args->args);
c->mdctx = args->mdctx;
c->master = args->master;
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
c->random = random_seed();
grpc_mdctx_ref(c->mdctx);
grpc_pollset_set_init(&c->pollset_set);
grpc_iomgr_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
gpr_mu_init(&c->mu);
return c;
}
@ -288,7 +308,7 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
static void continue_connect(grpc_subchannel *c) {
grpc_connect_in_args args;
args.interested_parties = &c->pollset_set;
args.interested_parties = c->pollset_set;
args.addr = c->addr;
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
@ -300,15 +320,16 @@ static void continue_connect(grpc_subchannel *c) {
}
static void start_connect(grpc_subchannel *c) {
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
c->next_attempt = now;
c->backoff_delta = gpr_time_from_seconds(1);
c->backoff_delta = gpr_time_from_seconds(
GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS, GPR_TIMESPAN);
c->next_attempt = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta);
continue_connect(c);
}
static void continue_creating_call(void *arg, int iomgr_success) {
waiting_for_connect *w4c = arg;
grpc_subchannel_del_interested_party(w4c->subchannel, w4c->pollset);
grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target,
w4c->notify);
GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect");
@ -341,9 +362,10 @@ void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset,
grpc_subchannel_add_interested_party(c, pollset);
if (!c->connecting) {
c->connecting = 1;
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "create_call");
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
gpr_mu_unlock(&c->mu);
start_connect(c);
@ -372,7 +394,8 @@ void grpc_subchannel_notify_on_state_change(grpc_subchannel *c,
c->connecting = 1;
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
connectivity_state_changed_locked(c);
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
connectivity_state_changed_locked(c, "state_change");
}
gpr_mu_unlock(&c->mu);
if (do_connect) {
@ -388,7 +411,7 @@ void grpc_subchannel_process_transport_op(grpc_subchannel *c,
gpr_mu_lock(&c->mu);
if (op->disconnect) {
c->disconnected = 1;
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "disconnect");
if (c->have_alarm) {
cancel_alarm = 1;
}
@ -456,13 +479,15 @@ static void on_state_changed(void *p, int iomgr_success) {
destroy_connection = sw->subchannel->active;
}
sw->subchannel->active = NULL;
grpc_connectivity_state_set(&c->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE);
grpc_connectivity_state_set(
&c->state_tracker, c->disconnected ? GRPC_CHANNEL_FATAL_FAILURE
: GRPC_CHANNEL_TRANSIENT_FAILURE,
"connection_failed");
break;
}
done:
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "transport_state_changed");
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
gpr_free(sw);
gpr_mu_unlock(mu);
@ -486,6 +511,8 @@ static void publish_transport(grpc_subchannel *c) {
connection *destroy_connection = NULL;
grpc_channel_element *elem;
gpr_log(GPR_DEBUG, "publish_transport: %p", c->master);
/* build final filter list */
num_filters = c->num_filters + c->connecting_result.num_filters + 1;
filters = gpr_malloc(sizeof(*filters) * num_filters);
@ -519,6 +546,8 @@ static void publish_transport(grpc_subchannel *c) {
gpr_free(sw);
gpr_free(filters);
grpc_channel_stack_destroy(stk);
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GRPC_SUBCHANNEL_UNREF(c, "connecting");
return;
}
@ -536,14 +565,16 @@ static void publish_transport(grpc_subchannel *c) {
memset(&op, 0, sizeof(op));
op.connectivity_state = &sw->connectivity_state;
op.on_connectivity_state_change = &sw->closure;
op.bind_pollset_set = c->pollset_set;
SUBCHANNEL_REF_LOCKED(c, "state_watcher");
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
elem =
grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
elem->filter->start_transport_op(elem, &op);
/* signal completion */
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "connected");
while ((w4c = c->waiting)) {
c->waiting = w4c->next;
grpc_iomgr_add_callback(&w4c->continuation);
@ -558,6 +589,35 @@ static void publish_transport(grpc_subchannel *c) {
}
}
/* Generate a random number between 0 and 1. */
static double generate_uniform_random_number(grpc_subchannel *c) {
c->random = (1103515245 * c->random + 12345) % ((gpr_uint32)1 << 31);
return c->random / (double)((gpr_uint32)1 << 31);
}
/* Update backoff_delta and next_attempt in subchannel */
static void update_reconnect_parameters(grpc_subchannel *c) {
gpr_int32 backoff_delta_millis, jitter;
gpr_int32 max_backoff_millis =
GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
double jitter_range;
backoff_delta_millis =
(gpr_int32)(gpr_time_to_millis(c->backoff_delta) *
GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER);
if (backoff_delta_millis > max_backoff_millis) {
backoff_delta_millis = max_backoff_millis;
}
c->backoff_delta = gpr_time_from_millis(backoff_delta_millis, GPR_TIMESPAN);
c->next_attempt =
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta);
jitter_range = GRPC_SUBCHANNEL_RECONNECT_JITTER * backoff_delta_millis;
jitter =
(gpr_int32)((2 * generate_uniform_random_number(c) - 1) * jitter_range);
c->next_attempt =
gpr_time_add(c->next_attempt, gpr_time_from_millis(jitter, GPR_TIMESPAN));
}
static void on_alarm(void *arg, int iomgr_success) {
grpc_subchannel *c = arg;
gpr_mu_lock(&c->mu);
@ -565,11 +625,13 @@ static void on_alarm(void *arg, int iomgr_success) {
if (c->disconnected) {
iomgr_success = 0;
}
connectivity_state_changed_locked(c);
connectivity_state_changed_locked(c, "alarm");
gpr_mu_unlock(&c->mu);
if (iomgr_success) {
update_reconnect_parameters(c);
continue_connect(c);
} else {
GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
GRPC_SUBCHANNEL_UNREF(c, "connecting");
}
}
@ -579,19 +641,25 @@ static void subchannel_connected(void *arg, int iomgr_success) {
if (c->connecting_result.transport != NULL) {
publish_transport(c);
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_mu_lock(&c->mu);
connectivity_state_changed_locked(c);
GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1;
c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta);
c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now(GPR_CLOCK_REALTIME));
connectivity_state_changed_locked(c, "connect_failed");
grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, now);
gpr_mu_unlock(&c->mu);
}
}
static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
return gpr_time_add(c->next_attempt, c->backoff_delta);
gpr_timespec current_deadline =
gpr_time_add(c->next_attempt, c->backoff_delta);
gpr_timespec min_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS,
GPR_TIMESPAN));
return gpr_time_cmp(current_deadline, min_deadline) > 0 ? current_deadline
: min_deadline;
}
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
@ -610,9 +678,10 @@ static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
return GRPC_CHANNEL_IDLE;
}
static void connectivity_state_changed_locked(grpc_subchannel *c) {
static void connectivity_state_changed_locked(grpc_subchannel *c,
const char *reason) {
grpc_connectivity_state current = compute_connectivity_locked(c);
grpc_connectivity_state_set(&c->state_tracker, current);
grpc_connectivity_state_set(&c->state_tracker, current, reason);
}
/*
@ -640,6 +709,12 @@ void grpc_subchannel_call_unref(
}
}
char *grpc_subchannel_call_get_peer(grpc_subchannel_call *call) {
grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
return top_elem->filter->get_peer(top_elem);
}
void grpc_subchannel_call_process_op(grpc_subchannel_call *call,
grpc_transport_stream_op *op) {
grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);

@ -100,6 +100,9 @@ void grpc_subchannel_del_interested_party(grpc_subchannel *channel,
void grpc_subchannel_call_process_op(grpc_subchannel_call *subchannel_call,
grpc_transport_stream_op *op);
/** continue querying for peer */
char *grpc_subchannel_call_get_peer(grpc_subchannel_call *subchannel_call);
struct grpc_subchannel_args {
/** Channel filters for this channel - wrapped factories will likely
want to mutate this */

@ -32,21 +32,39 @@
*/
#include <stdlib.h>
#include <string.h>
#include <grpc/compression.h>
const char *grpc_compression_algorithm_name(
grpc_compression_algorithm algorithm) {
int grpc_compression_algorithm_parse(const char* name,
grpc_compression_algorithm *algorithm) {
if (strcmp(name, "none") == 0) {
*algorithm = GRPC_COMPRESS_NONE;
} else if (strcmp(name, "gzip") == 0) {
*algorithm = GRPC_COMPRESS_GZIP;
} else if (strcmp(name, "deflate") == 0) {
*algorithm = GRPC_COMPRESS_DEFLATE;
} else {
return 0;
}
return 1;
}
int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
char **name) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return "none";
*name = "none";
break;
case GRPC_COMPRESS_DEFLATE:
return "deflate";
*name = "deflate";
break;
case GRPC_COMPRESS_GZIP:
return "gzip";
case GRPC_COMPRESS_ALGORITHMS_COUNT:
return "error";
*name = "gzip";
break;
default:
return 0;
}
return "error";
return 1;
}
/* TODO(dgq): Add the ability to specify parameters to the individual
@ -65,3 +83,15 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
abort();
}
}
grpc_compression_level grpc_compression_level_for_algorithm(
grpc_compression_algorithm algorithm) {
grpc_compression_level clevel;
for (clevel = GRPC_COMPRESS_LEVEL_NONE; clevel < GRPC_COMPRESS_LEVEL_COUNT;
++clevel) {
if (grpc_compression_algorithm_for_level(clevel) == algorithm) {
return clevel;
}
}
abort();
}

@ -36,6 +36,7 @@
#include "src/core/iomgr/alarm_heap.h"
#include "src/core/iomgr/alarm_internal.h"
#include "src/core/iomgr/time_averaged_stats.h"
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
@ -67,6 +68,7 @@ typedef struct {
static gpr_mu g_mu;
/* Allow only one run_some_expired_alarms at once */
static gpr_mu g_checker_mu;
static gpr_clock_type g_clock_type;
static shard_type g_shards[NUM_SHARDS];
/* Protected by g_mu */
static shard_type *g_shard_queue[NUM_SHARDS];
@ -85,6 +87,7 @@ void grpc_alarm_list_init(gpr_timespec now) {
gpr_mu_init(&g_mu);
gpr_mu_init(&g_checker_mu);
g_clock_type = now.clock_type;
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
@ -102,7 +105,8 @@ void grpc_alarm_list_init(gpr_timespec now) {
void grpc_alarm_list_shutdown(void) {
int i;
while (run_some_expired_alarms(NULL, gpr_inf_future, NULL, 0))
while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL,
0))
;
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
@ -127,6 +131,7 @@ static gpr_timespec dbl_to_ts(double d) {
gpr_timespec ts;
ts.tv_sec = d;
ts.tv_nsec = 1e9 * (d - ts.tv_sec);
ts.clock_type = GPR_TIMESPAN;
return ts;
}
@ -173,6 +178,8 @@ void grpc_alarm_init(grpc_alarm *alarm, gpr_timespec deadline,
gpr_timespec now) {
int is_first_alarm = 0;
shard_type *shard = &g_shards[shard_idx(alarm)];
GPR_ASSERT(deadline.clock_type == g_clock_type);
GPR_ASSERT(now.clock_type == g_clock_type);
alarm->cb = alarm_cb;
alarm->cb_arg = alarm_cb_arg;
alarm->deadline = deadline;
@ -353,7 +360,10 @@ static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now,
}
int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next) {
return run_some_expired_alarms(drop_mu, now, next, 1);
GPR_ASSERT(now.clock_type == g_clock_type);
return run_some_expired_alarms(
drop_mu, now, next,
gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
}
gpr_timespec grpc_alarm_list_next_timeout(void) {

@ -50,6 +50,14 @@ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
ep->vtable->add_to_pollset(ep, pollset);
}
void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
ep->vtable->add_to_pollset_set(ep, pollset_set);
}
void grpc_endpoint_shutdown(grpc_endpoint *ep) { ep->vtable->shutdown(ep); }
void grpc_endpoint_destroy(grpc_endpoint *ep) { ep->vtable->destroy(ep); }
char *grpc_endpoint_get_peer(grpc_endpoint *ep) {
return ep->vtable->get_peer(ep);
}

@ -35,6 +35,7 @@
#define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H
#include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/pollset_set.h"
#include <grpc/support/slice.h>
#include <grpc/support/time.h>
@ -70,14 +71,18 @@ struct grpc_endpoint_vtable {
size_t nslices, grpc_endpoint_write_cb cb,
void *user_data);
void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset);
void (*shutdown)(grpc_endpoint *ep);
void (*destroy)(grpc_endpoint *ep);
char *(*get_peer)(grpc_endpoint *ep);
};
/* When data is available on the connection, calls the callback with slices. */
void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
void *user_data);
char *grpc_endpoint_get_peer(grpc_endpoint *ep);
/* Write slices out to the socket.
If the connection is ready for more data after the end of the call, it
@ -98,6 +103,7 @@ void grpc_endpoint_destroy(grpc_endpoint *ep);
/* Add an endpoint to a pollset, so that when the pollset is polled, events from
this endpoint are considered */
void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset);
void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set);
struct grpc_endpoint {
const grpc_endpoint_vtable *vtable;

@ -66,12 +66,12 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
create_sockets(sv);
gpr_asprintf(&final_name, "%s:client", name);
p.client =
grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size);
p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size,
"socketpair-server");
gpr_free(final_name);
gpr_asprintf(&final_name, "%s:server", name);
p.server =
grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size);
p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size,
"socketpair-client");
gpr_free(final_name);
return p;
}

@ -81,8 +81,10 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read
SOCKET sv[2];
grpc_endpoint_pair p;
create_sockets(sv);
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"));
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"));
p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
"endpoint:server");
p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
"endpoint:client");
return p;
}

@ -157,7 +157,7 @@ void grpc_iocp_shutdown(void) {
BOOL success;
gpr_event_set(&g_shutdown_iocp, (void *)1);
grpc_iocp_kick();
gpr_event_wait(&g_iocp_done, gpr_inf_future);
gpr_event_wait(&g_iocp_done, gpr_inf_future(GPR_CLOCK_REALTIME));
success = CloseHandle(g_iocp);
GPR_ASSERT(success);
}

@ -57,9 +57,9 @@ static grpc_iomgr_object g_root_object;
static void background_callback_executor(void *ignored) {
gpr_mu_lock(&g_mu);
while (!g_shutdown) {
gpr_timespec deadline = gpr_inf_future;
gpr_timespec short_deadline =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
gpr_timespec short_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(100, GPR_TIMESPAN));
if (g_cbs_head) {
grpc_iomgr_closure *closure = g_cbs_head;
g_cbs_head = closure->next;
@ -67,7 +67,7 @@ static void background_callback_executor(void *ignored) {
gpr_mu_unlock(&g_mu);
closure->cb(closure->cb_arg, closure->success);
gpr_mu_lock(&g_mu);
} else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_REALTIME),
} else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_MONOTONIC),
&deadline)) {
} else {
gpr_mu_unlock(&g_mu);
@ -88,9 +88,10 @@ void grpc_kick_poller(void) {
void grpc_iomgr_init(void) {
gpr_thd_id id;
g_shutdown = 0;
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
grpc_alarm_list_init(gpr_now(GPR_CLOCK_REALTIME));
grpc_alarm_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = "root";
grpc_iomgr_platform_init();
@ -110,8 +111,8 @@ static size_t count_objects(void) {
void grpc_iomgr_shutdown(void) {
grpc_iomgr_object *obj;
grpc_iomgr_closure *closure;
gpr_timespec shutdown_deadline =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10));
gpr_timespec shutdown_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN));
gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
gpr_mu_lock(&g_mu);
@ -119,7 +120,7 @@ void grpc_iomgr_shutdown(void) {
while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
if (gpr_time_cmp(
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
gpr_time_from_seconds(1)) >= 0) {
gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) {
if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
gpr_log(GPR_DEBUG,
"Waiting for %d iomgr objects to be destroyed and executing "
@ -145,14 +146,13 @@ void grpc_iomgr_shutdown(void) {
} while (g_cbs_head);
continue;
}
if (grpc_alarm_check(&g_mu, gpr_inf_future, NULL)) {
gpr_log(GPR_DEBUG, "got late alarm");
if (grpc_alarm_check(&g_mu, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL)) {
continue;
}
if (g_root_object.next != &g_root_object) {
int timeout = 0;
gpr_timespec short_deadline =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
gpr_timespec short_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
timeout = 1;
@ -174,7 +174,8 @@ void grpc_iomgr_shutdown(void) {
gpr_mu_unlock(&g_mu);
grpc_kick_poller();
gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future);
gpr_event_wait(&g_background_callback_executor_done,
gpr_inf_future(GPR_CLOCK_REALTIME));
grpc_alarm_list_shutdown();

@ -50,12 +50,17 @@ typedef struct {
} pollset_hdr;
static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
grpc_fd *fd) {
grpc_fd *fd,
int and_unlock_pollset) {
pollset_hdr *h = pollset->data.ptr;
struct epoll_event ev;
int err;
grpc_fd_watcher watcher;
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
/* We pretend to be polling whilst adding an fd to keep the fd from being
closed during the add. This may result in a spurious wakeup being assigned
to this pollset whilst adding, but that should be benign. */
@ -76,9 +81,15 @@ static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
}
static void multipoll_with_epoll_pollset_del_fd(grpc_pollset *pollset,
grpc_fd *fd) {
grpc_fd *fd,
int and_unlock_pollset) {
pollset_hdr *h = pollset->data.ptr;
int err;
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
/* Note that this can race with concurrent poll, but that should be fine since
* at worst it creates a spurious read event on a reused grpc_fd object. */
err = epoll_ctl(h->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL);
@ -183,7 +194,7 @@ static void epoll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
abort();
}
for (i = 0; i < nfds; i++) {
multipoll_with_epoll_pollset_add_fd(pollset, fds[i]);
multipoll_with_epoll_pollset_add_fd(pollset, fds[i], 0);
}
grpc_wakeup_fd_create(&h->wakeup_fd);

@ -66,12 +66,13 @@ typedef struct {
} pollset_hdr;
static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
grpc_fd *fd) {
grpc_fd *fd,
int and_unlock_pollset) {
size_t i;
pollset_hdr *h = pollset->data.ptr;
/* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */
for (i = 0; i < h->fd_count; i++) {
if (h->fds[i] == fd) return;
if (h->fds[i] == fd) goto exit;
}
if (h->fd_count == h->fd_capacity) {
h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2);
@ -79,10 +80,15 @@ static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
}
h->fds[h->fd_count++] = fd;
GRPC_FD_REF(fd, "multipoller");
exit:
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
}
static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
grpc_fd *fd) {
grpc_fd *fd,
int and_unlock_pollset) {
/* will get removed next poll cycle */
pollset_hdr *h = pollset->data.ptr;
if (h->del_count == h->del_capacity) {
@ -91,6 +97,9 @@ static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
}
h->dels[h->del_count++] = fd;
GRPC_FD_REF(fd, "multipoller_del");
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
}
static void end_polling(grpc_pollset *pollset) {

@ -105,14 +105,28 @@ void grpc_pollset_init(grpc_pollset *pollset) {
void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
gpr_mu_lock(&pollset->mu);
pollset->vtable->add_fd(pollset, fd);
pollset->vtable->add_fd(pollset, fd, 1);
/* the following (enabled only in debug) will reacquire and then release
our lock - meaning that if the unlocking flag passed to del_fd above is
not respected, the code will deadlock (in a way that we have a chance of
debugging) */
#ifndef NDEBUG
gpr_mu_lock(&pollset->mu);
gpr_mu_unlock(&pollset->mu);
#endif
}
void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
gpr_mu_lock(&pollset->mu);
pollset->vtable->del_fd(pollset, fd);
pollset->vtable->del_fd(pollset, fd, 1);
/* the following (enabled only in debug) will reacquire and then release
our lock - meaning that if the unlocking flag passed to del_fd above is
not respected, the code will deadlock (in a way that we have a chance of
debugging) */
#ifndef NDEBUG
gpr_mu_lock(&pollset->mu);
gpr_mu_unlock(&pollset->mu);
#endif
}
static void finish_shutdown(grpc_pollset *pollset) {
@ -122,7 +136,7 @@ static void finish_shutdown(grpc_pollset *pollset) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
/* pollset->mu already held */
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
if (gpr_time_cmp(now, deadline) > 0) {
return 0;
}
@ -191,17 +205,17 @@ int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
gpr_timespec now) {
gpr_timespec timeout;
static const int max_spin_polling_us = 10;
if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
return -1;
}
if (gpr_time_cmp(
deadline,
gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
max_spin_polling_us,
GPR_TIMESPAN))) <= 0) {
return 0;
}
timeout = gpr_time_sub(deadline, now);
return gpr_time_to_millis(
gpr_time_add(timeout, gpr_time_from_nanos(GPR_NS_PER_SEC - 1)));
return gpr_time_to_millis(gpr_time_add(
timeout, gpr_time_from_nanos(GPR_NS_PER_SEC - 1, GPR_TIMESPAN)));
}
/*
@ -257,7 +271,7 @@ static void basic_do_promote(void *args, int success) {
} else if (grpc_fd_is_orphaned(fd)) {
/* Don't try to add it to anything, we'll drop our ref on it below */
} else if (pollset->vtable != original_vtable) {
pollset->vtable->add_fd(pollset, fd);
pollset->vtable->add_fd(pollset, fd, 0);
} else if (fd != pollset->data.ptr) {
grpc_fd *fds[2];
fds[0] = pollset->data.ptr;
@ -287,10 +301,11 @@ static void basic_do_promote(void *args, int success) {
GRPC_FD_UNREF(fd, "basicpoll_add");
}
static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd,
int and_unlock_pollset) {
grpc_unary_promote_args *up_args;
GPR_ASSERT(fd);
if (fd == pollset->data.ptr) return;
if (fd == pollset->data.ptr) goto exit;
if (!pollset->counter) {
/* Fast path -- no in flight cbs */
@ -313,7 +328,7 @@ static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
pollset->data.ptr = fd;
GRPC_FD_REF(fd, "basicpoll");
}
return;
goto exit;
}
/* Now we need to promote. This needs to happen when we're not polling. Since
@ -329,14 +344,24 @@ static void basic_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) {
grpc_iomgr_add_callback(&up_args->promotion_closure);
grpc_pollset_kick(pollset);
exit:
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
}
static void basic_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
static void basic_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd,
int and_unlock_pollset) {
GPR_ASSERT(fd);
if (fd == pollset->data.ptr) {
GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
pollset->data.ptr = NULL;
}
if (and_unlock_pollset) {
gpr_mu_unlock(&pollset->mu);
}
}
static void basic_pollset_maybe_work(grpc_pollset *pollset,

@ -66,8 +66,10 @@ typedef struct grpc_pollset {
} grpc_pollset;
struct grpc_pollset_vtable {
void (*add_fd)(grpc_pollset *pollset, struct grpc_fd *fd);
void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd);
void (*add_fd)(grpc_pollset *pollset, struct grpc_fd *fd,
int and_unlock_pollset);
void (*del_fd)(grpc_pollset *pollset, struct grpc_fd *fd,
int and_unlock_pollset);
void (*maybe_work)(grpc_pollset *pollset, gpr_timespec deadline,
gpr_timespec now, int allow_synchronous_callback);
void (*kick)(grpc_pollset *pollset);

@ -38,7 +38,7 @@
/* A grpc_pollset_set is a set of pollsets that are interested in an
action. Adding a pollset to a pollset_set automatically adds any
fd's (etc) that have been registered with the set_set with that pollset.
fd's (etc) that have been registered with the set_set to that pollset.
Registering fd's automatically adds them to all current pollsets. */
#ifdef GPR_POSIX_SOCKET

@ -60,7 +60,7 @@ void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
grpc_pollset *pollset) {
size_t i;
size_t i, j;
gpr_mu_lock(&pollset_set->mu);
if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
pollset_set->pollset_capacity =
@ -70,9 +70,15 @@ void grpc_pollset_set_add_pollset(grpc_pollset_set *pollset_set,
sizeof(*pollset_set->pollsets));
}
pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
for (i = 0; i < pollset_set->fd_count; i++) {
grpc_pollset_add_fd(pollset, pollset_set->fds[i]);
for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
} else {
grpc_pollset_add_fd(pollset, pollset_set->fds[i]);
pollset_set->fds[j++] = pollset_set->fds[i];
}
}
pollset_set->fd_count = j;
gpr_mu_unlock(&pollset_set->mu);
}

@ -70,7 +70,7 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
gpr_timespec now;
now = gpr_now(GPR_CLOCK_REALTIME);
now = gpr_now(GPR_CLOCK_MONOTONIC);
if (gpr_time_cmp(now, deadline) > 0) {
return 0 /* GPR_FALSE */;
}

@ -36,12 +36,18 @@
#include <errno.h>
#include <string.h>
#include "src/core/support/string.h"
#ifdef GPR_POSIX_SOCKET
#include <sys/un.h>
#endif
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
#include "src/core/support/string.h"
static const gpr_uint8 kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0xff, 0xff};
@ -161,6 +167,31 @@ int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
return ret;
}
char *grpc_sockaddr_to_uri(const struct sockaddr *addr) {
char *temp;
char *result;
switch (addr->sa_family) {
case AF_INET:
grpc_sockaddr_to_string(&temp, addr, 0);
gpr_asprintf(&result, "ipv4:%s", temp);
gpr_free(temp);
return result;
case AF_INET6:
grpc_sockaddr_to_string(&temp, addr, 0);
gpr_asprintf(&result, "ipv6:%s", temp);
gpr_free(temp);
return result;
#ifdef GPR_POSIX_SOCKET
case AF_UNIX:
gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path);
return result;
#endif
}
return NULL;
}
int grpc_sockaddr_get_port(const struct sockaddr *addr) {
switch (addr->sa_family) {
case AF_INET:

@ -84,4 +84,6 @@ int grpc_sockaddr_set_port(const struct sockaddr *addr, int port);
int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
int normalize);
char *grpc_sockaddr_to_uri(const struct sockaddr *addr);
#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */

@ -64,6 +64,7 @@ typedef struct {
int refs;
grpc_iomgr_closure write_closure;
grpc_pollset_set *interested_parties;
char *addr_str;
} async_connect;
static int prepare_socket(const struct sockaddr *addr, int fd) {
@ -88,17 +89,18 @@ error:
return 0;
}
static void on_alarm(void *acp, int success) {
static void tc_on_alarm(void *acp, int success) {
int done;
async_connect *ac = acp;
gpr_mu_lock(&ac->mu);
if (ac->fd != NULL && success) {
if (ac->fd != NULL) {
grpc_fd_shutdown(ac->fd);
}
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_str);
gpr_free(ac);
}
}
@ -108,17 +110,25 @@ static void on_writable(void *acp, int success) {
int so_error = 0;
socklen_t so_error_size;
int err;
int fd = ac->fd->fd;
int done;
grpc_endpoint *ep = NULL;
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
void *cb_arg = ac->cb_arg;
grpc_fd *fd;
gpr_mu_lock(&ac->mu);
GPR_ASSERT(ac->fd);
fd = ac->fd;
ac->fd = NULL;
gpr_mu_unlock(&ac->mu);
grpc_alarm_cancel(&ac->alarm);
gpr_mu_lock(&ac->mu);
if (success) {
do {
so_error_size = sizeof(so_error);
err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
} while (err < 0 && errno == EINTR);
if (err < 0) {
gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
@ -141,7 +151,7 @@ static void on_writable(void *acp, int success) {
don't do that! */
gpr_log(GPR_ERROR, "kernel out of buffers");
gpr_mu_unlock(&ac->mu);
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
grpc_fd_notify_on_write(fd, &ac->write_closure);
return;
} else {
switch (so_error) {
@ -155,8 +165,9 @@ static void on_writable(void *acp, int success) {
goto finish;
}
} else {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
grpc_pollset_set_del_fd(ac->interested_parties, fd);
ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str);
fd = NULL;
goto finish;
}
} else {
@ -167,19 +178,17 @@ static void on_writable(void *acp, int success) {
abort();
finish:
if (ep == NULL) {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
} else {
ac->fd = NULL;
if (fd != NULL) {
grpc_pollset_set_del_fd(ac->interested_parties, fd);
grpc_fd_orphan(fd, NULL, "tcp_client_orphan");
fd = NULL;
}
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_str);
gpr_free(ac);
} else {
grpc_alarm_cancel(&ac->alarm);
}
cb(cb_arg, ep);
}
@ -223,13 +232,13 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
err = connect(fd, addr, addr_len);
} while (err < 0 && errno == EINTR);
grpc_sockaddr_to_string(&addr_str, addr, 1);
addr_str = grpc_sockaddr_to_uri(addr);
gpr_asprintf(&name, "tcp-client:%s", addr_str);
fdobj = grpc_fd_create(fd, name);
if (err >= 0) {
cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str));
goto done;
}
@ -247,14 +256,16 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
ac->cb_arg = arg;
ac->fd = fdobj;
ac->interested_parties = interested_parties;
ac->addr_str = addr_str;
addr_str = NULL;
gpr_mu_init(&ac->mu);
ac->refs = 2;
ac->write_closure.cb = on_writable;
ac->write_closure.cb_arg = ac;
gpr_mu_lock(&ac->mu);
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
gpr_now(GPR_CLOCK_REALTIME));
grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
gpr_mu_unlock(&ac->mu);

@ -58,6 +58,7 @@ typedef struct {
grpc_winsocket *socket;
gpr_timespec deadline;
grpc_alarm alarm;
char *addr_name;
int refs;
int aborted;
} async_connect;
@ -67,6 +68,7 @@ static void async_connect_cleanup(async_connect *ac) {
gpr_mu_unlock(&ac->mu);
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_name);
gpr_free(ac);
}
}
@ -107,7 +109,7 @@ static void on_connect(void *acp, int from_iocp) {
gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
gpr_free(utf8_message);
} else if (!aborted) {
ep = grpc_tcp_create(ac->socket);
ep = grpc_tcp_create(ac->socket, ac->addr_name);
}
} else {
gpr_log(GPR_ERROR, "on_connect is shutting down");
@ -213,10 +215,11 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
ac->socket = socket;
gpr_mu_init(&ac->mu);
ac->refs = 2;
ac->addr_name = grpc_sockaddr_to_uri(addr);
ac->aborted = 0;
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
gpr_now(GPR_CLOCK_REALTIME));
gpr_now(GPR_CLOCK_MONOTONIC));
socket->write_info.outstanding = 1;
grpc_socket_notify_on_write(socket, on_connect, ac);
return;

@ -44,15 +44,17 @@
#include <sys/socket.h>
#include <unistd.h>
#include "src/core/support/string.h"
#include "src/core/debug/trace.h"
#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include "src/core/support/string.h"
#include "src/core/debug/trace.h"
#include "src/core/profiling/timers.h"
#ifdef GPR_HAVE_MSG_NOSIGNAL
#define SENDMSG_FLAGS MSG_NOSIGNAL
#else
@ -282,6 +284,8 @@ typedef struct {
grpc_iomgr_closure write_closure;
grpc_iomgr_closure handle_read_closure;
char *peer_string;
} grpc_tcp;
static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success);
@ -296,6 +300,7 @@ static void grpc_tcp_unref(grpc_tcp *tcp) {
int refcount_zero = gpr_unref(&tcp->refcount);
if (refcount_zero) {
grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan");
gpr_free(tcp->peer_string);
gpr_free(tcp);
}
}
@ -314,7 +319,7 @@ static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices,
gpr_log(GPR_DEBUG, "read: status=%d", status);
for (i = 0; i < nslices; i++) {
char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ: %s", dump);
gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump);
gpr_free(dump);
}
}
@ -443,7 +448,7 @@ static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure);
} else {
tcp->handle_read_closure.cb_arg = tcp;
grpc_iomgr_add_callback(&tcp->handle_read_closure);
grpc_iomgr_add_delayed_callback(&tcp->handle_read_closure, 1);
}
}
@ -567,13 +572,27 @@ static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_pollset_add_fd(pollset, tcp->em_fd);
}
static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_pollset_set_add_fd(pollset_set, tcp->em_fd);
}
static char *grpc_tcp_get_peer(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return gpr_strdup(tcp->peer_string);
}
static const grpc_endpoint_vtable vtable = {
grpc_tcp_notify_on_read, grpc_tcp_write, grpc_tcp_add_to_pollset,
grpc_tcp_shutdown, grpc_tcp_destroy};
grpc_tcp_notify_on_read, grpc_tcp_write,
grpc_tcp_add_to_pollset, grpc_tcp_add_to_pollset_set,
grpc_tcp_shutdown, grpc_tcp_destroy,
grpc_tcp_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size) {
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
const char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
tcp->peer_string = gpr_strdup(peer_string);
tcp->fd = em_fd->fd;
tcp->read_cb = NULL;
tcp->write_cb = NULL;

@ -53,6 +53,7 @@ extern int grpc_tcp_trace;
/* Create a tcp endpoint given a file desciptor and a read slice size.
Takes ownership of fd. */
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size);
grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
const char *peer_string);
#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */

@ -332,7 +332,7 @@ static void on_read(void *arg, int success) {
grpc_set_socket_no_sigpipe_if_possible(fd);
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr);
gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
fdobj = grpc_fd_create(fd, name);
@ -342,8 +342,9 @@ static void on_read(void *arg, int success) {
for (i = 0; i < sp->server->pollset_count; i++) {
grpc_pollset_add_fd(sp->server->pollsets[i], fdobj);
}
sp->server->cb(sp->server->cb_arg,
grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
sp->server->cb(
sp->server->cb_arg,
grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str));
gpr_free(name);
gpr_free(addr_str);

@ -79,6 +79,8 @@ struct grpc_tcp_server {
/* active port count: how many ports are actually still listening */
int active_ports;
/* number of iomgr callbacks that have been explicitly scheduled during shutdown */
int iomgr_callbacks_pending;
/* all listening ports */
server_port *ports;
@ -93,6 +95,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->active_ports = 0;
s->iomgr_callbacks_pending = 0;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@ -112,11 +115,11 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s,
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
sp->shutting_down = 1;
grpc_winsocket_shutdown(sp->socket);
s->iomgr_callbacks_pending += grpc_winsocket_shutdown(sp->socket);
}
/* This happens asynchronously. Wait while that happens. */
while (s->active_ports) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
while (s->active_ports || s->iomgr_callbacks_pending) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
}
gpr_mu_unlock(&s->mu);
@ -243,14 +246,27 @@ static void on_accept(void *arg, int from_iocp) {
SOCKET sock = sp->new_socket;
grpc_winsocket_callback_info *info = &sp->socket->read_info;
grpc_endpoint *ep = NULL;
struct sockaddr_storage peer_name;
char *peer_name_string;
char *fd_name;
int peer_name_len = sizeof(peer_name);
DWORD transfered_bytes;
DWORD flags;
BOOL wsa_success;
int err;
/* The general mechanism for shutting down is to queue abortion calls. While
this is necessary in the read/write case, it's useless for the accept
case. Let's do nothing. */
if (!from_iocp) return;
case. We only need to adjust the pending callback count */
if (!from_iocp) {
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->iomgr_callbacks_pending > 0);
if (0 == --sp->server->iomgr_callbacks_pending) {
gpr_cv_broadcast(&sp->server->cv);
}
gpr_mu_unlock(&sp->server->mu);
return;
}
/* The IOCP notified us of a completed operation. Let's grab the results,
and act accordingly. */
@ -259,11 +275,12 @@ static void on_accept(void *arg, int from_iocp) {
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
if (sp->shutting_down) {
/* During the shutdown case, we ARE expecting an error. So that's swell,
/* During the shutdown case, we ARE expecting an error. So that's well,
and we can wake up the shutdown thread. */
sp->shutting_down = 0;
sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
if (0 == --sp->server->active_ports) {
gpr_cv_broadcast(&sp->server->cv);
}
@ -277,8 +294,28 @@ static void on_accept(void *arg, int from_iocp) {
}
} else {
if (!sp->shutting_down) {
/* TODO(ctiller): add sockaddr address to label */
ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
peer_name_string = NULL;
err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char *)&sp->socket->socket,
sizeof(sp->socket->socket));
if (err) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
gpr_free(utf8_message);
}
err = getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len);
if (!err) {
peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name);
} else {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
gpr_free(utf8_message);
}
gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
peer_name_string);
gpr_free(fd_name);
gpr_free(peer_name_string);
}
}

@ -96,6 +96,8 @@ typedef struct grpc_tcp {
to protect ourselves when requesting a shutdown. */
gpr_mu mu;
int shutting_down;
char *peer_string;
} grpc_tcp;
static void tcp_ref(grpc_tcp *tcp) {
@ -107,6 +109,7 @@ static void tcp_unref(grpc_tcp *tcp) {
gpr_slice_buffer_destroy(&tcp->write_slices);
grpc_winsocket_orphan(tcp->socket);
gpr_mu_destroy(&tcp->mu);
gpr_free(tcp->peer_string);
gpr_free(tcp);
}
}
@ -365,7 +368,14 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
return GRPC_ENDPOINT_WRITE_PENDING;
}
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
(void) ps;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
(void) pss;
grpc_tcp *tcp = (grpc_tcp *) ep;
grpc_iocp_add_socket(tcp->socket);
}
@ -393,11 +403,17 @@ static void win_destroy(grpc_endpoint *ep) {
tcp_unref(tcp);
}
static grpc_endpoint_vtable vtable = {
win_notify_on_read, win_write, win_add_to_pollset, win_shutdown, win_destroy
};
static char *win_get_peer(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return gpr_strdup(tcp->peer_string);
}
static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write,
win_add_to_pollset, win_add_to_pollset_set,
win_shutdown, win_destroy,
win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
memset(tcp, 0, sizeof(grpc_tcp));
tcp->base.vtable = &vtable;
@ -405,6 +421,7 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket) {
gpr_mu_init(&tcp->mu);
gpr_slice_buffer_init(&tcp->write_slices);
gpr_ref_init(&tcp->refcount, 1);
tcp->peer_string = gpr_strdup(peer_string);
return &tcp->base;
}

@ -50,7 +50,7 @@
/* Create a tcp endpoint given a winsock handle.
* Takes ownership of the handle.
*/
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket);
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string);
int grpc_tcp_prepare_socket(SOCKET sock);

@ -77,10 +77,8 @@ typedef struct {
static void bubble_up_error(grpc_call_element *elem, const char *error_msg) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_stream_op_add_cancellation(
&calld->op, GRPC_STATUS_UNAUTHENTICATED,
grpc_mdstr_from_string(chand->md_ctx, error_msg));
grpc_transport_stream_op_add_cancellation(&calld->op,
GRPC_STATUS_UNAUTHENTICATED);
grpc_call_next_op(elem, &calld->op);
}
@ -316,10 +314,10 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
(grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
sc, "client_auth_filter");
chand->md_ctx = metadata_context;
chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0);
chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0);
chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0);
chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0);
}
/* Destructor for channel data */
@ -344,6 +342,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_client_auth_filter = {
auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "client-auth"};
auth_start_transport_op, grpc_channel_next_op,
sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem,
grpc_call_next_get_peer, "client-auth"};

@ -259,8 +259,10 @@ static void ssl_build_config(const char *pem_root_certs,
static void ssl_build_server_config(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, grpc_ssl_server_config *config) {
size_t num_key_cert_pairs, int force_client_auth,
grpc_ssl_server_config *config) {
size_t i;
config->force_client_auth = force_client_auth;
if (pem_root_certs != NULL) {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
@ -302,20 +304,20 @@ grpc_credentials *grpc_ssl_credentials_create(
grpc_server_credentials *grpc_ssl_server_credentials_create(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs) {
size_t num_key_cert_pairs, int force_client_auth) {
grpc_ssl_server_credentials *c =
gpr_malloc(sizeof(grpc_ssl_server_credentials));
memset(c, 0, sizeof(grpc_ssl_server_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_server_vtable;
ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
num_key_cert_pairs, &c->config);
num_key_cert_pairs, force_client_auth, &c->config);
return &c->base;
}
/* -- Jwt credentials -- */
static void jwt_reset_cache(grpc_jwt_credentials *c) {
static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
if (c->cached.jwt_md != NULL) {
grpc_credentials_md_store_unref(c->cached.jwt_md);
c->cached.jwt_md = NULL;
@ -324,11 +326,12 @@ static void jwt_reset_cache(grpc_jwt_credentials *c) {
gpr_free(c->cached.service_url);
c->cached.service_url = NULL;
}
c->cached.jwt_expiration = gpr_inf_past;
c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
}
static void jwt_destroy(grpc_credentials *creds) {
grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
grpc_service_account_jwt_access_credentials *c =
(grpc_service_account_jwt_access_credentials *)creds;
grpc_auth_json_key_destruct(&c->key);
jwt_reset_cache(c);
gpr_mu_destroy(&c->cache_mu);
@ -346,9 +349,10 @@ static void jwt_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data) {
grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
0};
grpc_service_account_jwt_access_credentials *c =
(grpc_service_account_jwt_access_credentials *)creds;
gpr_timespec refresh_threshold = gpr_time_from_seconds(
GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
/* See if we can return a cached jwt. */
grpc_credentials_md_store *jwt_md = NULL;
@ -399,15 +403,16 @@ static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_request_metadata, NULL};
grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
grpc_credentials *
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime) {
grpc_jwt_credentials *c;
grpc_service_account_jwt_access_credentials *c;
if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return NULL;
}
c = gpr_malloc(sizeof(grpc_jwt_credentials));
memset(c, 0, sizeof(grpc_jwt_credentials));
c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials));
memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_JWT;
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &jwt_vtable;
@ -418,9 +423,9 @@ grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
return &c->base;
}
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
return grpc_jwt_credentials_create_from_auth_json_key(
grpc_credentials *grpc_service_account_jwt_access_credentials_create(
const char *json_key, gpr_timespec token_lifetime) {
return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key_create_from_string(json_key), token_lifetime);
}
@ -516,6 +521,7 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
access_token->value);
token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
token_lifetime->tv_nsec = 0;
token_lifetime->clock_type = GPR_TIMESPAN;
if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md);
*token_md = grpc_credentials_md_store_create(1);
grpc_credentials_md_store_add_cstrings(
@ -552,7 +558,7 @@ static void on_oauth2_token_fetcher_http_response(
r->cb(r->user_data, c->access_token_md->entries,
c->access_token_md->num_entries, status);
} else {
c->token_expiration = gpr_inf_past;
c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
r->cb(r->user_data, NULL, 0, status);
}
gpr_mu_unlock(&c->mu);
@ -564,8 +570,8 @@ static void oauth2_token_fetcher_get_request_metadata(
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
0};
gpr_timespec refresh_threshold = gpr_time_from_seconds(
GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
grpc_credentials_md_store *cached_access_token_md = NULL;
{
gpr_mu_lock(&c->mu);
@ -596,7 +602,7 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
gpr_ref_init(&c->base.refcount, 1);
gpr_mu_init(&c->mu);
c->token_expiration = gpr_inf_past;
c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
c->fetch_func = fetch_func;
grpc_httpcli_context_init(&c->httpcli_context);
}

@ -52,6 +52,8 @@ typedef enum {
GRPC_CREDENTIALS_ERROR
} grpc_credentials_status;
#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
#define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
#define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
@ -112,6 +114,12 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
/* --- grpc_credentials. --- */
/* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void);
/* Creates a fake server transport security credentials object for testing. */
grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
void);
/* It is the caller's responsibility to gpr_free the result if not NULL. */
char *grpc_get_well_known_google_credentials_file_path(void);
@ -189,7 +197,8 @@ grpc_credentials *grpc_md_only_test_credentials_create(
/* Private constructor for jwt credentials from an already parsed json key.
Takes ownership of the key. */
grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
grpc_credentials *
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime);
/* Private constructor for refresh token credentials from an already parsed
@ -241,7 +250,7 @@ typedef struct {
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
} grpc_service_account_jwt_access_credentials;
/* -- Oauth2TokenFetcher credentials --

@ -91,7 +91,7 @@ static int is_stack_running_on_compute_engine(void) {
/* The http call is local. If it takes more than one sec, it is for sure not
on compute engine. */
gpr_timespec max_detection_delay = {1, 0};
gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN);
grpc_pollset_init(&detector.pollset);
detector.is_done = 0;
@ -112,7 +112,7 @@ static int is_stack_running_on_compute_engine(void) {
called once for the lifetime of the process by the default credentials. */
gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset));
while (!detector.is_done) {
grpc_pollset_work(&detector.pollset, gpr_inf_future);
grpc_pollset_work(&detector.pollset, gpr_inf_future(GPR_CLOCK_REALTIME));
}
gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset));
@ -140,8 +140,9 @@ static grpc_credentials *create_default_creds_from_path(char *creds_path) {
/* First, try an auth json key. */
key = grpc_auth_json_key_create_from_json(json);
if (grpc_auth_json_key_is_valid(&key)) {
result = grpc_jwt_credentials_create_from_auth_json_key(
key, grpc_max_auth_token_lifetime);
result =
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
key, grpc_max_auth_token_lifetime);
goto end;
}

@ -49,7 +49,7 @@
/* --- Constants. --- */
/* 1 hour max. */
const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0, GPR_TIMESPAN};
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT"

@ -109,7 +109,7 @@ static const char *validate_string_field(const grpc_json *json,
static gpr_timespec validate_time_field(const grpc_json *json,
const char *key) {
gpr_timespec result = gpr_time_0;
gpr_timespec result = gpr_time_0(GPR_CLOCK_REALTIME);
if (json->type != GRPC_JSON_NUMBER) {
gpr_log(GPR_ERROR, "Invalid %s field [%s]", key, json->value);
return result;
@ -221,17 +221,17 @@ const char *grpc_jwt_claims_audience(const grpc_jwt_claims *claims) {
}
gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims) {
if (claims == NULL) return gpr_inf_past;
if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME);
return claims->iat;
}
gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims) {
if (claims == NULL) return gpr_inf_future;
if (claims == NULL) return gpr_inf_future(GPR_CLOCK_REALTIME);
return claims->exp;
}
gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) {
if (claims == NULL) return gpr_inf_past;
if (claims == NULL) return gpr_inf_past(GPR_CLOCK_REALTIME);
return claims->nbf;
}
@ -242,9 +242,9 @@ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) {
memset(claims, 0, sizeof(grpc_jwt_claims));
claims->json = json;
claims->buffer = buffer;
claims->iat = gpr_inf_past;
claims->nbf = gpr_inf_past;
claims->exp = gpr_inf_future;
claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME);
claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME);
claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME);
/* Per the spec, all fields are optional. */
for (cur = json->child; cur != NULL; cur = cur->next) {
@ -262,13 +262,16 @@ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) {
if (claims->jti == NULL) goto error;
} else if (strcmp(cur->key, "iat") == 0) {
claims->iat = validate_time_field(cur, "iat");
if (gpr_time_cmp(claims->iat, gpr_time_0) == 0) goto error;
if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
goto error;
} else if (strcmp(cur->key, "exp") == 0) {
claims->exp = validate_time_field(cur, "exp");
if (gpr_time_cmp(claims->exp, gpr_time_0) == 0) goto error;
if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
goto error;
} else if (strcmp(cur->key, "nbf") == 0) {
claims->nbf = validate_time_field(cur, "nbf");
if (gpr_time_cmp(claims->nbf, gpr_time_0) == 0) goto error;
if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0)
goto error;
}
}
return claims;
@ -359,10 +362,10 @@ void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) {
/* --- grpc_jwt_verifier object. --- */
/* Clock skew defaults to one minute. */
gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0};
gpr_timespec grpc_jwt_verifier_clock_skew = {60, 0, GPR_TIMESPAN};
/* Max delay defaults to one minute. */
gpr_timespec grpc_jwt_verifier_max_delay = {60, 0};
gpr_timespec grpc_jwt_verifier_max_delay = {60, 0, GPR_TIMESPAN};
typedef struct {
char *email_domain;

@ -331,9 +331,22 @@ static void endpoint_add_to_pollset(grpc_endpoint *secure_ep,
grpc_endpoint_add_to_pollset(ep->wrapped_ep, pollset);
}
static void endpoint_add_to_pollset_set(grpc_endpoint *secure_ep,
grpc_pollset_set *pollset_set) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set);
}
static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
return grpc_endpoint_get_peer(ep->wrapped_ep);
}
static const grpc_endpoint_vtable vtable = {
endpoint_notify_on_read, endpoint_write, endpoint_add_to_pollset,
endpoint_shutdown, endpoint_unref};
endpoint_notify_on_read, endpoint_write,
endpoint_add_to_pollset, endpoint_add_to_pollset_set,
endpoint_shutdown, endpoint_unref,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport,

@ -657,9 +657,10 @@ grpc_security_status grpc_ssl_server_security_connector_create(
config->pem_private_keys_sizes,
(const unsigned char **)config->pem_cert_chains,
config->pem_cert_chains_sizes, config->num_key_cert_pairs,
config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
alpn_protocol_strings, alpn_protocol_string_lengths,
(uint16_t)num_alpn_protocols, &c->handshaker_factory);
config->pem_root_certs, config->pem_root_certs_size,
config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings,
alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols,
&c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));

@ -201,6 +201,7 @@ typedef struct {
size_t num_key_cert_pairs;
unsigned char *pem_root_certs;
size_t pem_root_certs_size;
int force_client_auth;
} grpc_ssl_server_config;
/* Creates an SSL server_security_connector.

@ -110,7 +110,6 @@ static void on_md_processing_done(void *user_data,
grpc_auth_context *result) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
if (success) {
calld->consumed_md = consumed_md;
@ -124,10 +123,11 @@ static void on_md_processing_done(void *user_data,
GRPC_AUTH_CONTEXT_REF(result, "refing new context.");
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
} else {
grpc_transport_stream_op_add_cancellation(
&calld->transport_op, GRPC_STATUS_UNAUTHENTICATED,
grpc_mdstr_from_string(chand->mdctx,
"Authentication metadata processing failed."));
gpr_slice message = gpr_slice_from_copied_string(
"Authentication metadata processing failed.");
grpc_sopb_reset(calld->recv_ops);
grpc_transport_stream_op_add_close(&calld->transport_op,
GRPC_STATUS_UNAUTHENTICATED, &message);
grpc_call_next_op(elem, &calld->transport_op);
}
}
@ -259,6 +259,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_server_auth_filter = {
auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "server-auth"};
auth_start_transport_op, grpc_channel_next_op,
sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem,
grpc_call_next_get_peer, "server-auth"};

@ -121,8 +121,9 @@ void gpr_cancellable_cancel(gpr_cancellable *c) {
} else {
gpr_event ev;
gpr_event_init(&ev);
gpr_event_wait(&ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_micros(1000)));
gpr_event_wait(
&ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_micros(1000, GPR_TIMESPAN)));
}
}
} while (failures != 0);

@ -50,7 +50,7 @@ int gpr_join_host_port(char **out, const char *host, int port) {
}
}
void gpr_split_host_port(const char *name, char **host, char **port) {
int gpr_split_host_port(const char *name, char **host, char **port) {
const char *host_start;
size_t host_len;
const char *port_start;
@ -63,7 +63,7 @@ void gpr_split_host_port(const char *name, char **host, char **port) {
const char *rbracket = strchr(name, ']');
if (rbracket == NULL) {
/* Unmatched [ */
return;
return 0;
}
if (rbracket[1] == '\0') {
/* ]<end> */
@ -73,14 +73,14 @@ void gpr_split_host_port(const char *name, char **host, char **port) {
port_start = rbracket + 2;
} else {
/* ]<invalid> */
return;
return 0;
}
host_start = name + 1;
host_len = (size_t)(rbracket - host_start);
if (memchr(host_start, ':', host_len) == NULL) {
/* Require all bracketed hosts to contain a colon, because a hostname or
IPv4 address should never use brackets. */
return;
return 0;
}
} else {
const char *colon = strchr(name, ':');
@ -105,4 +105,6 @@ void gpr_split_host_port(const char *name, char **host, char **port) {
if (port_start != NULL) {
*port = gpr_strdup(port_start);
}
return 1;
}

@ -65,12 +65,18 @@ typedef union lockfree_node {
} lockfree_node;
#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */
#define INVALID_ENTRY_INDEX ((1 << 16) - 1) /* reserve this entry as invalid \
*/
#define INVALID_ENTRY_INDEX \
((1 << 16) - 1) /* reserve this entry as invalid \
*/
struct gpr_stack_lockfree {
lockfree_node *entries;
lockfree_node head; /* An atomic entry describing curr head */
#ifndef NDEBUG
/* Bitmap of pushed entries to check for double-push or pop */
gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))];
#endif
};
gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
@ -85,6 +91,9 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
/* Clear out all entries */
memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
memset(&stack->head, 0, sizeof(stack->head));
#ifndef NDEBUG
memset(&stack->pushed, 0, sizeof(stack->pushed));
#endif
/* Point the head at reserved dummy entry */
stack->head.contents.index = INVALID_ENTRY_INDEX;
@ -96,7 +105,7 @@ void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) {
gpr_free(stack);
}
void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
lockfree_node head;
lockfree_node newhead;
@ -105,6 +114,19 @@ void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
/* Also post-increment the aba_ctr */
newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
#ifndef NDEBUG
/* Check for double push */
{
int pushed_index = entry / (8*sizeof(gpr_atm));
int pushed_bit = entry % (8*sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
(gpr_atm)(1UL << pushed_bit));
GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0);
}
#endif
do {
/* Atomically get the existing head value for use */
head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
@ -112,11 +134,13 @@ void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
stack->entries[entry].contents.index = head.contents.index;
} while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
/* Use rel_cas above to make sure that entry index is set properly */
return head.contents.index == INVALID_ENTRY_INDEX;
}
int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
lockfree_node head;
lockfree_node newhead;
do {
head.atm = gpr_atm_acq_load(&(stack->head.atm));
if (head.contents.index == INVALID_ENTRY_INDEX) {
@ -126,5 +150,18 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
} while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
#ifndef NDEBUG
/* Check for valid pop */
{
int pushed_index = head.contents.index / (8*sizeof(gpr_atm));
int pushed_bit = head.contents.index % (8*sizeof(gpr_atm));
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
-(gpr_atm)(1UL << pushed_bit));
GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0);
}
#endif
return head.contents.index;
}

@ -42,7 +42,8 @@ gpr_stack_lockfree* gpr_stack_lockfree_create(int entries);
void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
/* Pass in a valid entry number for the next stack entry */
void gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry);
/* Returns 1 if this is the first element on the stack, 0 otherwise */
int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry);
/* Returns -1 on empty or the actual entry number */
int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);

@ -38,6 +38,7 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/useful.h>
@ -174,6 +175,12 @@ int gpr_ltoa(long value, char *string) {
}
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return gpr_strjoin_sep(strs, nstrs, "", final_length);
}
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *final_length) {
const size_t sep_len = strlen(sep);
size_t out_length = 0;
size_t i;
char *out;
@ -181,10 +188,17 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
out_length += strlen(strs[i]);
}
out_length += 1; /* null terminator */
if (nstrs > 0) {
out_length += sep_len * (nstrs - 1); /* separators */
}
out = gpr_malloc(out_length);
out_length = 0;
for (i = 0; i < nstrs; i++) {
size_t slen = strlen(strs[i]);
const size_t slen = strlen(strs[i]);
if (i != 0) {
memcpy(out + out_length, sep, sep_len);
out_length += sep_len;
}
memcpy(out + out_length, strs[i], slen);
out_length += slen;
}
@ -195,6 +209,52 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return out;
}
/** Finds the initial (\a begin) and final (\a end) offsets of the next
* substring from \a str + \a read_offset until the next \a sep or the end of \a
* str.
*
* Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
static int slice_find_separator_offset(const gpr_slice str,
const char *sep,
const size_t read_offset,
size_t *begin,
size_t *end) {
size_t i;
const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset;
const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset;
const size_t sep_len = strlen(sep);
if (str_len < sep_len) {
return 0;
}
for (i = 0; i <= str_len - sep_len; i++) {
if (memcmp(str_ptr + i, sep, sep_len) == 0) {
*begin = read_offset;
*end = read_offset + i;
return 1;
}
}
return 0;
}
void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) {
const size_t sep_len = strlen(sep);
size_t begin, end;
GPR_ASSERT(sep_len > 0);
if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) {
do {
gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end));
} while (slice_find_separator_offset(str, sep, end + sep_len, &begin,
&end) != 0);
gpr_slice_buffer_add_indexed(
dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str)));
} else { /* no sep found, add whole input */
gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str));
}
}
void gpr_strvec_init(gpr_strvec *sv) {
memset(sv, 0, sizeof(*sv));
}

@ -37,6 +37,7 @@
#include <stddef.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/slice.h>
#ifdef __cplusplus
@ -77,6 +78,16 @@ void gpr_reverse_bytes(char *str, int len);
if it is non-null. */
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length);
/* Join a set of strings using a separator, returning the resulting string.
Total combined length (excluding null terminator) is returned in total_length
if it is non-null. */
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *total_length);
/** Split \a str by the separator \a sep. Results are stored in \a dst, which
* should be a properly initialized instance. */
void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst);
/* A vector of strings... for building up a final string one piece at a time */
typedef struct {
char **strs;

@ -63,10 +63,11 @@ void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }
int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
int err = 0;
if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) {
err = pthread_cond_wait(cv, mu);
} else {
struct timespec abs_deadline_ts;
abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
abs_deadline_ts.tv_sec = abs_deadline.tv_sec;
abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);

@ -83,10 +83,10 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
int timeout = 0;
DWORD timeout_max_ms;
mu->locked = 0;
if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) {
SleepConditionVariableCS(cv, &mu->cs, INFINITE);
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
gpr_timespec now = gpr_now(abs_deadline.clock_type);
gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
gpr_int64 deadline_ms =
abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;

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

Loading…
Cancel
Save