Merge branch 'master' of https://github.com/grpc/grpc into slice_to_cstring

pull/2200/head
Julien Boeuf 10 years ago
commit 607359467f
  1. 98
      BUILD
  2. 233
      Makefile
  3. 49
      build.json
  4. 52
      gRPC.podspec
  5. 128
      grpc.bzl
  6. 4
      include/grpc/byte_buffer.h
  7. 18
      include/grpc/grpc.h
  8. 2
      include/grpc/support/atm_win32.h
  9. 2
      include/grpc/support/log_win32.h
  10. 32
      include/grpc/support/port_platform.h
  11. 2
      include/grpc/support/sync_win32.h
  12. 38
      src/core/channel/census_filter.c
  13. 22
      src/core/channel/channel_args.c
  14. 13
      src/core/channel/channel_args.h
  15. 22
      src/core/channel/channel_stack.c
  16. 60
      src/core/channel/channel_stack.h
  17. 308
      src/core/channel/child_channel.c
  18. 65
      src/core/channel/child_channel.h
  19. 801
      src/core/channel/client_channel.c
  20. 15
      src/core/channel/client_channel.h
  21. 302
      src/core/channel/client_setup.c
  22. 77
      src/core/channel/client_setup.h
  23. 107
      src/core/channel/connected_channel.c
  24. 6
      src/core/channel/connected_channel.h
  25. 33
      src/core/channel/http_client_filter.c
  26. 35
      src/core/channel/http_server_filter.c
  27. 41
      src/core/channel/noop_filter.c
  28. 60
      src/core/client_config/README.md
  29. 74
      src/core/client_config/client_config.c
  30. 52
      src/core/client_config/client_config.h
  31. 49
      src/core/client_config/connector.c
  32. 85
      src/core/client_config/connector.h
  33. 268
      src/core/client_config/lb_policies/pick_first.c
  34. 11
      src/core/client_config/lb_policies/pick_first.h
  35. 79
      src/core/client_config/lb_policy.c
  36. 109
      src/core/client_config/lb_policy.h
  37. 83
      src/core/client_config/resolver.c
  38. 97
      src/core/client_config/resolver.h
  39. 50
      src/core/client_config/resolver_factory.c
  40. 67
      src/core/client_config/resolver_factory.h
  41. 124
      src/core/client_config/resolver_registry.c
  42. 62
      src/core/client_config/resolver_registry.h
  43. 246
      src/core/client_config/resolvers/dns_resolver.c
  44. 12
      src/core/client_config/resolvers/dns_resolver.h
  45. 195
      src/core/client_config/resolvers/unix_resolver_posix.c
  46. 44
      src/core/client_config/resolvers/unix_resolver_posix.h
  47. 659
      src/core/client_config/subchannel.c
  48. 124
      src/core/client_config/subchannel.h
  49. 46
      src/core/client_config/subchannel_factory.c
  50. 63
      src/core/client_config/subchannel_factory.h
  51. 149
      src/core/client_config/uri_parser.c
  52. 25
      src/core/client_config/uri_parser.h
  53. 2
      src/core/httpcli/httpcli.c
  54. 2
      src/core/iomgr/alarm.h
  55. 12
      src/core/iomgr/fd_posix.c
  56. 1
      src/core/iomgr/iocp_windows.h
  57. 18
      src/core/iomgr/iomgr.c
  58. 26
      src/core/iomgr/pollset_multipoller_with_epoll.c
  59. 3
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  60. 3
      src/core/iomgr/pollset_posix.c
  61. 2
      src/core/iomgr/pollset_set_posix.c
  62. 1
      src/core/iomgr/pollset_windows.h
  63. 2
      src/core/iomgr/resolve_address_posix.c
  64. 2
      src/core/iomgr/sockaddr_win32.h
  65. 3
      src/core/iomgr/socket_windows.h
  66. 4
      src/core/iomgr/tcp_client_posix.c
  67. 99
      src/core/security/base64.c
  68. 4
      src/core/security/base64.h
  69. 30
      src/core/security/client_auth_filter.c
  70. 2
      src/core/security/credentials.c
  71. 10
      src/core/security/secure_transport_setup.c
  72. 47
      src/core/security/security_connector.c
  73. 33
      src/core/security/security_connector.h
  74. 28
      src/core/security/server_auth_filter.c
  75. 29
      src/core/security/server_secure_chttp2.c
  76. 1
      src/core/support/cpu_windows.c
  77. 11
      src/core/support/log_linux.c
  78. 1
      src/core/support/string_win32.c
  79. 2
      src/core/support/string_win32.h
  80. 3
      src/core/support/sync_win32.c
  81. 1
      src/core/support/thd_win32.c
  82. 1
      src/core/support/time_win32.c
  83. 14
      src/core/surface/byte_buffer.c
  84. 69
      src/core/surface/call.c
  85. 2
      src/core/surface/call.h
  86. 33
      src/core/surface/channel.c
  87. 3
      src/core/surface/channel.h
  88. 235
      src/core/surface/channel_create.c
  89. 89
      src/core/surface/client.c
  90. 14
      src/core/surface/init.c
  91. 49
      src/core/surface/lame_client.c
  92. 254
      src/core/surface/secure_channel_create.c
  93. 255
      src/core/surface/server.c
  94. 8
      src/core/surface/server.h
  95. 19
      src/core/surface/server_chttp2.c
  96. 1
      src/core/transport/chttp2/incoming_metadata.c
  97. 49
      src/core/transport/chttp2/internal.h
  98. 3
      src/core/transport/chttp2/parsing.c
  99. 22
      src/core/transport/chttp2/stream_lists.c
  100. 13
      src/core/transport/chttp2/writing.c
  101. Some files were not shown because too many files have changed in this diff Show More

98
BUILD

@ -1,5 +1,5 @@
# GRPC Bazel BUILD file.
# This currently builds C and C++ code.
# This currently builds C, C++ and Objective-C code.
# This file has been automatically generated from a template file.
# Please look at the templates directory instead.
# This file can be regenerated from the template by running
@ -150,14 +150,24 @@ cc_library(
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
"src/core/channel/client_channel.h",
"src/core/channel/client_setup.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
"src/core/channel/http_server_filter.h",
"src/core/channel/noop_filter.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policy.h",
"src/core/client_config/resolver.h",
"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/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/iomgr/alarm.h",
@ -200,7 +210,6 @@ cc_library(
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
"src/core/surface/client.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
"src/core/surface/init.h",
@ -227,6 +236,7 @@ cc_library(
"src/core/transport/chttp2/timeout_encoding.h",
"src/core/transport/chttp2/varint.h",
"src/core/transport/chttp2_transport.h",
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",
@ -258,13 +268,23 @@ cc_library(
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
"src/core/channel/client_channel.c",
"src/core/channel/client_setup.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
"src/core/channel/noop_filter.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policy.c",
"src/core/client_config/resolver.c",
"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/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
"src/core/compression/algorithm.c",
"src/core/compression/message_compress.c",
"src/core/debug/trace.c",
@ -317,7 +337,6 @@ cc_library(
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_create.c",
"src/core/surface/client.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
"src/core/surface/init.c",
@ -348,6 +367,7 @@ cc_library(
"src/core/transport/chttp2/varint.c",
"src/core/transport/chttp2/writing.c",
"src/core/transport/chttp2_transport.c",
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
@ -382,14 +402,24 @@ cc_library(
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
"src/core/channel/client_channel.h",
"src/core/channel/client_setup.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
"src/core/channel/http_server_filter.h",
"src/core/channel/noop_filter.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policy.h",
"src/core/client_config/resolver.h",
"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/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/iomgr/alarm.h",
@ -432,7 +462,6 @@ cc_library(
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
"src/core/surface/client.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
"src/core/surface/init.h",
@ -459,6 +488,7 @@ cc_library(
"src/core/transport/chttp2/timeout_encoding.h",
"src/core/transport/chttp2/varint.h",
"src/core/transport/chttp2_transport.h",
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",
@ -468,13 +498,23 @@ cc_library(
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
"src/core/channel/client_channel.c",
"src/core/channel/client_setup.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
"src/core/channel/noop_filter.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policy.c",
"src/core/client_config/resolver.c",
"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/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
"src/core/compression/algorithm.c",
"src/core/compression/message_compress.c",
"src/core/debug/trace.c",
@ -527,7 +567,6 @@ cc_library(
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_create.c",
"src/core/surface/client.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
"src/core/surface/init.c",
@ -558,6 +597,7 @@ cc_library(
"src/core/transport/chttp2/varint.c",
"src/core/transport/chttp2/writing.c",
"src/core/transport/chttp2_transport.c",
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
@ -920,13 +960,23 @@ objc_library(
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
"src/core/channel/client_channel.c",
"src/core/channel/client_setup.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
"src/core/channel/noop_filter.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policy.c",
"src/core/client_config/resolver.c",
"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/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
"src/core/compression/algorithm.c",
"src/core/compression/message_compress.c",
"src/core/debug/trace.c",
@ -979,7 +1029,6 @@ objc_library(
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_create.c",
"src/core/surface/client.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
"src/core/surface/init.c",
@ -1010,6 +1059,7 @@ objc_library(
"src/core/transport/chttp2/varint.c",
"src/core/transport/chttp2/writing.c",
"src/core/transport/chttp2_transport.c",
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
@ -1045,14 +1095,24 @@ objc_library(
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
"src/core/channel/client_channel.h",
"src/core/channel/client_setup.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
"src/core/channel/http_server_filter.h",
"src/core/channel/noop_filter.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policy.h",
"src/core/client_config/resolver.h",
"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/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/iomgr/alarm.h",
@ -1095,7 +1155,6 @@ objc_library(
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
"src/core/surface/client.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
"src/core/surface/init.h",
@ -1122,6 +1181,7 @@ objc_library(
"src/core/transport/chttp2/timeout_encoding.h",
"src/core/transport/chttp2/varint.h",
"src/core/transport/chttp2_transport.h",
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",

File diff suppressed because one or more lines are too long

@ -111,14 +111,24 @@
"src/core/channel/census_filter.h",
"src/core/channel/channel_args.h",
"src/core/channel/channel_stack.h",
"src/core/channel/child_channel.h",
"src/core/channel/client_channel.h",
"src/core/channel/client_setup.h",
"src/core/channel/connected_channel.h",
"src/core/channel/context.h",
"src/core/channel/http_client_filter.h",
"src/core/channel/http_server_filter.h",
"src/core/channel/noop_filter.h",
"src/core/client_config/client_config.h",
"src/core/client_config/connector.h",
"src/core/client_config/lb_policies/pick_first.h",
"src/core/client_config/lb_policy.h",
"src/core/client_config/resolver.h",
"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/subchannel.h",
"src/core/client_config/subchannel_factory.h",
"src/core/client_config/uri_parser.h",
"src/core/compression/message_compress.h",
"src/core/debug/trace.h",
"src/core/iomgr/alarm.h",
@ -161,7 +171,6 @@
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/channel.h",
"src/core/surface/client.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
"src/core/surface/init.h",
@ -188,6 +197,7 @@
"src/core/transport/chttp2/timeout_encoding.h",
"src/core/transport/chttp2/varint.h",
"src/core/transport/chttp2_transport.h",
"src/core/transport/connectivity_state.h",
"src/core/transport/metadata.h",
"src/core/transport/stream_op.h",
"src/core/transport/transport.h",
@ -197,13 +207,23 @@
"src/core/census/grpc_context.c",
"src/core/channel/channel_args.c",
"src/core/channel/channel_stack.c",
"src/core/channel/child_channel.c",
"src/core/channel/client_channel.c",
"src/core/channel/client_setup.c",
"src/core/channel/connected_channel.c",
"src/core/channel/http_client_filter.c",
"src/core/channel/http_server_filter.c",
"src/core/channel/noop_filter.c",
"src/core/client_config/client_config.c",
"src/core/client_config/connector.c",
"src/core/client_config/lb_policies/pick_first.c",
"src/core/client_config/lb_policy.c",
"src/core/client_config/resolver.c",
"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/subchannel.c",
"src/core/client_config/subchannel_factory.c",
"src/core/client_config/uri_parser.c",
"src/core/compression/algorithm.c",
"src/core/compression/message_compress.c",
"src/core/debug/trace.c",
@ -256,7 +276,6 @@
"src/core/surface/call_log_batch.c",
"src/core/surface/channel.c",
"src/core/surface/channel_create.c",
"src/core/surface/client.c",
"src/core/surface/completion_queue.c",
"src/core/surface/event_string.c",
"src/core/surface/init.c",
@ -287,6 +306,7 @@
"src/core/transport/chttp2/varint.c",
"src/core/transport/chttp2/writing.c",
"src/core/transport/chttp2_transport.c",
"src/core/transport/connectivity_state.c",
"src/core/transport/metadata.c",
"src/core/transport/stream_op.c",
"src/core/transport/transport.c",
@ -748,6 +768,7 @@
"test/cpp/qps/driver.h",
"test/cpp/qps/histogram.h",
"test/cpp/qps/interarrival.h",
"test/cpp/qps/perf_db_client.h",
"test/cpp/qps/qps_worker.h",
"test/cpp/qps/report.h",
"test/cpp/qps/server.h",
@ -757,9 +778,11 @@
],
"src": [
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/perf_db.proto",
"test/cpp/qps/client_async.cc",
"test/cpp/qps/client_sync.cc",
"test/cpp/qps/driver.cc",
"test/cpp/qps/perf_db_client.cc",
"test/cpp/qps/qps_worker.cc",
"test/cpp/qps/report.cc",
"test/cpp/qps/server_async.cc",
@ -1779,6 +1802,20 @@
"gpr"
]
},
{
"name": "uri_parser_test",
"build": "test",
"language": "c",
"src": [
"test/core/client_config/uri_parser_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "async_end2end_test",
"build": "test",

@ -152,14 +152,24 @@ Pod::Spec.new do |s|
'src/core/channel/census_filter.h',
'src/core/channel/channel_args.h',
'src/core/channel/channel_stack.h',
'src/core/channel/child_channel.h',
'src/core/channel/client_channel.h',
'src/core/channel/client_setup.h',
'src/core/channel/connected_channel.h',
'src/core/channel/context.h',
'src/core/channel/http_client_filter.h',
'src/core/channel/http_server_filter.h',
'src/core/channel/noop_filter.h',
'src/core/client_config/client_config.h',
'src/core/client_config/connector.h',
'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policy.h',
'src/core/client_config/resolver.h',
'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/subchannel.h',
'src/core/client_config/subchannel_factory.h',
'src/core/client_config/uri_parser.h',
'src/core/compression/message_compress.h',
'src/core/debug/trace.h',
'src/core/iomgr/alarm.h',
@ -202,7 +212,6 @@ Pod::Spec.new do |s|
'src/core/surface/byte_buffer_queue.h',
'src/core/surface/call.h',
'src/core/surface/channel.h',
'src/core/surface/client.h',
'src/core/surface/completion_queue.h',
'src/core/surface/event_string.h',
'src/core/surface/init.h',
@ -229,6 +238,7 @@ Pod::Spec.new do |s|
'src/core/transport/chttp2/timeout_encoding.h',
'src/core/transport/chttp2/varint.h',
'src/core/transport/chttp2_transport.h',
'src/core/transport/connectivity_state.h',
'src/core/transport/metadata.h',
'src/core/transport/stream_op.h',
'src/core/transport/transport.h',
@ -267,13 +277,23 @@ Pod::Spec.new do |s|
'src/core/census/grpc_context.c',
'src/core/channel/channel_args.c',
'src/core/channel/channel_stack.c',
'src/core/channel/child_channel.c',
'src/core/channel/client_channel.c',
'src/core/channel/client_setup.c',
'src/core/channel/connected_channel.c',
'src/core/channel/http_client_filter.c',
'src/core/channel/http_server_filter.c',
'src/core/channel/noop_filter.c',
'src/core/client_config/client_config.c',
'src/core/client_config/connector.c',
'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policy.c',
'src/core/client_config/resolver.c',
'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/subchannel.c',
'src/core/client_config/subchannel_factory.c',
'src/core/client_config/uri_parser.c',
'src/core/compression/algorithm.c',
'src/core/compression/message_compress.c',
'src/core/debug/trace.c',
@ -326,7 +346,6 @@ Pod::Spec.new do |s|
'src/core/surface/call_log_batch.c',
'src/core/surface/channel.c',
'src/core/surface/channel_create.c',
'src/core/surface/client.c',
'src/core/surface/completion_queue.c',
'src/core/surface/event_string.c',
'src/core/surface/init.c',
@ -357,6 +376,7 @@ Pod::Spec.new do |s|
'src/core/transport/chttp2/varint.c',
'src/core/transport/chttp2/writing.c',
'src/core/transport/chttp2_transport.c',
'src/core/transport/connectivity_state.c',
'src/core/transport/metadata.c',
'src/core/transport/stream_op.c',
'src/core/transport/transport.c',
@ -390,14 +410,24 @@ Pod::Spec.new do |s|
'src/core/channel/census_filter.h',
'src/core/channel/channel_args.h',
'src/core/channel/channel_stack.h',
'src/core/channel/child_channel.h',
'src/core/channel/client_channel.h',
'src/core/channel/client_setup.h',
'src/core/channel/connected_channel.h',
'src/core/channel/context.h',
'src/core/channel/http_client_filter.h',
'src/core/channel/http_server_filter.h',
'src/core/channel/noop_filter.h',
'src/core/client_config/client_config.h',
'src/core/client_config/connector.h',
'src/core/client_config/lb_policies/pick_first.h',
'src/core/client_config/lb_policy.h',
'src/core/client_config/resolver.h',
'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/subchannel.h',
'src/core/client_config/subchannel_factory.h',
'src/core/client_config/uri_parser.h',
'src/core/compression/message_compress.h',
'src/core/debug/trace.h',
'src/core/iomgr/alarm.h',
@ -440,7 +470,6 @@ Pod::Spec.new do |s|
'src/core/surface/byte_buffer_queue.h',
'src/core/surface/call.h',
'src/core/surface/channel.h',
'src/core/surface/client.h',
'src/core/surface/completion_queue.h',
'src/core/surface/event_string.h',
'src/core/surface/init.h',
@ -467,6 +496,7 @@ Pod::Spec.new do |s|
'src/core/transport/chttp2/timeout_encoding.h',
'src/core/transport/chttp2/varint.h',
'src/core/transport/chttp2_transport.h',
'src/core/transport/connectivity_state.h',
'src/core/transport/metadata.h',
'src/core/transport/stream_op.h',
'src/core/transport/transport.h',
@ -494,9 +524,9 @@ Pod::Spec.new do |s|
BAD_TIME="$DIR_TIME/time.h"
GOOD_TIME="$DIR_TIME/grpc_time.h"
grep -rl "$BAD_TIME" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
if [ -f "include/$BAD_TIME" ];
if [ -f "$BAD_TIME" ];
then
mv -f "include/$BAD_TIME" "include/$GOOD_TIME"
mv -f "$BAD_TIME" "$GOOD_TIME"
fi
DIR_STRING="src/core/support"

@ -0,0 +1,128 @@
# 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.
"""
Bazel macros to declare gRPC libraries automatically generated from proto files.
This file declares two macros:
- objc_proto_library
- objc_grpc_library
"""
def _lower_underscore_to_upper_camel(str):
humps = []
for hump in str.split('_'):
humps += [hump[0].upper() + hump[1:]]
return "".join(humps)
def _file_to_upper_camel(src):
elements = src.rpartition('/')
upper_camel = _lower_underscore_to_upper_camel(elements[-1])
return "".join(elements[:-1] + [upper_camel])
def _file_with_extension(src, ext):
elements = src.rpartition('/')
basename = elements[-1].partition('.')[0]
return "".join(elements[:-1] + [basename, ext])
def _protoc_invocation(srcs, flags):
"""Returns a command line to invoke protoc from a genrule, on the given
sources, using the given flags.
"""
protoc_command = "$(location //external:protoc) -I . "
srcs_params = ""
for src in srcs:
srcs_params += " $(location %s)" % (src)
return protoc_command + flags + srcs_params
def objc_proto_library(name, srcs, visibility=None):
"""Declares an objc_library for the code generated by protoc from the given
proto sources. This generated code doesn't include proto services.
"""
h_files = []
m_files = []
for src in srcs:
src = _file_to_upper_camel(src)
h_files += [_file_with_extension(src, ".pbobjc.h")]
m_files += [_file_with_extension(src, ".pbobjc.m")]
protoc_flags = "--objc_out=$(GENDIR)"
native.genrule(
name = name + "_codegen",
srcs = srcs + ["//external:protoc"],
outs = h_files + m_files,
cmd = _protoc_invocation(srcs, protoc_flags),
)
native.objc_library(
name = name,
hdrs = h_files,
includes = ["."],
non_arc_srcs = m_files,
deps = ["//external:protobuf_objc"],
visibility = visibility,
)
def objc_grpc_library(name, services, other_messages, visibility=None):
"""Declares an objc_library for the code generated by gRPC and protoc from the
given proto sources (services and other_messages). The generated code doesn't
include proto services of the files passed as other_messages.
"""
objc_proto_library(name + "_messages", services + other_messages)
h_files = []
m_files = []
for src in services:
src = _file_to_upper_camel(src)
h_files += [_file_with_extension(src, ".pbrpc.h")]
m_files += [_file_with_extension(src, ".pbrpc.m")]
protoc_flags = ("--grpc_out=$(GENDIR) --plugin=" +
"protoc-gen-grpc=$(location //external:grpc_protoc_plugin_objc)")
native.genrule(
name = name + "_codegen",
srcs = services + [
"//external:grpc_protoc_plugin_objc",
"//external:protoc",
],
outs = h_files + m_files,
cmd = _protoc_invocation(services, protoc_flags),
)
native.objc_library(
name = name,
hdrs = h_files,
includes = ["."],
srcs = m_files,
deps = [
":" + name + "_messages",
"//external:proto_objc_rpc",
],
visibility = visibility,
)

@ -102,6 +102,10 @@ void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice);
/** Returns a RAW byte buffer instance from the output of \a reader. */
grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
grpc_byte_buffer_reader *reader);
#ifdef __cplusplus
}
#endif

@ -118,6 +118,20 @@ typedef struct {
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Connectivity state of a channel. */
typedef enum {
/** channel is idle */
GRPC_CHANNEL_IDLE,
/** channel is connecting */
GRPC_CHANNEL_CONNECTING,
/** channel is ready for work */
GRPC_CHANNEL_READY,
/** channel has seen a failure but expects to recover */
GRPC_CHANNEL_TRANSIENT_FAILURE,
/** channel has seen a failure that it cannot recover from */
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
@ -427,7 +441,7 @@ void grpc_channel_destroy(grpc_channel *channel);
has been made. */
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread.
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.*/
@ -443,7 +457,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
grpc_status_code status,
const char *description);
/* Destroy a call.
/* Destroy a call.
THREAD SAFETY: grpc_call_destroy is thread-compatible */
void grpc_call_destroy(grpc_call *call);

@ -37,8 +37,6 @@
/* Win32 variant of atm_platform.h */
#include <grpc/support/port_platform.h>
#include <windows.h>
typedef gpr_intptr gpr_atm;
#define gpr_atm_full_barrier MemoryBarrier

@ -34,8 +34,6 @@
#ifndef GRPC_SUPPORT_LOG_WIN32_H
#define GRPC_SUPPORT_LOG_WIN32_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif

@ -34,6 +34,38 @@
#ifndef GRPC_SUPPORT_PORT_PLATFORM_H
#define GRPC_SUPPORT_PORT_PLATFORM_H
/* Get windows.h included everywhere (we need it) */
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
#define WIN32_LEAN_AND_MEAN
#endif /* WIN32_LEAN_AND_MEAN */
#ifndef NOMINMAX
#define GRPC_NOMINMX_WAS_NOT_DEFINED
#define NOMINMAX
#endif /* NOMINMAX */
#if defined(_WIN32_WINNT)
#if _WIN32_WINNT < 0x0600
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif /* _WIN32_WINNT < 0x0600 */
#endif /* defined(_WIN32_WINNT) */
#include <windows.h>
#ifdef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
#undef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
#undef WIN32_LEAN_AND_MEAN
#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
#ifdef GRPC_NOMINMAX_WAS_NOT_DEFINED
#undef GRPC_NOMINMAX_WAS_NOT_DEFINED
#undef NOMINMAX
#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
#endif /* defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) */
/* Override this file with one for your platform if you need to redefine
things. */

@ -36,8 +36,6 @@
#include <grpc/support/sync_generic.h>
#include <windows.h>
typedef struct {
CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
int locked;

@ -84,7 +84,8 @@ static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb,
}
}
static void client_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
static void client_mutate_op(grpc_call_element* elem,
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
if (op->send_ops) {
@ -93,7 +94,7 @@ static void client_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
}
static void client_start_transport_op(grpc_call_element* elem,
grpc_transport_op* op) {
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
client_mutate_op(elem, op);
@ -110,7 +111,8 @@ static void server_on_done_recv(void* ptr, int success) {
calld->on_done_recv(calld->recv_user_data, success);
}
static void server_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
static void server_mutate_op(grpc_call_element* elem,
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
if (op->recv_ops) {
/* substitute our callback for the op callback */
@ -123,7 +125,7 @@ static void server_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
}
static void server_start_transport_op(grpc_call_element* elem,
grpc_transport_op* op) {
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
server_mutate_op(elem, op);
@ -145,7 +147,7 @@ static void channel_op(grpc_channel_element* elem,
static void client_init_call_elem(grpc_call_element* elem,
const void* server_transport_data,
grpc_transport_op* initial_op) {
grpc_transport_stream_op* initial_op) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
@ -163,7 +165,7 @@ static void client_destroy_call_elem(grpc_call_element* elem) {
static void server_init_call_elem(grpc_call_element* elem,
const void* server_transport_data,
grpc_transport_op* initial_op) {
grpc_transport_stream_op* initial_op) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
@ -200,11 +202,23 @@ static void destroy_channel_elem(grpc_channel_element* elem) {
}
const grpc_channel_filter grpc_client_census_filter = {
client_start_transport_op, channel_op, sizeof(call_data),
client_init_call_elem, client_destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "census-client"};
client_start_transport_op,
channel_op,
sizeof(call_data),
client_init_call_elem,
client_destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"census-client"};
const grpc_channel_filter grpc_server_census_filter = {
server_start_transport_op, channel_op, sizeof(call_data),
server_init_call_elem, server_destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "census-server"};
server_start_transport_op,
channel_op,
sizeof(call_data),
server_init_call_elem,
server_destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"census-server"};

@ -62,7 +62,8 @@ static grpc_arg copy_arg(const grpc_arg *src) {
}
grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
const grpc_arg *to_add) {
const grpc_arg *to_add,
size_t num_to_add) {
grpc_channel_args *dst = gpr_malloc(sizeof(grpc_channel_args));
size_t i;
size_t src_num_args = (src == NULL) ? 0 : src->num_args;
@ -71,17 +72,24 @@ grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
dst->args = NULL;
return dst;
}
dst->num_args = src_num_args + ((to_add == NULL) ? 0 : 1);
dst->num_args = src_num_args + num_to_add;
dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
for (i = 0; i < src_num_args; i++) {
dst->args[i] = copy_arg(&src->args[i]);
}
if (to_add != NULL) dst->args[src_num_args] = copy_arg(to_add);
for (i = 0; i < num_to_add; i++) {
dst->args[i + src_num_args] = copy_arg(&to_add[i]);
}
return dst;
}
grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src) {
return grpc_channel_args_copy_and_add(src, NULL);
return grpc_channel_args_copy_and_add(src, NULL, 0);
}
grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
const grpc_channel_args *b) {
return grpc_channel_args_copy_and_add(a, b->args, b->num_args);
}
void grpc_channel_args_destroy(grpc_channel_args *a) {
@ -131,11 +139,11 @@ grpc_compression_level grpc_channel_args_get_compression_level(
return GRPC_COMPRESS_LEVEL_NONE;
}
void grpc_channel_args_set_compression_level(
grpc_channel_args **a, grpc_compression_level level) {
void grpc_channel_args_set_compression_level(grpc_channel_args **a,
grpc_compression_level level) {
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);
*a = grpc_channel_args_copy_and_add(*a, &tmp, 1);
}

@ -43,7 +43,12 @@ grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
/** Copy some arguments and add the to_add parameter in the end.
If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */
grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
const grpc_arg *to_add);
const grpc_arg *to_add,
size_t num_to_add);
/** Copy args from a then args from b into a new channel args */
grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
const grpc_channel_args *b);
/** Destroy arguments created by grpc_channel_args_copy */
void grpc_channel_args_destroy(grpc_channel_args *a);
@ -58,7 +63,7 @@ grpc_compression_level grpc_channel_args_get_compression_level(
/** 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);
void grpc_channel_args_set_compression_level(grpc_channel_args **a,
grpc_compression_level level);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */

@ -102,7 +102,8 @@ grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
}
void grpc_channel_stack_init(const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack) {
size_t call_size =
@ -122,8 +123,9 @@ void grpc_channel_stack_init(const grpc_channel_filter **filters,
for (i = 0; i < filter_count; i++) {
elems[i].filter = filters[i];
elems[i].channel_data = user_data;
elems[i].filter->init_channel_elem(&elems[i], args, metadata_context,
i == 0, i == (filter_count - 1));
elems[i].filter->init_channel_elem(&elems[i], master, args,
metadata_context, i == 0,
i == (filter_count - 1));
user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
}
@ -148,7 +150,7 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack) {
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
grpc_transport_op *initial_op,
grpc_transport_stream_op *initial_op,
grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
size_t count = channel_stack->count;
@ -184,14 +186,14 @@ void grpc_call_stack_destroy(grpc_call_stack *stack) {
}
}
void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op) {
void grpc_call_next_op(grpc_call_element *elem, grpc_transport_stream_op *op) {
grpc_call_element *next_elem = elem + 1;
next_elem->filter->start_transport_op(next_elem, op);
next_elem->filter->start_transport_stream_op(next_elem, op);
}
void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
grpc_channel_element *next_elem = elem + op->dir;
next_elem->filter->channel_op(next_elem, elem, op);
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);
}
grpc_channel_stack *grpc_channel_stack_from_top_element(
@ -206,7 +208,7 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
}
void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
grpc_transport_op op;
grpc_transport_stream_op op;
memset(&op, 0, sizeof(op));
op.cancel_with_status = GRPC_STATUS_CANCELLED;
grpc_call_next_op(cur_elem, &op);

@ -51,45 +51,6 @@
typedef struct grpc_channel_element grpc_channel_element;
typedef struct grpc_call_element grpc_call_element;
/* The direction of the call.
The values of the enums (1, -1) matter here - they are used to increment
or decrement a pointer to find the next element to call */
typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir;
typedef enum {
/* send a goaway message to remote channels indicating that we are going
to disconnect in the future */
GRPC_CHANNEL_GOAWAY,
/* disconnect any underlying transports */
GRPC_CHANNEL_DISCONNECT,
/* transport received a new call */
GRPC_ACCEPT_CALL,
/* an underlying transport was closed */
GRPC_TRANSPORT_CLOSED,
/* an underlying transport is about to be closed */
GRPC_TRANSPORT_GOAWAY
} grpc_channel_op_type;
/* A single filterable operation to be performed on a channel */
typedef struct {
/* The type of operation we're performing */
grpc_channel_op_type type;
/* The directionality of this call - is it bubbling up the stack, or down? */
grpc_call_dir dir;
/* Argument data, matching up with grpc_channel_op_type names */
union {
struct {
grpc_transport *transport;
const void *transport_server_data;
} accept_call;
struct {
grpc_status_code status;
gpr_slice message;
} goaway;
} data;
} grpc_channel_op;
/* Channel filters specify:
1. the amount of memory needed in the channel & call (via the sizeof_XXX
members)
@ -103,12 +64,12 @@ typedef struct {
typedef struct {
/* Called to eg. send/receive data on a call.
See grpc_call_next_op on how to call the next element in the stack */
void (*start_transport_op)(grpc_call_element *elem, grpc_transport_op *op);
void (*start_transport_stream_op)(grpc_call_element *elem,
grpc_transport_stream_op *op);
/* Called to handle channel level operations - e.g. new calls, or transport
closure.
See grpc_channel_next_op on how to call the next element in the stack */
void (*channel_op)(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op);
void (*start_transport_op)(grpc_channel_element *elem, grpc_transport_op *op);
/* sizeof(per call data) */
size_t sizeof_call_data;
@ -122,7 +83,7 @@ typedef struct {
argument.*/
void (*init_call_elem)(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op);
grpc_transport_stream_op *initial_op);
/* Destroy per call data.
The filter does not need to do any chaining */
void (*destroy_call_elem)(grpc_call_element *elem);
@ -135,7 +96,7 @@ typedef struct {
is_first, is_last designate this elements position in the stack, and are
useful for asserting correct configuration by upper layer code.
The filter does not need to do any chaining */
void (*init_channel_elem)(grpc_channel_element *elem,
void (*init_channel_elem)(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last);
@ -190,7 +151,8 @@ size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count);
/* Initialize a channel stack given some filters */
void grpc_channel_stack_init(const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
size_t filter_count, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context,
grpc_channel_stack *stack);
/* Destroy a channel stack */
@ -201,16 +163,16 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack);
server. */
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
grpc_transport_op *initial_op,
grpc_transport_stream_op *initial_op,
grpc_call_stack *call_stack);
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_call_stack *stack);
/* Call the next operation in a call stack */
void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op);
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_channel_op *op);
void grpc_channel_next_op(grpc_channel_element *elem, grpc_transport_op *op);
/* Given the top element of a channel stack, get the channel stack itself */
grpc_channel_stack *grpc_channel_stack_from_top_element(
@ -219,7 +181,7 @@ grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
grpc_call_element *elem, grpc_transport_op *op);
grpc_call_element *elem, grpc_transport_stream_op *op);
void grpc_call_element_send_cancel(grpc_call_element *cur_elem);

@ -1,308 +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 "src/core/channel/child_channel.h"
#include "src/core/iomgr/iomgr.h"
#include <grpc/support/alloc.h>
/* Link back filter: passes up calls to the client channel, pushes down calls
down */
static void maybe_destroy_channel(grpc_child_channel *channel);
typedef struct {
gpr_mu mu;
gpr_cv cv;
grpc_channel_element *back;
/* # of active calls on the channel */
gpr_uint32 active_calls;
/* has grpc_child_channel_destroy been called? */
gpr_uint8 destroyed;
/* has the transport reported itself disconnected? */
gpr_uint8 disconnected;
/* are we calling 'back' - our parent channel */
gpr_uint8 calling_back;
/* have we or our parent sent goaway yet? - dup suppression */
gpr_uint8 sent_goaway;
/* are we currently sending farewell (in this file: goaway + disconnect) */
gpr_uint8 sending_farewell;
/* have we sent farewell (goaway + disconnect) */
gpr_uint8 sent_farewell;
grpc_iomgr_closure finally_destroy_channel_closure;
grpc_iomgr_closure send_farewells_closure;
} lb_channel_data;
typedef struct { grpc_child_channel *channel; } lb_call_data;
static void lb_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_call_next_op(elem, op);
}
/* Currently we assume all channel operations should just be pushed up. */
static void lb_channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem,
grpc_channel_op *op) {
lb_channel_data *chand = elem->channel_data;
grpc_channel_element *back;
int calling_back = 0;
switch (op->dir) {
case GRPC_CALL_UP:
gpr_mu_lock(&chand->mu);
back = chand->back;
if (back) {
chand->calling_back++;
calling_back = 1;
}
gpr_mu_unlock(&chand->mu);
if (back) {
back->filter->channel_op(chand->back, elem, op);
} else if (op->type == GRPC_TRANSPORT_GOAWAY) {
gpr_slice_unref(op->data.goaway.message);
}
break;
case GRPC_CALL_DOWN:
grpc_channel_next_op(elem, op);
break;
}
gpr_mu_lock(&chand->mu);
switch (op->type) {
case GRPC_TRANSPORT_CLOSED:
chand->disconnected = 1;
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
break;
case GRPC_CHANNEL_GOAWAY:
chand->sent_goaway = 1;
break;
case GRPC_CHANNEL_DISCONNECT:
case GRPC_TRANSPORT_GOAWAY:
case GRPC_ACCEPT_CALL:
break;
}
if (calling_back) {
chand->calling_back--;
gpr_cv_signal(&chand->cv);
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
}
gpr_mu_unlock(&chand->mu);
}
/* Constructor for call_data */
static void lb_init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {}
/* Destructor for call_data */
static void lb_destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void lb_init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
lb_channel_data *chand = elem->channel_data;
GPR_ASSERT(is_first);
GPR_ASSERT(!is_last);
gpr_mu_init(&chand->mu);
gpr_cv_init(&chand->cv);
chand->back = NULL;
chand->destroyed = 0;
chand->disconnected = 0;
chand->active_calls = 0;
chand->sent_goaway = 0;
chand->calling_back = 0;
chand->sending_farewell = 0;
chand->sent_farewell = 0;
}
/* Destructor for channel_data */
static void lb_destroy_channel_elem(grpc_channel_element *elem) {
lb_channel_data *chand = elem->channel_data;
gpr_mu_destroy(&chand->mu);
gpr_cv_destroy(&chand->cv);
}
const grpc_channel_filter grpc_child_channel_top_filter = {
lb_start_transport_op, lb_channel_op,
sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem,
sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem,
"child-channel",
};
/* grpc_child_channel proper */
#define LINK_BACK_ELEM_FROM_CHANNEL(channel) \
grpc_channel_stack_element((channel), 0)
#define LINK_BACK_ELEM_FROM_CALL(call) grpc_call_stack_element((call), 0)
static void finally_destroy_channel(void *c, int success) {
/* ignore success or not... this is a destruction callback and will only
happen once - the only purpose here is to release resources */
grpc_child_channel *channel = c;
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
/* wait for the initiator to leave the mutex */
gpr_mu_lock(&chand->mu);
gpr_mu_unlock(&chand->mu);
grpc_channel_stack_destroy(channel);
gpr_free(channel);
}
static void send_farewells(void *c, int success) {
grpc_child_channel *channel = c;
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
lb_channel_data *chand = lbelem->channel_data;
int send_goaway;
grpc_channel_op op;
gpr_mu_lock(&chand->mu);
send_goaway = !chand->sent_goaway;
chand->sent_goaway = 1;
gpr_mu_unlock(&chand->mu);
if (send_goaway) {
op.type = GRPC_CHANNEL_GOAWAY;
op.dir = GRPC_CALL_DOWN;
op.data.goaway.status = GRPC_STATUS_OK;
op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
grpc_channel_next_op(lbelem, &op);
}
op.type = GRPC_CHANNEL_DISCONNECT;
op.dir = GRPC_CALL_DOWN;
grpc_channel_next_op(lbelem, &op);
gpr_mu_lock(&chand->mu);
chand->sending_farewell = 0;
chand->sent_farewell = 1;
maybe_destroy_channel(channel);
gpr_mu_unlock(&chand->mu);
}
static void maybe_destroy_channel(grpc_child_channel *channel) {
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
if (chand->destroyed && chand->disconnected && chand->active_calls == 0 &&
!chand->sending_farewell && !chand->calling_back) {
chand->finally_destroy_channel_closure.cb = finally_destroy_channel;
chand->finally_destroy_channel_closure.cb_arg = channel;
grpc_iomgr_add_callback(&chand->finally_destroy_channel_closure);
} else if (chand->destroyed && !chand->disconnected &&
chand->active_calls == 0 && !chand->sending_farewell &&
!chand->sent_farewell) {
chand->sending_farewell = 1;
chand->send_farewells_closure.cb = send_farewells;
chand->send_farewells_closure.cb_arg = channel;
grpc_iomgr_add_callback(&chand->send_farewells_closure);
}
}
grpc_child_channel *grpc_child_channel_create(
grpc_channel_element *parent, const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
grpc_mdctx *metadata_context) {
grpc_channel_stack *stk =
gpr_malloc(grpc_channel_stack_size(filters, filter_count));
lb_channel_data *lb;
grpc_channel_stack_init(filters, filter_count, args, metadata_context, stk);
lb = LINK_BACK_ELEM_FROM_CHANNEL(stk)->channel_data;
gpr_mu_lock(&lb->mu);
lb->back = parent;
gpr_mu_unlock(&lb->mu);
return stk;
}
void grpc_child_channel_destroy(grpc_child_channel *channel,
int wait_for_callbacks) {
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
lb_channel_data *chand = lbelem->channel_data;
gpr_mu_lock(&chand->mu);
while (wait_for_callbacks && chand->calling_back) {
gpr_cv_wait(&chand->cv, &chand->mu, gpr_inf_future);
}
chand->back = NULL;
chand->destroyed = 1;
maybe_destroy_channel(channel);
gpr_mu_unlock(&chand->mu);
}
void grpc_child_channel_handle_op(grpc_child_channel *channel,
grpc_channel_op *op) {
grpc_channel_next_op(LINK_BACK_ELEM_FROM_CHANNEL(channel), op);
}
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
grpc_call_element *parent,
grpc_transport_op *initial_op) {
grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size);
grpc_call_element *lbelem;
lb_call_data *lbcalld;
lb_channel_data *lbchand;
grpc_call_stack_init(channel, NULL, initial_op, stk);
lbelem = LINK_BACK_ELEM_FROM_CALL(stk);
lbchand = lbelem->channel_data;
lbcalld = lbelem->call_data;
lbcalld->channel = channel;
gpr_mu_lock(&lbchand->mu);
lbchand->active_calls++;
gpr_mu_unlock(&lbchand->mu);
return stk;
}
void grpc_child_call_destroy(grpc_child_call *call) {
grpc_call_element *lbelem = LINK_BACK_ELEM_FROM_CALL(call);
lb_call_data *calld = lbelem->call_data;
lb_channel_data *chand = lbelem->channel_data;
grpc_child_channel *channel = calld->channel;
grpc_call_stack_destroy(call);
gpr_free(call);
gpr_mu_lock(&chand->mu);
chand->active_calls--;
maybe_destroy_channel(channel);
gpr_mu_unlock(&chand->mu);
}
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call) {
return LINK_BACK_ELEM_FROM_CALL(call);
}

@ -1,65 +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.
*
*/
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H
#define GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H
#include "src/core/channel/channel_stack.h"
/* helper for filters that need to host child channel stacks... handles
lifetime and upwards propagation cleanly */
extern const grpc_channel_filter grpc_child_channel_top_filter;
typedef grpc_channel_stack grpc_child_channel;
typedef grpc_call_stack grpc_child_call;
/* filters[0] must be &grpc_child_channel_top_filter */
grpc_child_channel *grpc_child_channel_create(
grpc_channel_element *parent, const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
grpc_mdctx *metadata_context);
void grpc_child_channel_handle_op(grpc_child_channel *channel,
grpc_channel_op *op);
grpc_channel_element *grpc_child_channel_get_bottom_element(
grpc_child_channel *channel);
void grpc_child_channel_destroy(grpc_child_channel *channel,
int wait_for_callbacks);
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
grpc_call_element *parent,
grpc_transport_op *initial_op);
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call);
void grpc_child_call_destroy(grpc_child_call *call);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */

@ -34,13 +34,15 @@
#include "src/core/channel/client_channel.h"
#include <stdio.h>
#include <string.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/child_channel.h"
#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>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
@ -51,31 +53,38 @@
typedef struct call_data call_data;
typedef struct {
/* protects children, child_count, child_capacity, active_child,
transport_setup_initiated
does not protect channel stacks held by children
transport_setup is assumed to be set once during construction */
gpr_mu mu;
/* the sending child (may be null) */
grpc_child_channel *active_child;
/** metadata context for this channel */
grpc_mdctx *mdctx;
/* calls waiting for a channel to be ready */
call_data **waiting_children;
size_t waiting_child_count;
size_t waiting_child_capacity;
/* transport setup for this channel */
grpc_transport_setup *transport_setup;
int transport_setup_initiated;
grpc_channel_args *args;
/** resolver for this channel */
grpc_resolver *resolver;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */
grpc_channel *master;
/** mutex protecting client configuration, including all
variables below in this data structure */
gpr_mu mu_config;
/** currently active load balancer - guarded by mu_config */
grpc_lb_policy *lb_policy;
/** incoming configuration - set by resolver.next
guarded by mu_config */
grpc_client_config *incoming_configuration;
/** a list of closures that are all waiting for config to come in */
grpc_iomgr_closure *waiting_for_config_closures;
/** resolver callback */
grpc_iomgr_closure on_config_changed;
/** connectivity state being tracked */
grpc_connectivity_state_tracker state_tracker;
} channel_data;
typedef enum {
CALL_CREATED,
CALL_WAITING,
CALL_WAITING_FOR_SEND,
CALL_WAITING_FOR_CONFIG,
CALL_WAITING_FOR_PICK,
CALL_WAITING_FOR_CALL,
CALL_ACTIVE,
CALL_CANCELLED
} call_state;
@ -84,75 +93,25 @@ struct call_data {
/* owning element */
grpc_call_element *elem;
gpr_mu mu_state;
call_state state;
gpr_timespec deadline;
union {
struct {
/* our child call stack */
grpc_child_call *child_call;
} active;
grpc_transport_op waiting_op;
struct {
grpc_linked_mdelem status;
grpc_linked_mdelem details;
} cancelled;
} s;
grpc_subchannel *picked_channel;
grpc_iomgr_closure async_setup_task;
grpc_transport_stream_op waiting_op;
/* our child call stack */
grpc_subchannel_call *subchannel_call;
grpc_linked_mdelem status;
grpc_linked_mdelem details;
};
static int prepare_activate(grpc_call_element *elem,
grpc_child_channel *on_child) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
if (calld->state == CALL_CANCELLED) return 0;
/* no more access to calld->s.waiting allowed */
GPR_ASSERT(calld->state == CALL_WAITING);
if (calld->s.waiting_op.bind_pollset) {
grpc_transport_setup_del_interested_party(chand->transport_setup,
calld->s.waiting_op.bind_pollset);
}
calld->state = CALL_ACTIVE;
/* create a child call */
/* TODO(ctiller): pass the waiting op down here */
calld->s.active.child_call =
grpc_child_channel_create_call(on_child, elem, NULL);
return 1;
}
static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) {
call_data *calld = elem->call_data;
grpc_call_element *child_elem =
grpc_child_call_get_top_element(calld->s.active.child_call);
GPR_ASSERT(calld->state == CALL_ACTIVE);
/* continue the start call down the stack, this nees to happen after metadata
are flushed*/
child_elem->filter->start_transport_op(child_elem, op);
}
static void remove_waiting_child(channel_data *chand, call_data *calld) {
size_t new_count;
size_t i;
for (i = 0, new_count = 0; i < chand->waiting_child_count; i++) {
if (chand->waiting_children[i] == calld) {
grpc_transport_setup_del_interested_party(
chand->transport_setup, calld->s.waiting_op.bind_pollset);
continue;
}
chand->waiting_children[new_count++] = chand->waiting_children[i];
}
GPR_ASSERT(new_count == chand->waiting_child_count - 1 ||
new_count == chand->waiting_child_count);
chand->waiting_child_count = new_count;
}
static grpc_iomgr_closure *merge_into_waiting_op(
grpc_call_element *elem,
grpc_transport_stream_op *new_op) GRPC_MUST_USE_RESULT;
static void handle_op_after_cancellation(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
if (op->send_ops) {
@ -163,15 +122,15 @@ static void handle_op_after_cancellation(grpc_call_element *elem,
char status[GPR_LTOA_MIN_BUFSIZE];
grpc_metadata_batch mdb;
gpr_ltoa(GRPC_STATUS_CANCELLED, status);
calld->s.cancelled.status.md =
calld->status.md =
grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status);
calld->s.cancelled.details.md =
calld->details.md =
grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled");
calld->s.cancelled.status.prev = calld->s.cancelled.details.next = NULL;
calld->s.cancelled.status.next = &calld->s.cancelled.details;
calld->s.cancelled.details.prev = &calld->s.cancelled.status;
mdb.list.head = &calld->s.cancelled.status;
mdb.list.tail = &calld->s.cancelled.details;
calld->status.prev = calld->details.next = NULL;
calld->status.next = &calld->details;
calld->details.prev = &calld->status;
mdb.list.head = &calld->status;
mdb.list.tail = &calld->details;
mdb.garbage.head = mdb.garbage.tail = NULL;
mdb.deadline = gpr_inf_future;
grpc_sopb_add_metadata(op->recv_ops, mdb);
@ -183,192 +142,372 @@ static void handle_op_after_cancellation(grpc_call_element *elem,
}
}
static void cc_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
typedef struct {
grpc_iomgr_closure closure;
grpc_call_element *elem;
} waiting_call;
static void perform_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op,
int continuation);
static void continue_with_pick(void *arg, int iomgr_success) {
waiting_call *wc = arg;
call_data *calld = wc->elem->call_data;
perform_transport_stream_op(wc->elem, &calld->waiting_op, 1);
gpr_free(wc);
}
static void add_to_lb_policy_wait_queue_locked_state_config(
grpc_call_element *elem) {
channel_data *chand = elem->channel_data;
waiting_call *wc = gpr_malloc(sizeof(*wc));
grpc_iomgr_closure_init(&wc->closure, continue_with_pick, wc);
wc->elem = elem;
wc->closure.next = chand->waiting_for_config_closures;
chand->waiting_for_config_closures = &wc->closure;
}
static int is_empty(void *p, int len) {
char *ptr = p;
int i;
for (i = 0; i < len; i++) {
if (ptr[i] != 0) return 0;
}
return 1;
}
static void started_call(void *arg, int iomgr_success) {
call_data *calld = arg;
grpc_transport_stream_op op;
int have_waiting;
gpr_mu_lock(&calld->mu_state);
if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) {
memset(&op, 0, sizeof(op));
op.cancel_with_status = GRPC_STATUS_CANCELLED;
gpr_mu_unlock(&calld->mu_state);
grpc_subchannel_call_process_op(calld->subchannel_call, &op);
} else if (calld->state == CALL_WAITING_FOR_CALL) {
have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op));
if (calld->subchannel_call != NULL) {
calld->state = CALL_ACTIVE;
gpr_mu_unlock(&calld->mu_state);
if (have_waiting) {
grpc_subchannel_call_process_op(calld->subchannel_call,
&calld->waiting_op);
}
} else {
calld->state = CALL_CANCELLED;
gpr_mu_unlock(&calld->mu_state);
if (have_waiting) {
handle_op_after_cancellation(calld->elem, &calld->waiting_op);
}
}
} else {
GPR_ASSERT(calld->state == CALL_CANCELLED);
gpr_mu_unlock(&calld->mu_state);
}
}
static void picked_target(void *arg, int iomgr_success) {
call_data *calld = arg;
grpc_pollset *pollset;
if (calld->picked_channel == NULL) {
/* treat this like a cancellation */
calld->waiting_op.cancel_with_status = GRPC_STATUS_UNAVAILABLE;
perform_transport_stream_op(calld->elem, &calld->waiting_op, 1);
} else {
gpr_mu_lock(&calld->mu_state);
if (calld->state == CALL_CANCELLED) {
gpr_mu_unlock(&calld->mu_state);
handle_op_after_cancellation(calld->elem, &calld->waiting_op);
} else {
GPR_ASSERT(calld->state == CALL_WAITING_FOR_PICK);
calld->state = CALL_WAITING_FOR_CALL;
pollset = calld->waiting_op.bind_pollset;
gpr_mu_unlock(&calld->mu_state);
grpc_iomgr_closure_init(&calld->async_setup_task, started_call, calld);
grpc_subchannel_create_call(calld->picked_channel, pollset,
&calld->subchannel_call,
&calld->async_setup_task);
}
}
}
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;
grpc_iomgr_closure *consumed_op = NULL;
grpc_transport_stream_op *waiting_op = &calld->waiting_op;
GPR_ASSERT((waiting_op->send_ops != NULL) + (new_op->send_ops != NULL) <= 1);
GPR_ASSERT((waiting_op->recv_ops != NULL) + (new_op->recv_ops != NULL) <= 1);
if (new_op->send_ops != NULL) {
waiting_op->send_ops = new_op->send_ops;
waiting_op->is_last_send = new_op->is_last_send;
waiting_op->on_done_send = new_op->on_done_send;
}
if (new_op->recv_ops != NULL) {
waiting_op->recv_ops = new_op->recv_ops;
waiting_op->recv_state = new_op->recv_state;
waiting_op->on_done_recv = new_op->on_done_recv;
}
if (new_op->on_consumed != NULL) {
if (waiting_op->on_consumed != NULL) {
consumed_op = waiting_op->on_consumed;
}
waiting_op->on_consumed = new_op->on_consumed;
}
if (new_op->cancel_with_status != GRPC_STATUS_OK) {
waiting_op->cancel_with_status = new_op->cancel_with_status;
}
return consumed_op;
}
static void perform_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op,
int continuation) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_call_element *child_elem;
grpc_transport_op waiting_op;
grpc_subchannel_call *subchannel_call;
grpc_lb_policy *lb_policy;
grpc_transport_stream_op op2;
grpc_iomgr_closure *consumed_op = NULL;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
gpr_mu_lock(&chand->mu);
gpr_mu_lock(&calld->mu_state);
switch (calld->state) {
case CALL_ACTIVE:
child_elem = grpc_child_call_get_top_element(calld->s.active.child_call);
gpr_mu_unlock(&chand->mu);
child_elem->filter->start_transport_op(child_elem, op);
GPR_ASSERT(!continuation);
subchannel_call = calld->subchannel_call;
gpr_mu_unlock(&calld->mu_state);
grpc_subchannel_call_process_op(subchannel_call, op);
break;
case CALL_CREATED:
if (op->cancel_with_status != GRPC_STATUS_OK) {
calld->state = CALL_CANCELLED;
gpr_mu_unlock(&chand->mu);
handle_op_after_cancellation(elem, op);
} else {
calld->state = CALL_WAITING;
calld->s.waiting_op.bind_pollset = NULL;
if (chand->active_child) {
/* channel is connected - use the connected stack */
if (prepare_activate(elem, chand->active_child)) {
gpr_mu_unlock(&chand->mu);
/* activate the request (pass it down) outside the lock */
complete_activate(elem, op);
} else {
gpr_mu_unlock(&chand->mu);
case CALL_CANCELLED:
gpr_mu_unlock(&calld->mu_state);
handle_op_after_cancellation(elem, op);
break;
case CALL_WAITING_FOR_SEND:
GPR_ASSERT(!continuation);
consumed_op = merge_into_waiting_op(elem, op);
if (!calld->waiting_op.send_ops &&
calld->waiting_op.cancel_with_status == GRPC_STATUS_OK) {
gpr_mu_unlock(&calld->mu_state);
break;
}
*op = calld->waiting_op;
memset(&calld->waiting_op, 0, sizeof(calld->waiting_op));
continuation = 1;
/* fall through */
case CALL_WAITING_FOR_CONFIG:
case CALL_WAITING_FOR_PICK:
case CALL_WAITING_FOR_CALL:
if (!continuation) {
if (op->cancel_with_status != GRPC_STATUS_OK) {
calld->state = CALL_CANCELLED;
op2 = calld->waiting_op;
memset(&calld->waiting_op, 0, sizeof(calld->waiting_op));
if (op->on_consumed) {
calld->waiting_op.on_consumed = op->on_consumed;
op->on_consumed = NULL;
} else if (op2.on_consumed) {
calld->waiting_op.on_consumed = op2.on_consumed;
op2.on_consumed = NULL;
}
gpr_mu_unlock(&calld->mu_state);
handle_op_after_cancellation(elem, op);
handle_op_after_cancellation(elem, &op2);
} else {
/* check to see if we should initiate a connection (if we're not
already),
but don't do so until outside the lock to avoid re-entrancy
problems if
the callback is immediate */
int initiate_transport_setup = 0;
if (!chand->transport_setup_initiated) {
chand->transport_setup_initiated = 1;
initiate_transport_setup = 1;
}
/* add this call to the waiting set to be resumed once we have a child
channel stack, growing the waiting set if needed */
if (chand->waiting_child_count == chand->waiting_child_capacity) {
chand->waiting_child_capacity =
GPR_MAX(chand->waiting_child_capacity * 2, 8);
chand->waiting_children = gpr_realloc(
chand->waiting_children,
chand->waiting_child_capacity * sizeof(call_data *));
}
calld->s.waiting_op = *op;
chand->waiting_children[chand->waiting_child_count++] = calld;
grpc_transport_setup_add_interested_party(chand->transport_setup,
op->bind_pollset);
gpr_mu_unlock(&chand->mu);
/* finally initiate transport setup if needed */
if (initiate_transport_setup) {
grpc_transport_setup_initiate(chand->transport_setup);
}
consumed_op = merge_into_waiting_op(elem, op);
gpr_mu_unlock(&calld->mu_state);
}
break;
}
break;
case CALL_WAITING:
/* fall through */
case CALL_CREATED:
if (op->cancel_with_status != GRPC_STATUS_OK) {
waiting_op = calld->s.waiting_op;
remove_waiting_child(chand, calld);
calld->state = CALL_CANCELLED;
gpr_mu_unlock(&chand->mu);
handle_op_after_cancellation(elem, &waiting_op);
gpr_mu_unlock(&calld->mu_state);
handle_op_after_cancellation(elem, op);
} else {
GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) !=
(op->send_ops == NULL));
GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) !=
(op->recv_ops == NULL));
if (op->send_ops) {
calld->s.waiting_op.send_ops = op->send_ops;
calld->s.waiting_op.is_last_send = op->is_last_send;
calld->s.waiting_op.on_done_send = op->on_done_send;
}
if (op->recv_ops) {
calld->s.waiting_op.recv_ops = op->recv_ops;
calld->s.waiting_op.recv_state = op->recv_state;
calld->s.waiting_op.on_done_recv = op->on_done_recv;
}
gpr_mu_unlock(&chand->mu);
if (op->on_consumed) {
op->on_consumed->cb(op->on_consumed->cb_arg, 0);
calld->waiting_op = *op;
if (op->send_ops == NULL) {
/* need to have some send ops before we can select the
lb target */
calld->state = CALL_WAITING_FOR_SEND;
gpr_mu_unlock(&calld->mu_state);
} else {
gpr_mu_lock(&chand->mu_config);
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "pick");
gpr_mu_unlock(&chand->mu_config);
calld->state = CALL_WAITING_FOR_PICK;
gpr_mu_unlock(&calld->mu_state);
pick_target(lb_policy, calld);
GRPC_LB_POLICY_UNREF(lb_policy, "pick");
} else if (chand->resolver != NULL) {
calld->state = CALL_WAITING_FOR_CONFIG;
add_to_lb_policy_wait_queue_locked_state_config(elem);
gpr_mu_unlock(&chand->mu_config);
gpr_mu_unlock(&calld->mu_state);
} else {
calld->state = CALL_CANCELLED;
gpr_mu_unlock(&chand->mu_config);
gpr_mu_unlock(&calld->mu_state);
handle_op_after_cancellation(elem, op);
}
}
}
break;
case CALL_CANCELLED:
gpr_mu_unlock(&chand->mu);
handle_op_after_cancellation(elem, op);
break;
}
if (consumed_op != NULL) {
consumed_op->cb(consumed_op->cb_arg, 1);
}
}
static void cc_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
perform_transport_stream_op(elem, op, 0);
}
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;
if (chand->incoming_configuration != NULL) {
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
GRPC_LB_POLICY_REF(lb_policy, "channel");
grpc_client_config_unref(chand->incoming_configuration);
}
chand->incoming_configuration = NULL;
gpr_mu_lock(&chand->mu_config);
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) {
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");
}
gpr_mu_lock(&chand->mu_config);
if (iomgr_success && chand->resolver) {
grpc_resolver *resolver = chand->resolver;
GRPC_RESOLVER_REF(resolver, "channel-next");
gpr_mu_unlock(&chand->mu_config);
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
grpc_resolver_next(chand->resolver, &chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(resolver, "channel-next");
} else {
old_resolver = chand->resolver;
chand->resolver = NULL;
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
gpr_mu_unlock(&chand->mu_config);
if (old_resolver != NULL) {
grpc_resolver_shutdown(old_resolver);
GRPC_RESOLVER_UNREF(old_resolver, "channel");
}
}
while (wakeup_closures) {
grpc_iomgr_closure *next = wakeup_closures->next;
grpc_iomgr_add_callback(wakeup_closures);
wakeup_closures = next;
}
GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver");
}
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
static void cc_start_transport_op(grpc_channel_element *elem,
grpc_transport_op *op) {
grpc_lb_policy *lb_policy = NULL;
channel_data *chand = elem->channel_data;
grpc_child_channel *child_channel;
grpc_channel_op rop;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
grpc_resolver *destroy_resolver = NULL;
grpc_iomgr_closure *on_consumed = op->on_consumed;
op->on_consumed = NULL;
GPR_ASSERT(op->set_accept_stream == NULL);
GPR_ASSERT(op->bind_pollset == NULL);
gpr_mu_lock(&chand->mu_config);
if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change(
&chand->state_tracker, op->connectivity_state,
op->on_connectivity_state_change);
op->on_connectivity_state_change = NULL;
op->connectivity_state = NULL;
}
switch (op->type) {
case GRPC_CHANNEL_GOAWAY:
/* sending goaway: clear out the active child on the way through */
gpr_mu_lock(&chand->mu);
child_channel = chand->active_child;
chand->active_child = NULL;
gpr_mu_unlock(&chand->mu);
if (child_channel) {
grpc_child_channel_handle_op(child_channel, op);
grpc_child_channel_destroy(child_channel, 1);
} else {
gpr_slice_unref(op->data.goaway.message);
}
break;
case GRPC_CHANNEL_DISCONNECT:
/* sending disconnect: clear out the active child on the way through */
gpr_mu_lock(&chand->mu);
child_channel = chand->active_child;
chand->active_child = NULL;
gpr_mu_unlock(&chand->mu);
if (child_channel) {
grpc_child_channel_destroy(child_channel, 1);
}
/* fake a transport closed to satisfy the refcounting in client */
rop.type = GRPC_TRANSPORT_CLOSED;
rop.dir = GRPC_CALL_UP;
grpc_channel_next_op(elem, &rop);
break;
case GRPC_TRANSPORT_GOAWAY:
/* receiving goaway: if it's from our active child, drop the active child;
in all cases consume the event here */
gpr_mu_lock(&chand->mu);
child_channel = grpc_channel_stack_from_top_element(from_elem);
if (child_channel == chand->active_child) {
chand->active_child = NULL;
} else {
child_channel = NULL;
}
gpr_mu_unlock(&chand->mu);
if (child_channel) {
grpc_child_channel_destroy(child_channel, 0);
}
gpr_slice_unref(op->data.goaway.message);
break;
case GRPC_TRANSPORT_CLOSED:
/* receiving disconnect: if it's from our active child, drop the active
child; in all cases consume the event here */
gpr_mu_lock(&chand->mu);
child_channel = grpc_channel_stack_from_top_element(from_elem);
if (child_channel == chand->active_child) {
chand->active_child = NULL;
} else {
child_channel = NULL;
}
gpr_mu_unlock(&chand->mu);
if (child_channel) {
grpc_child_channel_destroy(child_channel, 0);
}
break;
default:
switch (op->dir) {
case GRPC_CALL_UP:
grpc_channel_next_op(elem, op);
break;
case GRPC_CALL_DOWN:
gpr_log(GPR_ERROR, "unhandled channel op: %d", op->type);
abort();
break;
}
break;
if (op->disconnect && chand->resolver != NULL) {
grpc_connectivity_state_set(&chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE);
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");
}
}
gpr_mu_unlock(&chand->mu_config);
if (destroy_resolver) {
grpc_resolver_shutdown(destroy_resolver);
GRPC_RESOLVER_UNREF(destroy_resolver, "channel");
}
if (lb_policy) {
grpc_lb_policy_broadcast(lb_policy, op);
GRPC_LB_POLICY_UNREF(lb_policy, "broadcast");
}
if (on_consumed) {
grpc_iomgr_add_callback(on_consumed);
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
call_data *calld = elem->call_data;
/* TODO(ctiller): is there something useful we can do here? */
@ -376,6 +515,7 @@ static void init_call_elem(grpc_call_element *elem,
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GPR_ASSERT(server_transport_data == NULL);
gpr_mu_init(&calld->mu_state);
calld->elem = elem;
calld->state = CALL_CREATED;
calld->deadline = gpr_inf_future;
@ -384,161 +524,88 @@ static void init_call_elem(grpc_call_element *elem,
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_subchannel_call *subchannel_call;
/* if the call got activated, we need to destroy the child stack also, and
remove it from the in-flight requests tracked by the child_entry we
picked */
gpr_mu_lock(&chand->mu);
gpr_mu_lock(&calld->mu_state);
switch (calld->state) {
case CALL_ACTIVE:
gpr_mu_unlock(&chand->mu);
grpc_child_call_destroy(calld->s.active.child_call);
subchannel_call = calld->subchannel_call;
gpr_mu_unlock(&calld->mu_state);
GRPC_SUBCHANNEL_CALL_UNREF(subchannel_call, "client_channel");
break;
case CALL_WAITING:
remove_waiting_child(chand, calld);
gpr_mu_unlock(&chand->mu);
case CALL_CREATED:
case CALL_CANCELLED:
gpr_mu_unlock(&calld->mu_state);
break;
default:
gpr_mu_unlock(&chand->mu);
case CALL_WAITING_FOR_PICK:
case CALL_WAITING_FOR_CONFIG:
case CALL_WAITING_FOR_CALL:
case CALL_WAITING_FOR_SEND:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
}
GPR_ASSERT(calld->state != CALL_WAITING);
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(!is_first);
memset(chand, 0, sizeof(*chand));
GPR_ASSERT(is_last);
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu);
chand->active_child = NULL;
chand->waiting_children = NULL;
chand->waiting_child_count = 0;
chand->waiting_child_capacity = 0;
chand->transport_setup = NULL;
chand->transport_setup_initiated = 0;
chand->args = grpc_channel_args_copy(args);
gpr_mu_init(&chand->mu_config);
chand->mdctx = metadata_context;
chand->master = master;
grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed,
chand);
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE);
}
/* Destructor for channel_data */
static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
grpc_transport_setup_cancel(chand->transport_setup);
if (chand->active_child) {
grpc_child_channel_destroy(chand->active_child, 1);
chand->active_child = NULL;
if (chand->resolver != NULL) {
grpc_resolver_shutdown(chand->resolver);
GRPC_RESOLVER_UNREF(chand->resolver, "channel");
}
grpc_channel_args_destroy(chand->args);
gpr_mu_destroy(&chand->mu);
GPR_ASSERT(chand->waiting_child_count == 0);
gpr_free(chand->waiting_children);
if (chand->lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
}
gpr_mu_destroy(&chand->mu_config);
}
const grpc_channel_filter grpc_client_channel_filter = {
cc_start_transport_op, channel_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "client-channel",
cc_start_transport_stream_op,
cc_start_transport_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"client-channel",
};
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_stack *channel_stack, grpc_transport *transport,
grpc_channel_filter const **channel_filters, size_t num_channel_filters,
grpc_mdctx *mdctx) {
/* we just got a new transport: lets create a child channel stack for it */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
size_t num_child_filters = 2 + num_channel_filters;
grpc_channel_filter const **child_filters;
grpc_transport_setup_result result;
grpc_child_channel *old_active = NULL;
call_data **waiting_children;
size_t waiting_child_count;
size_t i;
grpc_transport_op *call_ops;
/* build the child filter stack */
child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters);
/* we always need a link back filter to get back to the connected channel */
child_filters[0] = &grpc_child_channel_top_filter;
for (i = 0; i < num_channel_filters; i++) {
child_filters[i + 1] = channel_filters[i];
}
/* and we always need a connected channel to talk to the transport */
child_filters[num_child_filters - 1] = &grpc_connected_channel_filter;
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
/* BEGIN LOCKING CHANNEL */
gpr_mu_lock(&chand->mu);
chand->transport_setup_initiated = 0;
if (chand->active_child) {
old_active = chand->active_child;
}
chand->active_child = grpc_child_channel_create(
elem, child_filters, num_child_filters, chand->args, mdctx);
result =
grpc_connected_channel_bind_transport(chand->active_child, transport);
/* capture the waiting children - we'll activate them outside the lock
to avoid re-entrancy problems */
waiting_children = chand->waiting_children;
waiting_child_count = chand->waiting_child_count;
/* bumping up inflight_requests here avoids taking a lock per rpc below */
chand->waiting_children = NULL;
chand->waiting_child_count = 0;
chand->waiting_child_capacity = 0;
call_ops = gpr_malloc(sizeof(*call_ops) * waiting_child_count);
for (i = 0; i < waiting_child_count; i++) {
call_ops[i] = waiting_children[i]->s.waiting_op;
if (!prepare_activate(waiting_children[i]->elem, chand->active_child)) {
waiting_children[i] = NULL;
grpc_transport_op_finish_with_failure(&call_ops[i]);
}
}
/* END LOCKING CHANNEL */
gpr_mu_unlock(&chand->mu);
/* activate any pending operations - this is safe to do as we guarantee one
and only one write operation per request at the surface api - if we lose
that guarantee we need to do some curly locking here */
for (i = 0; i < waiting_child_count; i++) {
if (waiting_children[i]) {
complete_activate(waiting_children[i]->elem, &call_ops[i]);
}
}
gpr_free(waiting_children);
gpr_free(call_ops);
gpr_free(child_filters);
if (old_active) {
grpc_child_channel_destroy(old_active, 1);
}
return result;
}
void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
grpc_transport_setup *setup) {
void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver *resolver) {
/* post construction initialization: set the transport setup pointer */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
GPR_ASSERT(!chand->transport_setup);
chand->transport_setup = setup;
GPR_ASSERT(!chand->resolver);
chand->resolver = resolver;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
GRPC_RESOLVER_REF(resolver, "channel");
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}

@ -35,6 +35,7 @@
#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/resolver.h"
/* A client channel is a channel that begins disconnected, and can connect
to some endpoint on demand. If that endpoint disconnects, it will be
@ -48,15 +49,7 @@ extern const grpc_channel_filter grpc_client_channel_filter;
/* post-construction initializer to let the client channel know which
transport setup it should cancel upon destruction, or initiate when it needs
a connection */
void grpc_client_channel_set_transport_setup(grpc_channel_stack *channel_stack,
grpc_transport_setup *setup);
void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
grpc_resolver *resolver);
/* grpc_transport_setup_callback for binding new transports into a client
channel - user_data should be the channel stack containing the client
channel */
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_stack *channel_stack, grpc_transport *transport,
grpc_channel_filter const **channel_filters, size_t num_channel_filters,
grpc_mdctx *mdctx);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */

@ -1,302 +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 "src/core/channel/client_setup.h"
#include "src/core/channel/channel_args.h"
#include "src/core/channel/channel_stack.h"
#include "src/core/iomgr/alarm.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
struct grpc_client_setup {
grpc_transport_setup base; /* must be first */
void (*initiate)(void *user_data, grpc_client_setup_request *request);
void (*done)(void *user_data);
void *user_data;
grpc_channel_args *args;
grpc_mdctx *mdctx;
grpc_alarm backoff_alarm;
gpr_timespec current_backoff_interval;
int in_alarm;
int in_cb;
int cancelled;
gpr_mu mu;
gpr_cv cv;
grpc_client_setup_request *active_request;
int refs;
/** The set of pollsets that are currently interested in this
connection being established */
grpc_pollset_set interested_parties;
};
struct grpc_client_setup_request {
/* pointer back to the setup object */
grpc_client_setup *setup;
gpr_timespec deadline;
};
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) {
return r->deadline;
}
grpc_pollset_set *grpc_client_setup_get_interested_parties(
grpc_client_setup_request *r) {
return &r->setup->interested_parties;
}
static void destroy_setup(grpc_client_setup *s) {
gpr_mu_destroy(&s->mu);
gpr_cv_destroy(&s->cv);
s->done(s->user_data);
grpc_channel_args_destroy(s->args);
grpc_pollset_set_destroy(&s->interested_parties);
gpr_free(s);
}
static void destroy_request(grpc_client_setup_request *r) { gpr_free(r); }
/* initiate handshaking */
static void setup_initiate(grpc_transport_setup *sp) {
grpc_client_setup *s = (grpc_client_setup *)sp;
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request));
int in_alarm = 0;
r->setup = s;
r->deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(60));
gpr_mu_lock(&s->mu);
GPR_ASSERT(s->refs > 0);
/* there might be more than one request outstanding if the caller calls
initiate in some kind of rapid-fire way: we try to connect each time,
and keep track of the latest request (which is the only one that gets
to finish) */
if (!s->in_alarm) {
s->active_request = r;
s->refs++;
} else {
/* TODO(klempner): Maybe do something more clever here */
in_alarm = 1;
}
gpr_mu_unlock(&s->mu);
if (!in_alarm) {
s->initiate(s->user_data, r);
} else {
destroy_request(r);
}
}
/** implementation of add_interested_party for setup vtable */
static void setup_add_interested_party(grpc_transport_setup *sp,
grpc_pollset *pollset) {
grpc_client_setup *s = (grpc_client_setup *)sp;
gpr_mu_lock(&s->mu);
grpc_pollset_set_add_pollset(&s->interested_parties, pollset);
gpr_mu_unlock(&s->mu);
}
/** implementation of del_interested_party for setup vtable */
static void setup_del_interested_party(grpc_transport_setup *sp,
grpc_pollset *pollset) {
grpc_client_setup *s = (grpc_client_setup *)sp;
gpr_mu_lock(&s->mu);
grpc_pollset_set_del_pollset(&s->interested_parties, pollset);
gpr_mu_unlock(&s->mu);
}
/* cancel handshaking: cancel all requests, and shutdown (the caller promises
not to initiate again) */
static void setup_cancel(grpc_transport_setup *sp) {
grpc_client_setup *s = (grpc_client_setup *)sp;
int cancel_alarm = 0;
gpr_mu_lock(&s->mu);
s->cancelled = 1;
while (s->in_cb) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
}
GPR_ASSERT(s->refs > 0);
/* effectively cancels the current request (if any) */
s->active_request = NULL;
if (s->in_alarm) {
cancel_alarm = 1;
}
if (--s->refs == 0) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
} else {
gpr_mu_unlock(&s->mu);
}
if (cancel_alarm) {
grpc_alarm_cancel(&s->backoff_alarm);
}
}
int grpc_client_setup_cb_begin(grpc_client_setup_request *r,
const char *reason) {
gpr_mu_lock(&r->setup->mu);
if (r->setup->cancelled) {
gpr_mu_unlock(&r->setup->mu);
return 0;
}
r->setup->in_cb++;
gpr_mu_unlock(&r->setup->mu);
return 1;
}
void grpc_client_setup_cb_end(grpc_client_setup_request *r,
const char *reason) {
gpr_mu_lock(&r->setup->mu);
r->setup->in_cb--;
if (r->setup->cancelled) gpr_cv_signal(&r->setup->cv);
gpr_mu_unlock(&r->setup->mu);
}
/* vtable for transport setup */
static const grpc_transport_setup_vtable setup_vtable = {
setup_initiate, setup_add_interested_party, setup_del_interested_party,
setup_cancel};
void grpc_client_setup_create_and_attach(
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
grpc_mdctx *mdctx,
void (*initiate)(void *user_data, grpc_client_setup_request *request),
void (*done)(void *user_data), void *user_data) {
grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup));
s->base.vtable = &setup_vtable;
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->refs = 1;
s->mdctx = mdctx;
s->initiate = initiate;
s->done = done;
s->user_data = user_data;
s->active_request = NULL;
s->args = grpc_channel_args_copy(args);
s->current_backoff_interval = gpr_time_from_micros(1000000);
s->in_alarm = 0;
s->in_cb = 0;
s->cancelled = 0;
grpc_pollset_set_init(&s->interested_parties);
grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base);
}
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r,
const char *reason) {
int result;
if (gpr_time_cmp(gpr_now(), r->deadline) > 0) {
result = 0;
} else {
gpr_mu_lock(&r->setup->mu);
result = r->setup->active_request == r;
gpr_mu_unlock(&r->setup->mu);
}
return result;
}
static void backoff_alarm_done(void *arg /* grpc_client_setup_request */,
int success) {
grpc_client_setup_request *r = arg;
grpc_client_setup *s = r->setup;
/* Handle status cancelled? */
gpr_mu_lock(&s->mu);
s->in_alarm = 0;
if (s->active_request != NULL || !success) {
if (0 == --s->refs) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
destroy_request(r);
return;
} else {
gpr_mu_unlock(&s->mu);
destroy_request(r);
return;
}
}
s->active_request = r;
gpr_mu_unlock(&s->mu);
s->initiate(s->user_data, r);
}
void grpc_client_setup_request_finish(grpc_client_setup_request *r,
int was_successful) {
int retry = !was_successful;
grpc_client_setup *s = r->setup;
gpr_mu_lock(&s->mu);
if (s->active_request == r) {
s->active_request = NULL;
} else {
retry = 0;
}
if (!retry && 0 == --s->refs) {
gpr_mu_unlock(&s->mu);
destroy_setup(s);
destroy_request(r);
} else if (retry) {
/* TODO(klempner): Replace these values with further consideration. 2x is
probably too aggressive of a backoff. */
gpr_timespec max_backoff = gpr_time_from_minutes(2);
gpr_timespec now = gpr_now();
gpr_timespec deadline = gpr_time_add(s->current_backoff_interval, now);
GPR_ASSERT(!s->in_alarm);
s->in_alarm = 1;
grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, r, now);
s->current_backoff_interval =
gpr_time_add(s->current_backoff_interval, s->current_backoff_interval);
if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) {
s->current_backoff_interval = max_backoff;
}
gpr_mu_unlock(&s->mu);
} else {
gpr_mu_unlock(&s->mu);
destroy_request(r);
}
}
const grpc_channel_args *grpc_client_setup_get_channel_args(
grpc_client_setup_request *r) {
return r->setup->args;
}
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) {
return r->setup->mdctx;
}

@ -1,77 +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.
*
*/
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H
#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H
#include "src/core/channel/client_channel.h"
#include "src/core/transport/metadata.h"
#include <grpc/support/time.h>
/* Convenience API's to simplify transport setup */
typedef struct grpc_client_setup grpc_client_setup;
typedef struct grpc_client_setup_request grpc_client_setup_request;
void grpc_client_setup_create_and_attach(
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args,
grpc_mdctx *mdctx,
void (*initiate)(void *user_data, grpc_client_setup_request *request),
void (*done)(void *user_data), void *user_data);
/* Check that r is the active request: needs to be performed at each callback.
If this races, we'll have two connection attempts running at once and the
old one will get cleaned up in due course, which is fine. */
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r,
const char *reason);
void grpc_client_setup_request_finish(grpc_client_setup_request *r,
int was_successful);
const grpc_channel_args *grpc_client_setup_get_channel_args(
grpc_client_setup_request *r);
/* Call before calling back into the setup listener, and call only if
this function returns 1. If it returns 1, also promise to call
grpc_client_setup_cb_end */
int grpc_client_setup_cb_begin(grpc_client_setup_request *r,
const char *reason);
void grpc_client_setup_cb_end(grpc_client_setup_request *r, const char *reason);
/* Get the deadline for a request passed in to initiate. Implementations should
make a best effort to honor this deadline. */
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
grpc_pollset_set *grpc_client_setup_get_interested_parties(
grpc_client_setup_request *r);
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */

@ -61,42 +61,27 @@ typedef struct connected_channel_call_data { void *unused; } call_data;
/* Intercept a call operation and either push it directly up or translate it
into transport stream operations */
static void con_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
static void con_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
grpc_transport_perform_op(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
grpc_transport_perform_stream_op(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
}
/* Currently we assume all channel operations should just be pushed up. */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
static void con_start_transport_op(grpc_channel_element *elem,
grpc_transport_op *op) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
switch (op->type) {
case GRPC_CHANNEL_GOAWAY:
grpc_transport_goaway(chand->transport, op->data.goaway.status,
op->data.goaway.message);
break;
case GRPC_CHANNEL_DISCONNECT:
grpc_transport_close(chand->transport);
break;
default:
GPR_ASSERT(op->dir == GRPC_CALL_UP);
grpc_channel_next_op(elem, op);
break;
}
grpc_transport_perform_op(chand->transport, op);
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
int r;
@ -118,11 +103,10 @@ static void destroy_call_elem(grpc_call_element *elem) {
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
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 *cd = (channel_data *)elem->channel_data;
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
cd->transport = NULL;
@ -136,70 +120,23 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_connected_channel_filter = {
con_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "connected",
con_start_transport_stream_op,
con_start_transport_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"connected",
};
/* Transport callback to accept a new stream... calls up to handle it */
static void accept_stream(void *user_data, grpc_transport *transport,
const void *transport_server_data) {
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
op.type = GRPC_ACCEPT_CALL;
op.dir = GRPC_CALL_UP;
op.data.accept_call.transport = transport;
op.data.accept_call.transport_server_data = transport_server_data;
channel_op(elem, NULL, &op);
}
static void transport_goaway(void *user_data, grpc_transport *transport,
grpc_status_code status, gpr_slice debug) {
/* transport got goaway ==> call up and handle it */
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
op.type = GRPC_TRANSPORT_GOAWAY;
op.dir = GRPC_CALL_UP;
op.data.goaway.status = status;
op.data.goaway.message = debug;
channel_op(elem, NULL, &op);
}
static void transport_closed(void *user_data, grpc_transport *transport) {
/* transport was closed ==> call up and handle it */
grpc_channel_element *elem = user_data;
channel_data *chand = elem->channel_data;
grpc_channel_op op;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(chand->transport == transport);
op.type = GRPC_TRANSPORT_CLOSED;
op.dir = GRPC_CALL_UP;
channel_op(elem, NULL, &op);
}
const grpc_transport_callbacks connected_channel_transport_callbacks = {
accept_stream, transport_goaway, transport_closed,
};
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport) {
void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack,
grpc_transport *transport) {
/* Assumes that the connected channel filter is always the last filter
in a channel stack */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *cd = (channel_data *)elem->channel_data;
grpc_transport_setup_result ret;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GPR_ASSERT(cd->transport == NULL);
cd->transport = transport;
@ -211,8 +148,4 @@ grpc_transport_setup_result grpc_connected_channel_bind_transport(
the last call element, and the last call element MUST be the connected
channel. */
channel_stack->call_stack_size += grpc_transport_stream_size(transport);
ret.user_data = elem;
ret.callbacks = &connected_channel_transport_callbacks;
return ret;
}

@ -43,7 +43,7 @@ extern const grpc_channel_filter grpc_connected_channel_filter;
/* Post construction fixup: set the transport in the connected channel.
Must be called before any call stack using this filter is used. */
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport);
void grpc_connected_channel_bind_transport(grpc_channel_stack *channel_stack,
grpc_transport *transport);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */

@ -92,7 +92,8 @@ static void hc_on_recv(void *user_data, int success) {
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
}
static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
static void hc_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@ -127,33 +128,16 @@ static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
}
static void hc_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
hc_mutate_op(elem, op);
grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
call_data *calld = elem->call_data;
calld->sent_initial_metadata = 0;
calld->got_initial_metadata = 0;
@ -186,7 +170,7 @@ static const char *scheme_from_args(const grpc_channel_args *args) {
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
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) {
/* grab pointers to our data from the channel element */
@ -195,7 +179,6 @@ static void init_channel_elem(grpc_channel_element *elem,
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
/* initialize members */
@ -221,6 +204,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_http_client_filter = {
hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "http-client"};
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"};

@ -72,9 +72,6 @@ typedef struct channel_data {
grpc_mdctx *mdctx;
} channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
grpc_call_element *elem = user_data;
channel_data *channeld = elem->channel_data;
@ -181,7 +178,8 @@ static void hs_on_recv(void *user_data, int success) {
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
}
static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
static void hs_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@ -209,33 +207,16 @@ static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
}
static void hs_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
hs_mutate_op(elem, op);
grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
/* initialize members */
@ -248,7 +229,7 @@ static void init_call_elem(grpc_call_element *elem,
static void destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
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) {
/* grab pointers to our data from the channel element */
@ -297,6 +278,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_http_server_filter = {
hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "http-server"};
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"};

@ -45,7 +45,8 @@ typedef struct channel_data {
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
static void noop_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@ -61,35 +62,18 @@ static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
- 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 noop_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
static void noop_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
noop_mutate_op(elem, op);
/* pass control down the stack */
grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
ignore_unused(channeld);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@ -111,7 +95,7 @@ static void destroy_call_elem(grpc_call_element *elem) {
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
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) {
/* grab pointers to our data from the channel element */
@ -135,7 +119,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
ignore_unused(channeld);
}
const grpc_channel_filter grpc_no_op_filter = {
noop_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "no-op"};
const grpc_channel_filter grpc_no_op_filter = {noop_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,
"no-op"};

@ -0,0 +1,60 @@
Client Configuration Support for GRPC
=====================================
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
to resolve a name into configuration data for the channel. Such configuration
data might include:
- a list of (ip, port) addresses to connect to
- a load balancing policy to decide which server to send a request to
- a set of filters to mutate outgoing requests (say, by adding metadata)
The resolver provides this data as a stream of grpc_client_config objects to
the channel. We represent configuration as a stream so that it can be changed
by the resolver during execution, by reacting to external events (such as a
new configuration file being pushed to some store).
Load Balancing
--------------
Load balancing configuration is provided by a grpc_lb_policy object, stored as
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
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
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.
Naming for GRPC
===============
Names in GRPC are represented by a URI.
The following schemes are currently supported:
dns:///host:port - dns schemes are currently supported so long as authority is
empty (authority based dns resolution is expected in a future
release)
unix:path - the unix scheme is used to create and connect to unix domain
sockets - the authority must be empty, and the path represents
the absolute or relative path to the desired socket

@ -0,0 +1,74 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/client_config.h"
#include <string.h>
#include <grpc/support/alloc.h>
struct grpc_client_config {
gpr_refcount refs;
grpc_lb_policy *lb_policy;
};
grpc_client_config *grpc_client_config_create() {
grpc_client_config *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
gpr_ref_init(&c->refs, 1);
return c;
}
void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); }
void grpc_client_config_unref(grpc_client_config *c) {
if (gpr_unref(&c->refs)) {
GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config");
gpr_free(c);
}
}
void grpc_client_config_set_lb_policy(grpc_client_config *c,
grpc_lb_policy *lb_policy) {
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "client_config");
}
if (c->lb_policy) {
GRPC_LB_POLICY_UNREF(c->lb_policy, "client_config");
}
c->lb_policy = lb_policy;
}
grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) {
return c->lb_policy;
}

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

@ -0,0 +1,49 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/connector.h"
void grpc_connector_ref(grpc_connector *connector) {
connector->vtable->ref(connector);
}
void grpc_connector_unref(grpc_connector *connector) {
connector->vtable->unref(connector);
}
void grpc_connector_connect(grpc_connector *connector,
const grpc_connect_in_args *in_args,
grpc_connect_out_args *out_args,
grpc_iomgr_closure *notify) {
connector->vtable->connect(connector, in_args, out_args, notify);
}

@ -0,0 +1,85 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CONNECTOR_H
#include "src/core/channel/channel_stack.h"
#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/transport.h"
typedef struct grpc_connector grpc_connector;
typedef struct grpc_connector_vtable grpc_connector_vtable;
struct grpc_connector {
const grpc_connector_vtable *vtable;
};
typedef struct {
/** set of pollsets interested in this connection */
grpc_pollset_set *interested_parties;
/** address to connect to */
const struct sockaddr *addr;
int addr_len;
/** deadline for connection */
gpr_timespec deadline;
/** channel arguments (to be passed to transport) */
const grpc_channel_args *channel_args;
/** metadata context */
grpc_mdctx *metadata_context;
} grpc_connect_in_args;
typedef struct {
/** the connected transport */
grpc_transport *transport;
/** any additional filters (owned by the caller of connect) */
const grpc_channel_filter **filters;
size_t num_filters;
} grpc_connect_out_args;
struct grpc_connector_vtable {
void (*ref)(grpc_connector *connector);
void (*unref)(grpc_connector *connector);
void (*connect)(grpc_connector *connector,
const grpc_connect_in_args *in_args,
grpc_connect_out_args *out_args, grpc_iomgr_closure *notify);
};
void grpc_connector_ref(grpc_connector *connector);
void grpc_connector_unref(grpc_connector *connector);
void grpc_connector_connect(grpc_connector *connector,
const grpc_connect_in_args *in_args,
grpc_connect_out_args *out_args,
grpc_iomgr_closure *notify);
#endif

@ -0,0 +1,268 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/lb_policies/pick_first.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include "src/core/transport/connectivity_state.h"
typedef struct pending_pick {
struct pending_pick *next;
grpc_pollset *pollset;
grpc_subchannel **target;
grpc_iomgr_closure *on_complete;
} pending_pick;
typedef struct {
/** base policy: must be first */
grpc_lb_policy base;
/** all our subchannels */
grpc_subchannel **subchannels;
size_t num_subchannels;
grpc_iomgr_closure connectivity_changed;
/** mutex protecting remaining members */
gpr_mu mu;
/** the selected channel
TODO(ctiller): this should be atomically set so we don't
need to take a mutex in the common case */
grpc_subchannel *selected;
/** have we started picking? */
int started_picking;
/** which subchannel are we watching? */
size_t checking_subchannel;
/** what is the connectivity of that channel? */
grpc_connectivity_state checking_connectivity;
/** list of picks that are waiting on connectivity */
pending_pick *pending_picks;
/** our connectivity state tracker */
grpc_connectivity_state_tracker state_tracker;
} pick_first_lb_policy;
void pf_destroy(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first");
}
gpr_free(p->subchannels);
gpr_mu_destroy(&p->mu);
gpr_free(p);
}
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);
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);
}
gpr_mu_unlock(&p->mu);
}
void pf_pick(grpc_lb_policy *pol, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
grpc_iomgr_closure *on_complete) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
if (p->selected) {
gpr_mu_unlock(&p->mu);
*target = p->selected;
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);
}
grpc_subchannel_add_interested_party(p->subchannels[p->checking_subchannel],
pollset);
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
pp->pollset = pollset;
pp->target = target;
pp->on_complete = on_complete;
p->pending_picks = pp;
gpr_mu_unlock(&p->mu);
}
}
static void 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:
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) {
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 {
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) {
GRPC_LB_POLICY_UNREF(&p->base, "pick_first_connectivity");
}
}
static void pf_broadcast(grpc_lb_policy *pol, grpc_transport_op *op) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
size_t n;
grpc_subchannel **subchannels;
gpr_mu_lock(&p->mu);
n = p->num_subchannels;
subchannels = gpr_malloc(n * sizeof(*subchannels));
for (i = 0; i < n; i++) {
subchannels[i] = p->subchannels[i];
GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast");
}
gpr_mu_unlock(&p->mu);
for (i = 0; i < n; i++) {
grpc_subchannel_process_transport_op(subchannels[i], op);
GRPC_SUBCHANNEL_UNREF(subchannels[i], "pf_broadcast");
}
gpr_free(subchannels);
}
static grpc_connectivity_state pf_check_connectivity(grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
grpc_connectivity_state st;
gpr_mu_lock(&p->mu);
st = grpc_connectivity_state_check(&p->state_tracker);
gpr_mu_unlock(&p->mu);
return st;
}
static void pf_notify_on_state_change(grpc_lb_policy *pol,
grpc_connectivity_state *current,
grpc_iomgr_closure *notify) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
gpr_mu_lock(&p->mu);
grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current,
notify);
gpr_mu_unlock(&p->mu);
}
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};
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
size_t num_subchannels) {
pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
GPR_ASSERT(num_subchannels);
memset(p, 0, sizeof(*p));
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;
memcpy(p->subchannels, subchannels,
sizeof(grpc_subchannel *) * num_subchannels);
grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
gpr_mu_init(&p->mu);
return &p->base;
}

@ -31,11 +31,12 @@
*
*/
#ifndef GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
#define GRPC_INTERNAL_CORE_SURFACE_CLIENT_H
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/lb_policy.h"
extern const grpc_channel_filter grpc_client_surface_filter;
grpc_lb_policy *grpc_create_pick_first_lb_policy(grpc_subchannel **subchannels,
size_t num_subchannels);
#endif /* GRPC_INTERNAL_CORE_SURFACE_CLIENT_H */
#endif

@ -0,0 +1,79 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/lb_policy.h"
void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable) {
policy->vtable = vtable;
gpr_ref_init(&policy->refs, 1);
}
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
const char *reason) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p ref %d -> %d %s",
policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason);
#else
void grpc_lb_policy_ref(grpc_lb_policy *policy) {
#endif
gpr_ref(&policy->refs);
}
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line,
const char *reason) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s",
policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason);
#else
void grpc_lb_policy_unref(grpc_lb_policy *policy) {
#endif
if (gpr_unref(&policy->refs)) {
policy->vtable->destroy(policy);
}
}
void grpc_lb_policy_shutdown(grpc_lb_policy *policy) {
policy->vtable->shutdown(policy);
}
void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata,
grpc_subchannel **target,
grpc_iomgr_closure *on_complete) {
policy->vtable->pick(policy, pollset, initial_metadata, target, on_complete);
}
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op) {
policy->vtable->broadcast(policy, op);
}

@ -0,0 +1,109 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H
#include "src/core/client_config/subchannel.h"
/** A load balancing policy: specified by a vtable and a struct (which
is expected to be extended to contain some parameters) */
typedef struct grpc_lb_policy grpc_lb_policy;
typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable;
typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel,
grpc_status_code status, const char *errmsg);
struct grpc_lb_policy {
const grpc_lb_policy_vtable *vtable;
gpr_refcount refs;
};
struct grpc_lb_policy_vtable {
void (*destroy)(grpc_lb_policy *policy);
void (*shutdown)(grpc_lb_policy *policy);
/** implement grpc_lb_policy_pick */
void (*pick)(grpc_lb_policy *policy, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
grpc_iomgr_closure *on_complete);
/** broadcast a transport op to all subchannels */
void (*broadcast)(grpc_lb_policy *policy, grpc_transport_op *op);
/** check the current connectivity of the lb_policy */
grpc_connectivity_state (*check_connectivity)(grpc_lb_policy *policy);
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the policy */
void (*notify_on_state_change)(grpc_lb_policy *policy,
grpc_connectivity_state *state,
grpc_iomgr_closure *closure);
};
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
#define GRPC_LB_POLICY_REF(p, r) \
grpc_lb_policy_ref((p), __FILE__, __LINE__, (r))
#define GRPC_LB_POLICY_UNREF(p, r) \
grpc_lb_policy_unref((p), __FILE__, __LINE__, (r))
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
const char *reason);
void grpc_lb_policy_unref(grpc_lb_policy *policy, const char *file, int line,
const char *reason);
#else
#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p))
#define GRPC_LB_POLICY_UNREF(p, r) grpc_lb_policy_unref((p))
void grpc_lb_policy_ref(grpc_lb_policy *policy);
void grpc_lb_policy_unref(grpc_lb_policy *policy);
#endif
/** called by concrete implementations to initialize the base struct */
void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable);
/** Start shutting down (fail any pending picks) */
void grpc_lb_policy_shutdown(grpc_lb_policy *policy);
/** Given initial metadata in \a initial_metadata, find an appropriate
target for this rpc, and 'return' it by calling \a on_complete after setting
\a target.
Picking can be asynchronous. Any IO should be done under \a pollset. */
void grpc_lb_policy_pick(grpc_lb_policy *policy, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata,
grpc_subchannel **target,
grpc_iomgr_closure *on_complete);
void grpc_lb_policy_broadcast(grpc_lb_policy *policy, grpc_transport_op *op);
#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */

@ -0,0 +1,83 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/resolver.h"
void grpc_resolver_init(grpc_resolver *resolver,
const grpc_resolver_vtable *vtable) {
resolver->vtable = vtable;
gpr_ref_init(&resolver->refs, 1);
}
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
void grpc_resolver_ref(grpc_resolver *resolver, const char *file, int line,
const char *reason) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p ref %d -> %d %s",
resolver, (int)resolver->refs.count, (int)resolver->refs.count + 1,
reason);
#else
void grpc_resolver_ref(grpc_resolver *resolver) {
#endif
gpr_ref(&resolver->refs);
}
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
void grpc_resolver_unref(grpc_resolver *resolver, const char *file, int line,
const char *reason) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "RESOLVER:%p unref %d -> %d %s",
resolver, (int)resolver->refs.count, (int)resolver->refs.count - 1,
reason);
#else
void grpc_resolver_unref(grpc_resolver *resolver) {
#endif
if (gpr_unref(&resolver->refs)) {
resolver->vtable->destroy(resolver);
}
}
void grpc_resolver_shutdown(grpc_resolver *resolver) {
resolver->vtable->shutdown(resolver);
}
void grpc_resolver_channel_saw_error(grpc_resolver *resolver,
struct sockaddr *failing_address,
int failing_address_len) {
resolver->vtable->channel_saw_error(resolver, failing_address,
failing_address_len);
}
void grpc_resolver_next(grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_iomgr_closure *on_complete) {
resolver->vtable->next(resolver, target_config, on_complete);
}

@ -0,0 +1,97 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
#include "src/core/client_config/client_config.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/sockaddr.h"
typedef struct grpc_resolver grpc_resolver;
typedef struct grpc_resolver_vtable grpc_resolver_vtable;
/** grpc_resolver provides grpc_client_config objects to grpc_channel
objects */
struct grpc_resolver {
const grpc_resolver_vtable *vtable;
gpr_refcount refs;
};
struct grpc_resolver_vtable {
void (*destroy)(grpc_resolver *resolver);
void (*shutdown)(grpc_resolver *resolver);
void (*channel_saw_error)(grpc_resolver *resolver,
struct sockaddr *failing_address,
int failing_address_len);
void (*next)(grpc_resolver *resolver, grpc_client_config **target_config,
grpc_iomgr_closure *on_complete);
};
#ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r))
#define GRPC_RESOLVER_UNREF(p, r) \
grpc_resolver_unref((p), __FILE__, __LINE__, (r))
void grpc_resolver_ref(grpc_resolver *policy, const char *file, int line,
const char *reason);
void grpc_resolver_unref(grpc_resolver *policy, const char *file, int line,
const char *reason);
#else
#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
#define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p))
void grpc_resolver_ref(grpc_resolver *policy);
void grpc_resolver_unref(grpc_resolver *policy);
#endif
void grpc_resolver_init(grpc_resolver *resolver,
const grpc_resolver_vtable *vtable);
void grpc_resolver_shutdown(grpc_resolver *resolver);
/** Notification that the channel has seen an error on some address.
Can be used as a hint that re-resolution is desirable soon. */
void grpc_resolver_channel_saw_error(grpc_resolver *resolver,
struct sockaddr *failing_address,
int failing_address_len);
/** Get the next client config. Called by the channel to fetch a new
configuration. Expected to set *target_config with a new configuration,
and then schedule on_complete for execution.
If resolution is fatally broken, set *target_config to NULL and
schedule on_complete. */
void grpc_resolver_next(grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_iomgr_closure *on_complete);
#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_H */

@ -0,0 +1,50 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/resolver_factory.h"
void grpc_resolver_factory_ref(grpc_resolver_factory *factory) {
factory->vtable->ref(factory);
}
void grpc_resolver_factory_unref(grpc_resolver_factory *factory) {
factory->vtable->unref(factory);
}
/** Create a resolver instance for a name */
grpc_resolver *grpc_resolver_factory_create_resolver(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory) {
if (!factory) return NULL;
return factory->vtable->create_resolver(factory, uri, subchannel_factory);
}

@ -0,0 +1,67 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_FACTORY_H
#include "src/core/client_config/resolver.h"
#include "src/core/client_config/subchannel_factory.h"
#include "src/core/client_config/uri_parser.h"
typedef struct grpc_resolver_factory grpc_resolver_factory;
typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
/** grpc_resolver provides grpc_client_config objects to grpc_channel
objects */
struct grpc_resolver_factory {
const grpc_resolver_factory_vtable *vtable;
};
struct grpc_resolver_factory_vtable {
void (*ref)(grpc_resolver_factory *factory);
void (*unref)(grpc_resolver_factory *factory);
grpc_resolver *(*create_resolver)(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory);
};
void grpc_resolver_factory_ref(grpc_resolver_factory *resolver);
void grpc_resolver_factory_unref(grpc_resolver_factory *resolver);
/** Create a resolver instance for a name */
grpc_resolver *grpc_resolver_factory_create_resolver(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory);
#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */

@ -0,0 +1,124 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/resolver_registry.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#define MAX_RESOLVERS 10
typedef struct {
char *scheme;
grpc_resolver_factory *factory;
} registered_resolver;
static registered_resolver g_all_of_the_resolvers[MAX_RESOLVERS];
static int g_number_of_resolvers = 0;
static char *g_default_resolver_scheme;
void grpc_resolver_registry_init(const char *default_resolver_scheme) {
g_number_of_resolvers = 0;
g_default_resolver_scheme = gpr_strdup(default_resolver_scheme);
}
void grpc_resolver_registry_shutdown(void) {
int i;
for (i = 0; i < g_number_of_resolvers; i++) {
gpr_free(g_all_of_the_resolvers[i].scheme);
grpc_resolver_factory_unref(g_all_of_the_resolvers[i].factory);
}
gpr_free(g_default_resolver_scheme);
}
void grpc_register_resolver_type(const char *scheme,
grpc_resolver_factory *factory) {
int i;
for (i = 0; i < g_number_of_resolvers; i++) {
GPR_ASSERT(0 != strcmp(scheme, g_all_of_the_resolvers[i].scheme));
}
GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
g_all_of_the_resolvers[g_number_of_resolvers].scheme = gpr_strdup(scheme);
grpc_resolver_factory_ref(factory);
g_all_of_the_resolvers[g_number_of_resolvers].factory = factory;
g_number_of_resolvers++;
}
static grpc_resolver_factory *lookup_factory(grpc_uri *uri) {
int i;
/* handling NULL uri's here simplifies grpc_resolver_create */
if (!uri) return NULL;
for (i = 0; i < g_number_of_resolvers; i++) {
if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i].scheme)) {
return g_all_of_the_resolvers[i].factory;
}
}
return NULL;
}
grpc_resolver *grpc_resolver_create(
const char *name, grpc_subchannel_factory *subchannel_factory) {
grpc_uri *uri;
char *tmp;
grpc_resolver_factory *factory = NULL;
grpc_resolver *resolver;
uri = grpc_uri_parse(name, 1);
factory = lookup_factory(uri);
if (factory == NULL && g_default_resolver_scheme != NULL) {
grpc_uri_destroy(uri);
gpr_asprintf(&tmp, "%s%s", g_default_resolver_scheme, name);
uri = grpc_uri_parse(tmp, 1);
factory = lookup_factory(uri);
if (factory == NULL) {
grpc_uri_destroy(grpc_uri_parse(name, 0));
grpc_uri_destroy(grpc_uri_parse(tmp, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", name, tmp);
}
gpr_free(tmp);
} else if (factory == NULL) {
grpc_uri_destroy(grpc_uri_parse(name, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s'", name);
}
resolver =
grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory);
grpc_uri_destroy(uri);
return resolver;
}

@ -0,0 +1,62 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H
#include "src/core/client_config/resolver_factory.h"
void grpc_resolver_registry_init(const char *default_prefix);
void grpc_resolver_registry_shutdown(void);
/** Register a resolver type.
URI's of \a scheme will be resolved with the given resolver.
If \a priority is greater than zero, then the resolver will be eligible
to resolve names that are passed in with no scheme. Higher priority
resolvers will be tried before lower priority schemes. */
void grpc_register_resolver_type(const char *scheme,
grpc_resolver_factory *factory);
/** Create a resolver given \a name.
First tries to parse \a name as a URI. If this succeeds, tries
to locate a registered resolver factory based on the URI scheme.
If parsing or location fails, prefixes default_prefix from
grpc_resolver_registry_init to name, and tries again (if default_prefix
was not NULL).
If a resolver factory was found, use it to instantiate a resolver and
return it.
If a resolver factory was not found, return NULL. */
grpc_resolver *grpc_resolver_create(
const char *name, grpc_subchannel_factory *subchannel_factory);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */

@ -0,0 +1,246 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/resolvers/dns_resolver.h"
#include <string.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;
/** name to resolve */
char *name;
/** default port to use */
char *default_port;
/** subchannel factory */
grpc_subchannel_factory *subchannel_factory;
/** load balancing policy factory */
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels);
/** mutex guarding the rest of the state */
gpr_mu mu;
/** are we currently resolving? */
int resolving;
/** which version of resolved_config have we published? */
int published_version;
/** which version of resolved_config is current? */
int resolved_version;
/** pending next completion, or NULL */
grpc_iomgr_closure *next_completion;
/** target config address for next completion */
grpc_client_config **target_config;
/** current (fully resolved) config */
grpc_client_config *resolved_config;
} dns_resolver;
static void dns_destroy(grpc_resolver *r);
static void dns_start_resolving_locked(dns_resolver *r);
static void dns_maybe_finish_next_locked(dns_resolver *r);
static void dns_shutdown(grpc_resolver *r);
static void dns_channel_saw_error(grpc_resolver *r,
struct sockaddr *failing_address,
int failing_address_len);
static void dns_next(grpc_resolver *r, grpc_client_config **target_config,
grpc_iomgr_closure *on_complete);
static const grpc_resolver_vtable dns_resolver_vtable = {
dns_destroy, dns_shutdown, dns_channel_saw_error, dns_next};
static void dns_shutdown(grpc_resolver *resolver) {
dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_config = NULL;
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
}
gpr_mu_unlock(&r->mu);
}
static void dns_channel_saw_error(grpc_resolver *resolver, struct sockaddr *sa,
int len) {
dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (!r->resolving) {
dns_start_resolving_locked(r);
}
gpr_mu_unlock(&r->mu);
}
static void dns_next(grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_iomgr_closure *on_complete) {
dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu);
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_config = target_config;
if (r->resolved_version == 0 && !r->resolving) {
dns_start_resolving_locked(r);
} else {
dns_maybe_finish_next_locked(r);
}
gpr_mu_unlock(&r->mu);
}
static void dns_on_resolved(void *arg, grpc_resolved_addresses *addresses) {
dns_resolver *r = arg;
grpc_client_config *config = NULL;
grpc_subchannel **subchannels;
grpc_subchannel_args args;
grpc_lb_policy *lb_policy;
size_t i;
if (addresses) {
config = grpc_client_config_create();
subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
for (i = 0; i < addresses->naddrs; i++) {
memset(&args, 0, sizeof(args));
args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
args.addr_len = addresses->addrs[i].len;
subchannels[i] = grpc_subchannel_factory_create_subchannel(
r->subchannel_factory, &args);
}
lb_policy = r->lb_policy_factory(subchannels, addresses->naddrs);
grpc_client_config_set_lb_policy(config, lb_policy);
GRPC_LB_POLICY_UNREF(lb_policy, "construction");
grpc_resolved_addresses_destroy(addresses);
gpr_free(subchannels);
}
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving);
r->resolving = 0;
if (r->resolved_config) {
grpc_client_config_unref(r->resolved_config);
}
r->resolved_config = config;
r->resolved_version++;
dns_maybe_finish_next_locked(r);
gpr_mu_unlock(&r->mu);
GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
}
static void dns_start_resolving_locked(dns_resolver *r) {
GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving);
r->resolving = 1;
grpc_resolve_address(r->name, r->default_port, dns_on_resolved, r);
}
static void dns_maybe_finish_next_locked(dns_resolver *r) {
if (r->next_completion != NULL &&
r->resolved_version != r->published_version) {
*r->target_config = r->resolved_config;
if (r->resolved_config) {
grpc_client_config_ref(r->resolved_config);
}
grpc_iomgr_add_callback(r->next_completion);
r->next_completion = NULL;
r->published_version = r->resolved_version;
}
}
static void dns_destroy(grpc_resolver *gr) {
dns_resolver *r = (dns_resolver *)gr;
gpr_mu_destroy(&r->mu);
if (r->resolved_config) {
grpc_client_config_unref(r->resolved_config);
}
grpc_subchannel_factory_unref(r->subchannel_factory);
gpr_free(r->name);
gpr_free(r->default_port);
gpr_free(r);
}
static grpc_resolver *dns_create(
grpc_uri *uri, const char *default_port,
grpc_lb_policy *(*lb_policy_factory)(grpc_subchannel **subchannels,
size_t num_subchannels),
grpc_subchannel_factory *subchannel_factory) {
dns_resolver *r;
const char *path = uri->path;
if (0 != strcmp(uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported");
return NULL;
}
if (path[0] == '/') ++path;
r = gpr_malloc(sizeof(dns_resolver));
memset(r, 0, sizeof(*r));
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &dns_resolver_vtable);
r->name = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
r->subchannel_factory = subchannel_factory;
r->lb_policy_factory = lb_policy_factory;
grpc_subchannel_factory_ref(subchannel_factory);
return &r->base;
}
/*
* FACTORY
*/
static void dns_factory_ref(grpc_resolver_factory *factory) {}
static void dns_factory_unref(grpc_resolver_factory *factory) {}
static grpc_resolver *dns_factory_create_resolver(
grpc_resolver_factory *factory, grpc_uri *uri,
grpc_subchannel_factory *subchannel_factory) {
return dns_create(uri, "https", grpc_create_pick_first_lb_policy,
subchannel_factory);
}
static const grpc_resolver_factory_vtable dns_factory_vtable = {
dns_factory_ref, dns_factory_unref, dns_factory_create_resolver};
static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable};
grpc_resolver_factory *grpc_dns_resolver_factory_create() {
return &dns_resolver_factory;
}

@ -31,10 +31,12 @@
*
*/
#import <Foundation/Foundation.h>
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
#import "GRPCClient/GRPCMethodName.h"
#include "src/core/client_config/resolver_factory.h"
@interface GRPCMethodName (HTTP2Encoding)
- (NSString *)HTTP2Path;
@end
/** Create a dns resolver factory */
grpc_resolver_factory *grpc_dns_resolver_factory_create(void);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */

@ -0,0 +1,195 @@
/*
*
* 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

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

@ -0,0 +1,659 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/subchannel.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/transport/connectivity_state.h"
typedef struct {
/* all fields protected by subchannel->mu */
/** refcount */
int refs;
/** parent subchannel */
grpc_subchannel *subchannel;
} connection;
typedef struct {
grpc_iomgr_closure closure;
size_t version;
grpc_subchannel *subchannel;
grpc_connectivity_state connectivity_state;
} state_watcher;
typedef struct waiting_for_connect {
struct waiting_for_connect *next;
grpc_iomgr_closure *notify;
grpc_pollset *pollset;
grpc_subchannel_call **target;
grpc_subchannel *subchannel;
grpc_iomgr_closure continuation;
} waiting_for_connect;
struct grpc_subchannel {
grpc_connector *connector;
/** non-transport related channel filters */
const grpc_channel_filter **filters;
size_t num_filters;
/** channel arguments */
grpc_channel_args *args;
/** address to connect to */
struct sockaddr *addr;
size_t addr_len;
/** metadata context */
grpc_mdctx *mdctx;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */
grpc_channel *master;
/** have we seen a disconnection? */
int disconnected;
/** set during connection */
grpc_connect_out_args connecting_result;
/** callback for connection finishing */
grpc_iomgr_closure connected;
/** pollset_set tracking who's interested in a connection
being setup */
grpc_pollset_set pollset_set;
/** mutex protecting remaining elements */
gpr_mu mu;
/** active connection */
connection *active;
/** version number for the active connection */
size_t active_version;
/** refcount */
int refs;
/** are we connecting */
int connecting;
/** things waiting for a connection */
waiting_for_connect *waiting;
/** connectivity state tracking */
grpc_connectivity_state_tracker state_tracker;
/** next connect attempt time */
gpr_timespec next_attempt;
/** amount to backoff each failure */
gpr_timespec backoff_delta;
/** do we have an active alarm? */
int have_alarm;
/** our alarm */
grpc_alarm alarm;
};
struct grpc_subchannel_call {
connection *connection;
gpr_refcount refs;
};
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
#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 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);
static void subchannel_ref_locked(
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
static int subchannel_unref_locked(
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
static grpc_subchannel *connection_unref_locked(
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
static void subchannel_destroy(grpc_subchannel *c);
#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG
#define SUBCHANNEL_REF_LOCKED(p, r) \
subchannel_ref_locked((p), __FILE__, __LINE__, (r))
#define SUBCHANNEL_UNREF_LOCKED(p, r) \
subchannel_unref_locked((p), __FILE__, __LINE__, (r))
#define CONNECTION_REF_LOCKED(p, r) \
connection_ref_locked((p), __FILE__, __LINE__, (r))
#define CONNECTION_UNREF_LOCKED(p, r) \
connection_unref_locked((p), __FILE__, __LINE__, (r))
#define REF_PASS_ARGS , file, line, reason
#define REF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \
(name), (p), (p)->refs, (p)->refs + 1, reason)
#define UNREF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
(name), (p), (p)->refs, (p)->refs - 1, reason)
#else
#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p))
#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p))
#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p))
#define CONNECTION_UNREF_LOCKED(p, r) connection_unref_locked((p))
#define REF_PASS_ARGS
#define REF_LOG(name, p) \
do { \
} while (0)
#define UNREF_LOG(name, p) \
do { \
} while (0)
#endif
/*
* connection implementation
*/
static void connection_destroy(connection *c) {
GPR_ASSERT(c->refs == 0);
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CONNECTION(c));
gpr_free(c);
}
static void connection_ref_locked(
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
REF_LOG("CONNECTION", c);
subchannel_ref_locked(c->subchannel REF_PASS_ARGS);
++c->refs;
}
static grpc_subchannel *connection_unref_locked(
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
grpc_subchannel *destroy = NULL;
UNREF_LOG("CONNECTION", c);
if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) {
destroy = c->subchannel;
}
if (--c->refs == 0 && c->subchannel->active != c) {
connection_destroy(c);
}
return destroy;
}
/*
* grpc_subchannel implementation
*/
static void subchannel_ref_locked(
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
REF_LOG("SUBCHANNEL", c);
++c->refs;
}
static int subchannel_unref_locked(
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
UNREF_LOG("SUBCHANNEL", c);
return --c->refs == 0;
}
void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
gpr_mu_lock(&c->mu);
subchannel_ref_locked(c REF_PASS_ARGS);
gpr_mu_unlock(&c->mu);
}
void grpc_subchannel_unref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
int destroy;
gpr_mu_lock(&c->mu);
destroy = subchannel_unref_locked(c REF_PASS_ARGS);
gpr_mu_unlock(&c->mu);
if (destroy) subchannel_destroy(c);
}
static void subchannel_destroy(grpc_subchannel *c) {
if (c->active != NULL) {
connection_destroy(c->active);
}
gpr_free(c->filters);
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);
}
void grpc_subchannel_add_interested_party(grpc_subchannel *c,
grpc_pollset *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_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args) {
grpc_subchannel *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
c->refs = 1;
c->connector = connector;
grpc_connector_ref(c->connector);
c->num_filters = args->filter_count;
c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
memcpy(c->filters, args->filters,
sizeof(grpc_channel_filter *) * c->num_filters);
c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len);
c->addr_len = args->addr_len;
c->args = grpc_channel_args_copy(args->args);
c->mdctx = args->mdctx;
c->master = args->master;
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);
gpr_mu_init(&c->mu);
return c;
}
static void continue_connect(grpc_subchannel *c) {
grpc_connect_in_args args;
args.interested_parties = &c->pollset_set;
args.addr = c->addr;
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
args.channel_args = c->args;
args.metadata_context = c->mdctx;
grpc_connector_connect(c->connector, &args, &c->connecting_result,
&c->connected);
}
static void start_connect(grpc_subchannel *c) {
gpr_timespec now = gpr_now();
c->next_attempt = now;
c->backoff_delta = gpr_time_from_seconds(1);
continue_connect(c);
}
static void continue_creating_call(void *arg, int iomgr_success) {
waiting_for_connect *w4c = arg;
grpc_subchannel_create_call(w4c->subchannel, w4c->pollset, w4c->target,
w4c->notify);
GRPC_SUBCHANNEL_UNREF(w4c->subchannel, "waiting_for_connect");
gpr_free(w4c);
}
void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset,
grpc_subchannel_call **target,
grpc_iomgr_closure *notify) {
connection *con;
gpr_mu_lock(&c->mu);
if (c->active != NULL) {
con = c->active;
CONNECTION_REF_LOCKED(con, "call");
gpr_mu_unlock(&c->mu);
*target = create_call(con);
notify->cb(notify->cb_arg, 1);
} else {
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
w4c->next = c->waiting;
w4c->notify = notify;
w4c->pollset = pollset;
w4c->target = target;
w4c->subchannel = c;
/* released when clearing w4c */
SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect");
grpc_iomgr_closure_init(&w4c->continuation, continue_creating_call, w4c);
c->waiting = w4c;
grpc_subchannel_add_interested_party(c, pollset);
if (!c->connecting) {
c->connecting = 1;
connectivity_state_changed_locked(c);
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
gpr_mu_unlock(&c->mu);
start_connect(c);
} else {
gpr_mu_unlock(&c->mu);
}
}
}
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
grpc_connectivity_state state;
gpr_mu_lock(&c->mu);
state = grpc_connectivity_state_check(&c->state_tracker);
gpr_mu_unlock(&c->mu);
return state;
}
void grpc_subchannel_notify_on_state_change(grpc_subchannel *c,
grpc_connectivity_state *state,
grpc_iomgr_closure *notify) {
int do_connect = 0;
gpr_mu_lock(&c->mu);
if (grpc_connectivity_state_notify_on_state_change(&c->state_tracker, state,
notify)) {
do_connect = 1;
c->connecting = 1;
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
connectivity_state_changed_locked(c);
}
gpr_mu_unlock(&c->mu);
if (do_connect) {
start_connect(c);
}
}
void grpc_subchannel_process_transport_op(grpc_subchannel *c,
grpc_transport_op *op) {
connection *con = NULL;
grpc_subchannel *destroy;
int cancel_alarm = 0;
gpr_mu_lock(&c->mu);
if (op->disconnect) {
c->disconnected = 1;
connectivity_state_changed_locked(c);
if (c->have_alarm) {
cancel_alarm = 1;
}
}
if (c->active != NULL) {
con = c->active;
CONNECTION_REF_LOCKED(con, "transport-op");
}
gpr_mu_unlock(&c->mu);
if (con != NULL) {
grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_channel_element *top_elem =
grpc_channel_stack_element(channel_stack, 0);
top_elem->filter->start_transport_op(top_elem, op);
gpr_mu_lock(&c->mu);
destroy = CONNECTION_UNREF_LOCKED(con, "transport-op");
gpr_mu_unlock(&c->mu);
if (destroy) {
subchannel_destroy(destroy);
}
}
if (cancel_alarm) {
grpc_alarm_cancel(&c->alarm);
}
}
static void on_state_changed(void *p, int iomgr_success) {
state_watcher *sw = p;
grpc_subchannel *c = sw->subchannel;
gpr_mu *mu = &c->mu;
int destroy;
grpc_transport_op op;
grpc_channel_element *elem;
connection *destroy_connection = NULL;
gpr_mu_lock(mu);
/* if we failed or there is a version number mismatch, just leave
this closure */
if (!iomgr_success || sw->subchannel->active_version != sw->version) {
goto done;
}
switch (sw->connectivity_state) {
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_READY:
case GRPC_CHANNEL_IDLE:
/* all is still good: keep watching */
memset(&op, 0, sizeof(op));
op.connectivity_state = &sw->connectivity_state;
op.on_connectivity_state_change = &sw->closure;
elem = grpc_channel_stack_element(
CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
elem->filter->start_transport_op(elem, &op);
/* early out */
gpr_mu_unlock(mu);
return;
case GRPC_CHANNEL_FATAL_FAILURE:
case GRPC_CHANNEL_TRANSIENT_FAILURE:
/* things have gone wrong, deactivate and enter idle */
if (sw->subchannel->active->refs == 0) {
destroy_connection = sw->subchannel->active;
}
sw->subchannel->active = NULL;
grpc_connectivity_state_set(&c->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE);
break;
}
done:
connectivity_state_changed_locked(c);
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
gpr_free(sw);
gpr_mu_unlock(mu);
if (destroy) {
subchannel_destroy(c);
}
if (destroy_connection != NULL) {
connection_destroy(destroy_connection);
}
}
static void publish_transport(grpc_subchannel *c) {
size_t channel_stack_size;
connection *con;
grpc_channel_stack *stk;
size_t num_filters;
const grpc_channel_filter **filters;
waiting_for_connect *w4c;
grpc_transport_op op;
state_watcher *sw;
connection *destroy_connection = NULL;
grpc_channel_element *elem;
/* build final filter list */
num_filters = c->num_filters + c->connecting_result.num_filters + 1;
filters = gpr_malloc(sizeof(*filters) * num_filters);
memcpy(filters, c->filters, sizeof(*filters) * c->num_filters);
memcpy(filters + c->num_filters, c->connecting_result.filters,
sizeof(*filters) * c->connecting_result.num_filters);
filters[num_filters - 1] = &grpc_connected_channel_filter;
/* construct channel stack */
channel_stack_size = grpc_channel_stack_size(filters, num_filters);
con = gpr_malloc(sizeof(connection) + channel_stack_size);
stk = (grpc_channel_stack *)(con + 1);
con->refs = 0;
con->subchannel = c;
grpc_channel_stack_init(filters, num_filters, c->master, c->args, c->mdctx,
stk);
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
gpr_free(c->connecting_result.filters);
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
/* initialize state watcher */
sw = gpr_malloc(sizeof(*sw));
grpc_iomgr_closure_init(&sw->closure, on_state_changed, sw);
sw->subchannel = c;
sw->connectivity_state = GRPC_CHANNEL_READY;
gpr_mu_lock(&c->mu);
if (c->disconnected) {
gpr_mu_unlock(&c->mu);
gpr_free(sw);
gpr_free(filters);
grpc_channel_stack_destroy(stk);
return;
}
/* publish */
if (c->active != NULL && c->active->refs == 0) {
destroy_connection = c->active;
}
c->active = con;
c->active_version++;
sw->version = c->active_version;
c->connecting = 0;
/* watch for changes; subchannel ref for connecting is donated
to the state watcher */
memset(&op, 0, sizeof(op));
op.connectivity_state = &sw->connectivity_state;
op.on_connectivity_state_change = &sw->closure;
SUBCHANNEL_REF_LOCKED(c, "state_watcher");
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);
while ((w4c = c->waiting)) {
c->waiting = w4c->next;
grpc_iomgr_add_callback(&w4c->continuation);
}
gpr_mu_unlock(&c->mu);
gpr_free(filters);
if (destroy_connection != NULL) {
connection_destroy(destroy_connection);
}
}
static void on_alarm(void *arg, int iomgr_success) {
grpc_subchannel *c = arg;
gpr_mu_lock(&c->mu);
c->have_alarm = 0;
if (c->disconnected) {
iomgr_success = 0;
}
connectivity_state_changed_locked(c);
gpr_mu_unlock(&c->mu);
if (iomgr_success) {
continue_connect(c);
} else {
GRPC_SUBCHANNEL_UNREF(c, "connecting");
}
}
static void subchannel_connected(void *arg, int iomgr_success) {
grpc_subchannel *c = arg;
if (c->connecting_result.transport != NULL) {
publish_transport(c);
} else {
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_mu_unlock(&c->mu);
}
}
static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
return gpr_time_add(c->next_attempt, c->backoff_delta);
}
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
if (c->disconnected) {
return GRPC_CHANNEL_FATAL_FAILURE;
}
if (c->connecting) {
if (c->have_alarm) {
return GRPC_CHANNEL_TRANSIENT_FAILURE;
}
return GRPC_CHANNEL_CONNECTING;
}
if (c->active) {
return GRPC_CHANNEL_READY;
}
return GRPC_CHANNEL_IDLE;
}
static void connectivity_state_changed_locked(grpc_subchannel *c) {
grpc_connectivity_state current = compute_connectivity_locked(c);
grpc_connectivity_state_set(&c->state_tracker, current);
}
/*
* grpc_subchannel_call implementation
*/
void grpc_subchannel_call_ref(
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
gpr_ref(&c->refs);
}
void grpc_subchannel_call_unref(
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
if (gpr_unref(&c->refs)) {
gpr_mu *mu = &c->connection->subchannel->mu;
grpc_subchannel *destroy;
grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c));
gpr_mu_lock(mu);
destroy = CONNECTION_UNREF_LOCKED(c->connection, "call");
gpr_mu_unlock(mu);
gpr_free(c);
if (destroy != NULL) {
subchannel_destroy(destroy);
}
}
}
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);
grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
top_elem->filter->start_transport_stream_op(top_elem, op);
}
grpc_subchannel_call *create_call(connection *con) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_subchannel_call *call =
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call);
call->connection = con;
gpr_ref_init(&call->refs, 1);
grpc_call_stack_init(chanstk, NULL, NULL, callstk);
return call;
}

@ -0,0 +1,124 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/connector.h"
/** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */
typedef struct grpc_subchannel grpc_subchannel;
typedef struct grpc_subchannel_call grpc_subchannel_call;
typedef struct grpc_subchannel_args grpc_subchannel_args;
#ifdef GRPC_SUBCHANNEL_REFCOUNT_DEBUG
#define GRPC_SUBCHANNEL_REF(p, r) \
grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_UNREF(p, r) \
grpc_subchannel_unref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) \
grpc_subchannel_call_unref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS \
, const char *file, int line, const char *reason
#else
#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p))
#define GRPC_SUBCHANNEL_UNREF(p, r) grpc_subchannel_unref((p))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
#define GRPC_SUBCHANNEL_CALL_UNREF(p, r) grpc_subchannel_call_unref((p))
#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
#endif
void grpc_subchannel_ref(
grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_unref(
grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_ref(
grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_unref(
grpc_subchannel_call *call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** construct a call (possibly asynchronously) */
void grpc_subchannel_create_call(grpc_subchannel *subchannel,
grpc_pollset *pollset,
grpc_subchannel_call **target,
grpc_iomgr_closure *notify);
/** process a transport level op */
void grpc_subchannel_process_transport_op(grpc_subchannel *subchannel,
grpc_transport_op *op);
/** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity(
grpc_subchannel *channel);
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the channel */
void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel,
grpc_connectivity_state *state,
grpc_iomgr_closure *notify);
void grpc_subchannel_add_interested_party(grpc_subchannel *channel,
grpc_pollset *pollset);
void grpc_subchannel_del_interested_party(grpc_subchannel *channel,
grpc_pollset *pollset);
/** continue processing a transport op */
void grpc_subchannel_call_process_op(grpc_subchannel_call *subchannel_call,
grpc_transport_stream_op *op);
struct grpc_subchannel_args {
/** Channel filters for this channel - wrapped factories will likely
want to mutate this */
const grpc_channel_filter **filters;
/** The number of filters in the above array */
size_t filter_count;
/** Channel arguments to be supplied to the newly created channel */
const grpc_channel_args *args;
/** Address to connect to */
struct sockaddr *addr;
size_t addr_len;
/** metadata context to use */
grpc_mdctx *mdctx;
/** master channel */
grpc_channel *master;
};
/** create a subchannel given a connector */
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */

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

@ -0,0 +1,63 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/subchannel.h"
typedef struct grpc_subchannel_factory grpc_subchannel_factory;
typedef struct grpc_subchannel_factory_vtable grpc_subchannel_factory_vtable;
/** Constructor for new configured channels.
Creating decorators around this type is encouraged to adapt behavior. */
struct grpc_subchannel_factory {
const grpc_subchannel_factory_vtable *vtable;
};
struct grpc_subchannel_factory_vtable {
void (*ref)(grpc_subchannel_factory *factory);
void (*unref)(grpc_subchannel_factory *factory);
grpc_subchannel *(*create_subchannel)(grpc_subchannel_factory *factory,
grpc_subchannel_args *args);
};
void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory);
void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory);
/** Create a new grpc_subchannel */
grpc_subchannel *grpc_subchannel_factory_create_subchannel(
grpc_subchannel_factory *factory, grpc_subchannel_args *args);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */

@ -0,0 +1,149 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/client_config/uri_parser.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
static grpc_uri *bad_uri(const char *uri_text, int pos, const char *section,
int suppress_errors) {
char *line_prefix;
int pfx_len;
if (!suppress_errors) {
gpr_asprintf(&line_prefix, "bad uri.%s: '", section);
pfx_len = strlen(line_prefix) + pos;
gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text);
gpr_free(line_prefix);
line_prefix = gpr_malloc(pfx_len + 1);
memset(line_prefix, ' ', pfx_len);
line_prefix[pfx_len] = 0;
gpr_log(GPR_ERROR, "%s^ here", line_prefix);
gpr_free(line_prefix);
}
return NULL;
}
static char *copy_fragment(const char *src, int begin, int end) {
char *out = gpr_malloc(end - begin + 1);
memcpy(out, src + begin, end - begin);
out[end - begin] = 0;
return out;
}
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
grpc_uri *uri;
int scheme_begin = 0;
int scheme_end = -1;
int authority_begin = -1;
int authority_end = -1;
int path_begin = -1;
int path_end = -1;
int i;
for (i = scheme_begin; uri_text[i] != 0; i++) {
if (uri_text[i] == ':') {
scheme_end = i;
break;
}
if (uri_text[i] >= 'a' && uri_text[i] <= 'z') continue;
if (uri_text[i] >= 'A' && uri_text[i] <= 'Z') continue;
if (i != scheme_begin) {
if (uri_text[i] >= '0' && uri_text[i] <= '9') continue;
if (uri_text[i] == '+') continue;
if (uri_text[i] == '-') continue;
if (uri_text[i] == '.') continue;
}
break;
}
if (scheme_end == -1) {
return bad_uri(uri_text, i, "scheme", suppress_errors);
}
if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') {
authority_begin = scheme_end + 3;
for (i = authority_begin; uri_text[i] != 0; i++) {
if (uri_text[i] == '/') {
authority_end = i;
}
if (uri_text[i] == '?') {
return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
}
if (uri_text[i] == '#') {
return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
}
}
if (authority_end == -1 && uri_text[i] == 0) {
authority_end = i;
}
if (authority_end == -1) {
return bad_uri(uri_text, i, "authority", suppress_errors);
}
/* TODO(ctiller): parse the authority correctly */
path_begin = authority_end;
} else {
path_begin = scheme_end + 1;
}
for (i = path_begin; uri_text[i] != 0; i++) {
if (uri_text[i] == '?') {
return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
}
if (uri_text[i] == '#') {
return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
}
}
path_end = i;
uri = gpr_malloc(sizeof(*uri));
memset(uri, 0, sizeof(*uri));
uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end);
uri->authority = copy_fragment(uri_text, authority_begin, authority_end);
uri->path = copy_fragment(uri_text, path_begin, path_end);
return uri;
}
void grpc_uri_destroy(grpc_uri *uri) {
if (!uri) return;
gpr_free(uri->scheme);
gpr_free(uri->authority);
gpr_free(uri->path);
gpr_free(uri);
}

@ -31,14 +31,19 @@
*
*/
#import "GRPCMethodName+HTTP2Encoding.h"
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
@implementation GRPCMethodName (HTTP2Encoding)
- (NSString *)HTTP2Path {
if (self.package) {
return [NSString stringWithFormat:@"/%@.%@/%@", self.package, self.interface, self.method];
} else {
return [NSString stringWithFormat:@"/%@/%@", self.interface, self.method];
}
}
@end
typedef struct {
char *scheme;
char *authority;
char *path;
} grpc_uri;
/** parse a uri, return NULL on failure */
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);
/** destroy a uri */
void grpc_uri_destroy(grpc_uri *uri);
#endif

@ -198,7 +198,7 @@ static void on_connected(void *arg, grpc_endpoint *tcp) {
GRPC_SECURITY_OK);
grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done,
req);
grpc_security_connector_unref(&sc->base);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
} else {
start_write(req);
}

@ -41,9 +41,9 @@
typedef struct grpc_alarm {
gpr_timespec deadline;
gpr_uint32 heap_index; /* INVALID_HEAP_INDEX if not in heap */
int triggered;
struct grpc_alarm *next;
struct grpc_alarm *prev;
int triggered;
grpc_iomgr_cb_func cb;
void *cb_arg;
} grpc_alarm;

@ -74,6 +74,7 @@ static void freelist_fd(grpc_fd *fd) {
gpr_mu_lock(&fd_freelist_mu);
fd->freelist_next = fd_freelist;
fd_freelist = fd;
grpc_iomgr_unregister_object(&fd->iomgr_object);
gpr_mu_unlock(&fd_freelist_mu);
}
@ -115,7 +116,7 @@ static void destroy(grpc_fd *fd) {
#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file,
int line) {
gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
gpr_atm_no_barrier_load(&fd->refst),
gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
#else
@ -139,7 +140,6 @@ static void unref_by(grpc_fd *fd, int n) {
#endif
old = gpr_atm_full_fetch_add(&fd->refst, -n);
if (old == n) {
grpc_iomgr_unregister_object(&fd->iomgr_object);
freelist_fd(fd);
} else {
GPR_ASSERT(old > n);
@ -198,7 +198,8 @@ static void wake_all_watchers_locked(grpc_fd *fd) {
}
static int has_watchers(grpc_fd *fd) {
return fd->read_watcher != NULL || fd->write_watcher != NULL || fd->inactive_watcher_root.next != &fd->inactive_watcher_root;
return fd->read_watcher != NULL || fd->write_watcher != NULL ||
fd->inactive_watcher_root.next != &fd->inactive_watcher_root;
}
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_closure *on_done,
@ -368,16 +369,17 @@ gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
watcher->fd = NULL;
watcher->pollset = NULL;
gpr_mu_unlock(&fd->watcher_mu);
GRPC_FD_UNREF(fd, "poll");
return 0;
}
/* if there is nobody polling for read, but we need to, then start doing so */
if (!fd->read_watcher && gpr_atm_acq_load(&fd->readst) > READY) {
if (read_mask && !fd->read_watcher && gpr_atm_acq_load(&fd->readst) > READY) {
fd->read_watcher = watcher;
mask |= read_mask;
}
/* if there is nobody polling for write, but we need to, then start doing so
*/
if (!fd->write_watcher && gpr_atm_acq_load(&fd->writest) > READY) {
if (write_mask && !fd->write_watcher && gpr_atm_acq_load(&fd->writest) > READY) {
fd->write_watcher = watcher;
mask |= write_mask;
}

@ -34,7 +34,6 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
#define GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
#include <windows.h>
#include <grpc/support/sync.h>
#include "src/core/iomgr/socket_windows.h"

@ -158,7 +158,7 @@ void grpc_iomgr_shutdown(void) {
"memory leaks are likely",
count_objects());
for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s", obj->name);
gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s %p", obj->name, obj);
}
break;
}
@ -177,8 +177,8 @@ void grpc_iomgr_shutdown(void) {
}
void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
gpr_mu_lock(&g_mu);
obj->name = gpr_strdup(name);
gpr_mu_lock(&g_mu);
obj->next = &g_root_object;
obj->prev = obj->next->prev;
obj->next->prev = obj->prev->next = obj;
@ -189,9 +189,9 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
gpr_mu_lock(&g_mu);
obj->next->prev = obj->prev;
obj->prev->next = obj->next;
gpr_free(obj->name);
gpr_cv_signal(&g_rcv);
gpr_mu_unlock(&g_mu);
gpr_free(obj->name);
}
void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
@ -201,9 +201,21 @@ void grpc_iomgr_closure_init(grpc_iomgr_closure *closure, grpc_iomgr_cb_func cb,
closure->next = NULL;
}
static void assert_not_scheduled_locked(grpc_iomgr_closure *closure) {
#ifndef NDEBUG
grpc_iomgr_closure *c;
for (c = g_cbs_head; c; c = c->next) {
GPR_ASSERT(c != closure);
}
#endif
}
void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *closure, int success) {
closure->success = success;
GPR_ASSERT(closure->cb);
gpr_mu_lock(&g_mu);
assert_not_scheduled_locked(closure);
closure->next = NULL;
if (!g_cbs_tail) {
g_cbs_head = g_cbs_tail = closure;

@ -54,17 +54,25 @@ static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
pollset_hdr *h = pollset->data.ptr;
struct epoll_event ev;
int err;
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.ptr = fd;
err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
if (err < 0) {
/* FDs may be added to a pollset multiple times, so EEXIST is normal. */
if (errno != EEXIST) {
gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
strerror(errno));
grpc_fd_watcher watcher;
/* 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. */
GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, 0, 0, &watcher) == 0);
if (watcher.fd != NULL) {
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.ptr = fd;
err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
if (err < 0) {
/* FDs may be added to a pollset multiple times, so EEXIST is normal. */
if (errno != EEXIST) {
gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
strerror(errno));
}
}
}
grpc_fd_end_poll(&watcher, 0, 0);
}
static void multipoll_with_epoll_pollset_del_fd(grpc_pollset *pollset,

@ -179,6 +179,9 @@ static void multipoll_with_poll_pollset_maybe_work(
grpc_pollset_kick_consume(&pollset->kick_state, kfd);
}
for (i = 1; i < np; i++) {
if (h->watchers[i].fd == NULL) {
continue;
}
if (h->pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
grpc_fd_become_readable(h->watchers[i].fd, allow_synchronous_callback);
}

@ -249,7 +249,8 @@ static void basic_do_promote(void *args, int success) {
pollset->in_flight_cbs--;
if (pollset->shutting_down) {
/* We don't care about this pollset anymore. */
if (pollset->in_flight_cbs == 0 && pollset->counter == 0) {
if (pollset->in_flight_cbs == 0 && pollset->counter == 0 && !pollset->called_shutdown) {
pollset->called_shutdown = 1;
do_shutdown_cb = 1;
}
} else if (grpc_fd_is_orphaned(fd)) {

@ -114,7 +114,7 @@ void grpc_pollset_set_del_fd(grpc_pollset_set *pollset_set, grpc_fd *fd) {
if (pollset_set->fds[i] == fd) {
pollset_set->fd_count--;
GPR_SWAP(grpc_fd *, pollset_set->fds[i],
pollset_set->fds[pollset_set->pollset_count]);
pollset_set->fds[pollset_set->fd_count]);
GRPC_FD_UNREF(fd, "pollset_set");
break;
}

@ -34,7 +34,6 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
#include <windows.h>
#include <grpc/support/sync.h>
#include "src/core/iomgr/socket_windows.h"

@ -155,9 +155,9 @@ static void do_request(void *rp) {
grpc_resolve_cb cb = r->cb;
gpr_free(r->name);
gpr_free(r->default_port);
cb(arg, resolved);
grpc_iomgr_unregister_object(&r->iomgr_object);
gpr_free(r);
cb(arg, resolved);
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {

@ -34,8 +34,8 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
#define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
#include <ws2tcpip.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#ifdef __MINGW32__

@ -34,7 +34,8 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H
#define GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H
#include <windows.h>
#include <grpc/support/port_platform.h>
#include <winsock2.h>
#include <grpc/support/sync.h>
#include <grpc/support/atm.h>

@ -63,6 +63,7 @@ typedef struct {
grpc_alarm alarm;
int refs;
grpc_iomgr_closure write_closure;
grpc_pollset_set *interested_parties;
} async_connect;
static int prepare_socket(const struct sockaddr *addr, int fd) {
@ -152,6 +153,7 @@ 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);
goto finish;
}
@ -165,6 +167,7 @@ static void on_writable(void *acp, int success) {
finish:
gpr_mu_lock(&ac->mu);
if (!ep) {
grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
}
done = (--ac->refs == 0);
@ -240,6 +243,7 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
ac->cb = cb;
ac->cb_arg = arg;
ac->fd = fdobj;
ac->interested_parties = interested_parties;
gpr_mu_init(&ac->mu);
ac->refs = 2;
ac->write_closure.cb = on_writable;

@ -120,7 +120,68 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
}
gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
size_t b64_len = strlen(b64);
return grpc_base64_decode_with_len(b64, strlen(b64), url_safe);
}
static void decode_one_char(const unsigned char *codes, unsigned char *result,
size_t *result_offset) {
gpr_uint32 packed = (codes[0] << 2) | (codes[1] >> 4);
result[(*result_offset)++] = (unsigned char)packed;
}
static void decode_two_chars(const unsigned char *codes, unsigned char *result,
size_t *result_offset) {
gpr_uint32 packed = (codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2);
result[(*result_offset)++] = (unsigned char)(packed >> 8);
result[(*result_offset)++] = (unsigned char)(packed);
}
static int decode_group(const unsigned char *codes, size_t num_codes,
unsigned char *result, size_t *result_offset) {
GPR_ASSERT(num_codes <= 4);
/* Short end groups that may not have padding. */
if (num_codes == 1) {
gpr_log(GPR_ERROR, "Invalid group. Must be at least 2 bytes.");
return 0;
}
if (num_codes == 2) {
decode_one_char(codes, result, result_offset);
return 1;
}
if (num_codes == 3) {
decode_two_chars(codes, result, result_offset);
return 1;
}
/* Regular 4 byte groups with padding or not. */
GPR_ASSERT(num_codes == 4);
if (codes[0] == GRPC_BASE64_PAD_BYTE || codes[1] == GRPC_BASE64_PAD_BYTE) {
gpr_log(GPR_ERROR, "Invalid padding detected.");
return 0;
}
if (codes[2] == GRPC_BASE64_PAD_BYTE) {
if (codes[3] == GRPC_BASE64_PAD_BYTE) {
decode_one_char(codes, result, result_offset);
} else {
gpr_log(GPR_ERROR, "Invalid padding detected.");
return 0;
}
} else if (codes[3] == GRPC_BASE64_PAD_BYTE) {
decode_two_chars(codes, result, result_offset);
} else {
/* No padding. */
gpr_uint32 packed =
(codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3];
result[(*result_offset)++] = (unsigned char)(packed >> 16);
result[(*result_offset)++] = (unsigned char)(packed >> 8);
result[(*result_offset)++] = (unsigned char)(packed);
}
return 1;
}
gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
int url_safe) {
gpr_slice result = gpr_slice_malloc(b64_len);
unsigned char *current = GPR_SLICE_START_PTR(result);
size_t result_size = 0;
@ -151,43 +212,15 @@ gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
} else {
codes[num_codes++] = (unsigned char)code;
if (num_codes == 4) {
if (codes[0] == GRPC_BASE64_PAD_BYTE ||
codes[1] == GRPC_BASE64_PAD_BYTE) {
gpr_log(GPR_ERROR, "Invalid padding detected.");
goto fail;
}
if (codes[2] == GRPC_BASE64_PAD_BYTE) {
if (codes[3] == GRPC_BASE64_PAD_BYTE) {
/* Double padding. */
gpr_uint32 packed = (gpr_uint32)((codes[0] << 2) | (codes[1] >> 4));
current[result_size++] = (unsigned char)packed;
} else {
gpr_log(GPR_ERROR, "Invalid padding detected.");
goto fail;
}
} else if (codes[3] == GRPC_BASE64_PAD_BYTE) {
/* Single padding. */
gpr_uint32 packed =
(gpr_uint32)((codes[0] << 10) | (codes[1] << 4) | (codes[2] >> 2));
current[result_size++] = (unsigned char)(packed >> 8);
current[result_size++] = (unsigned char)(packed);
} else {
/* No padding. */
gpr_uint32 packed =
(gpr_uint32)((codes[0] << 18) | (codes[1] << 12) | (codes[2] << 6) | codes[3]);
current[result_size++] = (unsigned char)(packed >> 16);
current[result_size++] = (unsigned char)(packed >> 8);
current[result_size++] = (unsigned char)(packed);
}
if (!decode_group(codes, num_codes, current, &result_size)) goto fail;
num_codes = 0;
}
}
}
if (num_codes != 0) {
gpr_log(GPR_ERROR, "Invalid base64.");
gpr_slice_unref(result);
return gpr_empty_slice();
if (num_codes != 0 &&
!decode_group(codes, num_codes, current, &result_size)) {
goto fail;
}
GPR_SLICE_SET_LENGTH(result, result_size);
return result;

@ -45,4 +45,8 @@ char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
slice in case of failure. */
gpr_slice grpc_base64_decode(const char *b64, int url_safe);
/* Same as above except that the length is provided by the caller. */
gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
int url_safe);
#endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */

@ -58,7 +58,7 @@ typedef struct {
so that work can progress when this call wants work to
progress */
grpc_pollset *pollset;
grpc_transport_op op;
grpc_transport_stream_op op;
size_t op_md_idx;
int sent_initial_metadata;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
@ -77,7 +77,7 @@ 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_op_add_cancellation(
grpc_transport_stream_op_add_cancellation(
&calld->op, GRPC_STATUS_UNAUTHENTICATED,
grpc_mdstr_from_string(chand->md_ctx, error_msg));
grpc_call_next_op(elem, &calld->op);
@ -90,7 +90,7 @@ static void on_credentials_metadata(void *user_data,
grpc_call_element *elem = (grpc_call_element *)user_data;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_op *op = &calld->op;
grpc_transport_stream_op *op = &calld->op;
grpc_metadata_batch *mdb;
size_t i;
if (status != GRPC_CREDENTIALS_OK) {
@ -131,7 +131,7 @@ static char *build_service_url(const char *url_scheme, call_data *calld) {
}
static void send_security_metadata(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_client_security_context *ctx =
@ -193,7 +193,7 @@ static void on_host_checked(void *user_data, grpc_security_status status) {
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void auth_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
@ -253,17 +253,10 @@ static void auth_start_transport_op(grpc_call_element *elem,
grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
grpc_channel_next_op(elem, op);
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
call_data *calld = elem->call_data;
calld->creds = NULL;
calld->host = NULL;
@ -287,7 +280,7 @@ static void destroy_call_elem(grpc_call_element *elem) {
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
@ -298,14 +291,14 @@ static void init_channel_elem(grpc_channel_element *elem,
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
GPR_ASSERT(sc != NULL);
/* initialize members */
GPR_ASSERT(sc->is_client_side);
chand->security_connector =
(grpc_channel_security_connector *)grpc_security_connector_ref(sc);
(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");
@ -318,7 +311,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
grpc_channel_security_connector *ctx = chand->security_connector;
if (ctx != NULL) grpc_security_connector_unref(&ctx->base);
if (ctx != NULL)
GRPC_SECURITY_CONNECTOR_UNREF(&ctx->base, "client_auth_filter");
if (chand->authority_string != NULL) {
grpc_mdstr_unref(chand->authority_string);
}
@ -334,6 +328,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_client_auth_filter = {
auth_start_transport_op, channel_op, sizeof(call_data),
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"};

@ -225,7 +225,7 @@ static grpc_security_status ssl_create_security_connector(
arg.type = GRPC_ARG_STRING;
arg.key = GRPC_ARG_HTTP2_SCHEME;
arg.value.string = "https";
*new_args = grpc_channel_args_copy_and_add(args, &arg);
*new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
return status;
}

@ -74,7 +74,7 @@ static void secure_transport_setup_done(grpc_secure_transport_setup *s,
if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
gpr_slice_buffer_destroy(&s->left_overs);
grpc_security_connector_unref(s->connector);
GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup");
gpr_free(s);
}
@ -234,8 +234,9 @@ static void on_handshake_data_received_from_peer(
gpr_slice_split_tail(&slices[i], consumed_slice_size));
gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */
}
gpr_slice_buffer_addn(&s->left_overs, &slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice);
gpr_slice_buffer_addn(
&s->left_overs, &slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice);
check_peer(s);
}
@ -275,7 +276,8 @@ void grpc_setup_secure_transport(grpc_security_connector *connector,
secure_transport_setup_done(s, 0);
return;
}
s->connector = grpc_security_connector_ref(connector);
s->connector =
GRPC_SECURITY_CONNECTOR_REF(connector, "secure_transport_setup");
s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
s->endpoint = nonsecure_endpoint;

@ -84,12 +84,12 @@ static const char *ssl_cipher_suites(void) {
/* -- Common methods. -- */
/* Returns the first property with that name. */
const tsi_peer_property *tsi_peer_get_property_by_name(
const tsi_peer *peer, const char *name) {
const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
const char *name) {
size_t i;
if (peer == NULL) return NULL;
for (i = 0; i < peer->property_count; i++) {
const tsi_peer_property* property = &peer->properties[i];
const tsi_peer_property *property = &peer->properties[i];
if (name == NULL && property->name == NULL) {
return property;
}
@ -124,24 +124,44 @@ grpc_security_status grpc_channel_security_connector_check_call_host(
return sc->check_call_host(sc, host, cb, user_data);
}
void grpc_security_connector_unref(grpc_security_connector *sc) {
if (sc == NULL) return;
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
}
#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
grpc_security_connector *grpc_security_connector_ref(
grpc_security_connector *sc, const char *file, int line,
const char *reason) {
if (sc == NULL) return NULL;
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SECURITY_CONNECTOR:%p ref %d -> %d %s", sc,
(int)sc->refcount.count, (int)sc->refcount.count + 1, reason);
#else
grpc_security_connector *grpc_security_connector_ref(
grpc_security_connector *sc) {
if (sc == NULL) return NULL;
#endif
gpr_ref(&sc->refcount);
return sc;
}
#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
void grpc_security_connector_unref(grpc_security_connector *sc,
const char *file, int line,
const char *reason) {
if (sc == NULL) return;
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
(int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
#else
void grpc_security_connector_unref(grpc_security_connector *sc) {
if (sc == NULL) return;
#endif
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
}
static void connector_pointer_arg_destroy(void *p) {
grpc_security_connector_unref(p);
GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg");
}
static void *connector_pointer_arg_copy(void *p) {
return grpc_security_connector_ref(p);
return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg");
}
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
@ -580,7 +600,8 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
config->pem_private_key, config->pem_private_key_size,
config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings,
alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, &c->handshaker_factory);
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));
@ -633,8 +654,8 @@ grpc_security_status grpc_ssl_server_security_connector_create(
(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);
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));

@ -80,12 +80,25 @@ struct grpc_security_connector {
grpc_auth_context *auth_context; /* Populated after the peer is checked. */
};
/* Increments the refcount. */
/* Refcounting. */
#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
#define GRPC_SECURITY_CONNECTOR_REF(p, r) \
grpc_security_connector_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \
grpc_security_connector_unref((p), __FILE__, __LINE__, (r))
grpc_security_connector *grpc_security_connector_ref(
grpc_security_connector *sc);
/* Decrements the refcount and destroys the object if it reaches 0. */
void grpc_security_connector_unref(grpc_security_connector *sc);
grpc_security_connector *policy, const char *file, int line,
const char *reason);
void grpc_security_connector_unref(grpc_security_connector *policy,
const char *file, int line,
const char *reason);
#else
#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p))
#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p))
grpc_security_connector *grpc_security_connector_ref(
grpc_security_connector *policy);
void grpc_security_connector_unref(grpc_security_connector *policy);
#endif
/* Handshake creation. */
grpc_security_status grpc_security_connector_create_handshaker(
@ -172,9 +185,9 @@ typedef struct {
specific error code otherwise.
*/
grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc);
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *target_name, const char *overridden_target_name,
grpc_channel_security_connector **sc);
/* Gets the default ssl roots. */
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
@ -200,8 +213,8 @@ grpc_security_status grpc_ssl_server_security_connector_create(
const grpc_ssl_server_config *config, grpc_security_connector **sc);
/* Util. */
const tsi_peer_property *tsi_peer_get_property_by_name(
const tsi_peer *peer, const char *name);
const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
const char *name);
/* Exposed for testing only. */
grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer);

@ -51,24 +51,17 @@ typedef struct channel_data {
op contains type and call direction information, in addition to the data
that is being sent or received. */
static void auth_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
grpc_transport_stream_op *op) {
/* TODO(jboeuf): Get the metadata and get a new context from it. */
/* pass control down the stack */
grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
grpc_channel_next_op(elem, op);
}
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
@ -95,11 +88,10 @@ static void init_call_elem(grpc_call_element *elem,
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
}
static void destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
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) {
grpc_security_connector *sc = grpc_find_security_connector_in_args(args);
@ -115,17 +107,19 @@ static void init_channel_elem(grpc_channel_element *elem,
/* initialize members */
GPR_ASSERT(!sc->is_client_side);
chand->security_connector = grpc_security_connector_ref(sc);
chand->security_connector =
GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter");
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
grpc_security_connector_unref(chand->security_connector);
GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector,
"server_auth_filter");
}
const grpc_channel_filter grpc_server_auth_filter = {
auth_start_transport_op, channel_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, "server-auth"};

@ -70,38 +70,39 @@ static void state_unref(grpc_server_secure_state *state) {
gpr_mu_lock(&state->mu);
gpr_mu_unlock(&state->mu);
/* clean up */
grpc_security_connector_unref(state->sc);
GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
gpr_free(state);
}
}
static grpc_transport_setup_result setup_transport(void *statep,
grpc_transport *transport,
grpc_mdctx *mdctx) {
static void setup_transport(void *statep, grpc_transport *transport,
grpc_mdctx *mdctx) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_server_auth_filter, &grpc_http_server_filter};
grpc_server_secure_state *state = statep;
grpc_transport_setup_result result;
grpc_arg connector_arg = grpc_security_connector_to_arg(state->sc);
grpc_channel_args *args_copy = grpc_channel_args_copy_and_add(
grpc_server_get_channel_args(state->server), &connector_arg);
result = grpc_server_setup_transport(state->server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx,
args_copy);
grpc_server_get_channel_args(state->server), &connector_arg, 1);
grpc_server_setup_transport(state->server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy);
grpc_channel_args_destroy(args_copy);
return result;
}
static void on_secure_transport_setup_done(void *statep,
grpc_security_status status,
grpc_endpoint *secure_endpoint) {
grpc_server_secure_state *state = statep;
grpc_transport *transport;
grpc_mdctx *mdctx;
if (status == GRPC_SECURITY_OK) {
gpr_mu_lock(&state->mu);
if (!state->is_shutdown) {
grpc_create_chttp2_transport(
setup_transport, state, grpc_server_get_channel_args(state->server),
secure_endpoint, NULL, 0, grpc_mdctx_create(), 0);
mdctx = grpc_mdctx_create();
transport = grpc_create_chttp2_transport(
grpc_server_get_channel_args(state->server), secure_endpoint, mdctx,
0);
setup_transport(state, transport, mdctx);
grpc_chttp2_transport_start_reading(transport, NULL, 0);
} else {
/* We need to consume this here, because the server may already have gone
* away. */
@ -220,7 +221,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
/* Error path: cleanup and return */
error:
if (sc) {
grpc_security_connector_unref(sc);
GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
}
if (resolved) {
grpc_resolved_addresses_destroy(resolved);

@ -34,7 +34,6 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#include <windows.h>
#include <grpc/support/log.h>
unsigned gpr_cpu_num_cores(void) {

@ -43,7 +43,9 @@
#ifdef GPR_LINUX
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <stdio.h>
#include <stdarg.h>
@ -71,6 +73,7 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
char *prefix;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
@ -89,10 +92,12 @@ void gpr_default_log(gpr_log_func_args *args) {
strcpy(time_buffer, "error:strftime");
}
fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), gettid(), display_file, args->line,
args->message);
(int)(now.tv_nsec), gettid(), display_file, args->line);
fprintf(stderr, "%-60s %s\n", prefix, args->message);
gpr_free(prefix);
}
#endif

@ -37,7 +37,6 @@
#ifdef GPR_WIN32
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

@ -38,8 +38,6 @@
#ifdef GPR_WIN32
#include <windows.h>
/* These allocate new strings using gpr_malloc to convert from and to utf-8. */
LPTSTR gpr_char_to_tchar(LPCSTR input);
LPSTR gpr_tchar_to_char(LPCTSTR input);

@ -37,9 +37,6 @@
#ifdef GPR_WIN32
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>

@ -37,7 +37,6 @@
#ifdef GPR_WIN32
#include <windows.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

@ -39,7 +39,6 @@
#include <grpc/support/time.h>
#include <sys/timeb.h>
#include <windows.h>
gpr_timespec gpr_now(void) {
gpr_timespec now_tv;

@ -55,6 +55,20 @@ grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
return bb;
}
grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
grpc_byte_buffer_reader *reader) {
grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
gpr_slice slice;
bb->type = GRPC_BB_RAW;
bb->data.raw.compression = GRPC_COMPRESS_NONE;
gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
while (grpc_byte_buffer_reader_next(reader, &slice)) {
gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice);
}
return bb;
}
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
switch (bb->type) {
case GRPC_BB_RAW:

@ -76,14 +76,14 @@ typedef struct {
typedef struct {
/* Overall status of the operation: starts OK, may degrade to
non-OK */
int success;
/* Completion function to call at the end of the operation */
grpc_ioreq_completion_func on_complete;
void *user_data;
gpr_uint8 success;
/* a bit mask of which request ops are needed (1u << opid) */
gpr_uint16 need_mask;
/* a bit mask of which request ops are now completed */
gpr_uint16 complete_mask;
/* Completion function to call at the end of the operation */
grpc_ioreq_completion_func on_complete;
void *user_data;
} reqinfo_master;
/* Status data for a request can come from several sources; this
@ -160,6 +160,8 @@ struct grpc_call {
gpr_uint8 bound_pollset;
/* is an error status set */
gpr_uint8 error_status_set;
/** should the alarm be cancelled */
gpr_uint8 cancel_alarm;
/* flags with bits corresponding to write states allowing us to determine
what was sent */
@ -260,8 +262,8 @@ struct grpc_call {
static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline);
static void call_on_done_recv(void *call, int success);
static void call_on_done_send(void *call, int success);
static int fill_send_ops(grpc_call *call, grpc_transport_op *op);
static void execute_op(grpc_call *call, grpc_transport_op *op);
static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op);
static void execute_op(grpc_call *call, grpc_transport_stream_op *op);
static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
static void finish_read_ops(grpc_call *call);
static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
@ -277,8 +279,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
size_t add_initial_metadata_count,
gpr_timespec send_deadline) {
size_t i;
grpc_transport_op initial_op;
grpc_transport_op *initial_op_ptr = NULL;
grpc_transport_stream_op initial_op;
grpc_transport_stream_op *initial_op_ptr = NULL;
grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
grpc_call *call =
gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
@ -462,16 +464,16 @@ static int need_more_data(grpc_call *call) {
(is_op_live(call, GRPC_IOREQ_RECV_CLOSE) &&
grpc_bbq_empty(&call->incoming_queue)) ||
(call->write_state == WRITE_STATE_INITIAL && !call->is_client) ||
(call->cancel_with_status != GRPC_STATUS_OK) ||
call->destroy_called;
(call->cancel_with_status != GRPC_STATUS_OK) || call->destroy_called;
}
static void unlock(grpc_call *call) {
grpc_transport_op op;
grpc_transport_stream_op op;
completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
int completing_requests = 0;
int start_op = 0;
int i;
int cancel_alarm = 0;
memset(&op, 0, sizeof(op));
@ -479,6 +481,9 @@ static void unlock(grpc_call *call) {
start_op = op.cancel_with_status != GRPC_STATUS_OK;
call->cancel_with_status = GRPC_STATUS_OK; /* reset */
cancel_alarm = call->cancel_alarm;
call->cancel_alarm = 0;
if (!call->receiving && need_more_data(call)) {
op.recv_ops = &call->recv_ops;
op.recv_state = &call->recv_state;
@ -513,6 +518,10 @@ static void unlock(grpc_call *call) {
gpr_mu_unlock(&call->mu);
if (cancel_alarm) {
grpc_alarm_cancel(&call->alarm);
}
if (start_op) {
execute_op(call, &op);
}
@ -805,10 +814,7 @@ static void call_on_done_recv(void *pc, int success) {
if (call->recv_state == GRPC_STREAM_CLOSED) {
GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED);
call->read_state = READ_STATE_STREAM_CLOSED;
if (call->have_alarm) {
grpc_alarm_cancel(&call->alarm);
call->have_alarm = 0;
}
call->cancel_alarm |= call->have_alarm;
GRPC_CALL_INTERNAL_UNREF(call, "closed", 0);
}
finish_read_ops(call);
@ -881,7 +887,7 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
}
}
static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
static int fill_send_ops(grpc_call *call, grpc_transport_stream_op *op) {
grpc_ioreq_data data;
gpr_uint32 flags;
grpc_metadata_batch mdb;
@ -987,7 +993,7 @@ static void finish_read_ops(grpc_call *call) {
switch (call->read_state) {
case READ_STATE_STREAM_CLOSED:
if (empty) {
if (empty && !call->have_alarm) {
finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, 1);
}
/* fallthrough */
@ -1085,10 +1091,7 @@ void grpc_call_destroy(grpc_call *c) {
lock(c);
GPR_ASSERT(!c->destroy_called);
c->destroy_called = 1;
if (c->have_alarm) {
grpc_alarm_cancel(&c->alarm);
c->have_alarm = 0;
}
c->cancel_alarm |= c->have_alarm;
cancel = c->read_state != READ_STATE_STREAM_CLOSED;
unlock(c);
if (cancel) grpc_call_cancel(c);
@ -1140,7 +1143,7 @@ static void finished_loose_op_allocated(void *alloc, int success) {
gpr_free(args);
}
static void execute_op(grpc_call *call, grpc_transport_op *op) {
static void execute_op(grpc_call *call, grpc_transport_stream_op *op) {
grpc_call_element *elem;
GPR_ASSERT(op->on_consumed == NULL);
@ -1151,14 +1154,15 @@ static void execute_op(grpc_call *call, grpc_transport_op *op) {
} else {
finished_loose_op_allocated_args *args = gpr_malloc(sizeof(*args));
args->call = call;
grpc_iomgr_closure_init(&args->closure, finished_loose_op_allocated, args);
grpc_iomgr_closure_init(&args->closure, finished_loose_op_allocated,
args);
op->on_consumed = &args->closure;
}
}
elem = CALL_ELEM_FROM_CALL(call, 0);
op->context = call->context;
elem->filter->start_transport_op(elem, op);
elem->filter->start_transport_stream_op(elem, op);
}
grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
@ -1167,12 +1171,14 @@ grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
static void call_alarm(void *arg, int success) {
grpc_call *call = arg;
lock(call);
call->have_alarm = 0;
if (success) {
lock(call);
cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
"Deadline Exceeded");
unlock(call);
}
finish_read_ops(call);
unlock(call);
GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1);
}
@ -1223,13 +1229,13 @@ static gpr_uint32 decode_compression(grpc_mdelem *md) {
} else {
gpr_uint32 parsed_clevel_bytes;
if (gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
GPR_SLICE_LENGTH(md->value->slice),
&parsed_clevel_bytes)) {
GPR_SLICE_LENGTH(md->value->slice),
&parsed_clevel_bytes)) {
/* the following cast is safe, as a gpr_uint32 should be able to hold all
* possible values of the grpc_compression_level enum */
clevel = (grpc_compression_level) parsed_clevel_bytes;
clevel = (grpc_compression_level)parsed_clevel_bytes;
} else {
clevel = GRPC_COMPRESS_LEVEL_NONE; /* could not parse, no compression */
clevel = GRPC_COMPRESS_LEVEL_NONE; /* could not parse, no compression */
}
grpc_mdelem_set_user_data(md, destroy_compression,
(void *)(gpr_intptr)(clevel + COMPRESS_OFFSET));
@ -1252,7 +1258,8 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
} else if (key == grpc_channel_get_message_string(call->channel)) {
set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
} else if (key == grpc_channel_get_compresssion_level_string(call->channel)) {
} else if (key ==
grpc_channel_get_compresssion_level_string(call->channel)) {
set_decode_compression_level(call, decode_compression(md));
} else {
dest = &call->buffered_metadata[is_trailing];

@ -78,8 +78,8 @@ typedef union {
typedef struct {
grpc_ioreq_op op;
grpc_ioreq_data data;
gpr_uint32 flags; /**< A copy of the write flags from grpc_op */
grpc_ioreq_data data;
} grpc_ioreq;
typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success,

@ -39,7 +39,6 @@
#include "src/core/iomgr/iomgr.h"
#include "src/core/support/string.h"
#include "src/core/surface/call.h"
#include "src/core/surface/client.h"
#include "src/core/surface/init.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -94,9 +93,8 @@ grpc_channel *grpc_channel_create_from_filters(
grpc_channel *channel = gpr_malloc(size);
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client;
/* decremented by grpc_channel_destroy, and grpc_client_channel_closed if
* is_client */
gpr_ref_init(&channel->refs, 1 + is_client);
/* decremented by grpc_channel_destroy */
gpr_ref_init(&channel->refs, 1);
channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
channel->grpc_compression_level_string =
@ -111,8 +109,6 @@ grpc_channel *grpc_channel_create_from_filters(
}
channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel));
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
@ -133,6 +129,10 @@ grpc_channel *grpc_channel_create_from_filters(
}
}
grpc_channel_stack_init(filters, num_filters, channel, args,
channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel));
return channel;
}
@ -239,28 +239,16 @@ void grpc_channel_internal_unref(grpc_channel *channel) {
}
void grpc_channel_destroy(grpc_channel *channel) {
grpc_channel_op op;
grpc_transport_op op;
grpc_channel_element *elem;
memset(&op, 0, sizeof(op));
op.disconnect = 1;
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
op.type = GRPC_CHANNEL_GOAWAY;
op.dir = GRPC_CALL_DOWN;
op.data.goaway.status = GRPC_STATUS_OK;
op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
elem->filter->channel_op(elem, NULL, &op);
op.type = GRPC_CHANNEL_DISCONNECT;
op.dir = GRPC_CALL_DOWN;
elem->filter->channel_op(elem, NULL, &op);
elem->filter->start_transport_op(elem, &op);
GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
}
void grpc_client_channel_closed(grpc_channel_element *elem) {
GRPC_CHANNEL_INTERNAL_UNREF(CHANNEL_FROM_TOP_ELEM(elem), "closed");
}
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
@ -277,7 +265,6 @@ grpc_mdstr *grpc_channel_get_compresssion_level_string(grpc_channel *channel) {
return channel->grpc_compression_level_string;
}
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) {
return grpc_mdelem_ref(channel->grpc_status_elem[i]);

@ -35,6 +35,7 @@
#define GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/subchannel_factory.h"
grpc_channel *grpc_channel_create_from_filters(
const grpc_channel_filter **filters, size_t count,
@ -57,8 +58,6 @@ grpc_mdstr *grpc_channel_get_compresssion_level_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
void grpc_client_channel_closed(grpc_channel_element *elem);
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
void grpc_channel_internal_unref(grpc_channel *channel, const char *reason);

@ -31,159 +31,120 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include <grpc/grpc.h>
#include <stdlib.h>
#include <string.h>
#include "src/core/channel/census_filter.h"
#include <grpc/support/alloc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/client_setup.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_client_filter.h"
#include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/client_config/resolver_registry.h"
#include "src/core/iomgr/tcp_client.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/client.h"
#include "src/core/support/string.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
typedef struct setup setup;
/* A single setup request (started via initiate) */
typedef struct {
grpc_client_setup_request *cs_request;
setup *setup;
/* Resolved addresses, or null if resolution not yet completed */
grpc_resolved_addresses *resolved;
/* which address in resolved should we pick for the next connection attempt */
size_t resolved_index;
} request;
/* Global setup logic (may be running many simultaneous setup requests, but
with only one 'active' */
struct setup {
const char *target;
grpc_transport_setup_callback setup_callback;
void *setup_user_data;
};
static int maybe_try_next_resolved(request *r);
static void done(request *r, int was_successful) {
grpc_client_setup_request_finish(r->cs_request, was_successful);
if (r->resolved) {
grpc_resolved_addresses_destroy(r->resolved);
}
gpr_free(r);
grpc_connector base;
gpr_refcount refs;
grpc_iomgr_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
} connector;
static void connector_ref(grpc_connector *con) {
connector *c = (connector *)con;
gpr_ref(&c->refs);
}
/* connection callback: tcp is either valid, or null on error */
static void on_connect(void *rp, grpc_endpoint *tcp) {
request *r = rp;
if (!grpc_client_setup_request_should_continue(r->cs_request, "on_connect")) {
if (tcp) {
grpc_endpoint_shutdown(tcp);
grpc_endpoint_destroy(tcp);
}
done(r, 0);
return;
static void connector_unref(grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
gpr_free(c);
}
}
if (!tcp) {
if (!maybe_try_next_resolved(r)) {
done(r, 0);
return;
} else {
return;
}
} else if (grpc_client_setup_cb_begin(r->cs_request, "on_connect")) {
grpc_create_chttp2_transport(
r->setup->setup_callback, r->setup->setup_user_data,
grpc_client_setup_get_channel_args(r->cs_request), tcp, NULL, 0,
grpc_client_setup_get_mdctx(r->cs_request), 1);
grpc_client_setup_cb_end(r->cs_request, "on_connect");
done(r, 1);
return;
static void connected(void *arg, grpc_endpoint *tcp) {
connector *c = arg;
grpc_iomgr_closure *notify;
if (tcp != NULL) {
c->result->transport = grpc_create_chttp2_transport(
c->args.channel_args, tcp, c->args.metadata_context, 1);
grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
GPR_ASSERT(c->result->transport);
c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *));
c->result->filters[0] = &grpc_http_client_filter;
c->result->num_filters = 1;
} else {
done(r, 0);
memset(c->result, 0, sizeof(*c->result));
}
notify = c->notify;
c->notify = NULL;
grpc_iomgr_add_callback(notify);
}
/* attempt to connect to the next available resolved address */
static int maybe_try_next_resolved(request *r) {
grpc_resolved_address *addr;
if (!r->resolved) return 0;
if (r->resolved_index == r->resolved->naddrs) return 0;
addr = &r->resolved->addrs[r->resolved_index++];
grpc_tcp_client_connect(
on_connect, r, grpc_client_setup_get_interested_parties(r->cs_request),
(struct sockaddr *)&addr->addr, addr->len,
grpc_client_setup_request_deadline(r->cs_request));
return 1;
static void connector_connect(grpc_connector *con,
const grpc_connect_in_args *args,
grpc_connect_out_args *result,
grpc_iomgr_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
GPR_ASSERT(notify->cb);
c->notify = notify;
c->args = *args;
c->result = result;
grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr,
args->addr_len, args->deadline);
}
/* callback for when our target address has been resolved */
static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
request *r = rp;
/* if we're not still the active request, abort */
if (!grpc_client_setup_request_should_continue(r->cs_request,
"on_resolved")) {
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
done(r, 0);
return;
}
static const grpc_connector_vtable connector_vtable = {
connector_ref, connector_unref, connector_connect};
if (!resolved) {
done(r, 0);
return;
} else {
r->resolved = resolved;
r->resolved_index = 0;
if (!maybe_try_next_resolved(r)) {
done(r, 0);
}
}
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
} subchannel_factory;
static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
subchannel_factory *f = (subchannel_factory *)scf;
gpr_ref(&f->refs);
}
static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
request *r = gpr_malloc(sizeof(request));
r->setup = sp;
r->cs_request = cs_request;
r->resolved = NULL;
r->resolved_index = 0;
/* TODO(klempner): Make grpc_resolve_address respect deadline */
grpc_resolve_address(r->setup->target, "http", on_resolved, r);
static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
subchannel_factory *f = (subchannel_factory *)scf;
if (gpr_unref(&f->refs)) {
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
static void done_setup(void *sp) {
setup *s = sp;
gpr_free((void *)s->target);
gpr_free(s);
static grpc_subchannel *subchannel_factory_create_subchannel(
grpc_subchannel_factory *scf, grpc_subchannel_args *args) {
subchannel_factory *f = (subchannel_factory *)scf;
connector *c = gpr_malloc(sizeof(*c));
grpc_channel_args *final_args =
grpc_channel_args_merge(args->args, f->merge_args);
grpc_subchannel *s;
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
gpr_ref_init(&c->refs, 1);
args->mdctx = f->mdctx;
args->args = final_args;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(&c->base);
grpc_channel_args_destroy(final_args);
return s;
}
static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_transport *transport,
grpc_mdctx *mdctx) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_client_filter};
return grpc_client_channel_transport_setup_complete(
channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
mdctx);
}
static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
subchannel_factory_ref, subchannel_factory_unref,
subchannel_factory_create_subchannel};
/* Create a client channel:
Asynchronously: - resolve target
@ -191,28 +152,36 @@ static grpc_transport_setup_result complete_setup(void *channel_stack,
- perform handshakes */
grpc_channel *grpc_channel_create(const char *target,
const grpc_channel_args *args) {
setup *s = gpr_malloc(sizeof(setup));
grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_channel *channel = NULL;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
grpc_resolver *resolver;
subchannel_factory *f;
grpc_mdctx *mdctx = grpc_mdctx_create();
int n = 0;
filters[n++] = &grpc_client_surface_filter;
/* TODO(census)
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
} */
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args, mdctx, 1);
s->target = gpr_strdup(target);
s->setup_callback = complete_setup;
s->setup_user_data = grpc_channel_get_channel_stack(channel);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
grpc_mdctx_ref(mdctx);
f->mdctx = mdctx;
f->merge_args = grpc_channel_args_copy(args);
resolver = grpc_resolver_create(target, &f->base);
if (!resolver) {
return NULL;
}
grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
args, mdctx, initiate_setup, done_setup,
s);
channel = grpc_channel_create_from_filters(filters, n, args, mdctx, 1);
grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
resolver);
GRPC_RESOLVER_UNREF(resolver, "create");
grpc_subchannel_factory_unref(&f->base);
return channel;
}

@ -1,89 +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 "src/core/surface/client.h"
#include "src/core/surface/call.h"
#include "src/core/surface/channel.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
typedef struct { void *unused; } call_data;
typedef struct { void *unused; } channel_data;
static void client_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
grpc_call_next_op(elem, op);
}
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
switch (op->type) {
case GRPC_ACCEPT_CALL:
gpr_log(GPR_ERROR, "Client cannot accept new calls");
break;
case GRPC_TRANSPORT_CLOSED:
grpc_client_channel_closed(elem);
break;
case GRPC_TRANSPORT_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
break;
default:
GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
grpc_channel_next_op(elem, op);
}
}
static void init_call_elem(grpc_call_element *elem,
const void *transport_server_data,
grpc_transport_op *initial_op) {}
static void destroy_call_elem(grpc_call_element *elem) {}
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
GPR_ASSERT(is_first);
GPR_ASSERT(!is_last);
}
static void destroy_channel_elem(grpc_channel_element *elem) {}
const grpc_channel_filter grpc_client_surface_filter = {
client_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
destroy_call_elem, sizeof(channel_data), init_channel_elem,
destroy_channel_elem, "client",
};

@ -31,9 +31,13 @@
*
*/
#include <grpc/support/port_platform.h>
#include <grpc/census.h>
#include <grpc/grpc.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/client_config/resolver_registry.h"
#include "src/core/client_config/resolvers/dns_resolver.h"
#include "src/core/debug/trace.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/profiling/timers.h"
@ -42,6 +46,10 @@
#include "src/core/surface/surface_trace.h"
#include "src/core/transport/chttp2_transport.h"
#ifdef GPR_POSIX_SOCKET
#include "src/core/client_config/resolvers/unix_resolver_posix.h"
#endif
static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
static int g_initializations;
@ -56,6 +64,11 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
grpc_resolver_registry_init("dns:///");
grpc_register_resolver_type("dns", grpc_dns_resolver_factory_create());
#ifdef GPR_POSIX_SOCKET
grpc_register_resolver_type("unix", grpc_unix_resolver_factory_create());
#endif
grpc_register_tracer("channel", &grpc_trace_channel);
grpc_register_tracer("surface", &grpc_surface_trace);
grpc_register_tracer("http", &grpc_http_trace);
@ -79,6 +92,7 @@ void grpc_shutdown(void) {
census_shutdown();
grpc_timers_global_destroy();
grpc_tracer_shutdown();
grpc_resolver_registry_shutdown();
}
gpr_mu_unlock(&g_init_mu);
}

@ -49,16 +49,16 @@ typedef struct {
typedef struct { grpc_mdctx *mdctx; } channel_data;
static void lame_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
static void lame_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
if (op->send_ops) {
if (op->send_ops != NULL) {
grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
op->on_done_send->cb(op->on_done_send->cb_arg, 0);
}
if (op->recv_ops) {
if (op->recv_ops != NULL) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
grpc_metadata_batch mdb;
gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp);
@ -77,36 +77,35 @@ static void lame_start_transport_op(grpc_call_element *elem,
*op->recv_state = GRPC_STREAM_CLOSED;
op->on_done_recv->cb(op->on_done_recv->cb_arg, 1);
}
if (op->on_consumed) {
if (op->on_consumed != NULL) {
op->on_consumed->cb(op->on_consumed->cb_arg, 0);
}
}
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
switch (op->type) {
case GRPC_CHANNEL_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
break;
case GRPC_CHANNEL_DISCONNECT:
grpc_client_channel_closed(elem);
break;
default:
break;
static void lame_start_transport_op(grpc_channel_element *elem,
grpc_transport_op *op) {
if (op->on_connectivity_state_change) {
GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE);
*op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
op->on_connectivity_state_change->cb(
op->on_connectivity_state_change->cb_arg, 1);
}
if (op->on_consumed != NULL) {
op->on_consumed->cb(op->on_consumed->cb_arg, 1);
}
}
static void init_call_elem(grpc_call_element *elem,
const void *transport_server_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
if (initial_op) {
grpc_transport_op_finish_with_failure(initial_op);
grpc_transport_stream_op_finish_with_failure(initial_op);
}
}
static void destroy_call_elem(grpc_call_element *elem) {}
static void init_channel_elem(grpc_channel_element *elem,
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 *chand = elem->channel_data;
@ -118,9 +117,15 @@ static void init_channel_elem(grpc_channel_element *elem,
static void destroy_channel_elem(grpc_channel_element *elem) {}
static const grpc_channel_filter lame_filter = {
lame_start_transport_op, channel_op, sizeof(call_data),
init_call_elem, destroy_call_elem, sizeof(channel_data),
init_channel_elem, destroy_channel_elem, "lame-client",
lame_start_transport_stream_op,
lame_start_transport_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
destroy_channel_elem,
"lame-client",
};
grpc_channel *grpc_lame_client_channel_create(void) {

@ -31,177 +31,147 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include <grpc/grpc.h>
#include <stdlib.h>
#include <string.h>
#include "src/core/channel/census_filter.h"
#include <grpc/support/alloc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/channel/client_channel.h"
#include "src/core/channel/client_setup.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_client_filter.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/client_config/resolver_registry.h"
#include "src/core/iomgr/tcp_client.h"
#include "src/core/security/auth_filters.h"
#include "src/core/security/credentials.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/client.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/tsi/transport_security_interface.h"
typedef struct setup setup;
/* A single setup request (started via initiate) */
typedef struct {
grpc_client_setup_request *cs_request;
setup *setup;
/* Resolved addresses, or null if resolution not yet completed. */
grpc_resolved_addresses *resolved;
/* which address in resolved should we pick for the next connection attempt */
size_t resolved_index;
} request;
grpc_connector base;
gpr_refcount refs;
struct setup {
grpc_channel_security_connector *security_connector;
const char *target;
grpc_transport_setup_callback setup_callback;
void *setup_user_data;
};
static int maybe_try_next_resolved(request *r);
grpc_iomgr_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
} connector;
static void done(request *r, int was_successful) {
grpc_client_setup_request_finish(r->cs_request, was_successful);
if (r->resolved) {
grpc_resolved_addresses_destroy(r->resolved);
static void connector_ref(grpc_connector *con) {
connector *c = (connector *)con;
gpr_ref(&c->refs);
}
static void connector_unref(grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
gpr_free(c);
}
gpr_free(r);
}
static void on_secure_transport_setup_done(void *rp,
static void on_secure_transport_setup_done(void *arg,
grpc_security_status status,
grpc_endpoint *secure_endpoint) {
request *r = rp;
connector *c = arg;
grpc_iomgr_closure *notify;
if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
done(r, 0);
} else if (grpc_client_setup_cb_begin(r->cs_request,
"on_secure_transport_setup_done")) {
grpc_create_chttp2_transport(
r->setup->setup_callback, r->setup->setup_user_data,
grpc_client_setup_get_channel_args(r->cs_request), secure_endpoint,
NULL, 0, grpc_client_setup_get_mdctx(r->cs_request), 1);
grpc_client_setup_cb_end(r->cs_request, "on_secure_transport_setup_done");
done(r, 1);
memset(c->result, 0, sizeof(*c->result));
} else {
done(r, 0);
c->result->transport = grpc_create_chttp2_transport(
c->args.channel_args, secure_endpoint, c->args.metadata_context, 1);
grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
c->result->filters[0] = &grpc_client_auth_filter;
c->result->filters[1] = &grpc_http_client_filter;
c->result->num_filters = 2;
}
notify = c->notify;
c->notify = NULL;
grpc_iomgr_add_callback(notify);
}
/* connection callback: tcp is either valid, or null on error */
static void on_connect(void *rp, grpc_endpoint *tcp) {
request *r = rp;
if (!grpc_client_setup_request_should_continue(r->cs_request,
"on_connect.secure")) {
if (tcp) {
grpc_endpoint_shutdown(tcp);
grpc_endpoint_destroy(tcp);
}
done(r, 0);
return;
}
if (!tcp) {
if (!maybe_try_next_resolved(r)) {
done(r, 0);
return;
} else {
return;
}
static void connected(void *arg, grpc_endpoint *tcp) {
connector *c = arg;
grpc_iomgr_closure *notify;
if (tcp != NULL) {
grpc_setup_secure_transport(&c->security_connector->base, tcp,
on_secure_transport_setup_done, c);
} else {
grpc_setup_secure_transport(&r->setup->security_connector->base, tcp,
on_secure_transport_setup_done, r);
memset(c->result, 0, sizeof(*c->result));
notify = c->notify;
c->notify = NULL;
grpc_iomgr_add_callback(notify);
}
}
/* attempt to connect to the next available resolved address */
static int maybe_try_next_resolved(request *r) {
grpc_resolved_address *addr;
if (!r->resolved) return 0;
if (r->resolved_index == r->resolved->naddrs) return 0;
addr = &r->resolved->addrs[r->resolved_index++];
grpc_tcp_client_connect(
on_connect, r, grpc_client_setup_get_interested_parties(r->cs_request),
(struct sockaddr *)&addr->addr, addr->len,
grpc_client_setup_request_deadline(r->cs_request));
return 1;
static void connector_connect(grpc_connector *con,
const grpc_connect_in_args *args,
grpc_connect_out_args *result,
grpc_iomgr_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
GPR_ASSERT(notify->cb);
c->notify = notify;
c->args = *args;
c->result = result;
grpc_tcp_client_connect(connected, c, args->interested_parties, args->addr,
args->addr_len, args->deadline);
}
/* callback for when our target address has been resolved */
static void on_resolved(void *rp, grpc_resolved_addresses *resolved) {
request *r = rp;
static const grpc_connector_vtable connector_vtable = {
connector_ref, connector_unref, connector_connect};
/* if we're not still the active request, abort */
if (!grpc_client_setup_request_should_continue(r->cs_request,
"on_resolved.secure")) {
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
done(r, 0);
return;
}
typedef struct {
grpc_subchannel_factory base;
gpr_refcount refs;
grpc_mdctx *mdctx;
grpc_channel_args *merge_args;
grpc_channel_security_connector *security_connector;
} subchannel_factory;
if (!resolved) {
done(r, 0);
return;
} else {
r->resolved = resolved;
r->resolved_index = 0;
if (!maybe_try_next_resolved(r)) {
done(r, 0);
}
}
static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
subchannel_factory *f = (subchannel_factory *)scf;
gpr_ref(&f->refs);
}
static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
request *r = gpr_malloc(sizeof(request));
r->setup = sp;
r->cs_request = cs_request;
r->resolved = NULL;
r->resolved_index = 0;
/* TODO(klempner): Make grpc_resolve_address respect deadline */
grpc_resolve_address(r->setup->target, "https", on_resolved, r);
static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
subchannel_factory *f = (subchannel_factory *)scf;
if (gpr_unref(&f->refs)) {
GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
"subchannel_factory");
grpc_channel_args_destroy(f->merge_args);
grpc_mdctx_unref(f->mdctx);
gpr_free(f);
}
}
static void done_setup(void *sp) {
setup *s = sp;
gpr_free((void *)s->target);
grpc_security_connector_unref(&s->security_connector->base);
gpr_free(s);
static grpc_subchannel *subchannel_factory_create_subchannel(
grpc_subchannel_factory *scf, grpc_subchannel_args *args) {
subchannel_factory *f = (subchannel_factory *)scf;
connector *c = gpr_malloc(sizeof(*c));
grpc_channel_args *final_args =
grpc_channel_args_merge(args->args, f->merge_args);
grpc_subchannel *s;
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
c->security_connector = f->security_connector;
gpr_ref_init(&c->refs, 1);
args->mdctx = f->mdctx;
args->args = final_args;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(&c->base);
grpc_channel_args_destroy(final_args);
return s;
}
static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_transport *transport,
grpc_mdctx *mdctx) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_client_auth_filter, &grpc_http_client_filter};
return grpc_client_channel_transport_setup_complete(
channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
mdctx);
}
static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
subchannel_factory_ref, subchannel_factory_unref,
subchannel_factory_create_subchannel};
/* Create a secure client channel:
Asynchronously: - resolve target
@ -210,13 +180,14 @@ static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const char *target,
const grpc_channel_args *args) {
setup *s;
grpc_channel *channel;
grpc_arg connector_arg;
grpc_channel_args *args_copy;
grpc_channel_args *new_args_from_connector;
grpc_channel_security_connector *connector;
grpc_mdctx *mdctx;
grpc_resolver *resolver;
subchannel_factory *f;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
int n = 0;
@ -233,30 +204,41 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
}
mdctx = grpc_mdctx_create();
s = gpr_malloc(sizeof(setup));
connector_arg = grpc_security_connector_to_arg(&connector->base);
args_copy = grpc_channel_args_copy_and_add(
new_args_from_connector != NULL ? new_args_from_connector : args,
&connector_arg);
filters[n++] = &grpc_client_surface_filter;
&connector_arg, 1);
/* TODO(census)
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
} */
filters[n++] = &grpc_client_channel_filter;
GPR_ASSERT(n <= MAX_FILTERS);
f = gpr_malloc(sizeof(*f));
f->base.vtable = &subchannel_factory_vtable;
gpr_ref_init(&f->refs, 1);
grpc_mdctx_ref(mdctx);
f->mdctx = mdctx;
GRPC_SECURITY_CONNECTOR_REF(&connector->base, "subchannel_factory");
f->security_connector = connector;
f->merge_args = grpc_channel_args_copy(args_copy);
resolver = grpc_resolver_create(target, &f->base);
if (!resolver) {
return NULL;
}
channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
resolver);
GRPC_RESOLVER_UNREF(resolver, "create");
grpc_subchannel_factory_unref(&f->base);
GRPC_SECURITY_CONNECTOR_UNREF(&connector->base, "channel_create");
grpc_channel_args_destroy(args_copy);
if (new_args_from_connector != NULL) {
grpc_channel_args_destroy(new_args_from_connector);
}
s->target = gpr_strdup(target);
s->setup_callback = complete_setup;
s->setup_user_data = grpc_channel_get_channel_stack(channel);
s->security_connector = connector;
grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
args, mdctx, initiate_setup, done_setup,
s);
return channel;
}

@ -115,6 +115,7 @@ typedef struct channel_registered_method {
struct channel_data {
grpc_server *server;
size_t num_calls;
grpc_connectivity_state connectivity_state;
grpc_channel *channel;
grpc_mdstr *path_key;
grpc_mdstr *authority_key;
@ -125,6 +126,7 @@ struct channel_data {
gpr_uint32 registered_method_slots;
gpr_uint32 registered_method_max_probes;
grpc_iomgr_closure finish_destroy_channel_closure;
grpc_iomgr_closure channel_connectivity_changed;
};
typedef struct shutdown_tag {
@ -149,7 +151,7 @@ struct grpc_server {
before mu_call. This is currently used in shutdown processing
(grpc_server_shutdown_and_notify and maybe_finish_shutdown) */
gpr_mu mu_global; /* mutex for server and channel state */
gpr_mu mu_call; /* mutex for call-specific state */
gpr_mu mu_call; /* mutex for call-specific state */
registered_method *registered_methods;
requested_call_array requested_calls;
@ -200,18 +202,101 @@ struct call_data {
call_link links[CALL_LIST_COUNT];
};
typedef struct {
grpc_channel **channels;
grpc_channel **disconnects;
size_t num_channels;
size_t num_disconnects;
} channel_broadcaster;
#define SERVER_FROM_CALL_ELEM(elem) \
(((channel_data *)(elem)->channel_data)->server)
static void begin_call(grpc_server *server, call_data *calld,
requested_call *rc);
static void fail_call(grpc_server *server, requested_call *rc);
static void shutdown_channel(channel_data *chand, int send_goaway,
int send_disconnect);
/* Before calling maybe_finish_shutdown, we must hold mu_global and not
hold mu_call */
static void maybe_finish_shutdown(grpc_server *server);
/* channel broadcaster */
/* assumes server locked */
static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) {
channel_data *c;
size_t count = 0;
size_t dc_count = 0;
for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
count++;
if (c->num_calls == 0) {
dc_count++;
}
}
cb->num_channels = count;
cb->num_disconnects = dc_count;
cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels);
cb->disconnects = gpr_malloc(sizeof(*cb->channels) * cb->num_disconnects);
count = 0;
dc_count = 0;
for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
cb->channels[count++] = c->channel;
GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast");
if (c->num_calls == 0) {
cb->disconnects[dc_count++] = c->channel;
GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast-disconnect");
}
}
}
struct shutdown_cleanup_args {
grpc_iomgr_closure closure;
gpr_slice slice;
};
static void shutdown_cleanup(void *arg, int iomgr_status_ignored) {
struct shutdown_cleanup_args *a = arg;
gpr_slice_unref(a->slice);
gpr_free(a);
}
static void send_shutdown(grpc_channel *channel, int send_goaway,
int send_disconnect) {
grpc_transport_op op;
struct shutdown_cleanup_args *sc;
grpc_channel_element *elem;
memset(&op, 0, sizeof(op));
op.send_goaway = send_goaway;
sc = gpr_malloc(sizeof(*sc));
sc->slice = gpr_slice_from_copied_string("Server shutdown");
op.goaway_message = &sc->slice;
op.goaway_status = GRPC_STATUS_OK;
op.disconnect = send_disconnect;
grpc_iomgr_closure_init(&sc->closure, shutdown_cleanup, sc);
op.on_consumed = &sc->closure;
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
elem->filter->start_transport_op(elem, &op);
}
static void channel_broadcaster_shutdown(channel_broadcaster *cb,
int send_goaway, int send_disconnect) {
size_t i;
for (i = 0; i < cb->num_channels; i++) {
send_shutdown(cb->channels[i], 1, 0);
GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast");
}
for (i = 0; i < cb->num_disconnects; i++) {
send_shutdown(cb->disconnects[i], 0, 1);
GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast-disconnect");
}
gpr_free(cb->channels);
gpr_free(cb->disconnects);
}
/* call list */
static int call_list_join(call_data **root, call_data *call, call_list list) {
GPR_ASSERT(!call->root[list]);
call->root[list] = root;
@ -456,12 +541,14 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
return md;
}
static void decrement_call_count(channel_data *chand) {
static int decrement_call_count(channel_data *chand) {
int disconnect = 0;
chand->num_calls--;
if (0 == chand->num_calls && chand->server->shutdown) {
shutdown_channel(chand, 0, 1);
disconnect = 1;
}
maybe_finish_shutdown(chand->server);
return disconnect;
}
static void server_on_recv(void *ptr, int success) {
@ -469,6 +556,7 @@ static void server_on_recv(void *ptr, int success) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
int remove_res;
int disconnect = 0;
if (success && !calld->got_initial_metadata) {
size_t i;
@ -517,16 +605,24 @@ static void server_on_recv(void *ptr, int success) {
gpr_mu_unlock(&chand->server->mu_call);
gpr_mu_lock(&chand->server->mu_global);
if (remove_res) {
decrement_call_count(chand);
disconnect = decrement_call_count(chand);
if (disconnect) {
GRPC_CHANNEL_INTERNAL_REF(chand->channel, "send-disconnect");
}
}
gpr_mu_unlock(&chand->server->mu_global);
if (disconnect) {
send_shutdown(chand->channel, 0, 1);
GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "send-disconnect");
}
break;
}
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
}
static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
static void server_mutate_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
call_data *calld = elem->call_data;
if (op->recv_ops) {
@ -538,92 +634,43 @@ static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
}
}
static void server_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
static void server_start_transport_stream_op(grpc_call_element *elem,
grpc_transport_stream_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
server_mutate_op(elem, op);
grpc_call_next_op(elem, op);
}
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
channel_data *chand = elem->channel_data;
grpc_server *server = chand->server;
switch (op->type) {
case GRPC_ACCEPT_CALL:
/* create a call */
grpc_call_create(chand->channel, NULL,
op->data.accept_call.transport_server_data, NULL, 0,
gpr_inf_future);
break;
case GRPC_TRANSPORT_CLOSED:
/* if the transport is closed for a server channel, we destroy the
channel */
gpr_mu_lock(&server->mu_global);
server_ref(server);
destroy_channel(chand);
gpr_mu_unlock(&server->mu_global);
server_unref(server);
break;
case GRPC_TRANSPORT_GOAWAY:
gpr_slice_unref(op->data.goaway.message);
break;
default:
GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
grpc_channel_next_op(elem, op);
break;
}
static void accept_stream(void *cd, grpc_transport *transport,
const void *transport_server_data) {
channel_data *chand = cd;
/* create a call */
grpc_call_create(chand->channel, NULL, transport_server_data, NULL, 0,
gpr_inf_future);
}
typedef struct {
channel_data *chand;
int send_goaway;
int send_disconnect;
grpc_iomgr_closure finish_shutdown_channel_closure;
} shutdown_channel_args;
static void finish_shutdown_channel(void *p, int success) {
shutdown_channel_args *sca = p;
grpc_channel_op op;
if (sca->send_goaway) {
op.type = GRPC_CHANNEL_GOAWAY;
op.dir = GRPC_CALL_DOWN;
op.data.goaway.status = GRPC_STATUS_OK;
op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown");
channel_op(grpc_channel_stack_element(
grpc_channel_get_channel_stack(sca->chand->channel), 0),
NULL, &op);
}
if (sca->send_disconnect) {
op.type = GRPC_CHANNEL_DISCONNECT;
op.dir = GRPC_CALL_DOWN;
channel_op(grpc_channel_stack_element(
grpc_channel_get_channel_stack(sca->chand->channel), 0),
NULL, &op);
static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) {
channel_data *chand = cd;
grpc_server *server = chand->server;
if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
grpc_transport_op op;
memset(&op, 0, sizeof(op));
op.on_connectivity_state_change = &chand->channel_connectivity_changed,
op.connectivity_state = &chand->connectivity_state;
grpc_channel_next_op(grpc_channel_stack_element(
grpc_channel_get_channel_stack(chand->channel), 0),
&op);
} else {
gpr_mu_lock(&server->mu_global);
destroy_channel(chand);
gpr_mu_unlock(&server->mu_global);
GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "connectivity");
}
GRPC_CHANNEL_INTERNAL_UNREF(sca->chand->channel, "shutdown");
gpr_free(sca);
}
static void shutdown_channel(channel_data *chand, int send_goaway,
int send_disconnect) {
shutdown_channel_args *sca;
GRPC_CHANNEL_INTERNAL_REF(chand->channel, "shutdown");
sca = gpr_malloc(sizeof(shutdown_channel_args));
sca->chand = chand;
sca->send_goaway = send_goaway;
sca->send_disconnect = send_disconnect;
sca->finish_shutdown_channel_closure.cb = finish_shutdown_channel;
sca->finish_shutdown_channel_closure.cb_arg = sca;
grpc_iomgr_add_callback(&sca->finish_shutdown_channel_closure);
}
static void init_call_elem(grpc_call_element *elem,
const void *server_transport_data,
grpc_transport_op *initial_op) {
grpc_transport_stream_op *initial_op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
memset(calld, 0, sizeof(call_data));
@ -672,7 +719,7 @@ static void destroy_call_elem(grpc_call_element *elem) {
server_unref(chand->server);
}
static void init_channel_elem(grpc_channel_element *elem,
static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
@ -686,6 +733,9 @@ static void init_channel_elem(grpc_channel_element *elem,
chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
chand->next = chand->prev = chand;
chand->registered_methods = NULL;
chand->connectivity_state = GRPC_CHANNEL_IDLE;
grpc_iomgr_closure_init(&chand->channel_connectivity_changed,
channel_connectivity_changed, chand);
}
static void destroy_channel_elem(grpc_channel_element *elem) {
@ -716,8 +766,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
static const grpc_channel_filter server_surface_filter = {
server_start_transport_op,
channel_op,
server_start_transport_stream_op,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
destroy_call_elem,
@ -831,10 +881,10 @@ void grpc_server_start(grpc_server *server) {
}
}
grpc_transport_setup_result grpc_server_setup_transport(
grpc_server *s, grpc_transport *transport,
grpc_channel_filter const **extra_filters, size_t num_extra_filters,
grpc_mdctx *mdctx, const grpc_channel_args *args) {
void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
grpc_channel_filter const **extra_filters,
size_t num_extra_filters, grpc_mdctx *mdctx,
const grpc_channel_args *args) {
size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
grpc_channel_filter const **filters =
gpr_malloc(sizeof(grpc_channel_filter *) * num_filters);
@ -851,7 +901,7 @@ grpc_transport_setup_result grpc_server_setup_transport(
gpr_uint32 slots;
gpr_uint32 probes;
gpr_uint32 max_probes = 0;
grpc_transport_setup_result result;
grpc_transport_op op;
for (i = 0; i < s->channel_filter_count; i++) {
filters[i] = s->channel_filters[i];
@ -862,7 +912,9 @@ grpc_transport_setup_result grpc_server_setup_transport(
filters[i] = &grpc_connected_channel_filter;
for (i = 0; i < s->cq_count; i++) {
grpc_transport_add_to_pollset(transport, grpc_cq_pollset(s->cqs[i]));
memset(&op, 0, sizeof(op));
op.bind_pollset = grpc_cq_pollset(s->cqs[i]);
grpc_transport_perform_op(transport, &op);
}
channel =
@ -903,8 +955,8 @@ grpc_transport_setup_result grpc_server_setup_transport(
chand->registered_method_max_probes = max_probes;
}
result = grpc_connected_channel_bind_transport(
grpc_channel_get_channel_stack(channel), transport);
grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
transport);
gpr_mu_lock(&s->mu_global);
chand->next = &s->root_channel_data;
@ -914,17 +966,23 @@ grpc_transport_setup_result grpc_server_setup_transport(
gpr_free(filters);
return result;
GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
memset(&op, 0, sizeof(op));
op.set_accept_stream = accept_stream;
op.set_accept_stream_user_data = chand;
op.on_connectivity_state_change = &chand->channel_connectivity_changed;
op.connectivity_state = &chand->connectivity_state;
grpc_transport_perform_op(transport, &op);
}
void grpc_server_shutdown_and_notify(grpc_server *server,
grpc_completion_queue *cq, void *tag) {
listener *l;
requested_call_array requested_calls;
channel_data *c;
size_t i;
registered_method *rm;
shutdown_tag *sdt;
channel_broadcaster broadcaster;
/* lock, and gather up some stuff to do */
gpr_mu_lock(&server->mu_global);
@ -940,10 +998,7 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
return;
}
for (c = server->root_channel_data.next; c != &server->root_channel_data;
c = c->next) {
shutdown_channel(c, 1, c->num_calls == 0);
}
channel_broadcaster_init(server, &broadcaster);
/* collect all unregistered then registered calls */
gpr_mu_lock(&server->mu_call);
@ -981,6 +1036,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
for (l = server->listeners; l; l = l->next) {
l->destroy(server, l->arg);
}
channel_broadcaster_shutdown(&broadcaster, 1, 0);
}
void grpc_server_listener_destroy_done(void *s) {
@ -1181,6 +1238,8 @@ static void begin_call(grpc_server *server, call_data *calld,
calld->cq_new = rc->cq_for_notification;
switch (rc->type) {
case BATCH_CALL:
GPR_ASSERT(calld->host != NULL);
GPR_ASSERT(calld->path != NULL);
cpstr(&rc->data.batch.details->host,
&rc->data.batch.details->host_capacity, calld->host);
cpstr(&rc->data.batch.details->method,

@ -55,10 +55,10 @@ void grpc_server_listener_destroy_done(void *server);
/* Setup a transport - creates a channel stack, binds the transport to the
server */
grpc_transport_setup_result grpc_server_setup_transport(
grpc_server *server, grpc_transport *transport,
grpc_channel_filter const **extra_filters, size_t num_extra_filters,
grpc_mdctx *mdctx, const grpc_channel_args *args);
void grpc_server_setup_transport(grpc_server *server, grpc_transport *transport,
grpc_channel_filter const **extra_filters,
size_t num_extra_filters, grpc_mdctx *mdctx,
const grpc_channel_args *args);
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);

@ -42,14 +42,13 @@
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
static grpc_transport_setup_result setup_transport(void *server,
grpc_transport *transport,
grpc_mdctx *mdctx) {
static void setup_transport(void *server, grpc_transport *transport,
grpc_mdctx *mdctx) {
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_server_filter};
return grpc_server_setup_transport(server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx,
grpc_server_get_channel_args(server));
grpc_server_setup_transport(server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx,
grpc_server_get_channel_args(server));
}
static void new_transport(void *server, grpc_endpoint *tcp) {
@ -60,9 +59,11 @@ static void new_transport(void *server, grpc_endpoint *tcp) {
* (as in server_secure_chttp2.c) needs to add synchronization to avoid this
* case.
*/
grpc_create_chttp2_transport(setup_transport, server,
grpc_server_get_channel_args(server), tcp, NULL,
0, grpc_mdctx_create(), 0);
grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_transport *transport = grpc_create_chttp2_transport(
grpc_server_get_channel_args(server), tcp, mdctx, 0);
setup_transport(server, transport, mdctx);
grpc_chttp2_transport_start_reading(transport, NULL, 0);
}
/* Server callback: start listening on our ports */

@ -124,6 +124,7 @@ void grpc_incoming_metadata_buffer_move_to_referencing_sopb(
sopb->ops[i].data.metadata.list.tail =
(void *)(delta + (gpr_intptr)sopb->ops[i].data.metadata.list.tail);
}
src->count = 0;
}
void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(

@ -34,7 +34,6 @@
#ifndef GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
#define GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
#include "src/core/transport/transport_impl.h"
#include "src/core/iomgr/endpoint.h"
#include "src/core/transport/chttp2/frame.h"
#include "src/core/transport/chttp2/frame_data.h"
@ -47,6 +46,8 @@
#include "src/core/transport/chttp2/incoming_metadata.h"
#include "src/core/transport/chttp2/stream_encoder.h"
#include "src/core/transport/chttp2/stream_map.h"
#include "src/core/transport/connectivity_state.h"
#include "src/core/transport/transport_impl.h"
typedef struct grpc_chttp2_transport grpc_chttp2_transport;
typedef struct grpc_chttp2_stream grpc_chttp2_stream;
@ -62,6 +63,7 @@ typedef enum {
GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE,
GRPC_CHTTP2_LIST_PARSING_SEEN,
GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING,
GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED,
/** streams that are waiting to start because there are too many concurrent
streams on the connection */
@ -134,12 +136,6 @@ typedef struct {
grpc_chttp2_stream *prev;
} grpc_chttp2_stream_link;
typedef enum {
GRPC_CHTTP2_ERROR_STATE_NONE,
GRPC_CHTTP2_ERROR_STATE_SEEN,
GRPC_CHTTP2_ERROR_STATE_NOTIFIED
} grpc_chttp2_error_state;
/* We keep several sets of connection wide parameters */
typedef enum {
/* The settings our peer has asked for (and we have acked) */
@ -165,7 +161,8 @@ typedef struct {
/** data to write next write */
gpr_slice_buffer qbuf;
/** queued callbacks */
grpc_iomgr_closure *pending_closures;
grpc_iomgr_closure *pending_closures_head;
grpc_iomgr_closure *pending_closures_tail;
/** window available for us to send to peer */
gpr_uint32 outgoing_window;
@ -174,6 +171,9 @@ typedef struct {
/** how much window would we like to have for incoming_window */
gpr_uint32 connection_window_target;
/** have we seen a goaway */
gpr_uint8 seen_goaway;
/** is this transport a client? */
gpr_uint8 is_client;
/** are the local settings dirty and need to be sent? */
@ -185,10 +185,6 @@ typedef struct {
/** settings values */
gpr_uint32 settings[GRPC_NUM_SETTING_SETS][GRPC_CHTTP2_NUM_SETTINGS];
/** has there been a connection level error, and have we notified
anyone about it? */
grpc_chttp2_error_state error_state;
/** what is the next stream id to be allocated by this peer?
copied to next_stream_id in parsing when parsing commences */
gpr_uint32 next_stream_id;
@ -204,13 +200,6 @@ typedef struct {
/** concurrent stream count: updated when not parsing,
so this is a strict over-estimation on the client */
gpr_uint32 concurrent_stream_count;
/** is there a goaway available? (boolean) */
grpc_chttp2_error_state goaway_state;
/** what is the debug text of the goaway? */
gpr_slice goaway_text;
/** what is the status code of the goaway? */
grpc_status_code goaway_error;
} grpc_chttp2_transport_global;
typedef struct {
@ -343,14 +332,13 @@ struct grpc_chttp2_transport {
grpc_chttp2_stream **accepting_stream;
struct {
/** is a thread currently performing channel callbacks */
gpr_uint8 executing;
/** transport channel-level callback */
const grpc_transport_callbacks *cb;
/** user data for cb calls */
void *cb_user_data;
/** closure for notifying transport closure */
grpc_iomgr_closure notify_closed;
/* accept stream callback */
void (*accept_stream)(void *user_data, grpc_transport *transport,
const void *server_data);
void *accept_stream_user_data;
/** connectivity tracking */
grpc_connectivity_state_tracker state_tracker;
} channel_callback;
};
@ -539,6 +527,13 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
void grpc_chttp2_list_add_cancelled_waiting_for_writing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
int grpc_chttp2_list_pop_cancelled_waiting_for_writing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
void grpc_chttp2_list_add_read_write_state_changed(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);

@ -109,9 +109,6 @@ void grpc_chttp2_publish_reads(
transport_parsing->incoming_stream_id;
}
/* TODO(ctiller): re-implement */
GPR_ASSERT(transport_parsing->initial_window_update == 0);
/* copy parsing qbuf to global qbuf */
gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);

@ -222,7 +222,9 @@ int grpc_chttp2_list_pop_writable_window_update_stream(
void grpc_chttp2_list_remove_writable_window_update_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE);
stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE);
}
void grpc_chttp2_list_add_parsing_seen_stream(
@ -282,6 +284,24 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing(
return r;
}
void grpc_chttp2_list_add_cancelled_waiting_for_writing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING);
}
int grpc_chttp2_list_pop_cancelled_waiting_for_writing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global) {
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING);
*stream_global = &stream->global;
return r;
}
void grpc_chttp2_list_add_incoming_window_updated(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {

@ -97,12 +97,8 @@ int grpc_chttp2_unlocking_check_writes(
grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
}
/* we should either exhaust window or have no ops left, but not both */
if (stream_global->outgoing_sopb->nops == 0) {
stream_global->outgoing_sopb = NULL;
grpc_chttp2_schedule_closure(transport_global,
stream_global->send_done_closure, 1);
} else if (stream_global->outgoing_window > 0) {
if (stream_global->outgoing_window > 0 &&
stream_global->outgoing_sopb->nops != 0) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
}
}
@ -201,6 +197,11 @@ void grpc_chttp2_cleanup_writing(
while (grpc_chttp2_list_pop_written_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_global->outgoing_sopb->nops == 0) {
stream_global->outgoing_sopb = NULL;
grpc_chttp2_schedule_closure(transport_global,
stream_global->send_done_closure, 1);
}
if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
if (!transport_global->is_client) {

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

Loading…
Cancel
Save