Merge branch 'master' into node_protobuf_js_6_upgrade

pull/10204/head
Michael Lumish 8 years ago committed by GitHub
commit cbe5036bb7
  1. 24
      BUILD
  2. 178
      CMakeLists.txt
  3. 24
      INSTALL.md
  4. 209
      Makefile
  5. 18
      README.md
  6. 3
      Rakefile
  7. 18
      binding.gyp
  8. 86
      build.yaml
  9. 10
      config.m4
  10. 158
      doc/combiner-explainer.md
  11. 160
      doc/core/grpc-error.md
  12. 1
      doc/g_stands_for.md
  13. 76
      doc/http2-interop-test-descriptions.md
  14. 9
      examples/node/static_codegen/README.md
  15. 31
      gRPC-Core.podspec
  16. 2
      gRPC-ProtoRPC.podspec
  17. 2
      gRPC-RxLibrary.podspec
  18. 2
      gRPC.podspec
  19. 3
      grpc.def
  20. 16
      grpc.gemspec
  21. 6
      include/grpc++/support/channel_arguments.h
  22. 65
      include/grpc/grpc.h
  23. 5
      include/grpc/impl/codegen/atm.h
  24. 5
      include/grpc/impl/codegen/grpc_types.h
  25. 2
      package.json
  26. 16
      package.xml
  27. 7
      setup.py
  28. 77
      src/compiler/csharp_generator.cc
  29. 2
      src/compiler/php_generator.cc
  30. 8
      src/compiler/python_generator.cc
  31. 4
      src/core/ext/census/grpc_filter.c
  32. 4
      src/core/ext/client_channel/channel_connectivity.c
  33. 188
      src/core/ext/client_channel/client_channel.c
  34. 3
      src/core/ext/client_channel/client_channel_plugin.c
  35. 2
      src/core/ext/client_channel/connector.h
  36. 4
      src/core/ext/client_channel/http_connect_handshaker.c
  37. 12
      src/core/ext/client_channel/proxy_mapper_registry.c
  38. 210
      src/core/ext/client_channel/retry_throttle.c
  39. 65
      src/core/ext/client_channel/retry_throttle.h
  40. 70
      src/core/ext/client_channel/subchannel.c
  41. 18
      src/core/ext/client_channel/subchannel.h
  42. 22
      src/core/ext/lb_policy/grpclb/grpclb.c
  43. 27
      src/core/ext/lb_policy/pick_first/pick_first.c
  44. 29
      src/core/ext/lb_policy/round_robin/round_robin.c
  45. 6
      src/core/ext/load_reporting/load_reporting_filter.c
  46. 5
      src/core/ext/resolver/dns/native/dns_resolver.c
  47. 41
      src/core/ext/transport/chttp2/client/chttp2_connector.c
  48. 4
      src/core/ext/transport/chttp2/server/chttp2_server.c
  49. 4
      src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
  50. 262
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  51. 17
      src/core/ext/transport/chttp2/transport/frame_data.c
  52. 5
      src/core/ext/transport/chttp2/transport/frame_goaway.c
  53. 2
      src/core/ext/transport/chttp2/transport/frame_ping.c
  54. 7
      src/core/ext/transport/chttp2/transport/frame_rst_stream.c
  55. 11
      src/core/ext/transport/chttp2/transport/frame_settings.c
  56. 4
      src/core/ext/transport/chttp2/transport/frame_window_update.c
  57. 73
      src/core/ext/transport/chttp2/transport/hpack_parser.c
  58. 4
      src/core/ext/transport/chttp2/transport/hpack_table.c
  59. 65
      src/core/ext/transport/chttp2/transport/incoming_metadata.c
  60. 18
      src/core/ext/transport/chttp2/transport/incoming_metadata.h
  61. 2
      src/core/ext/transport/chttp2/transport/internal.h
  62. 48
      src/core/ext/transport/chttp2/transport/parsing.c
  63. 115
      src/core/ext/transport/cronet/transport/cronet_transport.c
  64. 36
      src/core/lib/channel/channel_stack.c
  65. 23
      src/core/lib/channel/channel_stack.h
  66. 2
      src/core/lib/channel/compress_filter.c
  67. 9
      src/core/lib/channel/connected_channel.c
  68. 8
      src/core/lib/channel/deadline_filter.c
  69. 5
      src/core/lib/channel/handshaker.c
  70. 8
      src/core/lib/channel/http_client_filter.c
  71. 53
      src/core/lib/channel/http_server_filter.c
  72. 13
      src/core/lib/channel/message_size_filter.c
  73. 14
      src/core/lib/http/httpcli.c
  74. 2
      src/core/lib/http/httpcli_security_connector.c
  75. 88
      src/core/lib/http/parser.c
  76. 4
      src/core/lib/iomgr/closure.c
  77. 2
      src/core/lib/iomgr/combiner.c
  78. 88
      src/core/lib/iomgr/error.c
  79. 53
      src/core/lib/iomgr/error.h
  80. 14
      src/core/lib/iomgr/ev_epoll_linux.c
  81. 12
      src/core/lib/iomgr/ev_poll_posix.c
  82. 4
      src/core/lib/iomgr/executor.c
  83. 9
      src/core/lib/iomgr/load_file.c
  84. 4
      src/core/lib/iomgr/port.h
  85. 24
      src/core/lib/iomgr/resolve_address_posix.c
  86. 14
      src/core/lib/iomgr/resolve_address_uv.c
  87. 4
      src/core/lib/iomgr/resolve_address_windows.c
  88. 110
      src/core/lib/iomgr/socket_factory_posix.c
  89. 90
      src/core/lib/iomgr/socket_factory_posix.h
  90. 34
      src/core/lib/iomgr/socket_utils_common_posix.c
  91. 7
      src/core/lib/iomgr/socket_utils_posix.h
  92. 22
      src/core/lib/iomgr/tcp_client_posix.c
  93. 16
      src/core/lib/iomgr/tcp_client_uv.c
  94. 7
      src/core/lib/iomgr/tcp_client_windows.c
  95. 19
      src/core/lib/iomgr/tcp_posix.c
  96. 445
      src/core/lib/iomgr/tcp_server_posix.c
  97. 134
      src/core/lib/iomgr/tcp_server_utils_posix.h
  98. 221
      src/core/lib/iomgr/tcp_server_utils_posix_common.c
  99. 196
      src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
  100. 27
      src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
  101. Some files were not shown because too many files have changed in this diff Show More

24
BUILD

@ -37,11 +37,11 @@ package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_proto_plugin") load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_proto_plugin")
g_stands_for = "good" g_stands_for = "green"
core_version = "2.0.0-dev" core_version = "3.0.0-dev"
version = "1.1.0-dev" version = "1.2.0"
grpc_cc_library( grpc_cc_library(
name = "gpr", name = "gpr",
@ -309,6 +309,8 @@ grpc_cc_library(
"src/core/lib/profiling/basic_timers.c", "src/core/lib/profiling/basic_timers.c",
"src/core/lib/profiling/stap_timers.c", "src/core/lib/profiling/stap_timers.c",
"src/core/lib/support/alloc.c", "src/core/lib/support/alloc.c",
"src/core/lib/support/arena.c",
"src/core/lib/support/atm.c",
"src/core/lib/support/avl.c", "src/core/lib/support/avl.c",
"src/core/lib/support/backoff.c", "src/core/lib/support/backoff.c",
"src/core/lib/support/cmdline.c", "src/core/lib/support/cmdline.c",
@ -353,6 +355,7 @@ grpc_cc_library(
], ],
hdrs = [ hdrs = [
"src/core/lib/profiling/timers.h", "src/core/lib/profiling/timers.h",
"src/core/lib/support/arena.h",
"src/core/lib/support/backoff.h", "src/core/lib/support/backoff.h",
"src/core/lib/support/block_annotate.h", "src/core/lib/support/block_annotate.h",
"src/core/lib/support/env.h", "src/core/lib/support/env.h",
@ -469,6 +472,7 @@ grpc_cc_library(
"src/core/lib/iomgr/resolve_address_windows.c", "src/core/lib/iomgr/resolve_address_windows.c",
"src/core/lib/iomgr/resource_quota.c", "src/core/lib/iomgr/resource_quota.c",
"src/core/lib/iomgr/sockaddr_utils.c", "src/core/lib/iomgr/sockaddr_utils.c",
"src/core/lib/iomgr/socket_factory_posix.c",
"src/core/lib/iomgr/socket_mutator.c", "src/core/lib/iomgr/socket_mutator.c",
"src/core/lib/iomgr/socket_utils_common_posix.c", "src/core/lib/iomgr/socket_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c", "src/core/lib/iomgr/socket_utils_linux.c",
@ -481,6 +485,9 @@ grpc_cc_library(
"src/core/lib/iomgr/tcp_client_windows.c", "src/core/lib/iomgr/tcp_client_windows.c",
"src/core/lib/iomgr/tcp_posix.c", "src/core/lib/iomgr/tcp_posix.c",
"src/core/lib/iomgr/tcp_server_posix.c", "src/core/lib/iomgr/tcp_server_posix.c",
"src/core/lib/iomgr/tcp_server_utils_posix_common.c",
"src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c",
"src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c",
"src/core/lib/iomgr/tcp_server_uv.c", "src/core/lib/iomgr/tcp_server_uv.c",
"src/core/lib/iomgr/tcp_server_windows.c", "src/core/lib/iomgr/tcp_server_windows.c",
"src/core/lib/iomgr/tcp_uv.c", "src/core/lib/iomgr/tcp_uv.c",
@ -521,6 +528,7 @@ grpc_cc_library(
"src/core/lib/surface/channel_ping.c", "src/core/lib/surface/channel_ping.c",
"src/core/lib/surface/channel_stack_type.c", "src/core/lib/surface/channel_stack_type.c",
"src/core/lib/surface/completion_queue.c", "src/core/lib/surface/completion_queue.c",
"src/core/lib/surface/completion_queue_factory.c",
"src/core/lib/surface/event_string.c", "src/core/lib/surface/event_string.c",
"src/core/lib/surface/lame_client.c", "src/core/lib/surface/lame_client.c",
"src/core/lib/surface/metadata_array.c", "src/core/lib/surface/metadata_array.c",
@ -591,6 +599,7 @@ grpc_cc_library(
"src/core/lib/iomgr/sockaddr_posix.h", "src/core/lib/iomgr/sockaddr_posix.h",
"src/core/lib/iomgr/sockaddr_utils.h", "src/core/lib/iomgr/sockaddr_utils.h",
"src/core/lib/iomgr/sockaddr_windows.h", "src/core/lib/iomgr/sockaddr_windows.h",
"src/core/lib/iomgr/socket_factory_posix.h",
"src/core/lib/iomgr/socket_mutator.h", "src/core/lib/iomgr/socket_mutator.h",
"src/core/lib/iomgr/socket_utils.h", "src/core/lib/iomgr/socket_utils.h",
"src/core/lib/iomgr/socket_utils_posix.h", "src/core/lib/iomgr/socket_utils_posix.h",
@ -599,6 +608,7 @@ grpc_cc_library(
"src/core/lib/iomgr/tcp_client_posix.h", "src/core/lib/iomgr/tcp_client_posix.h",
"src/core/lib/iomgr/tcp_posix.h", "src/core/lib/iomgr/tcp_posix.h",
"src/core/lib/iomgr/tcp_server.h", "src/core/lib/iomgr/tcp_server.h",
"src/core/lib/iomgr/tcp_server_utils_posix.h",
"src/core/lib/iomgr/tcp_uv.h", "src/core/lib/iomgr/tcp_uv.h",
"src/core/lib/iomgr/tcp_windows.h", "src/core/lib/iomgr/tcp_windows.h",
"src/core/lib/iomgr/time_averaged_stats.h", "src/core/lib/iomgr/time_averaged_stats.h",
@ -629,6 +639,7 @@ grpc_cc_library(
"src/core/lib/surface/channel_init.h", "src/core/lib/surface/channel_init.h",
"src/core/lib/surface/channel_stack_type.h", "src/core/lib/surface/channel_stack_type.h",
"src/core/lib/surface/completion_queue.h", "src/core/lib/surface/completion_queue.h",
"src/core/lib/surface/completion_queue_factory.h",
"src/core/lib/surface/event_string.h", "src/core/lib/surface/event_string.h",
"src/core/lib/surface/init.h", "src/core/lib/surface/init.h",
"src/core/lib/surface/lame_client.h", "src/core/lib/surface/lame_client.h",
@ -679,10 +690,8 @@ grpc_cc_library(
"src/core/ext/client_channel/client_channel_factory.c", "src/core/ext/client_channel/client_channel_factory.c",
"src/core/ext/client_channel/client_channel_plugin.c", "src/core/ext/client_channel/client_channel_plugin.c",
"src/core/ext/client_channel/connector.c", "src/core/ext/client_channel/connector.c",
"src/core/ext/client_channel/default_initial_connect_string.c",
"src/core/ext/client_channel/http_connect_handshaker.c", "src/core/ext/client_channel/http_connect_handshaker.c",
"src/core/ext/client_channel/http_proxy.c", "src/core/ext/client_channel/http_proxy.c",
"src/core/ext/client_channel/initial_connect_string.c",
"src/core/ext/client_channel/lb_policy.c", "src/core/ext/client_channel/lb_policy.c",
"src/core/ext/client_channel/lb_policy_factory.c", "src/core/ext/client_channel/lb_policy_factory.c",
"src/core/ext/client_channel/lb_policy_registry.c", "src/core/ext/client_channel/lb_policy_registry.c",
@ -692,6 +701,7 @@ grpc_cc_library(
"src/core/ext/client_channel/resolver.c", "src/core/ext/client_channel/resolver.c",
"src/core/ext/client_channel/resolver_factory.c", "src/core/ext/client_channel/resolver_factory.c",
"src/core/ext/client_channel/resolver_registry.c", "src/core/ext/client_channel/resolver_registry.c",
"src/core/ext/client_channel/retry_throttle.c",
"src/core/ext/client_channel/subchannel.c", "src/core/ext/client_channel/subchannel.c",
"src/core/ext/client_channel/subchannel_index.c", "src/core/ext/client_channel/subchannel_index.c",
"src/core/ext/client_channel/uri_parser.c", "src/core/ext/client_channel/uri_parser.c",
@ -702,7 +712,6 @@ grpc_cc_library(
"src/core/ext/client_channel/connector.h", "src/core/ext/client_channel/connector.h",
"src/core/ext/client_channel/http_connect_handshaker.h", "src/core/ext/client_channel/http_connect_handshaker.h",
"src/core/ext/client_channel/http_proxy.h", "src/core/ext/client_channel/http_proxy.h",
"src/core/ext/client_channel/initial_connect_string.h",
"src/core/ext/client_channel/lb_policy.h", "src/core/ext/client_channel/lb_policy.h",
"src/core/ext/client_channel/lb_policy_factory.h", "src/core/ext/client_channel/lb_policy_factory.h",
"src/core/ext/client_channel/lb_policy_registry.h", "src/core/ext/client_channel/lb_policy_registry.h",
@ -712,6 +721,7 @@ grpc_cc_library(
"src/core/ext/client_channel/resolver.h", "src/core/ext/client_channel/resolver.h",
"src/core/ext/client_channel/resolver_factory.h", "src/core/ext/client_channel/resolver_factory.h",
"src/core/ext/client_channel/resolver_registry.h", "src/core/ext/client_channel/resolver_registry.h",
"src/core/ext/client_channel/retry_throttle.h",
"src/core/ext/client_channel/subchannel.h", "src/core/ext/client_channel/subchannel.h",
"src/core/ext/client_channel/subchannel_index.h", "src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.h", "src/core/ext/client_channel/uri_parser.h",
@ -1132,6 +1142,7 @@ grpc_cc_library(
"src/cpp/common/rpc_method.cc", "src/cpp/common/rpc_method.cc",
"src/cpp/common/version_cc.cc", "src/cpp/common/version_cc.cc",
"src/cpp/server/async_generic_service.cc", "src/cpp/server/async_generic_service.cc",
"src/cpp/server/channel_argument_option.cc",
"src/cpp/server/create_default_thread_pool.cc", "src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.cc",
"src/cpp/server/health/default_health_check_service.cc", "src/cpp/server/health/default_health_check_service.cc",
@ -1173,6 +1184,7 @@ grpc_cc_library(
"include/grpc++/grpc++.h", "include/grpc++/grpc++.h",
"include/grpc++/health_check_service_interface.h", "include/grpc++/health_check_service_interface.h",
"include/grpc++/impl/call.h", "include/grpc++/impl/call.h",
"include/grpc++/impl/channel_argument_option.h",
"include/grpc++/impl/client_unary_call.h", "include/grpc++/impl/client_unary_call.h",
"include/grpc++/impl/codegen/core_codegen.h", "include/grpc++/impl/codegen/core_codegen.h",
"include/grpc++/impl/grpc_library.h", "include/grpc++/impl/grpc_library.h",

@ -332,6 +332,7 @@ add_dependencies(buildtests_c alarm_test)
add_dependencies(buildtests_c algorithm_test) add_dependencies(buildtests_c algorithm_test)
add_dependencies(buildtests_c alloc_test) add_dependencies(buildtests_c alloc_test)
add_dependencies(buildtests_c alpn_test) add_dependencies(buildtests_c alpn_test)
add_dependencies(buildtests_c arena_test)
add_dependencies(buildtests_c bad_server_response_test) add_dependencies(buildtests_c bad_server_response_test)
add_dependencies(buildtests_c bdp_estimator_test) add_dependencies(buildtests_c bdp_estimator_test)
add_dependencies(buildtests_c bin_decoder_test) add_dependencies(buildtests_c bin_decoder_test)
@ -456,7 +457,6 @@ add_dependencies(buildtests_c secure_endpoint_test)
add_dependencies(buildtests_c sequential_connectivity_test) add_dependencies(buildtests_c sequential_connectivity_test)
add_dependencies(buildtests_c server_chttp2_test) add_dependencies(buildtests_c server_chttp2_test)
add_dependencies(buildtests_c server_test) add_dependencies(buildtests_c server_test)
add_dependencies(buildtests_c set_initial_connect_string_test)
add_dependencies(buildtests_c slice_buffer_test) add_dependencies(buildtests_c slice_buffer_test)
add_dependencies(buildtests_c slice_string_helpers_test) add_dependencies(buildtests_c slice_string_helpers_test)
add_dependencies(buildtests_c slice_test) add_dependencies(buildtests_c slice_test)
@ -574,12 +574,18 @@ add_dependencies(buildtests_cxx alarm_cpp_test)
add_dependencies(buildtests_cxx async_end2end_test) add_dependencies(buildtests_cxx async_end2end_test)
add_dependencies(buildtests_cxx auth_property_iterator_test) add_dependencies(buildtests_cxx auth_property_iterator_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_arena)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_call_create) add_dependencies(buildtests_cxx bm_call_create)
endif() endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_chttp2_hpack) add_dependencies(buildtests_cxx bm_chttp2_hpack)
endif() endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_chttp2_transport)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bm_closure) add_dependencies(buildtests_cxx bm_closure)
endif() endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -693,6 +699,8 @@ add_library(gpr
src/core/lib/profiling/basic_timers.c src/core/lib/profiling/basic_timers.c
src/core/lib/profiling/stap_timers.c src/core/lib/profiling/stap_timers.c
src/core/lib/support/alloc.c src/core/lib/support/alloc.c
src/core/lib/support/arena.c
src/core/lib/support/atm.c
src/core/lib/support/avl.c src/core/lib/support/avl.c
src/core/lib/support/backoff.c src/core/lib/support/backoff.c
src/core/lib/support/cmdline.c src/core/lib/support/cmdline.c
@ -905,6 +913,7 @@ add_library(grpc
src/core/lib/iomgr/resolve_address_windows.c src/core/lib/iomgr/resolve_address_windows.c
src/core/lib/iomgr/resource_quota.c src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_factory_posix.c
src/core/lib/iomgr/socket_mutator.c src/core/lib/iomgr/socket_mutator.c
src/core/lib/iomgr/socket_utils_common_posix.c src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c src/core/lib/iomgr/socket_utils_linux.c
@ -917,6 +926,9 @@ add_library(grpc
src/core/lib/iomgr/tcp_client_windows.c src/core/lib/iomgr/tcp_client_windows.c
src/core/lib/iomgr/tcp_posix.c src/core/lib/iomgr/tcp_posix.c
src/core/lib/iomgr/tcp_server_posix.c src/core/lib/iomgr/tcp_server_posix.c
src/core/lib/iomgr/tcp_server_utils_posix_common.c
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
src/core/lib/iomgr/tcp_server_uv.c src/core/lib/iomgr/tcp_server_uv.c
src/core/lib/iomgr/tcp_server_windows.c src/core/lib/iomgr/tcp_server_windows.c
src/core/lib/iomgr/tcp_uv.c src/core/lib/iomgr/tcp_uv.c
@ -957,6 +969,7 @@ add_library(grpc
src/core/lib/surface/channel_ping.c src/core/lib/surface/channel_ping.c
src/core/lib/surface/channel_stack_type.c src/core/lib/surface/channel_stack_type.c
src/core/lib/surface/completion_queue.c src/core/lib/surface/completion_queue.c
src/core/lib/surface/completion_queue_factory.c
src/core/lib/surface/event_string.c src/core/lib/surface/event_string.c
src/core/lib/surface/lame_client.c src/core/lib/surface/lame_client.c
src/core/lib/surface/metadata_array.c src/core/lib/surface/metadata_array.c
@ -1033,10 +1046,8 @@ add_library(grpc
src/core/ext/client_channel/client_channel_factory.c src/core/ext/client_channel/client_channel_factory.c
src/core/ext/client_channel/client_channel_plugin.c src/core/ext/client_channel/client_channel_plugin.c
src/core/ext/client_channel/connector.c src/core/ext/client_channel/connector.c
src/core/ext/client_channel/default_initial_connect_string.c
src/core/ext/client_channel/http_connect_handshaker.c src/core/ext/client_channel/http_connect_handshaker.c
src/core/ext/client_channel/http_proxy.c src/core/ext/client_channel/http_proxy.c
src/core/ext/client_channel/initial_connect_string.c
src/core/ext/client_channel/lb_policy.c src/core/ext/client_channel/lb_policy.c
src/core/ext/client_channel/lb_policy_factory.c src/core/ext/client_channel/lb_policy_factory.c
src/core/ext/client_channel/lb_policy_registry.c src/core/ext/client_channel/lb_policy_registry.c
@ -1046,6 +1057,7 @@ add_library(grpc
src/core/ext/client_channel/resolver.c src/core/ext/client_channel/resolver.c
src/core/ext/client_channel/resolver_factory.c src/core/ext/client_channel/resolver_factory.c
src/core/ext/client_channel/resolver_registry.c src/core/ext/client_channel/resolver_registry.c
src/core/ext/client_channel/retry_throttle.c
src/core/ext/client_channel/subchannel.c src/core/ext/client_channel/subchannel.c
src/core/ext/client_channel/subchannel_index.c src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.c src/core/ext/client_channel/uri_parser.c
@ -1214,6 +1226,7 @@ add_library(grpc_cronet
src/core/lib/iomgr/resolve_address_windows.c src/core/lib/iomgr/resolve_address_windows.c
src/core/lib/iomgr/resource_quota.c src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_factory_posix.c
src/core/lib/iomgr/socket_mutator.c src/core/lib/iomgr/socket_mutator.c
src/core/lib/iomgr/socket_utils_common_posix.c src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c src/core/lib/iomgr/socket_utils_linux.c
@ -1226,6 +1239,9 @@ add_library(grpc_cronet
src/core/lib/iomgr/tcp_client_windows.c src/core/lib/iomgr/tcp_client_windows.c
src/core/lib/iomgr/tcp_posix.c src/core/lib/iomgr/tcp_posix.c
src/core/lib/iomgr/tcp_server_posix.c src/core/lib/iomgr/tcp_server_posix.c
src/core/lib/iomgr/tcp_server_utils_posix_common.c
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
src/core/lib/iomgr/tcp_server_uv.c src/core/lib/iomgr/tcp_server_uv.c
src/core/lib/iomgr/tcp_server_windows.c src/core/lib/iomgr/tcp_server_windows.c
src/core/lib/iomgr/tcp_uv.c src/core/lib/iomgr/tcp_uv.c
@ -1266,6 +1282,7 @@ add_library(grpc_cronet
src/core/lib/surface/channel_ping.c src/core/lib/surface/channel_ping.c
src/core/lib/surface/channel_stack_type.c src/core/lib/surface/channel_stack_type.c
src/core/lib/surface/completion_queue.c src/core/lib/surface/completion_queue.c
src/core/lib/surface/completion_queue_factory.c
src/core/lib/surface/event_string.c src/core/lib/surface/event_string.c
src/core/lib/surface/lame_client.c src/core/lib/surface/lame_client.c
src/core/lib/surface/metadata_array.c src/core/lib/surface/metadata_array.c
@ -1315,10 +1332,8 @@ add_library(grpc_cronet
src/core/ext/client_channel/client_channel_factory.c src/core/ext/client_channel/client_channel_factory.c
src/core/ext/client_channel/client_channel_plugin.c src/core/ext/client_channel/client_channel_plugin.c
src/core/ext/client_channel/connector.c src/core/ext/client_channel/connector.c
src/core/ext/client_channel/default_initial_connect_string.c
src/core/ext/client_channel/http_connect_handshaker.c src/core/ext/client_channel/http_connect_handshaker.c
src/core/ext/client_channel/http_proxy.c src/core/ext/client_channel/http_proxy.c
src/core/ext/client_channel/initial_connect_string.c
src/core/ext/client_channel/lb_policy.c src/core/ext/client_channel/lb_policy.c
src/core/ext/client_channel/lb_policy_factory.c src/core/ext/client_channel/lb_policy_factory.c
src/core/ext/client_channel/lb_policy_registry.c src/core/ext/client_channel/lb_policy_registry.c
@ -1328,6 +1343,7 @@ add_library(grpc_cronet
src/core/ext/client_channel/resolver.c src/core/ext/client_channel/resolver.c
src/core/ext/client_channel/resolver_factory.c src/core/ext/client_channel/resolver_factory.c
src/core/ext/client_channel/resolver_registry.c src/core/ext/client_channel/resolver_registry.c
src/core/ext/client_channel/retry_throttle.c
src/core/ext/client_channel/subchannel.c src/core/ext/client_channel/subchannel.c
src/core/ext/client_channel/subchannel_index.c src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.c src/core/ext/client_channel/uri_parser.c
@ -1514,6 +1530,7 @@ add_library(grpc_test_util
src/core/lib/iomgr/resolve_address_windows.c src/core/lib/iomgr/resolve_address_windows.c
src/core/lib/iomgr/resource_quota.c src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_factory_posix.c
src/core/lib/iomgr/socket_mutator.c src/core/lib/iomgr/socket_mutator.c
src/core/lib/iomgr/socket_utils_common_posix.c src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c src/core/lib/iomgr/socket_utils_linux.c
@ -1526,6 +1543,9 @@ add_library(grpc_test_util
src/core/lib/iomgr/tcp_client_windows.c src/core/lib/iomgr/tcp_client_windows.c
src/core/lib/iomgr/tcp_posix.c src/core/lib/iomgr/tcp_posix.c
src/core/lib/iomgr/tcp_server_posix.c src/core/lib/iomgr/tcp_server_posix.c
src/core/lib/iomgr/tcp_server_utils_posix_common.c
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
src/core/lib/iomgr/tcp_server_uv.c src/core/lib/iomgr/tcp_server_uv.c
src/core/lib/iomgr/tcp_server_windows.c src/core/lib/iomgr/tcp_server_windows.c
src/core/lib/iomgr/tcp_uv.c src/core/lib/iomgr/tcp_uv.c
@ -1566,6 +1586,7 @@ add_library(grpc_test_util
src/core/lib/surface/channel_ping.c src/core/lib/surface/channel_ping.c
src/core/lib/surface/channel_stack_type.c src/core/lib/surface/channel_stack_type.c
src/core/lib/surface/completion_queue.c src/core/lib/surface/completion_queue.c
src/core/lib/surface/completion_queue_factory.c
src/core/lib/surface/event_string.c src/core/lib/surface/event_string.c
src/core/lib/surface/lame_client.c src/core/lib/surface/lame_client.c
src/core/lib/surface/metadata_array.c src/core/lib/surface/metadata_array.c
@ -1760,6 +1781,7 @@ add_library(grpc_unsecure
src/core/lib/iomgr/resolve_address_windows.c src/core/lib/iomgr/resolve_address_windows.c
src/core/lib/iomgr/resource_quota.c src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_factory_posix.c
src/core/lib/iomgr/socket_mutator.c src/core/lib/iomgr/socket_mutator.c
src/core/lib/iomgr/socket_utils_common_posix.c src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c src/core/lib/iomgr/socket_utils_linux.c
@ -1772,6 +1794,9 @@ add_library(grpc_unsecure
src/core/lib/iomgr/tcp_client_windows.c src/core/lib/iomgr/tcp_client_windows.c
src/core/lib/iomgr/tcp_posix.c src/core/lib/iomgr/tcp_posix.c
src/core/lib/iomgr/tcp_server_posix.c src/core/lib/iomgr/tcp_server_posix.c
src/core/lib/iomgr/tcp_server_utils_posix_common.c
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
src/core/lib/iomgr/tcp_server_uv.c src/core/lib/iomgr/tcp_server_uv.c
src/core/lib/iomgr/tcp_server_windows.c src/core/lib/iomgr/tcp_server_windows.c
src/core/lib/iomgr/tcp_uv.c src/core/lib/iomgr/tcp_uv.c
@ -1812,6 +1837,7 @@ add_library(grpc_unsecure
src/core/lib/surface/channel_ping.c src/core/lib/surface/channel_ping.c
src/core/lib/surface/channel_stack_type.c src/core/lib/surface/channel_stack_type.c
src/core/lib/surface/completion_queue.c src/core/lib/surface/completion_queue.c
src/core/lib/surface/completion_queue_factory.c
src/core/lib/surface/event_string.c src/core/lib/surface/event_string.c
src/core/lib/surface/lame_client.c src/core/lib/surface/lame_client.c
src/core/lib/surface/metadata_array.c src/core/lib/surface/metadata_array.c
@ -1863,10 +1889,8 @@ add_library(grpc_unsecure
src/core/ext/client_channel/client_channel_factory.c src/core/ext/client_channel/client_channel_factory.c
src/core/ext/client_channel/client_channel_plugin.c src/core/ext/client_channel/client_channel_plugin.c
src/core/ext/client_channel/connector.c src/core/ext/client_channel/connector.c
src/core/ext/client_channel/default_initial_connect_string.c
src/core/ext/client_channel/http_connect_handshaker.c src/core/ext/client_channel/http_connect_handshaker.c
src/core/ext/client_channel/http_proxy.c src/core/ext/client_channel/http_proxy.c
src/core/ext/client_channel/initial_connect_string.c
src/core/ext/client_channel/lb_policy.c src/core/ext/client_channel/lb_policy.c
src/core/ext/client_channel/lb_policy_factory.c src/core/ext/client_channel/lb_policy_factory.c
src/core/ext/client_channel/lb_policy_registry.c src/core/ext/client_channel/lb_policy_registry.c
@ -1876,6 +1900,7 @@ add_library(grpc_unsecure
src/core/ext/client_channel/resolver.c src/core/ext/client_channel/resolver.c
src/core/ext/client_channel/resolver_factory.c src/core/ext/client_channel/resolver_factory.c
src/core/ext/client_channel/resolver_registry.c src/core/ext/client_channel/resolver_registry.c
src/core/ext/client_channel/retry_throttle.c
src/core/ext/client_channel/subchannel.c src/core/ext/client_channel/subchannel.c
src/core/ext/client_channel/subchannel_index.c src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.c src/core/ext/client_channel/uri_parser.c
@ -2367,6 +2392,7 @@ add_library(grpc++_cronet
src/core/lib/iomgr/resolve_address_windows.c src/core/lib/iomgr/resolve_address_windows.c
src/core/lib/iomgr/resource_quota.c src/core/lib/iomgr/resource_quota.c
src/core/lib/iomgr/sockaddr_utils.c src/core/lib/iomgr/sockaddr_utils.c
src/core/lib/iomgr/socket_factory_posix.c
src/core/lib/iomgr/socket_mutator.c src/core/lib/iomgr/socket_mutator.c
src/core/lib/iomgr/socket_utils_common_posix.c src/core/lib/iomgr/socket_utils_common_posix.c
src/core/lib/iomgr/socket_utils_linux.c src/core/lib/iomgr/socket_utils_linux.c
@ -2379,6 +2405,9 @@ add_library(grpc++_cronet
src/core/lib/iomgr/tcp_client_windows.c src/core/lib/iomgr/tcp_client_windows.c
src/core/lib/iomgr/tcp_posix.c src/core/lib/iomgr/tcp_posix.c
src/core/lib/iomgr/tcp_server_posix.c src/core/lib/iomgr/tcp_server_posix.c
src/core/lib/iomgr/tcp_server_utils_posix_common.c
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
src/core/lib/iomgr/tcp_server_uv.c src/core/lib/iomgr/tcp_server_uv.c
src/core/lib/iomgr/tcp_server_windows.c src/core/lib/iomgr/tcp_server_windows.c
src/core/lib/iomgr/tcp_uv.c src/core/lib/iomgr/tcp_uv.c
@ -2419,6 +2448,7 @@ add_library(grpc++_cronet
src/core/lib/surface/channel_ping.c src/core/lib/surface/channel_ping.c
src/core/lib/surface/channel_stack_type.c src/core/lib/surface/channel_stack_type.c
src/core/lib/surface/completion_queue.c src/core/lib/surface/completion_queue.c
src/core/lib/surface/completion_queue_factory.c
src/core/lib/surface/event_string.c src/core/lib/surface/event_string.c
src/core/lib/surface/lame_client.c src/core/lib/surface/lame_client.c
src/core/lib/surface/metadata_array.c src/core/lib/surface/metadata_array.c
@ -2444,10 +2474,8 @@ add_library(grpc++_cronet
src/core/ext/client_channel/client_channel_factory.c src/core/ext/client_channel/client_channel_factory.c
src/core/ext/client_channel/client_channel_plugin.c src/core/ext/client_channel/client_channel_plugin.c
src/core/ext/client_channel/connector.c src/core/ext/client_channel/connector.c
src/core/ext/client_channel/default_initial_connect_string.c
src/core/ext/client_channel/http_connect_handshaker.c src/core/ext/client_channel/http_connect_handshaker.c
src/core/ext/client_channel/http_proxy.c src/core/ext/client_channel/http_proxy.c
src/core/ext/client_channel/initial_connect_string.c
src/core/ext/client_channel/lb_policy.c src/core/ext/client_channel/lb_policy.c
src/core/ext/client_channel/lb_policy_factory.c src/core/ext/client_channel/lb_policy_factory.c
src/core/ext/client_channel/lb_policy_registry.c src/core/ext/client_channel/lb_policy_registry.c
@ -2457,6 +2485,7 @@ add_library(grpc++_cronet
src/core/ext/client_channel/resolver.c src/core/ext/client_channel/resolver.c
src/core/ext/client_channel/resolver_factory.c src/core/ext/client_channel/resolver_factory.c
src/core/ext/client_channel/resolver_registry.c src/core/ext/client_channel/resolver_registry.c
src/core/ext/client_channel/retry_throttle.c
src/core/ext/client_channel/subchannel.c src/core/ext/client_channel/subchannel.c
src/core/ext/client_channel/subchannel_index.c src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.c src/core/ext/client_channel/uri_parser.c
@ -4115,6 +4144,31 @@ target_link_libraries(alpn_test
endif (gRPC_BUILD_TESTS) endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
add_executable(arena_test
test/core/support/arena_test.c
)
target_include_directories(arena_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
)
target_link_libraries(arena_test
${_gRPC_ALLTARGETS_LIBRARIES}
gpr_test_util
gpr
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(bad_server_response_test add_executable(bad_server_response_test
test/core/end2end/bad_server_response_test.c test/core/end2end/bad_server_response_test.c
) )
@ -6833,34 +6887,6 @@ target_link_libraries(server_test
endif (gRPC_BUILD_TESTS) endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
add_executable(set_initial_connect_string_test
test/core/client_channel/set_initial_connect_string_test.c
)
target_include_directories(set_initial_connect_string_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
)
target_link_libraries(set_initial_connect_string_test
${_gRPC_ALLTARGETS_LIBRARIES}
test_tcp_server
grpc_test_util
grpc
gpr_test_util
gpr
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(slice_buffer_test add_executable(slice_buffer_test
test/core/slice/slice_buffer_test.c test/core/slice/slice_buffer_test.c
) )
@ -7629,6 +7655,45 @@ endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_arena
test/cpp/microbenchmarks/bm_arena.cc
third_party/googletest/src/gtest-all.cc
)
target_include_directories(bm_arena
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
PRIVATE third_party/googletest/include
PRIVATE third_party/googletest
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(bm_arena
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_benchmark
benchmark
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_call_create add_executable(bm_call_create
test/cpp/microbenchmarks/bm_call_create.cc test/cpp/microbenchmarks/bm_call_create.cc
third_party/googletest/src/gtest-all.cc third_party/googletest/src/gtest-all.cc
@ -7707,6 +7772,45 @@ endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_chttp2_transport
test/cpp/microbenchmarks/bm_chttp2_transport.cc
third_party/googletest/src/gtest-all.cc
)
target_include_directories(bm_chttp2_transport
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
PRIVATE third_party/googletest/include
PRIVATE third_party/googletest
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(bm_chttp2_transport
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_benchmark
benchmark
grpc++_test_util
grpc_test_util
grpc++
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(bm_closure add_executable(bm_closure
test/cpp/microbenchmarks/bm_closure.cc test/cpp/microbenchmarks/bm_closure.cc
third_party/googletest/src/gtest-all.cc third_party/googletest/src/gtest-all.cc

@ -1,4 +1,4 @@
#If you are in a hurry # If you are in a hurry
For language-specific installation instructions for gRPC runtime, please For language-specific installation instructions for gRPC runtime, please
refer to these documents refer to these documents
@ -14,15 +14,15 @@ refer to these documents
* [Ruby](src/ruby): `gem install grpc` * [Ruby](src/ruby): `gem install grpc`
#Pre-requisites # Pre-requisites
##Linux ## Linux
```sh ```sh
$ [sudo] apt-get install build-essential autoconf libtool $ [sudo] apt-get install build-essential autoconf libtool
``` ```
##Mac OSX ## Mac OSX
For a Mac system, git is not available by default. You will first need to For a Mac system, git is not available by default. You will first need to
install Xcode from the Mac AppStore and then run the following command from a install Xcode from the Mac AppStore and then run the following command from a
@ -32,7 +32,7 @@ terminal:
$ [sudo] xcode-select --install $ [sudo] xcode-select --install
``` ```
##Protoc ## Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf), By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
you will need the `protoc` compiler to generate stub server and client code. you will need the `protoc` compiler to generate stub server and client code.
@ -43,7 +43,7 @@ repository recursively and it detects that you don't already have it
installed. installed.
#Build from Source # Build from Source
For developers who are interested to contribute, here is how to compile the For developers who are interested to contribute, here is how to compile the
gRPC C Core library. gRPC C Core library.
@ -56,16 +56,16 @@ gRPC C Core library.
$ [sudo] make install $ [sudo] make install
``` ```
##Windows ## Windows
There are several ways to build under Windows, of varying complexity depending There are several ways to build under Windows, of varying complexity depending
on experience with the tools involved. on experience with the tools involved.
###Pre-generated Visual Studio solution ### Pre-generated Visual Studio solution
The pre-generated VS projects & solution are checked into the repository under the [vsprojects](/vsprojects) directory. The pre-generated VS projects & solution are checked into the repository under the [vsprojects](/vsprojects) directory.
###Building using CMake (with BoringSSL) ### Building using CMake (with BoringSSL)
- Install [CMake](https://cmake.org/download/). - Install [CMake](https://cmake.org/download/).
- Install [Active State Perl](http://www.activestate.com/activeperl/) (`choco install activeperl`) - Install [Active State Perl](http://www.activestate.com/activeperl/) (`choco install activeperl`)
- Install [Ninja](https://ninja-build.org/) (`choco install ninja`) - Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
@ -81,14 +81,14 @@ The pre-generated VS projects & solution are checked into the repository under t
``` ```
NOTE: Currently you can only use Ninja to build using cmake on Windows (because of the boringssl dependency). NOTE: Currently you can only use Ninja to build using cmake on Windows (because of the boringssl dependency).
###msys2 (with mingw) ### msys2 (with mingw)
The Makefile (and source code) should support msys2's mingw32 and mingw64 The Makefile (and source code) should support msys2's mingw32 and mingw64
compilers. Building with msys2's native compiler is also possible, but compilers. Building with msys2's native compiler is also possible, but
difficult. difficult.
This approach requires having [msys2](https://msys2.github.io/) installed. This approach requires having [msys2](https://msys2.github.io/) installed.
``` ```
# Install prerequisites # Install prerequisites
MSYS2$ pacman -S autoconf automake gcc libtool mingw-w64-x86_64-toolchain perl pkg-config zlib MSYS2$ pacman -S autoconf automake gcc libtool mingw-w64-x86_64-toolchain perl pkg-config zlib

@ -189,7 +189,7 @@ CC_ubsan = clang
CXX_ubsan = clang++ CXX_ubsan = clang++
LD_ubsan = clang LD_ubsan = clang
LDXX_ubsan = clang++ LDXX_ubsan = clang++
CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined,unsigned-integer-overflow -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs
LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow
DEFINES_ubsan = NDEBUG DEFINES_ubsan = NDEBUG
@ -906,6 +906,7 @@ algorithm_test: $(BINDIR)/$(CONFIG)/algorithm_test
alloc_test: $(BINDIR)/$(CONFIG)/alloc_test alloc_test: $(BINDIR)/$(CONFIG)/alloc_test
alpn_test: $(BINDIR)/$(CONFIG)/alpn_test alpn_test: $(BINDIR)/$(CONFIG)/alpn_test
api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer
arena_test: $(BINDIR)/$(CONFIG)/arena_test
bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test
bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
@ -1017,7 +1018,6 @@ sequential_connectivity_test: $(BINDIR)/$(CONFIG)/sequential_connectivity_test
server_chttp2_test: $(BINDIR)/$(CONFIG)/server_chttp2_test server_chttp2_test: $(BINDIR)/$(CONFIG)/server_chttp2_test
server_fuzzer: $(BINDIR)/$(CONFIG)/server_fuzzer server_fuzzer: $(BINDIR)/$(CONFIG)/server_fuzzer
server_test: $(BINDIR)/$(CONFIG)/server_test server_test: $(BINDIR)/$(CONFIG)/server_test
set_initial_connect_string_test: $(BINDIR)/$(CONFIG)/set_initial_connect_string_test
slice_buffer_test: $(BINDIR)/$(CONFIG)/slice_buffer_test slice_buffer_test: $(BINDIR)/$(CONFIG)/slice_buffer_test
slice_string_helpers_test: $(BINDIR)/$(CONFIG)/slice_string_helpers_test slice_string_helpers_test: $(BINDIR)/$(CONFIG)/slice_string_helpers_test
slice_test: $(BINDIR)/$(CONFIG)/slice_test slice_test: $(BINDIR)/$(CONFIG)/slice_test
@ -1047,8 +1047,10 @@ wakeup_fd_cv_test: $(BINDIR)/$(CONFIG)/wakeup_fd_cv_test
alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
bm_arena: $(BINDIR)/$(CONFIG)/bm_arena
bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create
bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport
bm_closure: $(BINDIR)/$(CONFIG)/bm_closure bm_closure: $(BINDIR)/$(CONFIG)/bm_closure
bm_cq: $(BINDIR)/$(CONFIG)/bm_cq bm_cq: $(BINDIR)/$(CONFIG)/bm_cq
bm_error: $(BINDIR)/$(CONFIG)/bm_error bm_error: $(BINDIR)/$(CONFIG)/bm_error
@ -1286,6 +1288,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/algorithm_test \ $(BINDIR)/$(CONFIG)/algorithm_test \
$(BINDIR)/$(CONFIG)/alloc_test \ $(BINDIR)/$(CONFIG)/alloc_test \
$(BINDIR)/$(CONFIG)/alpn_test \ $(BINDIR)/$(CONFIG)/alpn_test \
$(BINDIR)/$(CONFIG)/arena_test \
$(BINDIR)/$(CONFIG)/bad_server_response_test \ $(BINDIR)/$(CONFIG)/bad_server_response_test \
$(BINDIR)/$(CONFIG)/bdp_estimator_test \ $(BINDIR)/$(CONFIG)/bdp_estimator_test \
$(BINDIR)/$(CONFIG)/bin_decoder_test \ $(BINDIR)/$(CONFIG)/bin_decoder_test \
@ -1380,7 +1383,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/sequential_connectivity_test \ $(BINDIR)/$(CONFIG)/sequential_connectivity_test \
$(BINDIR)/$(CONFIG)/server_chttp2_test \ $(BINDIR)/$(CONFIG)/server_chttp2_test \
$(BINDIR)/$(CONFIG)/server_test \ $(BINDIR)/$(CONFIG)/server_test \
$(BINDIR)/$(CONFIG)/set_initial_connect_string_test \
$(BINDIR)/$(CONFIG)/slice_buffer_test \ $(BINDIR)/$(CONFIG)/slice_buffer_test \
$(BINDIR)/$(CONFIG)/slice_string_helpers_test \ $(BINDIR)/$(CONFIG)/slice_string_helpers_test \
$(BINDIR)/$(CONFIG)/slice_test \ $(BINDIR)/$(CONFIG)/slice_test \
@ -1469,8 +1471,10 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/alarm_cpp_test \ $(BINDIR)/$(CONFIG)/alarm_cpp_test \
$(BINDIR)/$(CONFIG)/async_end2end_test \ $(BINDIR)/$(CONFIG)/async_end2end_test \
$(BINDIR)/$(CONFIG)/auth_property_iterator_test \ $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
$(BINDIR)/$(CONFIG)/bm_arena \
$(BINDIR)/$(CONFIG)/bm_call_create \ $(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
$(BINDIR)/$(CONFIG)/bm_chttp2_transport \
$(BINDIR)/$(CONFIG)/bm_closure \ $(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \ $(BINDIR)/$(CONFIG)/bm_cq \
$(BINDIR)/$(CONFIG)/bm_error \ $(BINDIR)/$(CONFIG)/bm_error \
@ -1585,8 +1589,10 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/alarm_cpp_test \ $(BINDIR)/$(CONFIG)/alarm_cpp_test \
$(BINDIR)/$(CONFIG)/async_end2end_test \ $(BINDIR)/$(CONFIG)/async_end2end_test \
$(BINDIR)/$(CONFIG)/auth_property_iterator_test \ $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
$(BINDIR)/$(CONFIG)/bm_arena \
$(BINDIR)/$(CONFIG)/bm_call_create \ $(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
$(BINDIR)/$(CONFIG)/bm_chttp2_transport \
$(BINDIR)/$(CONFIG)/bm_closure \ $(BINDIR)/$(CONFIG)/bm_closure \
$(BINDIR)/$(CONFIG)/bm_cq \ $(BINDIR)/$(CONFIG)/bm_cq \
$(BINDIR)/$(CONFIG)/bm_error \ $(BINDIR)/$(CONFIG)/bm_error \
@ -1666,6 +1672,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/alloc_test || ( echo test alloc_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/alloc_test || ( echo test alloc_test failed ; exit 1 )
$(E) "[RUN] Testing alpn_test" $(E) "[RUN] Testing alpn_test"
$(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 )
$(E) "[RUN] Testing arena_test"
$(Q) $(BINDIR)/$(CONFIG)/arena_test || ( echo test arena_test failed ; exit 1 )
$(E) "[RUN] Testing bad_server_response_test" $(E) "[RUN] Testing bad_server_response_test"
$(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 )
$(E) "[RUN] Testing bdp_estimator_test" $(E) "[RUN] Testing bdp_estimator_test"
@ -1838,8 +1846,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/server_chttp2_test || ( echo test server_chttp2_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/server_chttp2_test || ( echo test server_chttp2_test failed ; exit 1 )
$(E) "[RUN] Testing server_test" $(E) "[RUN] Testing server_test"
$(Q) $(BINDIR)/$(CONFIG)/server_test || ( echo test server_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/server_test || ( echo test server_test failed ; exit 1 )
$(E) "[RUN] Testing set_initial_connect_string_test"
$(Q) $(BINDIR)/$(CONFIG)/set_initial_connect_string_test || ( echo test set_initial_connect_string_test failed ; exit 1 )
$(E) "[RUN] Testing slice_buffer_test" $(E) "[RUN] Testing slice_buffer_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_buffer_test || ( echo test slice_buffer_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/slice_buffer_test || ( echo test slice_buffer_test failed ; exit 1 )
$(E) "[RUN] Testing slice_string_helpers_test" $(E) "[RUN] Testing slice_string_helpers_test"
@ -1926,10 +1932,14 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing auth_property_iterator_test" $(E) "[RUN] Testing auth_property_iterator_test"
$(Q) $(BINDIR)/$(CONFIG)/auth_property_iterator_test || ( echo test auth_property_iterator_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/auth_property_iterator_test || ( echo test auth_property_iterator_test failed ; exit 1 )
$(E) "[RUN] Testing bm_arena"
$(Q) $(BINDIR)/$(CONFIG)/bm_arena || ( echo test bm_arena failed ; exit 1 )
$(E) "[RUN] Testing bm_call_create" $(E) "[RUN] Testing bm_call_create"
$(Q) $(BINDIR)/$(CONFIG)/bm_call_create || ( echo test bm_call_create failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/bm_call_create || ( echo test bm_call_create failed ; exit 1 )
$(E) "[RUN] Testing bm_chttp2_hpack" $(E) "[RUN] Testing bm_chttp2_hpack"
$(Q) $(BINDIR)/$(CONFIG)/bm_chttp2_hpack || ( echo test bm_chttp2_hpack failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/bm_chttp2_hpack || ( echo test bm_chttp2_hpack failed ; exit 1 )
$(E) "[RUN] Testing bm_chttp2_transport"
$(Q) $(BINDIR)/$(CONFIG)/bm_chttp2_transport || ( echo test bm_chttp2_transport failed ; exit 1 )
$(E) "[RUN] Testing bm_closure" $(E) "[RUN] Testing bm_closure"
$(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 )
$(E) "[RUN] Testing bm_cq" $(E) "[RUN] Testing bm_cq"
@ -2599,6 +2609,8 @@ LIBGPR_SRC = \
src/core/lib/profiling/basic_timers.c \ src/core/lib/profiling/basic_timers.c \
src/core/lib/profiling/stap_timers.c \ src/core/lib/profiling/stap_timers.c \
src/core/lib/support/alloc.c \ src/core/lib/support/alloc.c \
src/core/lib/support/arena.c \
src/core/lib/support/atm.c \
src/core/lib/support/avl.c \ src/core/lib/support/avl.c \
src/core/lib/support/backoff.c \ src/core/lib/support/backoff.c \
src/core/lib/support/cmdline.c \ src/core/lib/support/cmdline.c \
@ -2792,6 +2804,7 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -2804,6 +2817,9 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -2844,6 +2860,7 @@ LIBGRPC_SRC = \
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -2920,10 +2937,8 @@ LIBGRPC_SRC = \
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
src/core/ext/client_channel/client_channel_plugin.c \ src/core/ext/client_channel/client_channel_plugin.c \
src/core/ext/client_channel/connector.c \ src/core/ext/client_channel/connector.c \
src/core/ext/client_channel/default_initial_connect_string.c \
src/core/ext/client_channel/http_connect_handshaker.c \ src/core/ext/client_channel/http_connect_handshaker.c \
src/core/ext/client_channel/http_proxy.c \ src/core/ext/client_channel/http_proxy.c \
src/core/ext/client_channel/initial_connect_string.c \
src/core/ext/client_channel/lb_policy.c \ src/core/ext/client_channel/lb_policy.c \
src/core/ext/client_channel/lb_policy_factory.c \ src/core/ext/client_channel/lb_policy_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \ src/core/ext/client_channel/lb_policy_registry.c \
@ -2933,6 +2948,7 @@ LIBGRPC_SRC = \
src/core/ext/client_channel/resolver.c \ src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.c \ src/core/ext/client_channel/resolver_factory.c \
src/core/ext/client_channel/resolver_registry.c \ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/retry_throttle.c \
src/core/ext/client_channel/subchannel.c \ src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \ src/core/ext/client_channel/uri_parser.c \
@ -3104,6 +3120,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -3116,6 +3133,9 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -3156,6 +3176,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -3205,10 +3226,8 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
src/core/ext/client_channel/client_channel_plugin.c \ src/core/ext/client_channel/client_channel_plugin.c \
src/core/ext/client_channel/connector.c \ src/core/ext/client_channel/connector.c \
src/core/ext/client_channel/default_initial_connect_string.c \
src/core/ext/client_channel/http_connect_handshaker.c \ src/core/ext/client_channel/http_connect_handshaker.c \
src/core/ext/client_channel/http_proxy.c \ src/core/ext/client_channel/http_proxy.c \
src/core/ext/client_channel/initial_connect_string.c \
src/core/ext/client_channel/lb_policy.c \ src/core/ext/client_channel/lb_policy.c \
src/core/ext/client_channel/lb_policy_factory.c \ src/core/ext/client_channel/lb_policy_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \ src/core/ext/client_channel/lb_policy_registry.c \
@ -3218,6 +3237,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/client_channel/resolver.c \ src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.c \ src/core/ext/client_channel/resolver_factory.c \
src/core/ext/client_channel/resolver_registry.c \ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/retry_throttle.c \
src/core/ext/client_channel/subchannel.c \ src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \ src/core/ext/client_channel/uri_parser.c \
@ -3407,6 +3427,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -3419,6 +3440,9 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -3459,6 +3483,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -3633,6 +3658,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -3645,6 +3671,9 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -3685,6 +3714,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -3736,10 +3766,8 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
src/core/ext/client_channel/client_channel_plugin.c \ src/core/ext/client_channel/client_channel_plugin.c \
src/core/ext/client_channel/connector.c \ src/core/ext/client_channel/connector.c \
src/core/ext/client_channel/default_initial_connect_string.c \
src/core/ext/client_channel/http_connect_handshaker.c \ src/core/ext/client_channel/http_connect_handshaker.c \
src/core/ext/client_channel/http_proxy.c \ src/core/ext/client_channel/http_proxy.c \
src/core/ext/client_channel/initial_connect_string.c \
src/core/ext/client_channel/lb_policy.c \ src/core/ext/client_channel/lb_policy.c \
src/core/ext/client_channel/lb_policy_factory.c \ src/core/ext/client_channel/lb_policy_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \ src/core/ext/client_channel/lb_policy_registry.c \
@ -3749,6 +3777,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/client_channel/resolver.c \ src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.c \ src/core/ext/client_channel/resolver_factory.c \
src/core/ext/client_channel/resolver_registry.c \ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/retry_throttle.c \
src/core/ext/client_channel/subchannel.c \ src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \ src/core/ext/client_channel/uri_parser.c \
@ -4242,6 +4271,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -4254,6 +4284,9 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -4294,6 +4327,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -4319,10 +4353,8 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
src/core/ext/client_channel/client_channel_plugin.c \ src/core/ext/client_channel/client_channel_plugin.c \
src/core/ext/client_channel/connector.c \ src/core/ext/client_channel/connector.c \
src/core/ext/client_channel/default_initial_connect_string.c \
src/core/ext/client_channel/http_connect_handshaker.c \ src/core/ext/client_channel/http_connect_handshaker.c \
src/core/ext/client_channel/http_proxy.c \ src/core/ext/client_channel/http_proxy.c \
src/core/ext/client_channel/initial_connect_string.c \
src/core/ext/client_channel/lb_policy.c \ src/core/ext/client_channel/lb_policy.c \
src/core/ext/client_channel/lb_policy_factory.c \ src/core/ext/client_channel/lb_policy_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \ src/core/ext/client_channel/lb_policy_registry.c \
@ -4332,6 +4364,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/client_channel/resolver.c \ src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.c \ src/core/ext/client_channel/resolver_factory.c \
src/core/ext/client_channel/resolver_registry.c \ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/retry_throttle.c \
src/core/ext/client_channel/subchannel.c \ src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \ src/core/ext/client_channel/uri_parser.c \
@ -8099,6 +8132,38 @@ endif
endif endif
ARENA_TEST_SRC = \
test/core/support/arena_test.c \
ARENA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ARENA_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/arena_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/arena_test: $(ARENA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(ARENA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/arena_test
endif
$(OBJDIR)/$(CONFIG)/test/core/support/arena_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_arena_test: $(ARENA_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(ARENA_TEST_OBJS:.o=.dep)
endif
endif
BAD_SERVER_RESPONSE_TEST_SRC = \ BAD_SERVER_RESPONSE_TEST_SRC = \
test/core/end2end/bad_server_response_test.c \ test/core/end2end/bad_server_response_test.c \
@ -11651,38 +11716,6 @@ endif
endif endif
SET_INITIAL_CONNECT_STRING_TEST_SRC = \
test/core/client_channel/set_initial_connect_string_test.c \
SET_INITIAL_CONNECT_STRING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SET_INITIAL_CONNECT_STRING_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/set_initial_connect_string_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/set_initial_connect_string_test: $(SET_INITIAL_CONNECT_STRING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(SET_INITIAL_CONNECT_STRING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/set_initial_connect_string_test
endif
$(OBJDIR)/$(CONFIG)/test/core/client_channel/set_initial_connect_string_test.o: $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_set_initial_connect_string_test: $(SET_INITIAL_CONNECT_STRING_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SET_INITIAL_CONNECT_STRING_TEST_OBJS:.o=.dep)
endif
endif
SLICE_BUFFER_TEST_SRC = \ SLICE_BUFFER_TEST_SRC = \
test/core/slice/slice_buffer_test.c \ test/core/slice/slice_buffer_test.c \
@ -12644,6 +12677,49 @@ endif
endif endif
BM_ARENA_SRC = \
test/cpp/microbenchmarks/bm_arena.cc \
BM_ARENA_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_ARENA_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/bm_arena: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/bm_arena: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/bm_arena: $(PROTOBUF_DEP) $(BM_ARENA_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(BM_ARENA_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_arena
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_arena.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_bm_arena: $(BM_ARENA_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(BM_ARENA_OBJS:.o=.dep)
endif
endif
BM_CALL_CREATE_SRC = \ BM_CALL_CREATE_SRC = \
test/cpp/microbenchmarks/bm_call_create.cc \ test/cpp/microbenchmarks/bm_call_create.cc \
@ -12730,6 +12806,49 @@ endif
endif endif
BM_CHTTP2_TRANSPORT_SRC = \
test/cpp/microbenchmarks/bm_chttp2_transport.cc \
BM_CHTTP2_TRANSPORT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CHTTP2_TRANSPORT_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/bm_chttp2_transport: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/bm_chttp2_transport: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/bm_chttp2_transport: $(PROTOBUF_DEP) $(BM_CHTTP2_TRANSPORT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(BM_CHTTP2_TRANSPORT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_chttp2_transport
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_chttp2_transport.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_bm_chttp2_transport: $(BM_CHTTP2_TRANSPORT_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(BM_CHTTP2_TRANSPORT_OBJS:.o=.dep)
endif
endif
BM_CLOSURE_SRC = \ BM_CLOSURE_SRC = \
test/cpp/microbenchmarks/bm_closure.cc \ test/cpp/microbenchmarks/bm_closure.cc \

@ -7,11 +7,11 @@
Copyright 2015 Google Inc. Copyright 2015 Google Inc.
#Documentation # Documentation
You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively. You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively.
#Installation & Testing # Installation & Testing
See [INSTALL](INSTALL.md) for installation instructions for various platforms. See [INSTALL](INSTALL.md) for installation instructions for various platforms.
@ -19,7 +19,7 @@ See [tools/run_tests](tools/run_tests) for more guidance on how to run various t
See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5712453606309888) for the performance numbers for v1.0.x. See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5712453606309888) for the performance numbers for v1.0.x.
#Repository Structure & Status # Repository Structure & Status
This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core). This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core).
@ -37,14 +37,14 @@ Libraries in different languages may be in different states of development. We a
| Objective-C | [src/objective-c] (src/objective-c) | 1.0 | | Objective-C | [src/objective-c] (src/objective-c) | 1.0 |
<small> <small>
Java source code is in the [grpc-java] (http://github.com/grpc/grpc-java) repository. Java source code is in the [grpc-java](http://github.com/grpc/grpc-java) repository.
Go source code is in the [grpc-go] (http://github.com/grpc/grpc-go) repository. Go source code is in the [grpc-go](http://github.com/grpc/grpc-go) repository.
</small> </small>
See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
repository. repository.
#Overview # Overview
Remote Procedure Calls (RPCs) provide a useful abstraction for building Remote Procedure Calls (RPCs) provide a useful abstraction for building
@ -54,7 +54,7 @@ These libraries enable communication between clients and servers using any
combination of the supported languages. combination of the supported languages.
##Interface ## Interface
Developers using gRPC typically start with the description of an RPC service Developers using gRPC typically start with the description of an RPC service
@ -66,7 +66,7 @@ Interface Definition Language (IDL) for describing both the service interface
and the structure of the payload messages. It is possible to use other and the structure of the payload messages. It is possible to use other
alternatives if desired. alternatives if desired.
###Surface API ### Surface API
Starting from an interface definition in a .proto file, gRPC provides Starting from an interface definition in a .proto file, gRPC provides
Protocol Compiler plugins that generate Client- and Server-side APIs. Protocol Compiler plugins that generate Client- and Server-side APIs.
gRPC users typically call into these APIs on the Client side and implement gRPC users typically call into these APIs on the Client side and implement
@ -94,7 +94,7 @@ the client and the server can send a stream of messages to each other. The strea
messages are delivered in the order they were sent. messages are delivered in the order they were sent.
#Protocol # Protocol
The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between
clients and servers. A concrete embedding over HTTP/2 completes the picture by clients and servers. A concrete embedding over HTTP/2 completes the picture by

@ -12,7 +12,8 @@ load 'tools/distrib/docker_for_windows.rb'
# Add rubocop style checking tasks # Add rubocop style checking tasks
RuboCop::RakeTask.new(:rubocop) do |task| RuboCop::RakeTask.new(:rubocop) do |task|
task.options = ['-c', 'src/ruby/.rubocop.yml'] task.options = ['-c', 'src/ruby/.rubocop.yml']
task.patterns = ['src/ruby/{lib,spec}/**/*.rb'] # add end2end tests to formatter but don't add generated proto _pb.rb's
task.patterns = ['src/ruby/{lib,spec}/**/*.rb', 'src/ruby/end2end/*.rb']
end end
spec = Gem::Specification.load('grpc.gemspec') spec = Gem::Specification.load('grpc.gemspec')

@ -39,11 +39,9 @@
{ {
'variables': { 'variables': {
'runtime%': 'node', 'runtime%': 'node',
# UV integration in C core is disabled by default while bugs are ironed # UV integration in C core is enabled by default. It can be disabled
# out. It can be re-enabled for one build by setting the npm config # by setting this argument to anything else.
# variable grpc_uv to true, and it can be re-enabled permanently by 'grpc_uv%': 'true',
# setting it to true here.
'grpc_uv%': 'false',
# Some Node installations use the system installation of OpenSSL, and on # Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This # some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN. # will let users recompile gRPC to work without ALPN.
@ -544,6 +542,8 @@
'src/core/lib/profiling/basic_timers.c', 'src/core/lib/profiling/basic_timers.c',
'src/core/lib/profiling/stap_timers.c', 'src/core/lib/profiling/stap_timers.c',
'src/core/lib/support/alloc.c', 'src/core/lib/support/alloc.c',
'src/core/lib/support/arena.c',
'src/core/lib/support/atm.c',
'src/core/lib/support/avl.c', 'src/core/lib/support/avl.c',
'src/core/lib/support/backoff.c', 'src/core/lib/support/backoff.c',
'src/core/lib/support/cmdline.c', 'src/core/lib/support/cmdline.c',
@ -655,6 +655,7 @@
'src/core/lib/iomgr/resolve_address_windows.c', 'src/core/lib/iomgr/resolve_address_windows.c',
'src/core/lib/iomgr/resource_quota.c', 'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c', 'src/core/lib/iomgr/sockaddr_utils.c',
'src/core/lib/iomgr/socket_factory_posix.c',
'src/core/lib/iomgr/socket_mutator.c', 'src/core/lib/iomgr/socket_mutator.c',
'src/core/lib/iomgr/socket_utils_common_posix.c', 'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c', 'src/core/lib/iomgr/socket_utils_linux.c',
@ -667,6 +668,9 @@
'src/core/lib/iomgr/tcp_client_windows.c', 'src/core/lib/iomgr/tcp_client_windows.c',
'src/core/lib/iomgr/tcp_posix.c', 'src/core/lib/iomgr/tcp_posix.c',
'src/core/lib/iomgr/tcp_server_posix.c', 'src/core/lib/iomgr/tcp_server_posix.c',
'src/core/lib/iomgr/tcp_server_utils_posix_common.c',
'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c',
'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c',
'src/core/lib/iomgr/tcp_server_uv.c', 'src/core/lib/iomgr/tcp_server_uv.c',
'src/core/lib/iomgr/tcp_server_windows.c', 'src/core/lib/iomgr/tcp_server_windows.c',
'src/core/lib/iomgr/tcp_uv.c', 'src/core/lib/iomgr/tcp_uv.c',
@ -707,6 +711,7 @@
'src/core/lib/surface/channel_ping.c', 'src/core/lib/surface/channel_ping.c',
'src/core/lib/surface/channel_stack_type.c', 'src/core/lib/surface/channel_stack_type.c',
'src/core/lib/surface/completion_queue.c', 'src/core/lib/surface/completion_queue.c',
'src/core/lib/surface/completion_queue_factory.c',
'src/core/lib/surface/event_string.c', 'src/core/lib/surface/event_string.c',
'src/core/lib/surface/lame_client.c', 'src/core/lib/surface/lame_client.c',
'src/core/lib/surface/metadata_array.c', 'src/core/lib/surface/metadata_array.c',
@ -783,10 +788,8 @@
'src/core/ext/client_channel/client_channel_factory.c', 'src/core/ext/client_channel/client_channel_factory.c',
'src/core/ext/client_channel/client_channel_plugin.c', 'src/core/ext/client_channel/client_channel_plugin.c',
'src/core/ext/client_channel/connector.c', 'src/core/ext/client_channel/connector.c',
'src/core/ext/client_channel/default_initial_connect_string.c',
'src/core/ext/client_channel/http_connect_handshaker.c', 'src/core/ext/client_channel/http_connect_handshaker.c',
'src/core/ext/client_channel/http_proxy.c', 'src/core/ext/client_channel/http_proxy.c',
'src/core/ext/client_channel/initial_connect_string.c',
'src/core/ext/client_channel/lb_policy.c', 'src/core/ext/client_channel/lb_policy.c',
'src/core/ext/client_channel/lb_policy_factory.c', 'src/core/ext/client_channel/lb_policy_factory.c',
'src/core/ext/client_channel/lb_policy_registry.c', 'src/core/ext/client_channel/lb_policy_registry.c',
@ -796,6 +799,7 @@
'src/core/ext/client_channel/resolver.c', 'src/core/ext/client_channel/resolver.c',
'src/core/ext/client_channel/resolver_factory.c', 'src/core/ext/client_channel/resolver_factory.c',
'src/core/ext/client_channel/resolver_registry.c', 'src/core/ext/client_channel/resolver_registry.c',
'src/core/ext/client_channel/retry_throttle.c',
'src/core/ext/client_channel/subchannel.c', 'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c', 'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c', 'src/core/ext/client_channel/uri_parser.c',

@ -13,7 +13,7 @@ settings:
'#09': Per-language overrides are possible with (eg) ruby_version tag here '#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here '#10': See the expand_version.py for all the quirks here
core_version: 3.0.0-dev core_version: 3.0.0-dev
g_stands_for: green g_stands_for: gentle
version: 1.3.0-dev version: 1.3.0-dev
filegroups: filegroups:
- name: census - name: census
@ -85,6 +85,7 @@ filegroups:
- include/grpc/support/useful.h - include/grpc/support/useful.h
headers: headers:
- src/core/lib/profiling/timers.h - src/core/lib/profiling/timers.h
- src/core/lib/support/arena.h
- src/core/lib/support/backoff.h - src/core/lib/support/backoff.h
- src/core/lib/support/block_annotate.h - src/core/lib/support/block_annotate.h
- src/core/lib/support/env.h - src/core/lib/support/env.h
@ -101,6 +102,8 @@ filegroups:
- src/core/lib/profiling/basic_timers.c - src/core/lib/profiling/basic_timers.c
- src/core/lib/profiling/stap_timers.c - src/core/lib/profiling/stap_timers.c
- src/core/lib/support/alloc.c - src/core/lib/support/alloc.c
- src/core/lib/support/arena.c
- src/core/lib/support/atm.c
- src/core/lib/support/avl.c - src/core/lib/support/avl.c
- src/core/lib/support/backoff.c - src/core/lib/support/backoff.c
- src/core/lib/support/cmdline.c - src/core/lib/support/cmdline.c
@ -220,6 +223,7 @@ filegroups:
- src/core/lib/iomgr/sockaddr_posix.h - src/core/lib/iomgr/sockaddr_posix.h
- src/core/lib/iomgr/sockaddr_utils.h - src/core/lib/iomgr/sockaddr_utils.h
- src/core/lib/iomgr/sockaddr_windows.h - src/core/lib/iomgr/sockaddr_windows.h
- src/core/lib/iomgr/socket_factory_posix.h
- src/core/lib/iomgr/socket_mutator.h - src/core/lib/iomgr/socket_mutator.h
- src/core/lib/iomgr/socket_utils.h - src/core/lib/iomgr/socket_utils.h
- src/core/lib/iomgr/socket_utils_posix.h - src/core/lib/iomgr/socket_utils_posix.h
@ -228,6 +232,7 @@ filegroups:
- src/core/lib/iomgr/tcp_client_posix.h - src/core/lib/iomgr/tcp_client_posix.h
- src/core/lib/iomgr/tcp_posix.h - src/core/lib/iomgr/tcp_posix.h
- src/core/lib/iomgr/tcp_server.h - src/core/lib/iomgr/tcp_server.h
- src/core/lib/iomgr/tcp_server_utils_posix.h
- src/core/lib/iomgr/tcp_uv.h - src/core/lib/iomgr/tcp_uv.h
- src/core/lib/iomgr/tcp_windows.h - src/core/lib/iomgr/tcp_windows.h
- src/core/lib/iomgr/time_averaged_stats.h - src/core/lib/iomgr/time_averaged_stats.h
@ -258,6 +263,7 @@ filegroups:
- src/core/lib/surface/channel_init.h - src/core/lib/surface/channel_init.h
- src/core/lib/surface/channel_stack_type.h - src/core/lib/surface/channel_stack_type.h
- src/core/lib/surface/completion_queue.h - src/core/lib/surface/completion_queue.h
- src/core/lib/surface/completion_queue_factory.h
- src/core/lib/surface/event_string.h - src/core/lib/surface/event_string.h
- src/core/lib/surface/init.h - src/core/lib/surface/init.h
- src/core/lib/surface/lame_client.h - src/core/lib/surface/lame_client.h
@ -325,6 +331,7 @@ filegroups:
- src/core/lib/iomgr/resolve_address_windows.c - src/core/lib/iomgr/resolve_address_windows.c
- src/core/lib/iomgr/resource_quota.c - src/core/lib/iomgr/resource_quota.c
- src/core/lib/iomgr/sockaddr_utils.c - src/core/lib/iomgr/sockaddr_utils.c
- src/core/lib/iomgr/socket_factory_posix.c
- src/core/lib/iomgr/socket_mutator.c - src/core/lib/iomgr/socket_mutator.c
- src/core/lib/iomgr/socket_utils_common_posix.c - src/core/lib/iomgr/socket_utils_common_posix.c
- src/core/lib/iomgr/socket_utils_linux.c - src/core/lib/iomgr/socket_utils_linux.c
@ -337,6 +344,9 @@ filegroups:
- src/core/lib/iomgr/tcp_client_windows.c - src/core/lib/iomgr/tcp_client_windows.c
- src/core/lib/iomgr/tcp_posix.c - src/core/lib/iomgr/tcp_posix.c
- src/core/lib/iomgr/tcp_server_posix.c - src/core/lib/iomgr/tcp_server_posix.c
- src/core/lib/iomgr/tcp_server_utils_posix_common.c
- src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c
- src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c
- src/core/lib/iomgr/tcp_server_uv.c - src/core/lib/iomgr/tcp_server_uv.c
- src/core/lib/iomgr/tcp_server_windows.c - src/core/lib/iomgr/tcp_server_windows.c
- src/core/lib/iomgr/tcp_uv.c - src/core/lib/iomgr/tcp_uv.c
@ -377,6 +387,7 @@ filegroups:
- src/core/lib/surface/channel_ping.c - src/core/lib/surface/channel_ping.c
- src/core/lib/surface/channel_stack_type.c - src/core/lib/surface/channel_stack_type.c
- src/core/lib/surface/completion_queue.c - src/core/lib/surface/completion_queue.c
- src/core/lib/surface/completion_queue_factory.c
- src/core/lib/surface/event_string.c - src/core/lib/surface/event_string.c
- src/core/lib/surface/lame_client.c - src/core/lib/surface/lame_client.c
- src/core/lib/surface/metadata_array.c - src/core/lib/surface/metadata_array.c
@ -407,7 +418,6 @@ filegroups:
- src/core/ext/client_channel/connector.h - src/core/ext/client_channel/connector.h
- src/core/ext/client_channel/http_connect_handshaker.h - src/core/ext/client_channel/http_connect_handshaker.h
- src/core/ext/client_channel/http_proxy.h - src/core/ext/client_channel/http_proxy.h
- src/core/ext/client_channel/initial_connect_string.h
- src/core/ext/client_channel/lb_policy.h - src/core/ext/client_channel/lb_policy.h
- src/core/ext/client_channel/lb_policy_factory.h - src/core/ext/client_channel/lb_policy_factory.h
- src/core/ext/client_channel/lb_policy_registry.h - src/core/ext/client_channel/lb_policy_registry.h
@ -417,6 +427,7 @@ filegroups:
- src/core/ext/client_channel/resolver.h - src/core/ext/client_channel/resolver.h
- src/core/ext/client_channel/resolver_factory.h - src/core/ext/client_channel/resolver_factory.h
- src/core/ext/client_channel/resolver_registry.h - src/core/ext/client_channel/resolver_registry.h
- src/core/ext/client_channel/retry_throttle.h
- src/core/ext/client_channel/subchannel.h - src/core/ext/client_channel/subchannel.h
- src/core/ext/client_channel/subchannel_index.h - src/core/ext/client_channel/subchannel_index.h
- src/core/ext/client_channel/uri_parser.h - src/core/ext/client_channel/uri_parser.h
@ -426,10 +437,8 @@ filegroups:
- src/core/ext/client_channel/client_channel_factory.c - src/core/ext/client_channel/client_channel_factory.c
- src/core/ext/client_channel/client_channel_plugin.c - src/core/ext/client_channel/client_channel_plugin.c
- src/core/ext/client_channel/connector.c - src/core/ext/client_channel/connector.c
- src/core/ext/client_channel/default_initial_connect_string.c
- src/core/ext/client_channel/http_connect_handshaker.c - src/core/ext/client_channel/http_connect_handshaker.c
- src/core/ext/client_channel/http_proxy.c - src/core/ext/client_channel/http_proxy.c
- src/core/ext/client_channel/initial_connect_string.c
- src/core/ext/client_channel/lb_policy.c - src/core/ext/client_channel/lb_policy.c
- src/core/ext/client_channel/lb_policy_factory.c - src/core/ext/client_channel/lb_policy_factory.c
- src/core/ext/client_channel/lb_policy_registry.c - src/core/ext/client_channel/lb_policy_registry.c
@ -439,6 +448,7 @@ filegroups:
- src/core/ext/client_channel/resolver.c - src/core/ext/client_channel/resolver.c
- src/core/ext/client_channel/resolver_factory.c - src/core/ext/client_channel/resolver_factory.c
- src/core/ext/client_channel/resolver_registry.c - src/core/ext/client_channel/resolver_registry.c
- src/core/ext/client_channel/retry_throttle.c
- src/core/ext/client_channel/subchannel.c - src/core/ext/client_channel/subchannel.c
- src/core/ext/client_channel/subchannel_index.c - src/core/ext/client_channel/subchannel_index.c
- src/core/ext/client_channel/uri_parser.c - src/core/ext/client_channel/uri_parser.c
@ -1483,6 +1493,14 @@ targets:
- test/core/end2end/fuzzers/api_fuzzer_corpus - test/core/end2end/fuzzers/api_fuzzer_corpus
dict: test/core/end2end/fuzzers/api_fuzzer.dictionary dict: test/core/end2end/fuzzers/api_fuzzer.dictionary
maxlen: 2048 maxlen: 2048
- name: arena_test
build: test
language: c
src:
- test/core/support/arena_test.c
deps:
- gpr_test_util
- gpr
- name: bad_server_response_test - name: bad_server_response_test
build: test build: test
language: c language: c
@ -2684,20 +2702,6 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: set_initial_connect_string_test
cpu_cost: 0.1
build: test
language: c
src:
- test/core/client_channel/set_initial_connect_string_test.c
deps:
- test_tcp_server
- grpc_test_util
- grpc
- gpr_test_util
- gpr
exclude_iomgrs:
- uv
- name: slice_buffer_test - name: slice_buffer_test
build: test build: test
language: c language: c
@ -3054,6 +3058,26 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: bm_arena
build: test
language: c++
src:
- test/cpp/microbenchmarks/bm_arena.cc
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
args:
- --benchmark_min_time=0
platforms:
- mac
- linux
- posix
- name: bm_call_create - name: bm_call_create
build: test build: test
language: c++ language: c++
@ -3094,6 +3118,26 @@ targets:
- mac - mac
- linux - linux
- posix - posix
- name: bm_chttp2_transport
build: test
language: c++
src:
- test/cpp/microbenchmarks/bm_chttp2_transport.cc
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
args:
- --benchmark_min_time=0
platforms:
- mac
- linux
- posix
- name: bm_closure - name: bm_closure
build: test build: test
language: c++ language: c++
@ -4255,8 +4299,8 @@ configs:
TSAN_OPTIONS: suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1 TSAN_OPTIONS: suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
ubsan: ubsan:
CC: clang CC: clang
CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=undefined,unsigned-integer-overflow CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer
-fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs -Wno-unused-command-line-argument -Wvarargs
CXX: clang++ CXX: clang++
DEFINES: NDEBUG DEFINES: NDEBUG
LD: clang LD: clang
@ -4264,7 +4308,7 @@ configs:
LDXX: clang++ LDXX: clang++
compile_the_world: true compile_the_world: true
test_environ: test_environ:
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1 UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt
defaults: defaults:
benchmark: benchmark:
CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX

@ -39,6 +39,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/profiling/basic_timers.c \ src/core/lib/profiling/basic_timers.c \
src/core/lib/profiling/stap_timers.c \ src/core/lib/profiling/stap_timers.c \
src/core/lib/support/alloc.c \ src/core/lib/support/alloc.c \
src/core/lib/support/arena.c \
src/core/lib/support/atm.c \
src/core/lib/support/avl.c \ src/core/lib/support/avl.c \
src/core/lib/support/backoff.c \ src/core/lib/support/backoff.c \
src/core/lib/support/cmdline.c \ src/core/lib/support/cmdline.c \
@ -128,6 +130,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/resolve_address_windows.c \ src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.c \ src/core/lib/iomgr/resource_quota.c \
src/core/lib/iomgr/sockaddr_utils.c \ src/core/lib/iomgr/sockaddr_utils.c \
src/core/lib/iomgr/socket_factory_posix.c \
src/core/lib/iomgr/socket_mutator.c \ src/core/lib/iomgr/socket_mutator.c \
src/core/lib/iomgr/socket_utils_common_posix.c \ src/core/lib/iomgr/socket_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \ src/core/lib/iomgr/socket_utils_linux.c \
@ -140,6 +143,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/tcp_client_windows.c \ src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_posix.c \ src/core/lib/iomgr/tcp_posix.c \
src/core/lib/iomgr/tcp_server_posix.c \ src/core/lib/iomgr/tcp_server_posix.c \
src/core/lib/iomgr/tcp_server_utils_posix_common.c \
src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c \
src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c \
src/core/lib/iomgr/tcp_server_uv.c \ src/core/lib/iomgr/tcp_server_uv.c \
src/core/lib/iomgr/tcp_server_windows.c \ src/core/lib/iomgr/tcp_server_windows.c \
src/core/lib/iomgr/tcp_uv.c \ src/core/lib/iomgr/tcp_uv.c \
@ -180,6 +186,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/surface/channel_ping.c \ src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.c \ src/core/lib/surface/channel_stack_type.c \
src/core/lib/surface/completion_queue.c \ src/core/lib/surface/completion_queue.c \
src/core/lib/surface/completion_queue_factory.c \
src/core/lib/surface/event_string.c \ src/core/lib/surface/event_string.c \
src/core/lib/surface/lame_client.c \ src/core/lib/surface/lame_client.c \
src/core/lib/surface/metadata_array.c \ src/core/lib/surface/metadata_array.c \
@ -256,10 +263,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
src/core/ext/client_channel/client_channel_plugin.c \ src/core/ext/client_channel/client_channel_plugin.c \
src/core/ext/client_channel/connector.c \ src/core/ext/client_channel/connector.c \
src/core/ext/client_channel/default_initial_connect_string.c \
src/core/ext/client_channel/http_connect_handshaker.c \ src/core/ext/client_channel/http_connect_handshaker.c \
src/core/ext/client_channel/http_proxy.c \ src/core/ext/client_channel/http_proxy.c \
src/core/ext/client_channel/initial_connect_string.c \
src/core/ext/client_channel/lb_policy.c \ src/core/ext/client_channel/lb_policy.c \
src/core/ext/client_channel/lb_policy_factory.c \ src/core/ext/client_channel/lb_policy_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \ src/core/ext/client_channel/lb_policy_registry.c \
@ -269,6 +274,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_channel/resolver.c \ src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.c \ src/core/ext/client_channel/resolver_factory.c \
src/core/ext/client_channel/resolver_registry.c \ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/retry_throttle.c \
src/core/ext/client_channel/subchannel.c \ src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \ src/core/ext/client_channel/uri_parser.c \

@ -0,0 +1,158 @@
# Combiner Explanation
## Talk by ctiller, notes by vjpai
Typical way of doing critical section
```
mu.lock()
do_stuff()
mu.unlock()
```
An alternative way of doing it is
```
class combiner {
run(f) {
mu.lock()
f()
mu.unlock()
}
mutex mu;
}
combiner.run(do_stuff)
```
If you have two threads calling combiner, there will be some kind of
queuing in place. It's called `combiner` because you can pass in more
than one do_stuff at once and they will run under a common `mu`.
The implementation described above has the issue that you're blocking a thread
for a period of time, and this is considered harmful because it's an application thread that you're blocking.
Instead, get a new property:
* Keep things running in serial execution
* Don't ever sleep the thread
* But maybe allow things to end up running on a different thread from where they were started
* This means that `do_stuff` doesn't necessarily run to completion when `combiner.run` is invoked
```
class combiner {
mpscq q; // multi-producer single-consumer queue can be made non-blocking
state s; // is it empty or executing
run(f) {
if (q.push(f)) {
// q.push returns true if it's the first thing
while (q.pop(&f)) { // modulo some extra work to avoid races
f();
}
}
}
}
```
The basic idea is that the first one to push onto the combiner
executes the work and then keeps executing functions from the queue
until the combiner is drained.
Our combiner does some additional work, with the motivation of write-batching.
We have a second tier of `run` called `run_finally`. Anything queued
onto `run_finally` runs after we have drained the queue. That means
that there is essentially a finally-queue. This is not guaranteed to
be final, but it's best-effort. In the process of running the finally
item, we might put something onto the main combiner queue and so we'll
need to re-enter.
`chttp2` runs all ops in the run state except if it sees a write it puts that into a finally. That way anything else that gets put into the combiner can add to that write.
```
class combiner {
mpscq q; // multi-producer single-consumer queue can be made non-blocking
state s; // is it empty or executing
queue finally; // you can only do run_finally when you are already running something from the combiner
run(f) {
if (q.push(f)) {
// q.push returns true if it's the first thing
loop:
while (q.pop(&f)) { // modulo some extra work to avoid races
f();
}
while (finally.pop(&f)) {
f();
}
goto loop;
}
}
}
```
So that explains how combiners work in general. In gRPC, there is
`start_batch(..., tag)` and then work only gets activated by somebody
calling `cq::next` which returns a tag. This gives an API-level
guarantee that there will be a thread doing polling to actually make
work happen. However, some operations are not covered by a poller
thread, such as cancellation that doesn't have a completion. Other
callbacks that don't have a completion are the internal work that gets
done before the batch gets completed. We need a condition called
`covered_by_poller` that means that the item will definitely need some
thread at some point to call `cq::next` . This includes those
callbacks that directly cause a completion but also those that are
indirectly required before getting a completion. If we can't tell for
sure for a specific path, we have to assumed it is not covered by
poller.
The above combiner has the problem that it keeps draining for a
potentially infinite amount of time and that can lead to a huge tail
latency for some operations. So we can tweak it by returning to the application
if we know that it is valid to do so:
```
while (q.pop(&f)) {
f();
if (control_can_be_returned && some_still_queued_thing_is_covered_by_poller) {
offload_combiner_work_to_some_other_thread();
}
}
```
`offload` is more than `break`; it does `break` but also causes some
other thread that is currently waiting on a poll to break out of its
poll. This is done by setting up a per-polling-island work-queue
(distributor) wakeup FD. The work-queue is the converse of the combiner; it
tries to spray events onto as many threads as possible to get as much concurrency as possible.
So `offload` really does:
```
workqueue.run(continue_from_while_loop);
break;
```
This needs us to add another class variable for a `workqueue`
(which is really conceptually a distributor).
```
workqueue::run(f) {
q.push(f)
eventfd.wakeup()
}
workqueue::readable() {
eventfd.consume();
q.pop(&f);
f();
if (!q.empty()) {
eventfd.wakeup(); // spray across as many threads as are waiting on this workqueue
}
}
```
In principle, `run_finally` could get starved, but this hasn't
happened in practice. If we were concerned about this, we could put a
limit on how many things come off the regular `q` before the `finally`
queue gets processed.

@ -0,0 +1,160 @@
# gRPC Error
## Background
`grpc_error` is the c-core's opaque representation of an error. It holds a
collection of integers, strings, timestamps, and child errors that related to
the final error.
always present are:
* GRPC_ERROR_STR_FILE and GRPC_ERROR_INT_FILE_LINE - the source location where
the error was generated
* GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error
* GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened
An error can also have children; these are other errors that are believed to
have contributed to this one. By accumulating children, we can begin to root
cause high level failures from low level failures, without having to derive
execution paths from log lines.
grpc_errors are refcounted objects, which means they need strict ownership
semantics. An extra ref on an error can cause a memory leak, and a missing ref
can cause a crash.
This document serves as a detailed overview of grpc_error's ownership rules. It
should help people use the errors, as well as help people debug refcount related
errors.
## Clarification of Ownership
If a particular function is said to "own" an error, that means it has the
responsibility of calling unref on the error. A function may have access to an
error without ownership of it.
This means the function may use the error, but must not call unref on it, since
that will be done elsewhere in the code. A function that does not own an error
may explicitly take ownership of it by manually calling GRPC_ERROR_REF.
## Ownership Rules
There are three rules of error ownership, which we will go over in detail.
* If `grpc_error` is returned by a function, the caller owns a ref to that
instance.
* If a `grpc_error` is passed to a `grpc_closure` callback function, then that
function does not own a ref to the error.
* if a `grpc_error` is passed to *any other function*, then that function
takes ownership of the error.
### Rule 1
> If `grpc_error` is returned by a function, the caller owns a ref to that
> instance.*
For example, in the following code block, error1 and error2 are owned by the
current function.
```C
grpc_error* error1 = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occured");
grpc_error* error2 = some_operation_that_might_fail(...);
```
The current function would have to explicitly call GRPC_ERROR_UNREF on the
errors, or pass them along to a function that would take over the ownership.
### Rule 2
> If a `grpc_error` is passed to a `grpc_closure` callback function, then that
> function does not own a ref to the error.
A `grpc_closure` callback function is any function that has the signature:
```C
void (*cb)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
```
This means that the error ownership is NOT transferred when a functions calls:
```C
c->cb(exec_ctx, c->cb_arg, err);
```
The caller is still responsible for unref-ing the error.
However, the above line is currently being phased out! It is safer to invoke
callbacks with `grpc_closure_run` and `grpc_closure_sched`. These functions are
not callbacks, so they will take ownership of the error passed to them.
```C
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occured");
grpc_closure_run(exec_ctx, cb, error);
// current function no longer has ownership of the error
```
If you schedule or run a closure, but still need ownership of the error, then
you must explicitly take a reference.
```C
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occured");
grpc_closure_run(exec_ctx, cb, GRPC_ERROR_REF(error));
// do some other things with the error
GRPC_ERROR_UNREF(error);
```
Rule 2 is more important to keep in mind when **implementing** `grpc_closure`
callback functions. You must keep in mind that you do not own the error, and
must not unref it. More importantly, you cannot pass it to any function that
would take ownership of the error, without explicitly taking ownership yourself.
For example:
```C
void on_some_action(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
// this would cause a crash, because some_function will unref the error,
// and the caller of this callback will also unref it.
some_function(error);
// this callback function must take ownership, so it can give that
// ownership to the function it is calling.
some_function(GRPC_ERROR_REF(error));
}
```
### Rule 3
> if a `grpc_error` is passed to *any other function*, then that function takes
> ownership of the error.
Take the following example:
```C
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occured");
// do some things
some_function(error);
// can't use error anymore! might be gone.
```
When some_function is called, it takes over the ownership of the error, and it
will eventually unref it. So the caller can no longer safely use the error.
If the caller needed to keep using the error (or passing it to other functions),
if would have to take on a reference to it. This is a common pattern seen.
```C
void func() {
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error");
some_function(GRPC_ERROR_REF(error));
// do things
some_other_function(GRPC_ERROR_REF(error));
// do more things
some_last_function(error);
}
```
The last call takes ownership and will eventually give the error its final
unref.
When **implementing** a function that takes an error (and is not a
`grpc_closure` callback function), you must ensure the error is unref-ed either
by doing it explicitly with GRPC_ERROR_UNREF, or by passing the error to a
function that takes over the ownership.

@ -7,3 +7,4 @@ future), and the corresponding version numbers that used them:
- 1.0 'g' stands for 'gRPC' - 1.0 'g' stands for 'gRPC'
- 1.1 'g' stands for 'good' - 1.1 'g' stands for 'good'
- 1.2 'g' stands for 'green' - 1.2 'g' stands for 'green'
- 1.3 'g' stands for 'gentle'

@ -193,3 +193,79 @@ Server Procedure:
1. Sets MAX_CONCURRENT_STREAMS to one after the connection is made. 1. Sets MAX_CONCURRENT_STREAMS to one after the connection is made.
*The assertion that the MAX_CONCURRENT_STREAMS limit is upheld occurs in the http2 library we used.* *The assertion that the MAX_CONCURRENT_STREAMS limit is upheld occurs in the http2 library we used.*
### data_frame_padding
This test verifies that the client can correctly receive padded http2 data
frames. It also stresses the client's flow control (there is a high chance
that the sender will deadlock if the client's flow control logic doesn't
correctly account for padding).
Client Procedure:
(Note this is the same procedure as in the "large_unary" gRPC interop tests.
Clients should use their "large_unary" gRPC interop test implementations.)
Procedure:
1. Client calls UnaryCall with:
```
{
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
Client asserts:
* call was successful
* response payload body is 314159 bytes in size
* clients are free to assert that the response payload body contents are zero
and comparing the entire response message against a golden response
Server Procedure:
1. Reply to the client's request with a `SimpleResponse`, with a payload
body length of `SimpleRequest.response_size`. But send it across specific
http2 data frames as follows:
* Each http2 data frame contains a 5 byte payload and 255 bytes of padding.
* Note the 5 byte payload and 255 byte padding are partly arbitrary,
and other numbers are also ok. With 255 bytes of padding for each 5 bytes of
payload containing actual gRPC message, the 300KB response size will
multiply into around 15 megabytes of flow control debt, which should stress
flow control accounting.
### no_df_padding_sanity_test
This test verifies that the client can correctly receive a series of small
data frames. Note that this test is intentionally a slight variation of
"data_frame_padding", with the only difference being that this test doesn't use data
frame padding when the response is sent. This test is primarily meant to
prove correctness of the http2 server implementation and highlight failures
of the "data_frame_padding" test.
Client Procedure:
(Note this is the same procedure as in the "large_unary" gRPC interop tests.
Clients should use their "large_unary" gRPC interop test implementations.)
Procedure:
1. Client calls UnaryCall with:
```
{
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
Client asserts:
* call was successful
* response payload body is 314159 bytes in size
* clients are free to assert that the response payload body contents are zero
and comparing the entire response message against a golden response
Server Procedure:
1. Reply to the client's request with a `SimpleResponse`, with a payload
body length of `SimpleRequest.response_size`. But send it across series of
http2 data frames that contain 5 bytes of "payload" and zero bytes of
"padding" (the padding flags on the data frames should not be set).

@ -1,7 +1,8 @@
This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the base directory of this package): This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the directory which contains this README.md file):
```sh ```sh
cd ../protos cd ../../protos
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=grpc_node_plugin helloworld.proto npm install -g grpc-tools
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=grpc_node_plugin route_guide.proto grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` helloworld.proto
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` route_guide.proto
``` ```

@ -51,7 +51,7 @@ Pod::Spec.new do |s|
:submodules => true, :submodules => true,
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9' s.osx.deployment_target = '10.9'
s.requires_arc = false s.requires_arc = false
@ -196,6 +196,7 @@ Pod::Spec.new do |s|
# To save you from scrolling, this is the last part of the podspec. # To save you from scrolling, this is the last part of the podspec.
ss.source_files = 'src/core/lib/profiling/timers.h', ss.source_files = 'src/core/lib/profiling/timers.h',
'src/core/lib/support/arena.h',
'src/core/lib/support/backoff.h', 'src/core/lib/support/backoff.h',
'src/core/lib/support/block_annotate.h', 'src/core/lib/support/block_annotate.h',
'src/core/lib/support/env.h', 'src/core/lib/support/env.h',
@ -211,6 +212,8 @@ Pod::Spec.new do |s|
'src/core/lib/profiling/basic_timers.c', 'src/core/lib/profiling/basic_timers.c',
'src/core/lib/profiling/stap_timers.c', 'src/core/lib/profiling/stap_timers.c',
'src/core/lib/support/alloc.c', 'src/core/lib/support/alloc.c',
'src/core/lib/support/arena.c',
'src/core/lib/support/atm.c',
'src/core/lib/support/avl.c', 'src/core/lib/support/avl.c',
'src/core/lib/support/backoff.c', 'src/core/lib/support/backoff.c',
'src/core/lib/support/cmdline.c', 'src/core/lib/support/cmdline.c',
@ -301,6 +304,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/sockaddr_posix.h', 'src/core/lib/iomgr/sockaddr_posix.h',
'src/core/lib/iomgr/sockaddr_utils.h', 'src/core/lib/iomgr/sockaddr_utils.h',
'src/core/lib/iomgr/sockaddr_windows.h', 'src/core/lib/iomgr/sockaddr_windows.h',
'src/core/lib/iomgr/socket_factory_posix.h',
'src/core/lib/iomgr/socket_mutator.h', 'src/core/lib/iomgr/socket_mutator.h',
'src/core/lib/iomgr/socket_utils.h', 'src/core/lib/iomgr/socket_utils.h',
'src/core/lib/iomgr/socket_utils_posix.h', 'src/core/lib/iomgr/socket_utils_posix.h',
@ -309,6 +313,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_posix.h', 'src/core/lib/iomgr/tcp_client_posix.h',
'src/core/lib/iomgr/tcp_posix.h', 'src/core/lib/iomgr/tcp_posix.h',
'src/core/lib/iomgr/tcp_server.h', 'src/core/lib/iomgr/tcp_server.h',
'src/core/lib/iomgr/tcp_server_utils_posix.h',
'src/core/lib/iomgr/tcp_uv.h', 'src/core/lib/iomgr/tcp_uv.h',
'src/core/lib/iomgr/tcp_windows.h', 'src/core/lib/iomgr/tcp_windows.h',
'src/core/lib/iomgr/time_averaged_stats.h', 'src/core/lib/iomgr/time_averaged_stats.h',
@ -339,6 +344,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_init.h',
'src/core/lib/surface/channel_stack_type.h', 'src/core/lib/surface/channel_stack_type.h',
'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue.h',
'src/core/lib/surface/completion_queue_factory.h',
'src/core/lib/surface/event_string.h', 'src/core/lib/surface/event_string.h',
'src/core/lib/surface/init.h', 'src/core/lib/surface/init.h',
'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/lame_client.h',
@ -408,7 +414,6 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/connector.h', 'src/core/ext/client_channel/connector.h',
'src/core/ext/client_channel/http_connect_handshaker.h', 'src/core/ext/client_channel/http_connect_handshaker.h',
'src/core/ext/client_channel/http_proxy.h', 'src/core/ext/client_channel/http_proxy.h',
'src/core/ext/client_channel/initial_connect_string.h',
'src/core/ext/client_channel/lb_policy.h', 'src/core/ext/client_channel/lb_policy.h',
'src/core/ext/client_channel/lb_policy_factory.h', 'src/core/ext/client_channel/lb_policy_factory.h',
'src/core/ext/client_channel/lb_policy_registry.h', 'src/core/ext/client_channel/lb_policy_registry.h',
@ -418,6 +423,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.h', 'src/core/ext/client_channel/resolver.h',
'src/core/ext/client_channel/resolver_factory.h', 'src/core/ext/client_channel/resolver_factory.h',
'src/core/ext/client_channel/resolver_registry.h', 'src/core/ext/client_channel/resolver_registry.h',
'src/core/ext/client_channel/retry_throttle.h',
'src/core/ext/client_channel/subchannel.h', 'src/core/ext/client_channel/subchannel.h',
'src/core/ext/client_channel/subchannel_index.h', 'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.h', 'src/core/ext/client_channel/uri_parser.h',
@ -496,6 +502,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/resolve_address_windows.c', 'src/core/lib/iomgr/resolve_address_windows.c',
'src/core/lib/iomgr/resource_quota.c', 'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c', 'src/core/lib/iomgr/sockaddr_utils.c',
'src/core/lib/iomgr/socket_factory_posix.c',
'src/core/lib/iomgr/socket_mutator.c', 'src/core/lib/iomgr/socket_mutator.c',
'src/core/lib/iomgr/socket_utils_common_posix.c', 'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c', 'src/core/lib/iomgr/socket_utils_linux.c',
@ -508,6 +515,9 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_windows.c', 'src/core/lib/iomgr/tcp_client_windows.c',
'src/core/lib/iomgr/tcp_posix.c', 'src/core/lib/iomgr/tcp_posix.c',
'src/core/lib/iomgr/tcp_server_posix.c', 'src/core/lib/iomgr/tcp_server_posix.c',
'src/core/lib/iomgr/tcp_server_utils_posix_common.c',
'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c',
'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c',
'src/core/lib/iomgr/tcp_server_uv.c', 'src/core/lib/iomgr/tcp_server_uv.c',
'src/core/lib/iomgr/tcp_server_windows.c', 'src/core/lib/iomgr/tcp_server_windows.c',
'src/core/lib/iomgr/tcp_uv.c', 'src/core/lib/iomgr/tcp_uv.c',
@ -548,6 +558,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_ping.c', 'src/core/lib/surface/channel_ping.c',
'src/core/lib/surface/channel_stack_type.c', 'src/core/lib/surface/channel_stack_type.c',
'src/core/lib/surface/completion_queue.c', 'src/core/lib/surface/completion_queue.c',
'src/core/lib/surface/completion_queue_factory.c',
'src/core/lib/surface/event_string.c', 'src/core/lib/surface/event_string.c',
'src/core/lib/surface/lame_client.c', 'src/core/lib/surface/lame_client.c',
'src/core/lib/surface/metadata_array.c', 'src/core/lib/surface/metadata_array.c',
@ -624,10 +635,8 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/client_channel_factory.c', 'src/core/ext/client_channel/client_channel_factory.c',
'src/core/ext/client_channel/client_channel_plugin.c', 'src/core/ext/client_channel/client_channel_plugin.c',
'src/core/ext/client_channel/connector.c', 'src/core/ext/client_channel/connector.c',
'src/core/ext/client_channel/default_initial_connect_string.c',
'src/core/ext/client_channel/http_connect_handshaker.c', 'src/core/ext/client_channel/http_connect_handshaker.c',
'src/core/ext/client_channel/http_proxy.c', 'src/core/ext/client_channel/http_proxy.c',
'src/core/ext/client_channel/initial_connect_string.c',
'src/core/ext/client_channel/lb_policy.c', 'src/core/ext/client_channel/lb_policy.c',
'src/core/ext/client_channel/lb_policy_factory.c', 'src/core/ext/client_channel/lb_policy_factory.c',
'src/core/ext/client_channel/lb_policy_registry.c', 'src/core/ext/client_channel/lb_policy_registry.c',
@ -637,6 +646,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.c', 'src/core/ext/client_channel/resolver.c',
'src/core/ext/client_channel/resolver_factory.c', 'src/core/ext/client_channel/resolver_factory.c',
'src/core/ext/client_channel/resolver_registry.c', 'src/core/ext/client_channel/resolver_registry.c',
'src/core/ext/client_channel/retry_throttle.c',
'src/core/ext/client_channel/subchannel.c', 'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c', 'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c', 'src/core/ext/client_channel/uri_parser.c',
@ -675,6 +685,7 @@ Pod::Spec.new do |s|
'src/core/plugin_registry/grpc_plugin_registry.c' 'src/core/plugin_registry/grpc_plugin_registry.c'
ss.private_header_files = 'src/core/lib/profiling/timers.h', ss.private_header_files = 'src/core/lib/profiling/timers.h',
'src/core/lib/support/arena.h',
'src/core/lib/support/backoff.h', 'src/core/lib/support/backoff.h',
'src/core/lib/support/block_annotate.h', 'src/core/lib/support/block_annotate.h',
'src/core/lib/support/env.h', 'src/core/lib/support/env.h',
@ -736,6 +747,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/sockaddr_posix.h', 'src/core/lib/iomgr/sockaddr_posix.h',
'src/core/lib/iomgr/sockaddr_utils.h', 'src/core/lib/iomgr/sockaddr_utils.h',
'src/core/lib/iomgr/sockaddr_windows.h', 'src/core/lib/iomgr/sockaddr_windows.h',
'src/core/lib/iomgr/socket_factory_posix.h',
'src/core/lib/iomgr/socket_mutator.h', 'src/core/lib/iomgr/socket_mutator.h',
'src/core/lib/iomgr/socket_utils.h', 'src/core/lib/iomgr/socket_utils.h',
'src/core/lib/iomgr/socket_utils_posix.h', 'src/core/lib/iomgr/socket_utils_posix.h',
@ -744,6 +756,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_posix.h', 'src/core/lib/iomgr/tcp_client_posix.h',
'src/core/lib/iomgr/tcp_posix.h', 'src/core/lib/iomgr/tcp_posix.h',
'src/core/lib/iomgr/tcp_server.h', 'src/core/lib/iomgr/tcp_server.h',
'src/core/lib/iomgr/tcp_server_utils_posix.h',
'src/core/lib/iomgr/tcp_uv.h', 'src/core/lib/iomgr/tcp_uv.h',
'src/core/lib/iomgr/tcp_windows.h', 'src/core/lib/iomgr/tcp_windows.h',
'src/core/lib/iomgr/time_averaged_stats.h', 'src/core/lib/iomgr/time_averaged_stats.h',
@ -774,6 +787,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_init.h',
'src/core/lib/surface/channel_stack_type.h', 'src/core/lib/surface/channel_stack_type.h',
'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue.h',
'src/core/lib/surface/completion_queue_factory.h',
'src/core/lib/surface/event_string.h', 'src/core/lib/surface/event_string.h',
'src/core/lib/surface/init.h', 'src/core/lib/surface/init.h',
'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/lame_client.h',
@ -843,7 +857,6 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/connector.h', 'src/core/ext/client_channel/connector.h',
'src/core/ext/client_channel/http_connect_handshaker.h', 'src/core/ext/client_channel/http_connect_handshaker.h',
'src/core/ext/client_channel/http_proxy.h', 'src/core/ext/client_channel/http_proxy.h',
'src/core/ext/client_channel/initial_connect_string.h',
'src/core/ext/client_channel/lb_policy.h', 'src/core/ext/client_channel/lb_policy.h',
'src/core/ext/client_channel/lb_policy_factory.h', 'src/core/ext/client_channel/lb_policy_factory.h',
'src/core/ext/client_channel/lb_policy_registry.h', 'src/core/ext/client_channel/lb_policy_registry.h',
@ -853,6 +866,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.h', 'src/core/ext/client_channel/resolver.h',
'src/core/ext/client_channel/resolver_factory.h', 'src/core/ext/client_channel/resolver_factory.h',
'src/core/ext/client_channel/resolver_registry.h', 'src/core/ext/client_channel/resolver_registry.h',
'src/core/ext/client_channel/retry_throttle.h',
'src/core/ext/client_channel/subchannel.h', 'src/core/ext/client_channel/subchannel.h',
'src/core/ext/client_channel/subchannel_index.h', 'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.h', 'src/core/ext/client_channel/uri_parser.h',
@ -887,8 +901,7 @@ Pod::Spec.new do |s|
s.subspec 'Cronet-Interface' do |ss| s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpc' ss.header_mappings_dir = 'include/grpc'
ss.source_files = 'include/grpc/grpc_cronet.h', ss.source_files = 'include/grpc/grpc_cronet.h'
'src/core/ext/transport/cronet/transport/cronet_transport.h'
end end
s.subspec 'Cronet-Implementation' do |ss| s.subspec 'Cronet-Implementation' do |ss|
@ -899,7 +912,7 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Cronet-Interface", version ss.dependency "#{s.name}/Cronet-Interface", version
ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c', ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
'src/core/ext/transport/cronet/transport/cronet_transport.c', 'src/core/ext/transport/cronet/transport/cronet_transport.{c,h}',
'third_party/objective_c/Cronet/bidirectional_stream_c.h' 'third_party/objective_c/Cronet/bidirectional_stream_c.h'
end end
@ -914,7 +927,7 @@ Pod::Spec.new do |s|
'test/core/end2end/end2end_test_utils.c', 'test/core/end2end/end2end_test_utils.c',
'test/core/end2end/tests/*.{c,h}', 'test/core/end2end/tests/*.{c,h}',
'test/core/end2end/data/*.{c,h}', 'test/core/end2end/data/*.{c,h}',
'test/core/util/debugger_macros.c', 'test/core/util/debugger_macros.{c,h}',
'test/core/util/test_config.{c,h}', 'test/core/util/test_config.{c,h}',
'test/core/util/port.h', 'test/core/util/port.h',
'test/core/util/port.c', 'test/core/util/port.c',

@ -48,7 +48,7 @@ Pod::Spec.new do |s|
:tag => "v#{version}", :tag => "v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9' s.osx.deployment_target = '10.9'
name = 'ProtoRPC' name = 'ProtoRPC'

@ -48,7 +48,7 @@ Pod::Spec.new do |s|
:tag => "v#{version}", :tag => "v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9' s.osx.deployment_target = '10.9'
name = 'RxLibrary' name = 'RxLibrary'

@ -47,7 +47,7 @@ Pod::Spec.new do |s|
:tag => "v#{version}", :tag => "v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9' s.osx.deployment_target = '10.9'
name = 'GRPCClient' name = 'GRPCClient'

@ -53,6 +53,9 @@ EXPORTS
grpc_shutdown grpc_shutdown
grpc_version_string grpc_version_string
grpc_g_stands_for grpc_g_stands_for
grpc_completion_queue_factory_lookup
grpc_completion_queue_create_for_next
grpc_completion_queue_create_for_pluck
grpc_completion_queue_create grpc_completion_queue_create
grpc_completion_queue_next grpc_completion_queue_next
grpc_completion_queue_pluck grpc_completion_queue_pluck

@ -82,6 +82,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/sync_posix.h ) s.files += %w( include/grpc/impl/codegen/sync_posix.h )
s.files += %w( include/grpc/impl/codegen/sync_windows.h ) s.files += %w( include/grpc/impl/codegen/sync_windows.h )
s.files += %w( src/core/lib/profiling/timers.h ) s.files += %w( src/core/lib/profiling/timers.h )
s.files += %w( src/core/lib/support/arena.h )
s.files += %w( src/core/lib/support/backoff.h ) s.files += %w( src/core/lib/support/backoff.h )
s.files += %w( src/core/lib/support/block_annotate.h ) s.files += %w( src/core/lib/support/block_annotate.h )
s.files += %w( src/core/lib/support/env.h ) s.files += %w( src/core/lib/support/env.h )
@ -97,6 +98,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/profiling/basic_timers.c ) s.files += %w( src/core/lib/profiling/basic_timers.c )
s.files += %w( src/core/lib/profiling/stap_timers.c ) s.files += %w( src/core/lib/profiling/stap_timers.c )
s.files += %w( src/core/lib/support/alloc.c ) s.files += %w( src/core/lib/support/alloc.c )
s.files += %w( src/core/lib/support/arena.c )
s.files += %w( src/core/lib/support/atm.c )
s.files += %w( src/core/lib/support/avl.c ) s.files += %w( src/core/lib/support/avl.c )
s.files += %w( src/core/lib/support/backoff.c ) s.files += %w( src/core/lib/support/backoff.c )
s.files += %w( src/core/lib/support/cmdline.c ) s.files += %w( src/core/lib/support/cmdline.c )
@ -218,6 +221,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/sockaddr_posix.h ) s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
s.files += %w( src/core/lib/iomgr/sockaddr_utils.h ) s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
s.files += %w( src/core/lib/iomgr/sockaddr_windows.h ) s.files += %w( src/core/lib/iomgr/sockaddr_windows.h )
s.files += %w( src/core/lib/iomgr/socket_factory_posix.h )
s.files += %w( src/core/lib/iomgr/socket_mutator.h ) s.files += %w( src/core/lib/iomgr/socket_mutator.h )
s.files += %w( src/core/lib/iomgr/socket_utils.h ) s.files += %w( src/core/lib/iomgr/socket_utils.h )
s.files += %w( src/core/lib/iomgr/socket_utils_posix.h ) s.files += %w( src/core/lib/iomgr/socket_utils_posix.h )
@ -226,6 +230,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/tcp_client_posix.h ) s.files += %w( src/core/lib/iomgr/tcp_client_posix.h )
s.files += %w( src/core/lib/iomgr/tcp_posix.h ) s.files += %w( src/core/lib/iomgr/tcp_posix.h )
s.files += %w( src/core/lib/iomgr/tcp_server.h ) s.files += %w( src/core/lib/iomgr/tcp_server.h )
s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix.h )
s.files += %w( src/core/lib/iomgr/tcp_uv.h ) s.files += %w( src/core/lib/iomgr/tcp_uv.h )
s.files += %w( src/core/lib/iomgr/tcp_windows.h ) s.files += %w( src/core/lib/iomgr/tcp_windows.h )
s.files += %w( src/core/lib/iomgr/time_averaged_stats.h ) s.files += %w( src/core/lib/iomgr/time_averaged_stats.h )
@ -256,6 +261,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/channel_init.h ) s.files += %w( src/core/lib/surface/channel_init.h )
s.files += %w( src/core/lib/surface/channel_stack_type.h ) s.files += %w( src/core/lib/surface/channel_stack_type.h )
s.files += %w( src/core/lib/surface/completion_queue.h ) s.files += %w( src/core/lib/surface/completion_queue.h )
s.files += %w( src/core/lib/surface/completion_queue_factory.h )
s.files += %w( src/core/lib/surface/event_string.h ) s.files += %w( src/core/lib/surface/event_string.h )
s.files += %w( src/core/lib/surface/init.h ) s.files += %w( src/core/lib/surface/init.h )
s.files += %w( src/core/lib/surface/lame_client.h ) s.files += %w( src/core/lib/surface/lame_client.h )
@ -325,7 +331,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/connector.h ) s.files += %w( src/core/ext/client_channel/connector.h )
s.files += %w( src/core/ext/client_channel/http_connect_handshaker.h ) s.files += %w( src/core/ext/client_channel/http_connect_handshaker.h )
s.files += %w( src/core/ext/client_channel/http_proxy.h ) s.files += %w( src/core/ext/client_channel/http_proxy.h )
s.files += %w( src/core/ext/client_channel/initial_connect_string.h )
s.files += %w( src/core/ext/client_channel/lb_policy.h ) s.files += %w( src/core/ext/client_channel/lb_policy.h )
s.files += %w( src/core/ext/client_channel/lb_policy_factory.h ) s.files += %w( src/core/ext/client_channel/lb_policy_factory.h )
s.files += %w( src/core/ext/client_channel/lb_policy_registry.h ) s.files += %w( src/core/ext/client_channel/lb_policy_registry.h )
@ -335,6 +340,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/resolver.h ) s.files += %w( src/core/ext/client_channel/resolver.h )
s.files += %w( src/core/ext/client_channel/resolver_factory.h ) s.files += %w( src/core/ext/client_channel/resolver_factory.h )
s.files += %w( src/core/ext/client_channel/resolver_registry.h ) s.files += %w( src/core/ext/client_channel/resolver_registry.h )
s.files += %w( src/core/ext/client_channel/retry_throttle.h )
s.files += %w( src/core/ext/client_channel/subchannel.h ) s.files += %w( src/core/ext/client_channel/subchannel.h )
s.files += %w( src/core/ext/client_channel/subchannel_index.h ) s.files += %w( src/core/ext/client_channel/subchannel_index.h )
s.files += %w( src/core/ext/client_channel/uri_parser.h ) s.files += %w( src/core/ext/client_channel/uri_parser.h )
@ -413,6 +419,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/resolve_address_windows.c ) s.files += %w( src/core/lib/iomgr/resolve_address_windows.c )
s.files += %w( src/core/lib/iomgr/resource_quota.c ) s.files += %w( src/core/lib/iomgr/resource_quota.c )
s.files += %w( src/core/lib/iomgr/sockaddr_utils.c ) s.files += %w( src/core/lib/iomgr/sockaddr_utils.c )
s.files += %w( src/core/lib/iomgr/socket_factory_posix.c )
s.files += %w( src/core/lib/iomgr/socket_mutator.c ) s.files += %w( src/core/lib/iomgr/socket_mutator.c )
s.files += %w( src/core/lib/iomgr/socket_utils_common_posix.c ) s.files += %w( src/core/lib/iomgr/socket_utils_common_posix.c )
s.files += %w( src/core/lib/iomgr/socket_utils_linux.c ) s.files += %w( src/core/lib/iomgr/socket_utils_linux.c )
@ -425,6 +432,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/tcp_client_windows.c ) s.files += %w( src/core/lib/iomgr/tcp_client_windows.c )
s.files += %w( src/core/lib/iomgr/tcp_posix.c ) s.files += %w( src/core/lib/iomgr/tcp_posix.c )
s.files += %w( src/core/lib/iomgr/tcp_server_posix.c ) s.files += %w( src/core/lib/iomgr/tcp_server_posix.c )
s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_common.c )
s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c )
s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c )
s.files += %w( src/core/lib/iomgr/tcp_server_uv.c ) s.files += %w( src/core/lib/iomgr/tcp_server_uv.c )
s.files += %w( src/core/lib/iomgr/tcp_server_windows.c ) s.files += %w( src/core/lib/iomgr/tcp_server_windows.c )
s.files += %w( src/core/lib/iomgr/tcp_uv.c ) s.files += %w( src/core/lib/iomgr/tcp_uv.c )
@ -465,6 +475,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/channel_ping.c ) s.files += %w( src/core/lib/surface/channel_ping.c )
s.files += %w( src/core/lib/surface/channel_stack_type.c ) s.files += %w( src/core/lib/surface/channel_stack_type.c )
s.files += %w( src/core/lib/surface/completion_queue.c ) s.files += %w( src/core/lib/surface/completion_queue.c )
s.files += %w( src/core/lib/surface/completion_queue_factory.c )
s.files += %w( src/core/lib/surface/event_string.c ) s.files += %w( src/core/lib/surface/event_string.c )
s.files += %w( src/core/lib/surface/lame_client.c ) s.files += %w( src/core/lib/surface/lame_client.c )
s.files += %w( src/core/lib/surface/metadata_array.c ) s.files += %w( src/core/lib/surface/metadata_array.c )
@ -541,10 +552,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/client_channel_factory.c ) s.files += %w( src/core/ext/client_channel/client_channel_factory.c )
s.files += %w( src/core/ext/client_channel/client_channel_plugin.c ) s.files += %w( src/core/ext/client_channel/client_channel_plugin.c )
s.files += %w( src/core/ext/client_channel/connector.c ) s.files += %w( src/core/ext/client_channel/connector.c )
s.files += %w( src/core/ext/client_channel/default_initial_connect_string.c )
s.files += %w( src/core/ext/client_channel/http_connect_handshaker.c ) s.files += %w( src/core/ext/client_channel/http_connect_handshaker.c )
s.files += %w( src/core/ext/client_channel/http_proxy.c ) s.files += %w( src/core/ext/client_channel/http_proxy.c )
s.files += %w( src/core/ext/client_channel/initial_connect_string.c )
s.files += %w( src/core/ext/client_channel/lb_policy.c ) s.files += %w( src/core/ext/client_channel/lb_policy.c )
s.files += %w( src/core/ext/client_channel/lb_policy_factory.c ) s.files += %w( src/core/ext/client_channel/lb_policy_factory.c )
s.files += %w( src/core/ext/client_channel/lb_policy_registry.c ) s.files += %w( src/core/ext/client_channel/lb_policy_registry.c )
@ -554,6 +563,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/resolver.c ) s.files += %w( src/core/ext/client_channel/resolver.c )
s.files += %w( src/core/ext/client_channel/resolver_factory.c ) s.files += %w( src/core/ext/client_channel/resolver_factory.c )
s.files += %w( src/core/ext/client_channel/resolver_registry.c ) s.files += %w( src/core/ext/client_channel/resolver_registry.c )
s.files += %w( src/core/ext/client_channel/retry_throttle.c )
s.files += %w( src/core/ext/client_channel/subchannel.c ) s.files += %w( src/core/ext/client_channel/subchannel.c )
s.files += %w( src/core/ext/client_channel/subchannel_index.c ) s.files += %w( src/core/ext/client_channel/subchannel_index.c )
s.files += %w( src/core/ext/client_channel/uri_parser.c ) s.files += %w( src/core/ext/client_channel/uri_parser.c )

@ -54,7 +54,7 @@ class ResourceQuota;
class ChannelArguments { class ChannelArguments {
public: public:
ChannelArguments(); ChannelArguments();
~ChannelArguments() {} ~ChannelArguments();
ChannelArguments(const ChannelArguments& other); ChannelArguments(const ChannelArguments& other);
ChannelArguments& operator=(ChannelArguments other) { ChannelArguments& operator=(ChannelArguments other) {
@ -117,10 +117,10 @@ class ChannelArguments {
/// Return (by value) a c grpc_channel_args structure which points to /// Return (by value) a c grpc_channel_args structure which points to
/// arguments owned by this ChannelArguments instance /// arguments owned by this ChannelArguments instance
grpc_channel_args c_channel_args() { grpc_channel_args c_channel_args() const {
grpc_channel_args out; grpc_channel_args out;
out.num_args = args_.size(); out.num_args = args_.size();
out.args = args_.empty() ? NULL : &args_[0]; out.args = args_.empty() ? NULL : const_cast<grpc_arg*>(&args_[0]);
return out; return out;
} }

@ -93,6 +93,71 @@ GRPCAPI const char *grpc_version_string(void);
/** Return a string specifying what the 'g' in gRPC stands for */ /** Return a string specifying what the 'g' in gRPC stands for */
GRPCAPI const char *grpc_g_stands_for(void); GRPCAPI const char *grpc_g_stands_for(void);
/** Specifies the type of APIs to use to pop events from the completion queue */
typedef enum {
/* Events are popped out by calling grpc_completion_queue_next() API ONLY */
GRPC_CQ_NEXT = 1,
/* Events are popped out by calling grpc_completion_queue_pluck() API ONLY */
GRPC_CQ_PLUCK
} grpc_cq_completion_type;
/** Completion queues internally MAY maintain a set of file descriptors in a
structure called 'pollset'. This enum specifies if a completion queue has an
associated pollset and any restrictions on the type of file descriptors that
can be present in the pollset.
I/O progress can only be made when grpc_completion_queue_next() or
grpc_completion_queue_pluck() are called on the completion queue (unless the
grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important
to actively call these APIs */
typedef enum {
/** The completion queue will have an associated pollset and there is no
restriction on the type of file descriptors the pollset may contain */
GRPC_CQ_DEFAULT_POLLING,
/* Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
not contain any 'listening file descriptors' (i.e file descriptors used to
listen to incoming channels) */
GRPC_CQ_NON_LISTENING,
/* The completion queue will not have an associated pollset. Note that
grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still be
called to pop events from the completion queue; it is not required to call
them actively to make I/O progress */
GRPC_CQ_NON_POLLING
} grpc_cq_polling_type;
#define GRPC_CQ_CURRENT_VERSION 1
typedef struct grpc_completion_queue_attributes {
/* The version number of this structure. More fields might be added to this
structure in future. */
int version; /* Set to GRPC_CQ_CURRENT_VERSION */
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */
typedef struct grpc_completion_queue_factory grpc_completion_queue_factory;
/** Returns the completion queue factory based on the attributes. MAY return a
NULL if no factory can be found */
GRPCAPI const grpc_completion_queue_factory *
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes *attributes);
/** Helper function to create a completion queue with grpc_cq_completion_type
of GRPC_CQ_NEXT and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING */
GRPCAPI grpc_completion_queue *grpc_completion_queue_create_for_next(
void *reserved);
/** Helper function to create a completion queue with grpc_cq_completion_type
of GRPC_CQ_PLUCK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING */
GRPCAPI grpc_completion_queue *grpc_completion_queue_create_for_pluck(
void *reserved);
/** Create a completion queue */ /** Create a completion queue */
GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved); GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved);

@ -92,4 +92,9 @@
#error could not determine platform for atm #error could not determine platform for atm
#endif #endif
/** Adds \a delta to \a *value, clamping the result to the range specified
by \a min and \a max. Returns the new value. */
gpr_atm gpr_atm_no_barrier_clamped_add(gpr_atm *value, gpr_atm delta,
gpr_atm min, gpr_atm max);
#endif /* GRPC_IMPL_CODEGEN_ATM_H */ #endif /* GRPC_IMPL_CODEGEN_ATM_H */

@ -87,6 +87,9 @@ typedef struct grpc_call grpc_call;
/** The Socket Mutator interface allows changes on socket options */ /** The Socket Mutator interface allows changes on socket options */
typedef struct grpc_socket_mutator grpc_socket_mutator; typedef struct grpc_socket_mutator grpc_socket_mutator;
/** The Socket Factory interface creates and binds sockets */
typedef struct grpc_socket_factory grpc_socket_factory;
/** Type specifier for grpc_arg */ /** Type specifier for grpc_arg */
typedef enum { typedef enum {
GRPC_ARG_STRING, GRPC_ARG_STRING,
@ -240,6 +243,8 @@ typedef struct {
#define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name" #define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name"
/** The grpc_socket_mutator instance that set the socket options. A pointer. */ /** The grpc_socket_mutator instance that set the socket options. A pointer. */
#define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator" #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator"
/** The grpc_socket_factory instance to create and bind sockets. A pointer. */
#define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory"
/** If non-zero, Cronet transport will coalesce packets to fewer frames when /** If non-zero, Cronet transport will coalesce packets to fewer frames when
* possible. */ * possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \ #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \

@ -52,7 +52,7 @@
"poisson-process": "^0.2.1" "poisson-process": "^0.2.1"
}, },
"engines": { "engines": {
"node": ">=1.1.0" "node": ">=4"
}, },
"binary": { "binary": {
"module_name": "grpc_node", "module_name": "grpc_node",

@ -91,6 +91,7 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" /> <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" /> <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
@ -106,6 +107,8 @@
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/alloc.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/alloc.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/arena.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/atm.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/avl.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/avl.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/backoff.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/backoff.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/cmdline.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/cmdline.c" role="src" />
@ -227,6 +230,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_mutator.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_mutator.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.h" role="src" />
@ -235,6 +239,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.h" role="src" />
@ -265,6 +270,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/channel_init.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/channel_init.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/completion_queue.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/completion_queue.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/completion_queue_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/event_string.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/event_string.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/init.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/init.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/lame_client.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/lame_client.h" role="src" />
@ -334,7 +340,6 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/initial_connect_string.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.h" role="src" />
@ -344,6 +349,7 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/retry_throttle.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.h" role="src" />
@ -422,6 +428,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_mutator.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_mutator.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_common_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_common_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_linux.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_linux.c" role="src" />
@ -434,6 +441,9 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_common.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_uv.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_uv.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.c" role="src" />
@ -474,6 +484,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/channel_ping.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/channel_ping.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/completion_queue.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/completion_queue.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/completion_queue_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/event_string.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/event_string.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/lame_client.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/lame_client.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/metadata_array.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/metadata_array.c" role="src" />
@ -550,10 +561,8 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_plugin.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_plugin.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/connector.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/connector.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/default_initial_connect_string.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/initial_connect_string.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.c" role="src" />
@ -563,6 +572,7 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/retry_throttle.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.c" role="src" />

@ -206,14 +206,13 @@ PACKAGE_DIRECTORIES = {
INSTALL_REQUIRES = ( INSTALL_REQUIRES = (
'six>=1.5.2', 'six>=1.5.2',
'enum34>=1.0.4',
# TODO(atash): eventually split the grpcio package into a metapackage # TODO(atash): eventually split the grpcio package into a metapackage
# depending on protobuf and the runtime component (independent of protobuf) # depending on protobuf and the runtime component (independent of protobuf)
'protobuf>=3.2.0', 'protobuf>=3.2.0',
) )
if not PY3: if not PY3:
INSTALL_REQUIRES += ('futures>=2.2.0',) INSTALL_REQUIRES += ('futures>=2.2.0', 'enum34>=1.0.4')
SETUP_REQUIRES = INSTALL_REQUIRES + ( SETUP_REQUIRES = INSTALL_REQUIRES + (
'sphinx>=1.3', 'sphinx>=1.3',
@ -265,6 +264,10 @@ PACKAGES = setuptools.find_packages(PYTHON_STEM)
setuptools.setup( setuptools.setup(
name='grpcio', name='grpcio',
version=grpc_version.VERSION, version=grpc_version.VERSION,
description='HTTP/2-based RPC framework',
author='The gRPC Authors',
author_email='grpc-io@googlegroups.com',
url='http://www.grpc.io',
license=LICENSE, license=LICENSE,
long_description=open(README).read(), long_description=open(README).read(),
ext_modules=CYTHON_EXTENSION_MODULES, ext_modules=CYTHON_EXTENSION_MODULES,

@ -203,13 +203,13 @@ std::string GetServerClassName(const ServiceDescriptor *service) {
std::string GetCSharpMethodType(MethodType method_type) { std::string GetCSharpMethodType(MethodType method_type) {
switch (method_type) { switch (method_type) {
case METHODTYPE_NO_STREAMING: case METHODTYPE_NO_STREAMING:
return "MethodType.Unary"; return "grpc::MethodType.Unary";
case METHODTYPE_CLIENT_STREAMING: case METHODTYPE_CLIENT_STREAMING:
return "MethodType.ClientStreaming"; return "grpc::MethodType.ClientStreaming";
case METHODTYPE_SERVER_STREAMING: case METHODTYPE_SERVER_STREAMING:
return "MethodType.ServerStreaming"; return "grpc::MethodType.ServerStreaming";
case METHODTYPE_BIDI_STREAMING: case METHODTYPE_BIDI_STREAMING:
return "MethodType.DuplexStreaming"; return "grpc::MethodType.DuplexStreaming";
} }
GOOGLE_LOG(FATAL) << "Can't get here."; GOOGLE_LOG(FATAL) << "Can't get here.";
return ""; return "";
@ -243,16 +243,19 @@ std::string GetAccessLevel(bool internal_access) {
std::string GetMethodReturnTypeClient(const MethodDescriptor *method) { std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
switch (GetMethodType(method)) { switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING: case METHODTYPE_NO_STREAMING:
return "AsyncUnaryCall<" + GetClassName(method->output_type()) + ">"; return "grpc::AsyncUnaryCall<" + GetClassName(method->output_type()) +
">";
case METHODTYPE_CLIENT_STREAMING: case METHODTYPE_CLIENT_STREAMING:
return "AsyncClientStreamingCall<" + GetClassName(method->input_type()) + return "grpc::AsyncClientStreamingCall<" +
", " + GetClassName(method->output_type()) + ">"; GetClassName(method->input_type()) + ", " +
GetClassName(method->output_type()) + ">";
case METHODTYPE_SERVER_STREAMING: case METHODTYPE_SERVER_STREAMING:
return "AsyncServerStreamingCall<" + GetClassName(method->output_type()) + return "grpc::AsyncServerStreamingCall<" +
">"; GetClassName(method->output_type()) + ">";
case METHODTYPE_BIDI_STREAMING: case METHODTYPE_BIDI_STREAMING:
return "AsyncDuplexStreamingCall<" + GetClassName(method->input_type()) + return "grpc::AsyncDuplexStreamingCall<" +
", " + GetClassName(method->output_type()) + ">"; GetClassName(method->input_type()) + ", " +
GetClassName(method->output_type()) + ">";
} }
GOOGLE_LOG(FATAL) << "Can't get here."; GOOGLE_LOG(FATAL) << "Can't get here.";
return ""; return "";
@ -265,7 +268,7 @@ std::string GetMethodRequestParamServer(const MethodDescriptor *method) {
return GetClassName(method->input_type()) + " request"; return GetClassName(method->input_type()) + " request";
case METHODTYPE_CLIENT_STREAMING: case METHODTYPE_CLIENT_STREAMING:
case METHODTYPE_BIDI_STREAMING: case METHODTYPE_BIDI_STREAMING:
return "IAsyncStreamReader<" + GetClassName(method->input_type()) + return "grpc::IAsyncStreamReader<" + GetClassName(method->input_type()) +
"> requestStream"; "> requestStream";
} }
GOOGLE_LOG(FATAL) << "Can't get here."; GOOGLE_LOG(FATAL) << "Can't get here.";
@ -293,8 +296,8 @@ std::string GetMethodResponseStreamMaybe(const MethodDescriptor *method) {
return ""; return "";
case METHODTYPE_SERVER_STREAMING: case METHODTYPE_SERVER_STREAMING:
case METHODTYPE_BIDI_STREAMING: case METHODTYPE_BIDI_STREAMING:
return ", IServerStreamWriter<" + GetClassName(method->output_type()) + return ", grpc::IServerStreamWriter<" +
"> responseStream"; GetClassName(method->output_type()) + "> responseStream";
} }
GOOGLE_LOG(FATAL) << "Can't get here."; GOOGLE_LOG(FATAL) << "Can't get here.";
return ""; return "";
@ -325,8 +328,8 @@ void GenerateMarshallerFields(Printer *out, const ServiceDescriptor *service) {
for (size_t i = 0; i < used_messages.size(); i++) { for (size_t i = 0; i < used_messages.size(); i++) {
const Descriptor *message = used_messages[i]; const Descriptor *message = used_messages[i];
out->Print( out->Print(
"static readonly Marshaller<$type$> $fieldname$ = " "static readonly grpc::Marshaller<$type$> $fieldname$ = "
"Marshallers.Create((arg) => " "grpc::Marshallers.Create((arg) => "
"global::Google.Protobuf.MessageExtensions.ToByteArray(arg), " "global::Google.Protobuf.MessageExtensions.ToByteArray(arg), "
"$type$.Parser.ParseFrom);\n", "$type$.Parser.ParseFrom);\n",
"fieldname", GetMarshallerFieldName(message), "type", "fieldname", GetMarshallerFieldName(message), "type",
@ -337,8 +340,8 @@ void GenerateMarshallerFields(Printer *out, const ServiceDescriptor *service) {
void GenerateStaticMethodField(Printer *out, const MethodDescriptor *method) { void GenerateStaticMethodField(Printer *out, const MethodDescriptor *method) {
out->Print( out->Print(
"static readonly Method<$request$, $response$> $fieldname$ = new " "static readonly grpc::Method<$request$, $response$> $fieldname$ = new "
"Method<$request$, $response$>(\n", "grpc::Method<$request$, $response$>(\n",
"fieldname", GetMethodFieldName(method), "request", "fieldname", GetMethodFieldName(method), "request",
GetClassName(method->input_type()), "response", GetClassName(method->input_type()), "response",
GetClassName(method->output_type())); GetClassName(method->output_type()));
@ -389,7 +392,7 @@ void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
out->Print( out->Print(
"public virtual $returntype$ " "public virtual $returntype$ "
"$methodname$($request$$response_stream_maybe$, " "$methodname$($request$$response_stream_maybe$, "
"ServerCallContext context)\n", "grpc::ServerCallContext context)\n",
"methodname", method->name(), "returntype", "methodname", method->name(), "returntype",
GetMethodReturnTypeServer(method), "request", GetMethodReturnTypeServer(method), "request",
GetMethodRequestParamServer(method), "response_stream_maybe", GetMethodRequestParamServer(method), "response_stream_maybe",
@ -397,8 +400,8 @@ void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
out->Print("{\n"); out->Print("{\n");
out->Indent(); out->Indent();
out->Print( out->Print(
"throw new RpcException(" "throw new grpc::RpcException("
"new Status(StatusCode.Unimplemented, \"\"));\n"); "new grpc::Status(grpc::StatusCode.Unimplemented, \"\"));\n");
out->Outdent(); out->Outdent();
out->Print("}\n\n"); out->Print("}\n\n");
} }
@ -410,7 +413,7 @@ void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
void GenerateClientStub(Printer *out, const ServiceDescriptor *service) { void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename", out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename",
GetServiceClassName(service)); GetServiceClassName(service));
out->Print("public partial class $name$ : ClientBase<$name$>\n", "name", out->Print("public partial class $name$ : grpc::ClientBase<$name$>\n", "name",
GetClientClassName(service)); GetClientClassName(service));
out->Print("{\n"); out->Print("{\n");
out->Indent(); out->Indent();
@ -421,7 +424,7 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
"/// <param name=\"channel\">The channel to use to make remote " "/// <param name=\"channel\">The channel to use to make remote "
"calls.</param>\n", "calls.</param>\n",
"servicename", GetServiceClassName(service)); "servicename", GetServiceClassName(service));
out->Print("public $name$(Channel channel) : base(channel)\n", "name", out->Print("public $name$(grpc::Channel channel) : base(channel)\n", "name",
GetClientClassName(service)); GetClientClassName(service));
out->Print("{\n"); out->Print("{\n");
out->Print("}\n"); out->Print("}\n");
@ -431,8 +434,9 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
"/// <param name=\"callInvoker\">The callInvoker to use to make remote " "/// <param name=\"callInvoker\">The callInvoker to use to make remote "
"calls.</param>\n", "calls.</param>\n",
"servicename", GetServiceClassName(service)); "servicename", GetServiceClassName(service));
out->Print("public $name$(CallInvoker callInvoker) : base(callInvoker)\n", out->Print(
"name", GetClientClassName(service)); "public $name$(grpc::CallInvoker callInvoker) : base(callInvoker)\n",
"name", GetClientClassName(service));
out->Print("{\n"); out->Print("{\n");
out->Print("}\n"); out->Print("}\n");
out->Print( out->Print(
@ -461,7 +465,8 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
// unary calls have an extra synchronous stub method // unary calls have an extra synchronous stub method
GenerateDocCommentClientMethod(out, method, true, false); GenerateDocCommentClientMethod(out, method, true, false);
out->Print( out->Print(
"public virtual $response$ $methodname$($request$ request, Metadata " "public virtual $response$ $methodname$($request$ request, "
"grpc::Metadata "
"headers = null, DateTime? deadline = null, CancellationToken " "headers = null, DateTime? deadline = null, CancellationToken "
"cancellationToken = default(CancellationToken))\n", "cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request", "methodname", method->name(), "request",
@ -470,7 +475,8 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
out->Print("{\n"); out->Print("{\n");
out->Indent(); out->Indent();
out->Print( out->Print(
"return $methodname$(request, new CallOptions(headers, deadline, " "return $methodname$(request, new grpc::CallOptions(headers, "
"deadline, "
"cancellationToken));\n", "cancellationToken));\n",
"methodname", method->name()); "methodname", method->name());
out->Outdent(); out->Outdent();
@ -480,7 +486,7 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
GenerateDocCommentClientMethod(out, method, true, true); GenerateDocCommentClientMethod(out, method, true, true);
out->Print( out->Print(
"public virtual $response$ $methodname$($request$ request, " "public virtual $response$ $methodname$($request$ request, "
"CallOptions options)\n", "grpc::CallOptions options)\n",
"methodname", method->name(), "request", "methodname", method->name(), "request",
GetClassName(method->input_type()), "response", GetClassName(method->input_type()), "response",
GetClassName(method->output_type())); GetClassName(method->output_type()));
@ -500,7 +506,8 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
} }
GenerateDocCommentClientMethod(out, method, false, false); GenerateDocCommentClientMethod(out, method, false, false);
out->Print( out->Print(
"public virtual $returntype$ $methodname$($request_maybe$Metadata " "public virtual $returntype$ "
"$methodname$($request_maybe$grpc::Metadata "
"headers = null, DateTime? deadline = null, CancellationToken " "headers = null, DateTime? deadline = null, CancellationToken "
"cancellationToken = default(CancellationToken))\n", "cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe", "methodname", method_name, "request_maybe",
@ -510,7 +517,8 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
out->Indent(); out->Indent();
out->Print( out->Print(
"return $methodname$($request_maybe$new CallOptions(headers, deadline, " "return $methodname$($request_maybe$new grpc::CallOptions(headers, "
"deadline, "
"cancellationToken));\n", "cancellationToken));\n",
"methodname", method_name, "request_maybe", "methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method, true)); GetMethodRequestParamMaybe(method, true));
@ -520,7 +528,8 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
// overload taking CallOptions as a param // overload taking CallOptions as a param
GenerateDocCommentClientMethod(out, method, false, true); GenerateDocCommentClientMethod(out, method, false, true);
out->Print( out->Print(
"public virtual $returntype$ $methodname$($request_maybe$CallOptions " "public virtual $returntype$ "
"$methodname$($request_maybe$grpc::CallOptions "
"options)\n", "options)\n",
"methodname", method_name, "request_maybe", "methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype", GetMethodRequestParamMaybe(method), "returntype",
@ -587,13 +596,13 @@ void GenerateBindServiceMethod(Printer *out, const ServiceDescriptor *service) {
"/// <param name=\"serviceImpl\">An object implementing the server-side" "/// <param name=\"serviceImpl\">An object implementing the server-side"
" handling logic.</param>\n"); " handling logic.</param>\n");
out->Print( out->Print(
"public static ServerServiceDefinition BindService($implclass$ " "public static grpc::ServerServiceDefinition BindService($implclass$ "
"serviceImpl)\n", "serviceImpl)\n",
"implclass", GetServerClassName(service)); "implclass", GetServerClassName(service));
out->Print("{\n"); out->Print("{\n");
out->Indent(); out->Indent();
out->Print("return ServerServiceDefinition.CreateBuilder()\n"); out->Print("return grpc::ServerServiceDefinition.CreateBuilder()\n");
out->Indent(); out->Indent();
out->Indent(); out->Indent();
for (int i = 0; i < service->method_count(); i++) { for (int i = 0; i < service->method_count(); i++) {
@ -681,7 +690,7 @@ grpc::string GetServices(const FileDescriptor *file, bool generate_client,
out.Print("using System;\n"); out.Print("using System;\n");
out.Print("using System.Threading;\n"); out.Print("using System.Threading;\n");
out.Print("using System.Threading.Tasks;\n"); out.Print("using System.Threading.Tasks;\n");
out.Print("using Grpc.Core;\n"); out.Print("using grpc = global::Grpc.Core;\n");
out.Print("\n"); out.Print("\n");
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file)); out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));

@ -118,7 +118,7 @@ void PrintService(const ServiceDescriptor *service, Printer *out) {
out->Print( out->Print(
"/**\n * @param string $$hostname hostname\n" "/**\n * @param string $$hostname hostname\n"
" * @param array $$opts channel options\n" " * @param array $$opts channel options\n"
" * @param Grpc\\Channel $$channel (optional) re-use channel " " * @param \\Grpc\\Channel $$channel (optional) re-use channel "
"object\n */\n" "object\n */\n"
"public function __construct($$hostname, $$opts, " "public function __construct($$hostname, $$opts, "
"$$channel = null) {\n"); "$$channel = null) {\n");

@ -647,15 +647,15 @@ bool PrivateGenerator::PrintBetaPreamble() {
"Package", config.beta_package_root); "Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package", out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
config.beta_package_root); config.beta_package_root);
out->Print("from grpc.framework.common import cardinality\n");
out->Print(
"from grpc.framework.interfaces.face import utilities as "
"face_utilities\n");
return true; return true;
} }
bool PrivateGenerator::PrintPreamble() { bool PrivateGenerator::PrintPreamble() {
out->Print("import $Package$\n", "Package", config.grpc_package_root); out->Print("import $Package$\n", "Package", config.grpc_package_root);
out->Print("from grpc.framework.common import cardinality\n");
out->Print(
"from grpc.framework.interfaces.face import utilities as "
"face_utilities\n");
if (generate_in_pb2_grpc) { if (generate_in_pb2_grpc) {
out->Print("\n"); out->Print("\n");
StringPairSet imports_set; StringPairSet imports_set;

@ -138,7 +138,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx,
static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx, static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
call_data *d = elem->call_data; call_data *d = elem->call_data;
GPR_ASSERT(d != NULL); GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc client stats and census_rpc_end_op here */ /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@ -160,7 +160,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx,
static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx, static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
call_data *d = elem->call_data; call_data *d = elem->call_data;
GPR_ASSERT(d != NULL); GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc server stats and census_tracing_end_op here */ /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */

@ -139,8 +139,8 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
error = GRPC_ERROR_NONE; error = GRPC_ERROR_NONE;
} else { } else {
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
error = error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Timed out waiting for connection state change"); "Timed out waiting for connection state change");
} else if (error == GRPC_ERROR_CANCELLED) { } else if (error == GRPC_ERROR_CANCELLED) {
error = GRPC_ERROR_NONE; error = GRPC_ERROR_NONE;
} }

@ -47,6 +47,7 @@
#include "src/core/ext/client_channel/lb_policy_registry.h" #include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/proxy_mapper_registry.h" #include "src/core/ext/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/client_channel/resolver_registry.h" #include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/ext/client_channel/retry_throttle.h"
#include "src/core/ext/client_channel/subchannel.h" #include "src/core/ext/client_channel/subchannel.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h" #include "src/core/lib/channel/connected_channel.h"
@ -189,6 +190,8 @@ typedef struct client_channel_channel_data {
grpc_combiner *combiner; grpc_combiner *combiner;
/** currently active load balancer */ /** currently active load balancer */
grpc_lb_policy *lb_policy; grpc_lb_policy *lb_policy;
/** retry throttle data */
grpc_server_retry_throttle_data *retry_throttle_data;
/** maps method names to method_parameters structs */ /** maps method names to method_parameters structs */
grpc_slice_hash_table *method_params_table; grpc_slice_hash_table *method_params_table;
/** incoming resolver result - set by resolver.next() */ /** incoming resolver result - set by resolver.next() */
@ -284,6 +287,65 @@ static void watch_lb_policy_locked(grpc_exec_ctx *exec_ctx, channel_data *chand,
&w->on_changed); &w->on_changed);
} }
typedef struct {
char *server_name;
grpc_server_retry_throttle_data *retry_throttle_data;
} service_config_parsing_state;
static void parse_retry_throttle_params(const grpc_json *field, void *arg) {
service_config_parsing_state *parsing_state = arg;
if (strcmp(field->key, "retryThrottling") == 0) {
if (parsing_state->retry_throttle_data != NULL) return; // Duplicate.
if (field->type != GRPC_JSON_OBJECT) return;
int max_milli_tokens = 0;
int milli_token_ratio = 0;
for (grpc_json *sub_field = field->child; sub_field != NULL;
sub_field = sub_field->next) {
if (sub_field->key == NULL) return;
if (strcmp(sub_field->key, "maxTokens") == 0) {
if (max_milli_tokens != 0) return; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return;
max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
if (max_milli_tokens == -1) return;
max_milli_tokens *= 1000;
} else if (strcmp(sub_field->key, "tokenRatio") == 0) {
if (milli_token_ratio != 0) return; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return;
// We support up to 3 decimal digits.
size_t whole_len = strlen(sub_field->value);
uint32_t multiplier = 1;
uint32_t decimal_value = 0;
const char *decimal_point = strchr(sub_field->value, '.');
if (decimal_point != NULL) {
whole_len = (size_t)(decimal_point - sub_field->value);
multiplier = 1000;
size_t decimal_len = strlen(decimal_point + 1);
if (decimal_len > 3) decimal_len = 3;
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
&decimal_value)) {
return;
}
uint32_t decimal_multiplier = 1;
for (size_t i = 0; i < (3 - decimal_len); ++i) {
decimal_multiplier *= 10;
}
decimal_value *= decimal_multiplier;
}
uint32_t whole_value;
if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
&whole_value)) {
return;
}
milli_token_ratio = (int)((whole_value * multiplier) + decimal_value);
if (milli_token_ratio <= 0) return;
}
}
parsing_state->retry_throttle_data =
grpc_retry_throttle_map_get_data_for_server(
parsing_state->server_name, max_milli_tokens, milli_token_ratio);
}
}
static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx, static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
void *arg, grpc_error *error) { void *arg, grpc_error *error) {
channel_data *chand = arg; channel_data *chand = arg;
@ -293,8 +355,11 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_slice_hash_table *method_params_table = NULL; grpc_slice_hash_table *method_params_table = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false; bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); grpc_error *state_error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
char *service_config_json = NULL; char *service_config_json = NULL;
service_config_parsing_state parsing_state;
memset(&parsing_state, 0, sizeof(parsing_state));
if (chand->resolver_result != NULL) { if (chand->resolver_result != NULL) {
// Find LB policy name. // Find LB policy name.
@ -355,6 +420,19 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_service_config *service_config = grpc_service_config *service_config =
grpc_service_config_create(service_config_json); grpc_service_config_create(service_config_json);
if (service_config != NULL) { if (service_config != NULL) {
channel_arg =
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVER_URI);
GPR_ASSERT(channel_arg != NULL);
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
grpc_uri *uri =
grpc_uri_parse(exec_ctx, channel_arg->value.string, true);
GPR_ASSERT(uri->path[0] != '\0');
parsing_state.server_name =
uri->path[0] == '/' ? uri->path + 1 : uri->path;
grpc_service_config_parse_global_params(
service_config, parse_retry_throttle_params, &parsing_state);
parsing_state.server_name = NULL;
grpc_uri_destroy(uri);
method_params_table = grpc_service_config_create_method_config_table( method_params_table = grpc_service_config_create_method_config_table(
exec_ctx, service_config, method_parameters_create_from_json, exec_ctx, service_config, method_parameters_create_from_json,
&method_parameters_vtable); &method_parameters_vtable);
@ -386,6 +464,11 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
chand->info_service_config_json = service_config_json; chand->info_service_config_json = service_config_json;
} }
gpr_mu_unlock(&chand->info_mu); gpr_mu_unlock(&chand->info_mu);
if (chand->retry_throttle_data != NULL) {
grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
}
chand->retry_throttle_data = parsing_state.retry_throttle_data;
if (chand->method_params_table != NULL) { if (chand->method_params_table != NULL) {
grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table); grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
} }
@ -393,9 +476,9 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
if (lb_policy != NULL) { if (lb_policy != NULL) {
grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures); grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
} else if (chand->resolver == NULL /* disconnected */) { } else if (chand->resolver == NULL /* disconnected */) {
grpc_closure_list_fail_all( grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
&chand->waiting_for_config_closures, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1)); "Channel disconnected", &error, 1));
grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures); grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
} }
if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) { if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
@ -423,8 +506,8 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_error *refs[] = {error, state_error}; grpc_error *refs[] = {error, state_error};
set_channel_connectivity_state_locked( set_channel_connectivity_state_locked(
exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GPR_ARRAY_SIZE(refs)), "Got config after disconnection", refs, GPR_ARRAY_SIZE(refs)),
"resolver_gone"); "resolver_gone");
} }
@ -463,8 +546,9 @@ static void start_transport_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (op->send_ping != NULL) { if (op->send_ping != NULL) {
if (chand->lb_policy == NULL) { if (chand->lb_policy == NULL) {
grpc_closure_sched(exec_ctx, op->send_ping, grpc_closure_sched(
GRPC_ERROR_CREATE("Ping with no load balancing")); exec_ctx, op->send_ping,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
} else { } else {
grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping); grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping);
op->bind_pollset = NULL; op->bind_pollset = NULL;
@ -579,7 +663,7 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
if (proxy_name != NULL) gpr_free(proxy_name); if (proxy_name != NULL) gpr_free(proxy_name);
if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args); if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args);
if (chand->resolver == NULL) { if (chand->resolver == NULL) {
return GRPC_ERROR_CREATE("resolver creation failed"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -613,6 +697,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
} }
gpr_free(chand->info_lb_policy_name); gpr_free(chand->info_lb_policy_name);
gpr_free(chand->info_service_config_json); gpr_free(chand->info_service_config_json);
if (chand->retry_throttle_data != NULL) {
grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
}
if (chand->method_params_table != NULL) { if (chand->method_params_table != NULL) {
grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table); grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
} }
@ -654,6 +741,7 @@ typedef struct client_channel_call_data {
grpc_slice path; // Request path. grpc_slice path; // Request path.
gpr_timespec call_start_time; gpr_timespec call_start_time;
gpr_timespec deadline; gpr_timespec deadline;
grpc_server_retry_throttle_data *retry_throttle_data;
method_parameters *method_params; method_parameters *method_params;
grpc_error *cancel_error; grpc_error *cancel_error;
@ -661,6 +749,7 @@ typedef struct client_channel_call_data {
/** either 0 for no call, 1 for cancelled, or a pointer to a /** either 0 for no call, 1 for cancelled, or a pointer to a
grpc_subchannel_call */ grpc_subchannel_call */
gpr_atm subchannel_call; gpr_atm subchannel_call;
gpr_arena *arena;
subchannel_creation_phase creation_phase; subchannel_creation_phase creation_phase;
grpc_connected_subchannel *connected_subchannel; grpc_connected_subchannel *connected_subchannel;
@ -675,6 +764,9 @@ typedef struct client_channel_call_data {
grpc_call_stack *owning_call; grpc_call_stack *owning_call;
grpc_linked_mdelem lb_token_mdelem; grpc_linked_mdelem lb_token_mdelem;
grpc_closure on_complete;
grpc_closure *original_on_complete;
} call_data; } call_data;
grpc_subchannel_call *grpc_client_channel_get_subchannel_call( grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
@ -727,7 +819,7 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
gpr_free(ops); gpr_free(ops);
} }
// Sets calld->method_params. // Sets calld->method_params and calld->retry_throttle_data.
// If the method params specify a timeout, populates // If the method params specify a timeout, populates
// *per_method_deadline and returns true. // *per_method_deadline and returns true.
static bool set_call_method_params_from_service_config_locked( static bool set_call_method_params_from_service_config_locked(
@ -735,6 +827,10 @@ static bool set_call_method_params_from_service_config_locked(
gpr_timespec *per_method_deadline) { gpr_timespec *per_method_deadline) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
if (chand->retry_throttle_data != NULL) {
calld->retry_throttle_data =
grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
}
if (chand->method_params_table != NULL) { if (chand->method_params_table != NULL) {
calld->method_params = grpc_method_config_table_get( calld->method_params = grpc_method_config_table_get(
exec_ctx, chand->method_params_table, calld->path); exec_ctx, chand->method_params_table, calld->path);
@ -780,12 +876,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (calld->connected_subchannel == NULL) { if (calld->connected_subchannel == NULL) {
gpr_atm_no_barrier_store(&calld->subchannel_call, 1); gpr_atm_no_barrier_store(&calld->subchannel_call, 1);
fail_locked(exec_ctx, calld, GRPC_ERROR_CREATE_REFERENCING( fail_locked(exec_ctx, calld,
"Failed to create subchannel", &error, 1)); GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed to create subchannel", &error, 1));
} else if (GET_CALL(calld) == CANCELLED_CALL) { } else if (GET_CALL(calld) == CANCELLED_CALL) {
/* already cancelled before subchannel became ready */ /* already cancelled before subchannel became ready */
grpc_error *cancellation_error = GRPC_ERROR_CREATE_REFERENCING( grpc_error *cancellation_error =
"Cancelled before creating subchannel", &error, 1); GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Cancelled before creating subchannel", &error, 1);
/* if due to deadline, attach the deadline exceeded status to the error */ /* if due to deadline, attach the deadline exceeded status to the error */
if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) { if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) {
cancellation_error = cancellation_error =
@ -796,9 +894,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
} else { } else {
/* Create call on subchannel. */ /* Create call on subchannel. */
grpc_subchannel_call *subchannel_call = NULL; grpc_subchannel_call *subchannel_call = NULL;
const grpc_connected_subchannel_call_args call_args = {
.pollent = calld->pollent,
.path = calld->path,
.start_time = calld->call_start_time,
.deadline = calld->deadline,
.arena = calld->arena};
grpc_error *new_error = grpc_connected_subchannel_create_call( grpc_error *new_error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
calld->call_start_time, calld->deadline, &subchannel_call);
if (new_error != GRPC_ERROR_NONE) { if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error); new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL; subchannel_call = CANCELLED_CALL;
@ -882,9 +985,9 @@ static bool pick_subchannel_locked(
cpa = closure->cb_arg; cpa = closure->cb_arg;
if (cpa->connected_subchannel == connected_subchannel) { if (cpa->connected_subchannel == connected_subchannel) {
cpa->connected_subchannel = NULL; cpa->connected_subchannel = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, cpa->on_ready,
exec_ctx, cpa->on_ready, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1)); "Pick cancelled", &error, 1));
} }
} }
GPR_TIMER_END("pick_subchannel", 0); GPR_TIMER_END("pick_subchannel", 0);
@ -941,7 +1044,8 @@ static bool pick_subchannel_locked(
grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure, grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
GRPC_ERROR_NONE); GRPC_ERROR_NONE);
} else { } else {
grpc_closure_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected")); grpc_closure_sched(exec_ctx, on_ready,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
} }
GPR_TIMER_END("pick_subchannel", 0); GPR_TIMER_END("pick_subchannel", 0);
@ -1025,9 +1129,14 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
calld->connected_subchannel != NULL) { calld->connected_subchannel != NULL) {
grpc_subchannel_call *subchannel_call = NULL; grpc_subchannel_call *subchannel_call = NULL;
const grpc_connected_subchannel_call_args call_args = {
.pollent = calld->pollent,
.path = calld->path,
.start_time = calld->call_start_time,
.deadline = calld->deadline,
.arena = calld->arena};
grpc_error *error = grpc_connected_subchannel_create_call( grpc_error *error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
calld->call_start_time, calld->deadline, &subchannel_call);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL; subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error)); fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
@ -1045,6 +1154,26 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
add_waiting_locked(calld, op); add_waiting_locked(calld, op);
} }
static void on_complete(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_call_element *elem = arg;
call_data *calld = elem->call_data;
if (calld->retry_throttle_data != NULL) {
if (error == GRPC_ERROR_NONE) {
grpc_server_retry_throttle_data_record_success(
calld->retry_throttle_data);
} else {
// TODO(roth): In a subsequent PR, check the return value here and
// decide whether or not to retry. Note that we should only
// record failures whose statuses match the configured retryable
// or non-fatal status codes.
grpc_server_retry_throttle_data_record_failure(
calld->retry_throttle_data);
}
}
grpc_closure_run(exec_ctx, calld->original_on_complete,
GRPC_ERROR_REF(error));
}
static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg, static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error_ignored) { grpc_error *error_ignored) {
GPR_TIMER_BEGIN("start_transport_stream_op_locked", 0); GPR_TIMER_BEGIN("start_transport_stream_op_locked", 0);
@ -1053,6 +1182,14 @@ static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_call_element *elem = op->handler_private.args[0]; grpc_call_element *elem = op->handler_private.args[0];
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
if (op->recv_trailing_metadata != NULL) {
GPR_ASSERT(op->on_complete != NULL);
calld->original_on_complete = op->on_complete;
grpc_closure_init(&calld->on_complete, on_complete, elem,
grpc_schedule_on_exec_ctx);
op->on_complete = &calld->on_complete;
}
start_transport_stream_op_locked_inner(exec_ctx, op, elem); start_transport_stream_op_locked_inner(exec_ctx, op, elem);
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,
@ -1114,6 +1251,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
calld->call_start_time = args->start_time; calld->call_start_time = args->start_time;
calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
calld->owning_call = args->call_stack; calld->owning_call = args->call_stack;
calld->arena = args->arena;
grpc_deadline_state_start(exec_ctx, elem, calld->deadline); grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -1122,7 +1260,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *and_free_memory) { grpc_closure *then_schedule_closure) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
grpc_deadline_state_destroy(exec_ctx, elem); grpc_deadline_state_destroy(exec_ctx, elem);
grpc_slice_unref_internal(exec_ctx, calld->path); grpc_slice_unref_internal(exec_ctx, calld->path);
@ -1132,6 +1270,8 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_UNREF(calld->cancel_error); GRPC_ERROR_UNREF(calld->cancel_error);
grpc_subchannel_call *call = GET_CALL(calld); grpc_subchannel_call *call = GET_CALL(calld);
if (call != NULL && call != CANCELLED_CALL) { if (call != NULL && call != CANCELLED_CALL) {
grpc_subchannel_call_set_cleanup_closure(call, then_schedule_closure);
then_schedule_closure = NULL;
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call"); GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call");
} }
GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
@ -1141,7 +1281,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
"picked"); "picked");
} }
gpr_free(calld->waiting_ops); gpr_free(calld->waiting_ops);
gpr_free(and_free_memory); grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
} }
static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,

@ -43,6 +43,7 @@
#include "src/core/ext/client_channel/lb_policy_registry.h" #include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/proxy_mapper_registry.h" #include "src/core/ext/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/client_channel/resolver_registry.h" #include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/ext/client_channel/retry_throttle.h"
#include "src/core/ext/client_channel/subchannel_index.h" #include "src/core/ext/client_channel/subchannel_index.h"
#include "src/core/lib/surface/channel_init.h" #include "src/core/lib/surface/channel_init.h"
@ -82,6 +83,7 @@ static bool set_default_host_if_unset(grpc_exec_ctx *exec_ctx,
void grpc_client_channel_init(void) { void grpc_client_channel_init(void) {
grpc_lb_policy_registry_init(); grpc_lb_policy_registry_init();
grpc_resolver_registry_init(); grpc_resolver_registry_init();
grpc_retry_throttle_map_init();
grpc_proxy_mapper_registry_init(); grpc_proxy_mapper_registry_init();
grpc_register_http_proxy_mapper(); grpc_register_http_proxy_mapper();
grpc_subchannel_index_init(); grpc_subchannel_index_init();
@ -96,6 +98,7 @@ void grpc_client_channel_shutdown(void) {
grpc_subchannel_index_shutdown(); grpc_subchannel_index_shutdown();
grpc_channel_init_shutdown(); grpc_channel_init_shutdown();
grpc_proxy_mapper_registry_shutdown(); grpc_proxy_mapper_registry_shutdown();
grpc_retry_throttle_map_shutdown();
grpc_resolver_registry_shutdown(); grpc_resolver_registry_shutdown();
grpc_lb_policy_registry_shutdown(); grpc_lb_policy_registry_shutdown();
} }

@ -48,8 +48,6 @@ struct grpc_connector {
typedef struct { typedef struct {
/** set of pollsets interested in this connection */ /** set of pollsets interested in this connection */
grpc_pollset_set *interested_parties; grpc_pollset_set *interested_parties;
/** initial connect string to send */
grpc_slice initial_connect_string;
/** deadline for connection */ /** deadline for connection */
gpr_timespec deadline; gpr_timespec deadline;
/** channel arguments (to be passed to transport) */ /** channel arguments (to be passed to transport) */

@ -116,7 +116,7 @@ static void handshake_failed_locked(grpc_exec_ctx* exec_ctx,
// If we were shut down after an endpoint operation succeeded but // If we were shut down after an endpoint operation succeeded but
// before the endpoint callback was invoked, we need to generate our // before the endpoint callback was invoked, we need to generate our
// own error. // own error.
error = GRPC_ERROR_CREATE("Handshaker shutdown"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
} }
if (!handshaker->shutdown) { if (!handshaker->shutdown) {
// TODO(ctiller): It is currently necessary to shutdown endpoints // TODO(ctiller): It is currently necessary to shutdown endpoints
@ -226,7 +226,7 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
char* msg; char* msg;
gpr_asprintf(&msg, "HTTP proxy returned response code %d", gpr_asprintf(&msg, "HTTP proxy returned response code %d",
handshaker->http_response.status); handshaker->http_response.status);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
handshake_failed_locked(exec_ctx, handshaker, error); handshake_failed_locked(exec_ctx, handshaker, error);
goto done; goto done;

@ -94,6 +94,14 @@ static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) {
grpc_proxy_mapper_destroy(list->list[i]); grpc_proxy_mapper_destroy(list->list[i]);
} }
gpr_free(list->list); gpr_free(list->list);
// Clean up in case we re-initialze later.
// TODO(ctiller): This should ideally live in
// grpc_proxy_mapper_registry_init(). However, if we did this there,
// then we would do it AFTER we start registering proxy mappers from
// third-party plugins, so they'd never show up (and would leak memory).
// We probably need some sort of dependency system for plugins to fix
// this.
memset(list, 0, sizeof(*list));
} }
// //
@ -102,9 +110,7 @@ static void grpc_proxy_mapper_list_destroy(grpc_proxy_mapper_list* list) {
static grpc_proxy_mapper_list g_proxy_mapper_list; static grpc_proxy_mapper_list g_proxy_mapper_list;
void grpc_proxy_mapper_registry_init() { void grpc_proxy_mapper_registry_init() {}
memset(&g_proxy_mapper_list, 0, sizeof(g_proxy_mapper_list));
}
void grpc_proxy_mapper_registry_shutdown() { void grpc_proxy_mapper_registry_shutdown() {
grpc_proxy_mapper_list_destroy(&g_proxy_mapper_list); grpc_proxy_mapper_list_destroy(&g_proxy_mapper_list);

@ -0,0 +1,210 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/ext/client_channel/retry_throttle.h"
#include <limits.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/avl.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
//
// server_retry_throttle_data
//
struct grpc_server_retry_throttle_data {
gpr_refcount refs;
int max_milli_tokens;
int milli_token_ratio;
gpr_atm milli_tokens;
// A pointer to the replacement for this grpc_server_retry_throttle_data
// entry. If non-NULL, then this entry is stale and must not be used.
// We hold a reference to the replacement.
gpr_atm replacement;
};
static void get_replacement_throttle_data_if_needed(
grpc_server_retry_throttle_data** throttle_data) {
while (true) {
grpc_server_retry_throttle_data* new_throttle_data =
(grpc_server_retry_throttle_data*)gpr_atm_acq_load(
&(*throttle_data)->replacement);
if (new_throttle_data == NULL) return;
*throttle_data = new_throttle_data;
}
}
bool grpc_server_retry_throttle_data_record_failure(
grpc_server_retry_throttle_data* throttle_data) {
// First, check if we are stale and need to be replaced.
get_replacement_throttle_data_if_needed(&throttle_data);
// We decrement milli_tokens by 1000 (1 token) for each failure.
const int new_value = (int)gpr_atm_no_barrier_clamped_add(
&throttle_data->milli_tokens, (gpr_atm)-1000, (gpr_atm)0,
(gpr_atm)throttle_data->max_milli_tokens);
// Retries are allowed as long as the new value is above the threshold
// (max_milli_tokens / 2).
return new_value > throttle_data->max_milli_tokens / 2;
}
void grpc_server_retry_throttle_data_record_success(
grpc_server_retry_throttle_data* throttle_data) {
// First, check if we are stale and need to be replaced.
get_replacement_throttle_data_if_needed(&throttle_data);
// We increment milli_tokens by milli_token_ratio for each success.
gpr_atm_no_barrier_clamped_add(
&throttle_data->milli_tokens, (gpr_atm)throttle_data->milli_token_ratio,
(gpr_atm)0, (gpr_atm)throttle_data->max_milli_tokens);
}
grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_ref(
grpc_server_retry_throttle_data* throttle_data) {
gpr_ref(&throttle_data->refs);
return throttle_data;
}
void grpc_server_retry_throttle_data_unref(
grpc_server_retry_throttle_data* throttle_data) {
if (gpr_unref(&throttle_data->refs)) {
grpc_server_retry_throttle_data* replacement =
(grpc_server_retry_throttle_data*)gpr_atm_acq_load(
&throttle_data->replacement);
if (replacement != NULL) {
grpc_server_retry_throttle_data_unref(replacement);
}
gpr_free(throttle_data);
}
}
static grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_create(
int max_milli_tokens, int milli_token_ratio,
grpc_server_retry_throttle_data* old_throttle_data) {
grpc_server_retry_throttle_data* throttle_data =
gpr_malloc(sizeof(*throttle_data));
memset(throttle_data, 0, sizeof(*throttle_data));
gpr_ref_init(&throttle_data->refs, 1);
throttle_data->max_milli_tokens = max_milli_tokens;
throttle_data->milli_token_ratio = milli_token_ratio;
int initial_milli_tokens = max_milli_tokens;
// If there was a pre-existing entry for this server name, initialize
// the token count by scaling proportionately to the old data. This
// ensures that if we're already throttling retries on the old scale,
// we will start out doing the same thing on the new one.
if (old_throttle_data != NULL) {
double token_fraction =
(int)gpr_atm_acq_load(&old_throttle_data->milli_tokens) /
(double)old_throttle_data->max_milli_tokens;
initial_milli_tokens = (int)(token_fraction * max_milli_tokens);
}
gpr_atm_rel_store(&throttle_data->milli_tokens,
(gpr_atm)initial_milli_tokens);
// If there was a pre-existing entry, mark it as stale and give it a
// pointer to the new entry, which is its replacement.
if (old_throttle_data != NULL) {
grpc_server_retry_throttle_data_ref(throttle_data);
gpr_atm_rel_store(&old_throttle_data->replacement, (gpr_atm)throttle_data);
}
return throttle_data;
}
//
// avl vtable for string -> server_retry_throttle_data map
//
static void* copy_server_name(void* key) { return gpr_strdup(key); }
static long compare_server_name(void* key1, void* key2) {
return strcmp(key1, key2);
}
static void destroy_server_retry_throttle_data(void* value) {
grpc_server_retry_throttle_data* throttle_data = value;
grpc_server_retry_throttle_data_unref(throttle_data);
}
static void* copy_server_retry_throttle_data(void* value) {
grpc_server_retry_throttle_data* throttle_data = value;
return grpc_server_retry_throttle_data_ref(throttle_data);
}
static const gpr_avl_vtable avl_vtable = {
gpr_free /* destroy_key */, copy_server_name, compare_server_name,
destroy_server_retry_throttle_data, copy_server_retry_throttle_data};
//
// server_retry_throttle_map
//
static gpr_mu g_mu;
static gpr_avl g_avl;
void grpc_retry_throttle_map_init() {
gpr_mu_init(&g_mu);
g_avl = gpr_avl_create(&avl_vtable);
}
void grpc_retry_throttle_map_shutdown() {
gpr_mu_destroy(&g_mu);
gpr_avl_unref(g_avl);
}
grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
const char* server_name, int max_milli_tokens, int milli_token_ratio) {
gpr_mu_lock(&g_mu);
grpc_server_retry_throttle_data* throttle_data =
gpr_avl_get(g_avl, (char*)server_name);
if (throttle_data == NULL) {
// Entry not found. Create a new one.
throttle_data = grpc_server_retry_throttle_data_create(
max_milli_tokens, milli_token_ratio, NULL);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data);
} else {
if (throttle_data->max_milli_tokens != max_milli_tokens ||
throttle_data->milli_token_ratio != milli_token_ratio) {
// Entry found but with old parameters. Create a new one based on
// the original one.
throttle_data = grpc_server_retry_throttle_data_create(
max_milli_tokens, milli_token_ratio, throttle_data);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data);
} else {
// Entry found. Increase refcount.
grpc_server_retry_throttle_data_ref(throttle_data);
}
}
gpr_mu_unlock(&g_mu);
return throttle_data;
}

@ -0,0 +1,65 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H
#define GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H
#include <stdbool.h>
/// Tracks retry throttling data for an individual server name.
typedef struct grpc_server_retry_throttle_data grpc_server_retry_throttle_data;
/// Records a failure. Returns true if it's okay to send a retry.
bool grpc_server_retry_throttle_data_record_failure(
grpc_server_retry_throttle_data* throttle_data);
/// Records a success.
void grpc_server_retry_throttle_data_record_success(
grpc_server_retry_throttle_data* throttle_data);
grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_ref(
grpc_server_retry_throttle_data* throttle_data);
void grpc_server_retry_throttle_data_unref(
grpc_server_retry_throttle_data* throttle_data);
/// Initializes global map of failure data for each server name.
void grpc_retry_throttle_map_init();
/// Shuts down global map of failure data for each server name.
void grpc_retry_throttle_map_shutdown();
/// Returns a reference to the failure data for \a server_name, creating
/// a new entry if needed.
/// Caller must eventually unref via \a grpc_server_retry_throttle_data_unref().
grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
const char* server_name, int max_milli_tokens, int milli_token_ratio);
#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H */

@ -41,7 +41,6 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h" #include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/initial_connect_string.h"
#include "src/core/ext/client_channel/parse_address.h" #include "src/core/ext/client_channel/parse_address.h"
#include "src/core/ext/client_channel/proxy_mapper_registry.h" #include "src/core/ext/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/client_channel/subchannel_index.h" #include "src/core/ext/client_channel/subchannel_index.h"
@ -103,9 +102,6 @@ struct grpc_subchannel {
grpc_subchannel_key *key; grpc_subchannel_key *key;
/** initial string to send to peer */
grpc_slice initial_connect_string;
/** set during connection */ /** set during connection */
grpc_connect_out_args connecting_result; grpc_connect_out_args connecting_result;
@ -148,6 +144,7 @@ struct grpc_subchannel {
struct grpc_subchannel_call { struct grpc_subchannel_call {
grpc_connected_subchannel *connection; grpc_connected_subchannel *connection;
grpc_closure *schedule_closure_after_destroy;
}; };
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) #define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
@ -214,7 +211,6 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel *c = arg; grpc_subchannel *c = arg;
gpr_free((void *)c->filters); gpr_free((void *)c->filters);
grpc_channel_args_destroy(exec_ctx, c->args); grpc_channel_args_destroy(exec_ctx, c->args);
grpc_slice_unref_internal(exec_ctx, c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector); grpc_connector_unref(exec_ctx, c->connector);
grpc_pollset_set_destroy(exec_ctx, c->pollset_set); grpc_pollset_set_destroy(exec_ctx, c->pollset_set);
@ -273,8 +269,9 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->disconnected); GPR_ASSERT(!c->disconnected);
c->disconnected = true; c->disconnected = true;
grpc_connector_shutdown(exec_ctx, c->connector, grpc_connector_shutdown(
GRPC_ERROR_CREATE("Subchannel disconnected")); exec_ctx, c->connector,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Subchannel disconnected"));
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier); con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) { if (con != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection"); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
@ -332,7 +329,6 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
c->pollset_set = grpc_pollset_set_create(); c->pollset_set = grpc_pollset_set_create();
grpc_resolved_address *addr = gpr_malloc(sizeof(*addr)); grpc_resolved_address *addr = gpr_malloc(sizeof(*addr));
grpc_get_subchannel_address_arg(exec_ctx, args->args, addr); grpc_get_subchannel_address_arg(exec_ctx, args->args, addr);
grpc_set_initial_connect_string(&addr, &c->initial_connect_string);
grpc_resolved_address *new_address = NULL; grpc_resolved_address *new_address = NULL;
grpc_channel_args *new_args = NULL; grpc_channel_args *new_args = NULL;
if (grpc_proxy_mappers_map_address(exec_ctx, addr, args->args, &new_address, if (grpc_proxy_mappers_map_address(exec_ctx, addr, args->args, &new_address,
@ -340,17 +336,15 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(new_address != NULL); GPR_ASSERT(new_address != NULL);
gpr_free(addr); gpr_free(addr);
addr = new_address; addr = new_address;
if (new_args != NULL) c->args = new_args;
}
if (c->args == NULL) {
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
c->args = grpc_channel_args_copy_and_add_and_remove(
args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &new_arg,
1);
gpr_free(new_arg.value.string);
} }
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
gpr_free(addr); gpr_free(addr);
c->args = grpc_channel_args_copy_and_add_and_remove(
new_args != NULL ? new_args : args->args, keys_to_remove,
GPR_ARRAY_SIZE(keys_to_remove), &new_arg, 1);
gpr_free(new_arg.value.string);
if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args);
c->root_external_state_watcher.next = c->root_external_state_watcher.prev = c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
&c->root_external_state_watcher; &c->root_external_state_watcher;
grpc_closure_init(&c->connected, subchannel_connected, c, grpc_closure_init(&c->connected, subchannel_connected, c,
@ -405,7 +399,6 @@ static void continue_connect_locked(grpc_exec_ctx *exec_ctx,
args.interested_parties = c->pollset_set; args.interested_parties = c->pollset_set;
args.deadline = c->next_attempt; args.deadline = c->next_attempt;
args.channel_args = c->args; args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE, GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
@ -445,7 +438,8 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
c->have_alarm = false; c->have_alarm = false;
if (c->disconnected) { if (c->disconnected) {
error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1); error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected",
&error, 1);
} else { } else {
GRPC_ERROR_REF(error); GRPC_ERROR_REF(error);
} }
@ -696,9 +690,9 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
} else { } else {
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1), "Connect Failed", &error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
"connect_failed"); "connect_failed");
const char *errmsg = grpc_error_string(error); const char *errmsg = grpc_error_string(error);
@ -719,13 +713,22 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
grpc_error *error) { grpc_error *error) {
grpc_subchannel_call *c = call; grpc_subchannel_call *c = call;
GPR_ASSERT(c->schedule_closure_after_destroy != NULL);
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_connected_subchannel *connection = c->connection; grpc_connected_subchannel *connection = c->connection;
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL, c); grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), NULL,
c->schedule_closure_after_destroy);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call"); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
} }
void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call *call,
grpc_closure *closure) {
GPR_ASSERT(call->schedule_closure_after_destroy == NULL);
GPR_ASSERT(closure != NULL);
call->schedule_closure_after_destroy = closure;
}
void grpc_subchannel_call_ref( void grpc_subchannel_call_ref(
grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
@ -761,15 +764,22 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call( grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time, const grpc_connected_subchannel_call_args *args,
gpr_timespec deadline, grpc_subchannel_call **call) { grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
*call = gpr_zalloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); *call = gpr_arena_alloc(
args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call); grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
(*call)->connection = con; // Ref is added below. (*call)->connection = con; // Ref is added below.
grpc_error *error = const grpc_call_element_args call_args = {.call_stack = callstk,
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call, .server_transport_data = NULL,
NULL, NULL, path, start_time, deadline, callstk); .context = NULL,
.path = args->path,
.start_time = args->start_time,
.deadline = args->deadline,
.arena = args->arena};
grpc_error *error = grpc_call_stack_init(
exec_ctx, chanstk, 1, subchannel_call_destroy, *call, &call_args);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error); const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string); gpr_log(GPR_ERROR, "error: %s", error_string);
@ -778,7 +788,7 @@ grpc_error *grpc_connected_subchannel_create_call(
return error; return error;
} }
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, pollent); grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent);
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }

@ -37,6 +37,7 @@
#include "src/core/ext/client_channel/connector.h" #include "src/core/ext/client_channel/connector.h"
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/support/arena.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/metadata.h"
@ -112,10 +113,18 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** construct a subchannel call */ /** construct a subchannel call */
typedef struct {
grpc_polling_entity *pollent;
grpc_slice path;
gpr_timespec start_time;
gpr_timespec deadline;
gpr_arena *arena;
} grpc_connected_subchannel_call_args;
grpc_error *grpc_connected_subchannel_create_call( grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
grpc_polling_entity *pollent, grpc_slice path, gpr_timespec start_time, const grpc_connected_subchannel_call_args *args,
gpr_timespec deadline, grpc_subchannel_call **subchannel_call); grpc_subchannel_call **subchannel_call);
/** process a transport level op */ /** process a transport level op */
void grpc_connected_subchannel_process_transport_op( void grpc_connected_subchannel_process_transport_op(
@ -154,6 +163,11 @@ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *subchannel_call); grpc_subchannel_call *subchannel_call);
/** Must be called once per call. Sets the 'then_schedule_closure' argument for
call stack destruction. */
void grpc_subchannel_call_set_cleanup_closure(
grpc_subchannel_call *subchannel_call, grpc_closure *closure);
grpc_call_stack *grpc_subchannel_call_get_call_stack( grpc_call_stack *grpc_subchannel_call_get_call_stack(
grpc_subchannel_call *subchannel_call); grpc_subchannel_call *subchannel_call);

@ -925,7 +925,7 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
} }
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN, exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown"); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "glb_shutdown");
/* We need a copy of the lb_call pointer because we can't cancell the call /* We need a copy of the lb_call pointer because we can't cancell the call
* while holding glb_policy->mu: lb_on_server_status_received, invoked due to * while holding glb_policy->mu: lb_on_server_status_received, invoked due to
* the cancel, needs to acquire that same lock */ * the cancel, needs to acquire that same lock */
@ -965,9 +965,9 @@ static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
*target = NULL; *target = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1)); "Pick Cancelled", &error, 1));
} else { } else {
pp->next = glb_policy->pending_picks; pp->next = glb_policy->pending_picks;
glb_policy->pending_picks = pp; glb_policy->pending_picks = pp;
@ -989,9 +989,9 @@ static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx,
pending_pick *next = pp->next; pending_pick *next = pp->next;
if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) == if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) { initial_metadata_flags_eq) {
grpc_closure_sched( grpc_closure_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1)); "Pick Cancelled", &error, 1));
} else { } else {
pp->next = glb_policy->pending_picks; pp->next = glb_policy->pending_picks;
glb_policy->pending_picks = pp; glb_policy->pending_picks = pp;
@ -1023,10 +1023,10 @@ static int glb_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_closure *on_complete) { grpc_closure *on_complete) {
if (pick_args->lb_token_mdelem_storage == NULL) { if (pick_args->lb_token_mdelem_storage == NULL) {
*target = NULL; *target = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, on_complete,
exec_ctx, on_complete, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting " "No mdelem storage for the LB token. Load reporting "
"won't work without it. Failing")); "won't work without it. Failing"));
return 0; return 0;
} }

@ -101,7 +101,7 @@ static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
p->pending_picks = NULL; p->pending_picks = NULL;
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE("Channel shutdown"), "shutdown"); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"), "shutdown");
/* cancel subscription */ /* cancel subscription */
if (p->selected != NULL) { if (p->selected != NULL) {
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
@ -131,9 +131,9 @@ static void pf_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
*target = NULL; *target = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, pp->on_complete,
exec_ctx, pp->on_complete, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1)); "Pick Cancelled", &error, 1));
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -156,9 +156,9 @@ static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next; pending_pick *next = pp->next;
if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) { initial_metadata_flags_eq) {
grpc_closure_sched( grpc_closure_sched(exec_ctx, pp->on_complete,
exec_ctx, pp->on_complete, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1)); "Pick Cancelled", &error, 1));
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -325,8 +325,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (p->num_subchannels == 0) { if (p->num_subchannels == 0) {
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels", GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
&error, 1), "Pick first exhausted channels", &error, 1),
"no_more_channels"); "no_more_channels");
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
@ -373,7 +373,8 @@ static void pf_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if (p->selected) { if (p->selected) {
grpc_connected_subchannel_ping(exec_ctx, p->selected, closure); grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
} else { } else {
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected")); grpc_closure_sched(exec_ctx, closure,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
} }
} }
@ -423,11 +424,13 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
"This LB policy doesn't support user data. It will be ignored"); "This LB policy doesn't support user data. It will be ignored");
} }
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
memset(&sc_args, 0, sizeof(grpc_subchannel_args)); memset(&sc_args, 0, sizeof(grpc_subchannel_args));
grpc_arg addr_arg = grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address); grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args = grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1); args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
1);
gpr_free(addr_arg.value.string); gpr_free(addr_arg.value.string);
sc_args.args = new_args; sc_args.args = new_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(

@ -320,13 +320,14 @@ static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_closure_sched(exec_ctx, pp->on_complete, grpc_closure_sched(
GRPC_ERROR_CREATE("Channel Shutdown")); exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"));
gpr_free(pp); gpr_free(pp);
} }
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE("Channel Shutdown"), "rr_shutdown"); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "rr_shutdown");
for (i = 0; i < p->num_subchannels; i++) { for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i]; subchannel_data *sd = p->subchannels[i];
grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
@ -345,9 +346,9 @@ static void rr_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
*target = NULL; *target = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, pp->on_complete,
exec_ctx, pp->on_complete, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1)); "Pick cancelled", &error, 1));
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -371,9 +372,9 @@ static void rr_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) { initial_metadata_flags_eq) {
*pp->target = NULL; *pp->target = NULL;
grpc_closure_sched( grpc_closure_sched(exec_ctx, pp->on_complete,
exec_ctx, pp->on_complete, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1)); "Pick cancelled", &error, 1));
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -661,8 +662,8 @@ static void rr_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_connected_subchannel_ping(exec_ctx, target, closure); grpc_connected_subchannel_ping(exec_ctx, target, closure);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked"); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked");
} else { } else {
grpc_closure_sched(exec_ctx, closure, grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Round Robin not connected")); "Round Robin not connected"));
} }
} }
@ -709,11 +710,13 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
/* Skip balancer addresses, since we only know how to handle backends. */ /* Skip balancer addresses, since we only know how to handle backends. */
if (addresses->addresses[i].is_balancer) continue; if (addresses->addresses[i].is_balancer) continue;
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
memset(&sc_args, 0, sizeof(grpc_subchannel_args)); memset(&sc_args, 0, sizeof(grpc_subchannel_args));
grpc_arg addr_arg = grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address); grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args = grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1); args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
1);
gpr_free(addr_arg.value.string); gpr_free(addr_arg.value.string);
sc_args.args = new_args; sc_args.args = new_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(

@ -78,8 +78,8 @@ static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md)); GRPC_MDVALUE(calld->recv_initial_metadata->idx.named.path->md));
calld->have_service_method = true; calld->have_service_method = true;
} else { } else {
err = err = grpc_error_add_child(
grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header")); err, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing :path header"));
} }
if (calld->recv_initial_metadata->idx.named.lb_token != NULL) { if (calld->recv_initial_metadata->idx.named.lb_token != NULL) {
calld->initial_md_string = grpc_slice_ref_internal( calld->initial_md_string = grpc_slice_ref_internal(
@ -123,7 +123,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */ /* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
/* TODO(dgq): do something with the data /* TODO(dgq): do something with the data

@ -113,8 +113,9 @@ static void dns_shutdown_locked(grpc_exec_ctx *exec_ctx,
} }
if (r->next_completion != NULL) { if (r->next_completion != NULL) {
*r->target_result = NULL; *r->target_result = NULL;
grpc_closure_sched(exec_ctx, r->next_completion, grpc_closure_sched(
GRPC_ERROR_CREATE("Resolver Shutdown")); exec_ctx, r->next_completion,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown"));
r->next_completion = NULL; r->next_completion = NULL;
} }
} }

@ -63,8 +63,6 @@ typedef struct {
grpc_closure *notify; grpc_closure *notify;
grpc_connect_in_args args; grpc_connect_in_args args;
grpc_connect_out_args *result; grpc_connect_out_args *result;
grpc_closure initial_string_sent;
grpc_slice_buffer initial_string_buffer;
grpc_endpoint *endpoint; // Non-NULL until handshaking starts. grpc_endpoint *endpoint; // Non-NULL until handshaking starts.
@ -82,7 +80,6 @@ static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx,
grpc_connector *con) { grpc_connector *con) {
chttp2_connector *c = (chttp2_connector *)con; chttp2_connector *c = (chttp2_connector *)con;
if (gpr_unref(&c->refs)) { if (gpr_unref(&c->refs)) {
/* c->initial_string_buffer does not need to be destroyed */
gpr_mu_destroy(&c->mu); gpr_mu_destroy(&c->mu);
// If handshaking is not yet in progress, destroy the endpoint. // If handshaking is not yet in progress, destroy the endpoint.
// Otherwise, the handshaker will do this for us. // Otherwise, the handshaker will do this for us.
@ -116,7 +113,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
if (error != GRPC_ERROR_NONE || c->shutdown) { if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown");
// We were shut down after handshaking completed successfully, so // We were shut down after handshaking completed successfully, so
// destroy the endpoint here. // destroy the endpoint here.
// TODO(ctiller): It is currently necessary to shutdown endpoints // TODO(ctiller): It is currently necessary to shutdown endpoints
@ -160,28 +157,6 @@ static void start_handshake_locked(grpc_exec_ctx *exec_ctx,
c->endpoint = NULL; // Endpoint handed off to handshake manager. c->endpoint = NULL; // Endpoint handed off to handshake manager.
} }
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
chttp2_connector *c = arg;
gpr_mu_lock(&c->mu);
if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown");
} else {
error = GRPC_ERROR_REF(error);
}
memset(c->result, 0, sizeof(*c->result));
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_closure_sched(exec_ctx, notify, error);
gpr_mu_unlock(&c->mu);
chttp2_connector_unref(exec_ctx, arg);
} else {
start_handshake_locked(exec_ctx, c);
gpr_mu_unlock(&c->mu);
}
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
chttp2_connector *c = arg; chttp2_connector *c = arg;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
@ -189,7 +164,7 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
c->connecting = false; c->connecting = false;
if (error != GRPC_ERROR_NONE || c->shutdown) { if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown");
} else { } else {
error = GRPC_ERROR_REF(error); error = GRPC_ERROR_REF(error);
} }
@ -204,17 +179,7 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
chttp2_connector_unref(exec_ctx, arg); chttp2_connector_unref(exec_ctx, arg);
} else { } else {
GPR_ASSERT(c->endpoint != NULL); GPR_ASSERT(c->endpoint != NULL);
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) { start_handshake_locked(exec_ctx, c);
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c, grpc_schedule_on_exec_ctx);
grpc_slice_buffer_init(&c->initial_string_buffer);
grpc_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer,
&c->initial_string_sent);
} else {
start_handshake_locked(exec_ctx, c);
}
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
} }
} }

@ -256,7 +256,7 @@ grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
char *msg; char *msg;
gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved", gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
naddrs); naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs);
gpr_free(msg); gpr_free(msg);
goto error; goto error;
} else if (count != naddrs) { } else if (count != naddrs) {
@ -264,7 +264,7 @@ grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&msg, "Only %" PRIuPTR gpr_asprintf(&msg, "Only %" PRIuPTR
" addresses added out of total %" PRIuPTR " resolved", " addresses added out of total %" PRIuPTR " resolved",
count, naddrs); count, naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs); err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs);
gpr_free(msg); gpr_free(msg);
const char *warning_message = grpc_error_string(err); const char *warning_message = grpc_error_string(err);

@ -61,7 +61,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
3, (server, addr, creds)); 3, (server, addr, creds));
// Create security context. // Create security context.
if (creds == NULL) { if (creds == NULL) {
err = GRPC_ERROR_CREATE( err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No credentials specified for secure server port (creds==NULL)"); "No credentials specified for secure server port (creds==NULL)");
goto done; goto done;
} }
@ -72,7 +72,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
gpr_asprintf(&msg, gpr_asprintf(&msg,
"Unable to create secure server with credentials of type %s.", "Unable to create secure server with credentials of type %s.",
creds->type); creds->type);
err = grpc_error_set_int(GRPC_ERROR_CREATE(msg), err = grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status); GRPC_ERROR_INT_SECURITY_STATUS, status);
gpr_free(msg); gpr_free(msg);
goto done; goto done;

@ -187,7 +187,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
GRPC_COMBINER_UNREF(exec_ctx, t->combiner, "chttp2_transport"); GRPC_COMBINER_UNREF(exec_ctx, t->combiner, "chttp2_transport");
cancel_pings(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed")); cancel_pings(exec_ctx, t,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"));
while (t->write_cb_pool) { while (t->write_cb_pool) {
grpc_chttp2_write_cb *next = t->write_cb_pool->next; grpc_chttp2_write_cb *next = t->write_cb_pool->next;
@ -494,8 +495,9 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp,
t->destroying = 1; t->destroying = 1;
close_transport_locked( close_transport_locked(
exec_ctx, t, exec_ctx, t,
grpc_error_set_int(GRPC_ERROR_CREATE("Transport destroyed"), grpc_error_set_int(
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state)); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport destroyed"),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state));
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destroy"); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destroy");
} }
@ -518,7 +520,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) { if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) {
if (t->close_transport_on_writes_finished == NULL) { if (t->close_transport_on_writes_finished == NULL) {
t->close_transport_on_writes_finished = t->close_transport_on_writes_finished =
GRPC_ERROR_CREATE("Delayed close due to in-progress write"); GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Delayed close due to in-progress write");
} }
t->close_transport_on_writes_finished = t->close_transport_on_writes_finished =
grpc_error_add_child(t->close_transport_on_writes_finished, error); grpc_error_add_child(t->close_transport_on_writes_finished, error);
@ -575,7 +578,7 @@ void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) {
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount, grpc_stream *gs, grpc_stream_refcount *refcount,
const void *server_data) { const void *server_data, gpr_arena *arena) {
GPR_TIMER_BEGIN("init_stream", 0); GPR_TIMER_BEGIN("init_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
@ -588,8 +591,8 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
gpr_ref_init(&s->active_streams, 1); gpr_ref_init(&s->active_streams, 1);
GRPC_CHTTP2_STREAM_REF(s, "chttp2"); GRPC_CHTTP2_STREAM_REF(s, "chttp2");
grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]); grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena);
grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]); grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1], arena);
grpc_chttp2_data_parser_init(&s->data_parser); grpc_chttp2_data_parser_init(&s->data_parser);
grpc_slice_buffer_init(&s->flow_controlled_buffer); grpc_slice_buffer_init(&s->flow_controlled_buffer);
s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
@ -665,16 +668,17 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
GPR_TIMER_END("destroy_stream", 0); GPR_TIMER_END("destroy_stream", 0);
gpr_free(s->destroy_stream_arg); grpc_closure_sched(exec_ctx, s->destroy_stream_arg, GRPC_ERROR_NONE);
} }
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, void *and_free_memory) { grpc_stream *gs,
grpc_closure *then_schedule_closure) {
GPR_TIMER_BEGIN("destroy_stream", 0); GPR_TIMER_BEGIN("destroy_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
s->destroy_stream_arg = and_free_memory; s->destroy_stream_arg = then_schedule_closure;
grpc_closure_sched( grpc_closure_sched(
exec_ctx, grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s, exec_ctx, grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s,
grpc_combiner_scheduler(t->combiner, false)), grpc_combiner_scheduler(t->combiner, false)),
@ -833,7 +837,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED) { if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SENT; t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SENT;
if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) { if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE("goaway sent")); close_transport_locked(
exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("goaway sent"));
} }
} }
@ -897,22 +902,19 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
uint32_t goaway_error, uint32_t goaway_error,
grpc_slice goaway_text) { grpc_slice goaway_text) {
char *msg = grpc_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); // GRPC_CHTTP2_IF_TRACING(
GRPC_CHTTP2_IF_TRACING( // gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
grpc_slice_unref_internal(exec_ctx, goaway_text);
t->seen_goaway = 1; t->seen_goaway = 1;
/* lie: use transient failure from the transport to indicate goaway has been /* lie: use transient failure from the transport to indicate goaway has been
* received */ * received */
connectivity_state_set( connectivity_state_set(
exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_str( grpc_error_set_str(
grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"), grpc_error_set_int(
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
(intptr_t)goaway_error), GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)goaway_error),
GRPC_ERROR_STR_RAW_BYTES, msg), GRPC_ERROR_STR_RAW_BYTES, goaway_text),
"got_goaway"); "got_goaway");
gpr_free(msg);
} }
static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
@ -935,9 +937,10 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
t->next_stream_id += 2; t->next_stream_id += 2;
if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) { if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) {
connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, connectivity_state_set(
GRPC_ERROR_CREATE("Stream IDs exhausted"), exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
"no_more_stream_ids"); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"),
"no_more_stream_ids");
} }
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
@ -951,9 +954,9 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) { grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) {
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"), grpc_error_set_int(
GRPC_ERROR_INT_GRPC_STATUS, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"),
GRPC_STATUS_UNAVAILABLE)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
} }
} }
@ -1002,11 +1005,11 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
} }
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
if (closure->error_data.error == GRPC_ERROR_NONE) { if (closure->error_data.error == GRPC_ERROR_NONE) {
closure->error_data.error = closure->error_data.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Error in HTTP transport completing operation"); "Error in HTTP transport completing operation");
closure->error_data.error = closure->error_data.error = grpc_error_set_str(
grpc_error_set_str(closure->error_data.error, closure->error_data.error, GRPC_ERROR_STR_TARGET_ADDRESS,
GRPC_ERROR_STR_TARGET_ADDRESS, t->peer_string); grpc_slice_from_copied_string(t->peer_string));
} }
closure->error_data.error = closure->error_data.error =
grpc_error_add_child(closure->error_data.error, error); grpc_error_add_child(closure->error_data.error, error);
@ -1181,10 +1184,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("to-be-sent initial metadata size " "to-be-sent initial metadata size "
"exceeds peer limit"), "exceeds peer limit"),
GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size), GRPC_ERROR_INT_SIZE,
(intptr_t)metadata_size),
GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
} else { } else {
@ -1200,9 +1204,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} else { } else {
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int(GRPC_ERROR_CREATE("Transport closed"), grpc_error_set_int(
GRPC_ERROR_INT_GRPC_STATUS, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"),
GRPC_STATUS_UNAVAILABLE)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
} }
} else { } else {
GPR_ASSERT(s->id != 0); GPR_ASSERT(s->id != 0);
@ -1214,7 +1218,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
s->send_initial_metadata = NULL; s->send_initial_metadata = NULL;
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->send_initial_metadata_finished, exec_ctx, t, s, &s->send_initial_metadata_finished,
GRPC_ERROR_CREATE_REFERENCING( GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Attempt to send initial metadata after stream was closed", "Attempt to send initial metadata after stream was closed",
&s->write_closed_error, 1), &s->write_closed_error, 1),
"send_initial_metadata_finished"); "send_initial_metadata_finished");
@ -1228,7 +1232,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (s->write_closed) { if (s->write_closed) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->fetching_send_message_finished, exec_ctx, t, s, &s->fetching_send_message_finished,
GRPC_ERROR_CREATE_REFERENCING( GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Attempt to send message after stream was closed", "Attempt to send message after stream was closed",
&s->write_closed_error, 1), &s->write_closed_error, 1),
"fetching_send_message_finished"); "fetching_send_message_finished");
@ -1276,10 +1280,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("to-be-sent trailing metadata size " "to-be-sent trailing metadata size "
"exceeds peer limit"), "exceeds peer limit"),
GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size), GRPC_ERROR_INT_SIZE,
(intptr_t)metadata_size),
GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
} else { } else {
@ -1292,8 +1297,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s, &s->send_trailing_metadata_finished, exec_ctx, t, s, &s->send_trailing_metadata_finished,
grpc_metadata_batch_is_empty(op->send_trailing_metadata) grpc_metadata_batch_is_empty(op->send_trailing_metadata)
? GRPC_ERROR_NONE ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("Attempt to send trailing metadata after " : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"stream was closed"), "Attempt to send trailing metadata after "
"stream was closed"),
"send_trailing_metadata_finished"); "send_trailing_metadata_finished");
} else if (s->id != 0) { } else if (s->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding /* TODO(ctiller): check if there's flow control for any outstanding
@ -1408,11 +1414,11 @@ static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error) { grpc_error *error) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED; t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
grpc_http2_error_code http_error; grpc_http2_error_code http_error;
const char *msg; grpc_slice slice;
grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL, &msg, grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL,
&http_error); &slice, &http_error);
grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error, grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
grpc_slice_from_copied_string(msg), &t->qbuf); grpc_slice_ref_internal(slice), &t->qbuf);
grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent"); grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }
@ -1572,7 +1578,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SENT) { if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SENT) {
close_transport_locked( close_transport_locked(
exec_ctx, t, exec_ctx, t,
GRPC_ERROR_CREATE_REFERENCING( GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Last stream closed after sending GOAWAY", &error, 1)); "Last stream closed after sending GOAWAY", &error, 1));
} }
} }
@ -1613,8 +1619,8 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error) { grpc_chttp2_stream *s, grpc_error *error) {
grpc_status_code status; grpc_status_code status;
const char *msg; grpc_slice slice;
grpc_error_get_status(error, s->deadline, &status, &msg, NULL); grpc_error_get_status(error, s->deadline, &status, &slice, NULL);
if (status != GRPC_STATUS_OK) { if (status != GRPC_STATUS_OK) {
s->seen_error = true; s->seen_error = true;
@ -1629,15 +1635,19 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
s->recv_trailing_metadata_finished != NULL) { s->recv_trailing_metadata_finished != NULL) {
char status_string[GPR_LTOA_MIN_BUFSIZE]; char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string); gpr_ltoa(status, status_string);
grpc_chttp2_incoming_metadata_buffer_replace_or_add( GRPC_LOG_IF_ERROR("add_status",
exec_ctx, &s->metadata_buffer[1], grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS, exec_ctx, &s->metadata_buffer[1],
grpc_slice_from_copied_string(status_string))); grpc_mdelem_from_slices(
if (msg != NULL) { exec_ctx, GRPC_MDSTR_GRPC_STATUS,
grpc_chttp2_incoming_metadata_buffer_replace_or_add( grpc_slice_from_copied_string(status_string))));
exec_ctx, &s->metadata_buffer[1], if (!GRPC_SLICE_IS_EMPTY(slice)) {
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE, GRPC_LOG_IF_ERROR(
grpc_slice_from_copied_string(msg))); "add_status_message",
grpc_chttp2_incoming_metadata_buffer_replace_or_add(
exec_ctx, &s->metadata_buffer[1],
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
grpc_slice_ref_internal(slice))));
} }
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE; s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
@ -1666,7 +1676,8 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s,
add_error(extra_error, refs, &nrefs); add_error(extra_error, refs, &nrefs);
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
if (nrefs > 0) { if (nrefs > 0) {
error = GRPC_ERROR_CREATE_REFERENCING(master_error_msg, refs, nrefs); error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(master_error_msg,
refs, nrefs);
} }
GRPC_ERROR_UNREF(extra_error); GRPC_ERROR_UNREF(extra_error);
return error; return error;
@ -1760,12 +1771,13 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error) { grpc_chttp2_stream *s, grpc_error *error) {
grpc_slice hdr; grpc_slice hdr;
grpc_slice status_hdr; grpc_slice status_hdr;
grpc_slice http_status_hdr;
grpc_slice message_pfx; grpc_slice message_pfx;
uint8_t *p; uint8_t *p;
uint32_t len = 0; uint32_t len = 0;
grpc_status_code grpc_status; grpc_status_code grpc_status;
const char *msg; grpc_slice slice;
grpc_error_get_status(error, s->deadline, &grpc_status, &msg, NULL); grpc_error_get_status(error, s->deadline, &grpc_status, &slice, NULL);
GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100); GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
@ -1775,6 +1787,26 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
It's complicated by the fact that our send machinery would be dead by It's complicated by the fact that our send machinery would be dead by
the time we got around to sending this, so instead we ignore HPACK the time we got around to sending this, so instead we ignore HPACK
compression and just write the uncompressed bytes onto the wire. */ compression and just write the uncompressed bytes onto the wire. */
if (!s->sent_initial_metadata) {
http_status_hdr = grpc_slice_malloc(13);
p = GRPC_SLICE_START_PTR(http_status_hdr);
*p++ = 0x00;
*p++ = 7;
*p++ = ':';
*p++ = 's';
*p++ = 't';
*p++ = 'a';
*p++ = 't';
*p++ = 'u';
*p++ = 's';
*p++ = 3;
*p++ = '2';
*p++ = '0';
*p++ = '0';
GPR_ASSERT(p == GRPC_SLICE_END_PTR(http_status_hdr));
len += (uint32_t)GRPC_SLICE_LENGTH(http_status_hdr);
}
status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10)); status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
p = GRPC_SLICE_START_PTR(status_hdr); p = GRPC_SLICE_START_PTR(status_hdr);
*p++ = 0x00; /* literal header, not indexed */ *p++ = 0x00; /* literal header, not indexed */
@ -1801,32 +1833,30 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr)); GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr); len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
if (msg != NULL) { size_t msg_len = GRPC_SLICE_LENGTH(slice);
size_t msg_len = strlen(msg); GPR_ASSERT(msg_len <= UINT32_MAX);
GPR_ASSERT(msg_len <= UINT32_MAX); uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 1);
uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0); message_pfx = grpc_slice_malloc(14 + msg_len_len);
message_pfx = grpc_slice_malloc(14 + msg_len_len); p = GRPC_SLICE_START_PTR(message_pfx);
p = GRPC_SLICE_START_PTR(message_pfx); *p++ = 0x00; /* literal header, not indexed */
*p++ = 0x00; /* literal header, not indexed */ *p++ = 12; /* len(grpc-message) */
*p++ = 12; /* len(grpc-message) */ *p++ = 'g';
*p++ = 'g'; *p++ = 'r';
*p++ = 'r'; *p++ = 'p';
*p++ = 'p'; *p++ = 'c';
*p++ = 'c'; *p++ = '-';
*p++ = '-'; *p++ = 'm';
*p++ = 'm'; *p++ = 'e';
*p++ = 'e'; *p++ = 's';
*p++ = 's'; *p++ = 's';
*p++ = 's'; *p++ = 'a';
*p++ = 'a'; *p++ = 'g';
*p++ = 'g'; *p++ = 'e';
*p++ = 'e'; GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 1, 0, p, (uint32_t)msg_len_len);
GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, (uint32_t)msg_len_len); p += msg_len_len;
p += msg_len_len; GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); len += (uint32_t)msg_len;
len += (uint32_t)msg_len;
}
hdr = grpc_slice_malloc(9); hdr = grpc_slice_malloc(9);
p = GRPC_SLICE_START_PTR(hdr); p = GRPC_SLICE_START_PTR(hdr);
@ -1842,11 +1872,12 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr)); GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
grpc_slice_buffer_add(&t->qbuf, hdr); grpc_slice_buffer_add(&t->qbuf, hdr);
grpc_slice_buffer_add(&t->qbuf, status_hdr); if (!s->sent_initial_metadata) {
if (msg != NULL) { grpc_slice_buffer_add(&t->qbuf, http_status_hdr);
grpc_slice_buffer_add(&t->qbuf, message_pfx);
grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg));
} }
grpc_slice_buffer_add(&t->qbuf, status_hdr);
grpc_slice_buffer_add(&t->qbuf, message_pfx);
grpc_slice_buffer_add(&t->qbuf, grpc_slice_ref_internal(slice));
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR, &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
@ -1921,9 +1952,9 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
if (parse_error == GRPC_ERROR_NONE && if (parse_error == GRPC_ERROR_NONE &&
(parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) { (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
error = grpc_error_set_int( error = grpc_error_set_int(
grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Trying to connect an http1.x server"), "Trying to connect an http1.x server"),
GRPC_ERROR_INT_HTTP_STATUS, response.status), GRPC_ERROR_INT_HTTP_STATUS, response.status),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
} }
GRPC_ERROR_UNREF(parse_error); GRPC_ERROR_UNREF(parse_error);
@ -1944,9 +1975,10 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *err = error; grpc_error *err = error;
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
err = grpc_error_set_int( err = grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("Endpoint read failed", &err, 1), "Endpoint read failed", &err, 1),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state); GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
t->write_state);
} }
GPR_SWAP(grpc_error *, err, error); GPR_SWAP(grpc_error *, err, error);
GRPC_ERROR_UNREF(err); GRPC_ERROR_UNREF(err);
@ -1967,8 +1999,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (errors[1] != GRPC_ERROR_NONE) { if (errors[1] != GRPC_ERROR_NONE) {
errors[2] = try_http_parsing(exec_ctx, t); errors[2] = try_http_parsing(exec_ctx, t);
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors, error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GPR_ARRAY_SIZE(errors)); "Failed parsing HTTP/2", errors, GPR_ARRAY_SIZE(errors));
} }
for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) { for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
GRPC_ERROR_UNREF(errors[i]); GRPC_ERROR_UNREF(errors[i]);
@ -1993,7 +2025,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_BEGIN("post_reading_action_locked", 0); GPR_TIMER_BEGIN("post_reading_action_locked", 0);
bool keep_reading = false; bool keep_reading = false;
if (error == GRPC_ERROR_NONE && t->closed) { if (error == GRPC_ERROR_NONE && t->closed) {
error = GRPC_ERROR_CREATE("Transport closed"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed");
} }
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
@ -2128,8 +2160,8 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
close_transport_locked(exec_ctx, t, close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("keepalive watchdog timeout")); "keepalive watchdog timeout"));
} }
} else { } else {
/** The watchdog timer should have been cancelled by /** The watchdog timer should have been cancelled by
@ -2328,7 +2360,8 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&bs->slice_mu); gpr_mu_lock(&bs->slice_mu);
if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) { if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) {
incoming_byte_stream_publish_error( incoming_byte_stream_publish_error(
exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream")); exec_ctx, bs,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream"));
} else { } else {
bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice); bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
if (bs->on_next != NULL) { if (bs->on_next != NULL) {
@ -2348,7 +2381,7 @@ void grpc_chttp2_incoming_byte_stream_finished(
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
gpr_mu_lock(&bs->slice_mu); gpr_mu_lock(&bs->slice_mu);
if (bs->remaining_bytes != 0) { if (bs->remaining_bytes != 0) {
error = GRPC_ERROR_CREATE("Truncated message"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
} }
gpr_mu_unlock(&bs->slice_mu); gpr_mu_unlock(&bs->slice_mu);
} }
@ -2428,9 +2461,9 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
t->peer_string); t->peer_string);
} }
send_goaway(exec_ctx, t, send_goaway(exec_ctx, t,
grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"), grpc_error_set_int(
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"),
GRPC_HTTP2_ENHANCE_YOUR_CALM)); GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
} else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) { } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
@ -2457,9 +2490,10 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
s->id); s->id);
} }
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"), exec_ctx, t, s,
GRPC_ERROR_INT_HTTP2_ERROR, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"),
GRPC_HTTP2_ENHANCE_YOUR_CALM)); GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_ENHANCE_YOUR_CALM));
if (n > 1) { if (n > 1) {
/* Since we cancel one stream per destructive reclamation, if /* Since we cancel one stream per destructive reclamation, if
there are more streams left, we can immediately post a new there are more streams left, we can immediately post a new

@ -54,7 +54,8 @@ void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser) { grpc_chttp2_data_parser *parser) {
if (parser->parsing_frame != NULL) { if (parser->parsing_frame != NULL) {
grpc_chttp2_incoming_byte_stream_finished( grpc_chttp2_incoming_byte_stream_finished(
exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed")); exec_ctx, parser->parsing_frame,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"));
} }
GRPC_ERROR_UNREF(parser->error); GRPC_ERROR_UNREF(parser->error);
} }
@ -65,8 +66,9 @@ grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
char *msg; char *msg;
gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags); gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
grpc_error *err = grpc_error_set_int( grpc_error *err =
GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id); grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg),
GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -173,13 +175,13 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
break; break;
default: default:
gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type); gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
p->error = GRPC_ERROR_CREATE(msg); p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
(intptr_t)s->id); (intptr_t)s->id);
gpr_free(msg); gpr_free(msg);
msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
p->error = p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg); grpc_slice_from_copied_string(msg));
gpr_free(msg); gpr_free(msg);
p->error = p->error =
grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg); grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
@ -265,7 +267,8 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
} }
} }
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); GPR_UNREACHABLE_CODE(
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
} }
grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,

@ -54,7 +54,7 @@ grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p,
if (length < 8) { if (length < 8) {
char *msg; char *msg;
gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length); gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -156,7 +156,8 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); GPR_UNREACHABLE_CODE(
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
} }
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,

@ -71,7 +71,7 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
if (flags & 0xfe || length != 8) { if (flags & 0xfe || length != 8) {
char *msg; char *msg;
gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags); gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags);
grpc_error *error = GRPC_ERROR_CREATE(msg); grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return error; return error;
} }

@ -76,7 +76,7 @@ grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
char *msg; char *msg;
gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length, gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length,
flags); flags);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -112,8 +112,9 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
char *message; char *message;
gpr_asprintf(&message, "Received RST_STREAM with error code %d", reason); gpr_asprintf(&message, "Received RST_STREAM with error code %d", reason);
error = grpc_error_set_int( error = grpc_error_set_int(
grpc_error_set_str(GRPC_ERROR_CREATE("RST_STREAM"), grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"),
GRPC_ERROR_STR_GRPC_MESSAGE, message), GRPC_ERROR_STR_GRPC_MESSAGE,
grpc_slice_from_copied_string(message)),
GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason); GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason);
gpr_free(message); gpr_free(message);
} }

@ -131,13 +131,16 @@ grpc_error *grpc_chttp2_settings_parser_begin_frame(
if (flags == GRPC_CHTTP2_FLAG_ACK) { if (flags == GRPC_CHTTP2_FLAG_ACK) {
parser->is_ack = 1; parser->is_ack = 1;
if (length != 0) { if (length != 0) {
return GRPC_ERROR_CREATE("non-empty settings ack frame received"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"non-empty settings ack frame received");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} else if (flags != 0) { } else if (flags != 0) {
return GRPC_ERROR_CREATE("invalid flags on settings frame"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"invalid flags on settings frame");
} else if (length % 6 != 0) { } else if (length % 6 != 0) {
return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"settings frames must be a multiple of six bytes");
} else { } else {
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -229,7 +232,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
&t->qbuf); &t->qbuf);
gpr_asprintf(&msg, "invalid value %u passed for %s", gpr_asprintf(&msg, "invalid value %u passed for %s",
parser->value, sp->name); parser->value, sp->name);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }

@ -70,7 +70,7 @@ grpc_error *grpc_chttp2_window_update_parser_begin_frame(
char *msg; char *msg;
gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length, gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length,
flags); flags);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -102,7 +102,7 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
if (received_update == 0 || (received_update & 0x80000000u)) { if (received_update == 0 || (received_update & 0x80000000u)) {
char *msg; char *msg;
gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount); gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }

@ -693,7 +693,7 @@ static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
} }
if (p->on_header == NULL) { if (p->on_header == NULL) {
GRPC_MDELEM_UNREF(exec_ctx, md); GRPC_MDELEM_UNREF(exec_ctx, md);
return GRPC_ERROR_CREATE("on_header callback not set"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("on_header callback not set");
} }
p->on_header(exec_ctx, p->on_header_user_data, md); p->on_header(exec_ctx, p->on_header_user_data, md);
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
@ -810,7 +810,8 @@ static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
if (GRPC_MDISNULL(md)) { if (GRPC_MDISNULL(md)) {
return grpc_error_set_int( return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"), grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index), GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
} }
@ -1074,7 +1075,7 @@ static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx,
if (p->dynamic_table_update_allowed == 0) { if (p->dynamic_table_update_allowed == 0) {
return parse_error( return parse_error(
exec_ctx, p, cur, end, exec_ctx, p, cur, end,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"More than two max table size changes in a single frame")); "More than two max table size changes in a single frame"));
} }
p->dynamic_table_update_allowed--; p->dynamic_table_update_allowed--;
@ -1092,7 +1093,7 @@ static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx,
if (p->dynamic_table_update_allowed == 0) { if (p->dynamic_table_update_allowed == 0) {
return parse_error( return parse_error(
exec_ctx, p, cur, end, exec_ctx, p, cur, end,
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"More than two max table size changes in a single frame")); "More than two max table size changes in a single frame"));
} }
p->dynamic_table_update_allowed--; p->dynamic_table_update_allowed--;
@ -1126,7 +1127,7 @@ static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(cur != end); GPR_ASSERT(cur != end);
char *msg; char *msg;
gpr_asprintf(&msg, "Illegal hpack op code %d", *cur); gpr_asprintf(&msg, "Illegal hpack op code %d", *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(exec_ctx, p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
@ -1246,7 +1247,7 @@ error:
"integer overflow in hpack integer decoding: have 0x%08x, " "integer overflow in hpack integer decoding: have 0x%08x, "
"got byte 0x%02x on byte 5", "got byte 0x%02x on byte 5",
*p->parsing.value, *cur); *p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(exec_ctx, p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
@ -1275,7 +1276,7 @@ static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx,
"integer overflow in hpack integer decoding: have 0x%08x, " "integer overflow in hpack integer decoding: have 0x%08x, "
"got byte 0x%02x sometime after byte 5", "got byte 0x%02x sometime after byte 5",
*p->parsing.value, *cur); *p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(exec_ctx, p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
@ -1333,8 +1334,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(exec_ctx, p, cur, end, return parse_error(
GRPC_ERROR_CREATE("Illegal base64 character")); exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte0; goto b64_byte0;
p->base64_buffer = bits << 18; p->base64_buffer = bits << 18;
@ -1348,8 +1350,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(exec_ctx, p, cur, end, return parse_error(
GRPC_ERROR_CREATE("Illegal base64 character")); exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte1; goto b64_byte1;
p->base64_buffer |= bits << 12; p->base64_buffer |= bits << 12;
@ -1363,8 +1366,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(exec_ctx, p, cur, end, return parse_error(
GRPC_ERROR_CREATE("Illegal base64 character")); exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte2; goto b64_byte2;
p->base64_buffer |= bits << 6; p->base64_buffer |= bits << 6;
@ -1378,8 +1382,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur]; bits = inverse_base64[*cur];
++cur; ++cur;
if (bits == 255) if (bits == 255)
return parse_error(exec_ctx, p, cur, end, return parse_error(
GRPC_ERROR_CREATE("Illegal base64 character")); exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64) else if (bits == 64)
goto b64_byte3; goto b64_byte3;
p->base64_buffer |= bits; p->base64_buffer |= bits;
@ -1391,7 +1396,8 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
goto b64_byte0; goto b64_byte0;
} }
GPR_UNREACHABLE_CODE(return parse_error( GPR_UNREACHABLE_CODE(return parse_error(
exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here"))); exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here")));
} }
static grpc_error *finish_str(grpc_exec_ctx *exec_ctx, static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
@ -1406,16 +1412,16 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
case B64_BYTE0: case B64_BYTE0:
break; break;
case B64_BYTE1: case B64_BYTE1:
return parse_error( return parse_error(exec_ctx, p, cur, end,
exec_ctx, p, cur, end, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */ "illegal base64 encoding")); /* illegal encoding */
case B64_BYTE2: case B64_BYTE2:
bits = p->base64_buffer; bits = p->base64_buffer;
if (bits & 0xffff) { if (bits & 0xffff) {
char *msg; char *msg;
gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x", gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x",
bits & 0xffff); bits & 0xffff);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(exec_ctx, p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
@ -1428,7 +1434,7 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
char *msg; char *msg;
gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x", gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x",
bits & 0xff); bits & 0xff);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return parse_error(exec_ctx, p, cur, end, err); return parse_error(exec_ctx, p, cur, end, err);
} }
@ -1550,7 +1556,8 @@ static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index); grpc_mdelem elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
if (GRPC_MDISNULL(elem)) { if (GRPC_MDISNULL(elem)) {
return grpc_error_set_int( return grpc_error_set_int(
grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"), grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Invalid HPACK index received"),
GRPC_ERROR_INT_INDEX, (intptr_t)p->index), GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
} }
@ -1620,13 +1627,18 @@ void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx, grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_parser *p, grpc_chttp2_hpack_parser *p,
grpc_slice slice) { grpc_slice slice) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple /* max number of bytes to parse at a time... limits call stack depth on
steps in the event of a large chunk of data to limit * compilers without TCO */
stack space usage when no tail call optimization is #define MAX_PARSE_LENGTH 1024
available */
p->current_slice_refcount = slice.refcount; p->current_slice_refcount = slice.refcount;
grpc_error *error = p->state(exec_ctx, p, GRPC_SLICE_START_PTR(slice), uint8_t *start = GRPC_SLICE_START_PTR(slice);
GRPC_SLICE_END_PTR(slice)); uint8_t *end = GRPC_SLICE_END_PTR(slice);
grpc_error *error = GRPC_ERROR_NONE;
while (start != end && error == GRPC_ERROR_NONE) {
uint8_t *target = start + GPR_MIN(MAX_PARSE_LENGTH, end - start);
error = p->state(exec_ctx, p, start, target);
start = target;
}
p->current_slice_refcount = NULL; p->current_slice_refcount = NULL;
return error; return error;
} }
@ -1670,7 +1682,7 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
if (is_last) { if (is_last) {
if (parser->is_boundary && parser->state != parse_begin) { if (parser->is_boundary && parser->state != parse_begin) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return GRPC_ERROR_CREATE( return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"end of header frame not aligned with a hpack record boundary"); "end of header frame not aligned with a hpack record boundary");
} }
/* need to check for null stream: this can occur if we receive an invalid /* need to check for null stream: this can occur if we receive an invalid
@ -1678,7 +1690,8 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
if (s != NULL) { if (s != NULL) {
if (parser->is_boundary) { if (parser->is_boundary) {
if (s->header_frames_received == GPR_ARRAY_SIZE(s->metadata_buffer)) { if (s->header_frames_received == GPR_ARRAY_SIZE(s->metadata_buffer)) {
return GRPC_ERROR_CREATE("Too many trailer frames"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Too many trailer frames");
} }
s->published_metadata[s->header_frames_received] = s->published_metadata[s->header_frames_received] =
GRPC_METADATA_PUBLISHED_FROM_WIRE; GRPC_METADATA_PUBLISHED_FROM_WIRE;

@ -280,7 +280,7 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&msg, gpr_asprintf(&msg,
"Attempt to make hpack table %d bytes when max is %d bytes", "Attempt to make hpack table %d bytes when max is %d bytes",
bytes, tbl->max_bytes); bytes, tbl->max_bytes);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -317,7 +317,7 @@ grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
"HPACK max table size reduced to %d but not reflected by hpack " "HPACK max table size reduced to %d but not reflected by hpack "
"stream (still at %d)", "stream (still at %d)",
tbl->max_bytes, tbl->current_table_bytes); tbl->max_bytes, tbl->current_table_bytes);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }

@ -41,69 +41,48 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
void grpc_chttp2_incoming_metadata_buffer_init( void grpc_chttp2_incoming_metadata_buffer_init(
grpc_chttp2_incoming_metadata_buffer *buffer) { grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena) {
buffer->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); buffer->arena = arena;
grpc_metadata_batch_init(&buffer->batch);
buffer->batch.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
} }
void grpc_chttp2_incoming_metadata_buffer_destroy( void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer) { grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer) {
size_t i; grpc_metadata_batch_destroy(exec_ctx, &buffer->batch);
if (!buffer->published) {
for (i = 0; i < buffer->count; i++) {
GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
}
}
gpr_free(buffer->elems);
} }
void grpc_chttp2_incoming_metadata_buffer_add( grpc_error *grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem) { grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
GPR_ASSERT(!buffer->published); grpc_mdelem elem) {
if (buffer->capacity == buffer->count) {
buffer->capacity = GPR_MAX(8, 2 * buffer->capacity);
buffer->elems =
gpr_realloc(buffer->elems, sizeof(*buffer->elems) * buffer->capacity);
}
buffer->elems[buffer->count++].md = elem;
buffer->size += GRPC_MDELEM_LENGTH(elem); buffer->size += GRPC_MDELEM_LENGTH(elem);
return grpc_metadata_batch_add_tail(
exec_ctx, &buffer->batch,
gpr_arena_alloc(buffer->arena, sizeof(grpc_linked_mdelem)), elem);
} }
void grpc_chttp2_incoming_metadata_buffer_replace_or_add( grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_mdelem elem) { grpc_mdelem elem) {
for (size_t i = 0; i < buffer->count; i++) { for (grpc_linked_mdelem *l = buffer->batch.list.head; l != NULL;
if (grpc_slice_eq(GRPC_MDKEY(buffer->elems[i].md), GRPC_MDKEY(elem))) { l = l->next) {
GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md); if (grpc_slice_eq(GRPC_MDKEY(l->md), GRPC_MDKEY(elem))) {
buffer->elems[i].md = elem; GRPC_MDELEM_UNREF(exec_ctx, l->md);
return; l->md = elem;
return GRPC_ERROR_NONE;
} }
} }
grpc_chttp2_incoming_metadata_buffer_add(buffer, elem); return grpc_chttp2_incoming_metadata_buffer_add(exec_ctx, buffer, elem);
} }
void grpc_chttp2_incoming_metadata_buffer_set_deadline( void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) { grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline) {
GPR_ASSERT(!buffer->published); buffer->batch.deadline = deadline;
buffer->deadline = deadline;
} }
void grpc_chttp2_incoming_metadata_buffer_publish( void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_metadata_batch *batch) { grpc_metadata_batch *batch) {
GPR_ASSERT(!buffer->published); *batch = buffer->batch;
buffer->published = 1; grpc_metadata_batch_init(&buffer->batch);
if (buffer->count > 0) {
size_t i;
for (i = 0; i < buffer->count; i++) {
/* TODO(ctiller): do something better here */
if (!GRPC_LOG_IF_ERROR("grpc_chttp2_incoming_metadata_buffer_publish",
grpc_metadata_batch_link_tail(
exec_ctx, batch, &buffer->elems[i]))) {
GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
}
}
} else {
batch->list.head = batch->list.tail = NULL;
}
batch->deadline = buffer->deadline;
} }

@ -37,28 +37,26 @@
#include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport.h"
typedef struct { typedef struct {
grpc_linked_mdelem *elems; gpr_arena *arena;
size_t count; grpc_metadata_batch batch;
size_t capacity;
gpr_timespec deadline;
int published;
size_t size; // total size of metadata size_t size; // total size of metadata
} grpc_chttp2_incoming_metadata_buffer; } grpc_chttp2_incoming_metadata_buffer;
/** assumes everything initially zeroed */ /** assumes everything initially zeroed */
void grpc_chttp2_incoming_metadata_buffer_init( void grpc_chttp2_incoming_metadata_buffer_init(
grpc_chttp2_incoming_metadata_buffer *buffer); grpc_chttp2_incoming_metadata_buffer *buffer, gpr_arena *arena);
void grpc_chttp2_incoming_metadata_buffer_destroy( void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer); grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer);
void grpc_chttp2_incoming_metadata_buffer_publish( void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_metadata_batch *batch); grpc_metadata_batch *batch);
void grpc_chttp2_incoming_metadata_buffer_add( grpc_error *grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem elem);
void grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_mdelem elem); grpc_mdelem elem) GRPC_MUST_USE_RESULT;
grpc_error *grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer,
grpc_mdelem elem) GRPC_MUST_USE_RESULT;
void grpc_chttp2_incoming_metadata_buffer_set_deadline( void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline); grpc_chttp2_incoming_metadata_buffer *buffer, gpr_timespec deadline);

@ -425,7 +425,7 @@ struct grpc_chttp2_stream {
grpc_stream_refcount *refcount; grpc_stream_refcount *refcount;
grpc_closure destroy_stream; grpc_closure destroy_stream;
void *destroy_stream_arg; grpc_closure *destroy_stream_arg;
grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
uint8_t included[STREAM_LIST_COUNT]; uint8_t included[STREAM_LIST_COUNT];

@ -116,7 +116,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
(int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
*cur, (int)*cur, t->deframe_state); *cur, (int)*cur, t->deframe_state);
err = GRPC_ERROR_CREATE(msg); err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -219,7 +219,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
t->incoming_frame_size, t->incoming_frame_size,
t->settings[GRPC_ACKED_SETTINGS] t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]); [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]);
err = GRPC_ERROR_CREATE(msg); err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -278,7 +278,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
gpr_asprintf( gpr_asprintf(
&msg, "Expected SETTINGS frame as the first frame, got frame type %d", &msg, "Expected SETTINGS frame as the first frame, got frame type %d",
t->incoming_frame_type); t->incoming_frame_type);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -288,7 +288,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
char *msg; char *msg;
gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x", gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
t->incoming_frame_type); t->incoming_frame_type);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -299,7 +299,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
"Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
"grpc_chttp2_stream %08x", "grpc_chttp2_stream %08x",
t->expect_continuation_stream_id, t->incoming_stream_id); t->expect_continuation_stream_id, t->incoming_stream_id);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -311,7 +311,8 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_HEADER: case GRPC_CHTTP2_FRAME_HEADER:
return init_header_frame_parser(exec_ctx, t, 0); return init_header_frame_parser(exec_ctx, t, 0);
case GRPC_CHTTP2_FRAME_CONTINUATION: case GRPC_CHTTP2_FRAME_CONTINUATION:
return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Unexpected CONTINUATION frame");
case GRPC_CHTTP2_FRAME_RST_STREAM: case GRPC_CHTTP2_FRAME_RST_STREAM:
return init_rst_stream_parser(exec_ctx, t); return init_rst_stream_parser(exec_ctx, t);
case GRPC_CHTTP2_FRAME_SETTINGS: case GRPC_CHTTP2_FRAME_SETTINGS:
@ -371,7 +372,7 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
char *msg; char *msg;
gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
t->incoming_frame_size, t->incoming_window); t->incoming_frame_size, t->incoming_window);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -409,7 +410,7 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
s->incoming_window_delta + s->incoming_window_delta +
t->settings[GRPC_ACKED_SETTINGS] t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
grpc_error *err = GRPC_ERROR_CREATE(msg); grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
@ -542,13 +543,21 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int( grpc_error_set_int(
GRPC_ERROR_CREATE("received initial metadata size exceeds limit"), GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true; s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md); GRPC_MDELEM_UNREF(exec_ctx, md);
} else { } else {
grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add(
exec_ctx, &s->metadata_buffer[0], md);
if (error != GRPC_ERROR_NONE) {
grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md);
}
} }
} }
@ -591,14 +600,22 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
new_size, metadata_size_limit); new_size, metadata_size_limit);
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"), "received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true; s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md); GRPC_MDELEM_UNREF(exec_ctx, md);
} else { } else {
grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md); grpc_error *error = grpc_chttp2_incoming_metadata_buffer_add(
exec_ctx, &s->metadata_buffer[1], md);
if (error != GRPC_ERROR_NONE) {
grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md);
}
} }
GPR_TIMER_END("on_trailing_header", 0); GPR_TIMER_END("on_trailing_header", 0);
@ -757,7 +774,8 @@ static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx,
static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) { grpc_chttp2_transport *t) {
if (t->incoming_stream_id != 0) { if (t->incoming_stream_id != 0) {
return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Settings frame received for grpc_chttp2_stream");
} }
grpc_error *err = grpc_chttp2_settings_parser_begin_frame( grpc_error *err = grpc_chttp2_settings_parser_begin_frame(

@ -128,6 +128,7 @@ struct read_state {
int received_bytes; int received_bytes;
int remaining_bytes; int remaining_bytes;
int length_field; int length_field;
bool compressed;
char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES]; char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES];
char *payload_field; char *payload_field;
bool read_stream_closed; bool read_stream_closed;
@ -184,6 +185,7 @@ struct op_storage {
}; };
struct stream_obj { struct stream_obj {
gpr_arena *arena;
struct op_and_state *oas; struct op_and_state *oas;
grpc_transport_stream_op *curr_op; grpc_transport_stream_op *curr_op;
grpc_cronet_transport *curr_ct; grpc_cronet_transport *curr_ct;
@ -272,7 +274,7 @@ static void maybe_flush_read(stream_obj *s) {
/* Whenever the evaluation of any of the two condition is changed, we check /* Whenever the evaluation of any of the two condition is changed, we check
* whether we should enter the flush read state. */ * whether we should enter the flush read state. */
if (s->state.pending_recv_trailing_metadata && s->state.fail_state) { if (s->state.pending_recv_trailing_metadata && s->state.fail_state) {
if (!s->state.flush_read) { if (!s->state.flush_read && !s->state.rs.read_stream_closed) {
CRONET_LOG(GPR_DEBUG, "%p: Flush read", s); CRONET_LOG(GPR_DEBUG, "%p: Flush read", s);
s->state.flush_read = true; s->state.flush_read = true;
null_and_maybe_free_read_buffer(s); null_and_maybe_free_read_buffer(s);
@ -288,7 +290,7 @@ static void maybe_flush_read(stream_obj *s) {
} }
static grpc_error *make_error_with_desc(int error_code, const char *desc) { static grpc_error *make_error_with_desc(int error_code, const char *desc) {
grpc_error *error = GRPC_ERROR_CREATE(desc); grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error_code); error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error_code);
return error; return error;
} }
@ -483,18 +485,31 @@ static void on_response_headers_received(
CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream, CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
headers, negotiated_protocol); headers, negotiated_protocol);
stream_obj *s = (stream_obj *)stream->annotation; stream_obj *s = (stream_obj *)stream->annotation;
/* Identify if this is a header or a trailer (in a trailer-only response case)
*/
for (size_t i = 0; i < headers->count; i++) {
if (0 == strcmp("grpc-status", headers->headers[i].key)) {
on_response_trailers_received(stream, headers);
return;
}
}
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
memset(&s->state.rs.initial_metadata, 0, memset(&s->state.rs.initial_metadata, 0,
sizeof(s->state.rs.initial_metadata)); sizeof(s->state.rs.initial_metadata));
grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata); grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata,
s->arena);
for (size_t i = 0; i < headers->count; i++) { for (size_t i = 0; i < headers->count; i++) {
grpc_chttp2_incoming_metadata_buffer_add( GRPC_LOG_IF_ERROR(
&s->state.rs.initial_metadata, "on_response_headers_received",
grpc_mdelem_from_slices( grpc_chttp2_incoming_metadata_buffer_add(
&exec_ctx, grpc_slice_intern(grpc_slice_from_static_string( &exec_ctx, &s->state.rs.initial_metadata,
headers->headers[i].key)), grpc_mdelem_from_slices(
grpc_slice_intern( &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
grpc_slice_from_static_string(headers->headers[i].value)))); headers->headers[i].key)),
grpc_slice_intern(grpc_slice_from_static_string(
headers->headers[i].value)))));
} }
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true; s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
if (!(s->state.state_op_done[OP_CANCEL_ERROR] || if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
@ -503,6 +518,7 @@ static void on_response_headers_received(
is closed */ is closed */
GPR_ASSERT(s->state.rs.length_field_received == false); GPR_ASSERT(s->state.rs.length_field_received == false);
s->state.rs.read_buffer = s->state.rs.grpc_header_bytes; s->state.rs.read_buffer = s->state.rs.grpc_header_bytes;
s->state.rs.compressed = false;
s->state.rs.received_bytes = 0; s->state.rs.received_bytes = 0;
s->state.rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; s->state.rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs); CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
@ -586,17 +602,20 @@ static void on_response_trailers_received(
memset(&s->state.rs.trailing_metadata, 0, memset(&s->state.rs.trailing_metadata, 0,
sizeof(s->state.rs.trailing_metadata)); sizeof(s->state.rs.trailing_metadata));
s->state.rs.trailing_metadata_valid = false; s->state.rs.trailing_metadata_valid = false;
grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata); grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata,
s->arena);
for (size_t i = 0; i < trailers->count; i++) { for (size_t i = 0; i < trailers->count; i++) {
CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key, CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
trailers->headers[i].value); trailers->headers[i].value);
grpc_chttp2_incoming_metadata_buffer_add( GRPC_LOG_IF_ERROR(
&s->state.rs.trailing_metadata, "on_response_trailers_received",
grpc_mdelem_from_slices( grpc_chttp2_incoming_metadata_buffer_add(
&exec_ctx, grpc_slice_intern(grpc_slice_from_static_string( &exec_ctx, &s->state.rs.trailing_metadata,
trailers->headers[i].key)), grpc_mdelem_from_slices(
grpc_slice_intern( &exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(
grpc_slice_from_static_string(trailers->headers[i].value)))); trailers->headers[i].key)),
grpc_slice_intern(grpc_slice_from_static_string(
trailers->headers[i].value)))));
s->state.rs.trailing_metadata_valid = true; s->state.rs.trailing_metadata_valid = true;
if (0 == strcmp(trailers->headers[i].key, "grpc-status") && if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
0 != strcmp(trailers->headers[i].value, "0")) { 0 != strcmp(trailers->headers[i].value, "0")) {
@ -634,7 +653,7 @@ static void on_response_trailers_received(
*/ */
static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer, static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer,
char **pp_write_buffer, char **pp_write_buffer,
size_t *p_write_buffer_size) { size_t *p_write_buffer_size, uint32_t flags) {
grpc_slice slice = grpc_slice_buffer_take_first(write_slice_buffer); grpc_slice slice = grpc_slice_buffer_take_first(write_slice_buffer);
size_t length = GRPC_SLICE_LENGTH(slice); size_t length = GRPC_SLICE_LENGTH(slice);
*p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES; *p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
@ -643,7 +662,9 @@ static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer,
*pp_write_buffer = write_buffer; *pp_write_buffer = write_buffer;
uint8_t *p = (uint8_t *)write_buffer; uint8_t *p = (uint8_t *)write_buffer;
/* Append 5 byte header */ /* Append 5 byte header */
*p++ = 0; /* Compressed flag */
*p++ = (flags & GRPC_WRITE_INTERNAL_COMPRESS) ? 1 : 0;
/* Message length */
*p++ = (uint8_t)(length >> 24); *p++ = (uint8_t)(length >> 24);
*p++ = (uint8_t)(length >> 16); *p++ = (uint8_t)(length >> 16);
*p++ = (uint8_t)(length >> 8); *p++ = (uint8_t)(length >> 8);
@ -721,14 +742,16 @@ static void convert_metadata_to_cronet_headers(
*p_num_headers = (size_t)num_headers; *p_num_headers = (size_t)num_headers;
} }
static int parse_grpc_header(const uint8_t *data) { static void parse_grpc_header(const uint8_t *data, int *length,
bool *compressed) {
const uint8_t c = *data;
const uint8_t *p = data + 1; const uint8_t *p = data + 1;
int length = 0; *compressed = ((c & 0x01) == 0x01);
length |= ((uint8_t)*p++) << 24; *length = 0;
length |= ((uint8_t)*p++) << 16; *length |= ((uint8_t)*p++) << 24;
length |= ((uint8_t)*p++) << 8; *length |= ((uint8_t)*p++) << 16;
length |= ((uint8_t)*p++); *length |= ((uint8_t)*p++) << 8;
return length; *length |= ((uint8_t)*p++);
} }
static bool header_has_authority(grpc_linked_mdelem *head) { static bool header_has_authority(grpc_linked_mdelem *head) {
@ -781,7 +804,8 @@ static bool op_can_be_run(grpc_transport_stream_op *curr_op,
else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA]) else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
result = false; result = false;
/* we haven't received headers yet. */ /* we haven't received headers yet. */
else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA]) else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA] &&
!stream_state->state_op_done[OP_RECV_TRAILING_METADATA])
result = false; result = false;
} else if (op_id == OP_SEND_MESSAGE) { } else if (op_id == OP_SEND_MESSAGE) {
/* already executed (note we're checking op specific state, not stream /* already executed (note we're checking op specific state, not stream
@ -794,7 +818,8 @@ static bool op_can_be_run(grpc_transport_stream_op *curr_op,
/* already executed */ /* already executed */
if (op_state->state_op_done[OP_RECV_MESSAGE]) result = false; if (op_state->state_op_done[OP_RECV_MESSAGE]) result = false;
/* we haven't received headers yet. */ /* we haven't received headers yet. */
else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA]) else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA] &&
!stream_state->state_op_done[OP_RECV_TRAILING_METADATA])
result = false; result = false;
} else if (op_id == OP_RECV_TRAILING_METADATA) { } else if (op_id == OP_RECV_TRAILING_METADATA) {
/* already executed */ /* already executed */
@ -948,12 +973,6 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_init(&write_slice_buffer); grpc_slice_buffer_init(&write_slice_buffer);
grpc_byte_stream_next(NULL, stream_op->send_message, &slice, grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
stream_op->send_message->length, NULL); stream_op->send_message->length, NULL);
/* Check that compression flag is OFF. We don't support compression yet.
*/
if (stream_op->send_message->flags != 0) {
gpr_log(GPR_ERROR, "Compression is not supported");
GPR_ASSERT(stream_op->send_message->flags == 0);
}
grpc_slice_buffer_add(&write_slice_buffer, slice); grpc_slice_buffer_add(&write_slice_buffer, slice);
if (write_slice_buffer.count != 1) { if (write_slice_buffer.count != 1) {
/* Empty request not handled yet */ /* Empty request not handled yet */
@ -963,7 +982,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
if (write_slice_buffer.count > 0) { if (write_slice_buffer.count > 0) {
size_t write_buffer_size; size_t write_buffer_size;
create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer, create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
&write_buffer_size); &write_buffer_size, stream_op->send_message->flags);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs, CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs,
stream_state->ws.write_buffer); stream_state->ws.write_buffer);
stream_state->state_callback_received[OP_SEND_MESSAGE] = false; stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
@ -1015,6 +1034,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
} else if (stream_state->state_callback_received[OP_FAILED]) { } else if (stream_state->state_callback_received[OP_FAILED]) {
grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready, grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
GRPC_ERROR_NONE); GRPC_ERROR_NONE);
} else if (stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) {
grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
GRPC_ERROR_NONE);
} else { } else {
grpc_chttp2_incoming_metadata_buffer_publish( grpc_chttp2_incoming_metadata_buffer_publish(
exec_ctx, &oas->s->state.rs.initial_metadata, exec_ctx, &oas->s->state.rs.initial_metadata,
@ -1059,8 +1081,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.remaining_bytes == 0) { stream_state->rs.remaining_bytes == 0) {
/* Start a read operation for data */ /* Start a read operation for data */
stream_state->rs.length_field_received = true; stream_state->rs.length_field_received = true;
stream_state->rs.length_field = stream_state->rs.remaining_bytes = parse_grpc_header((const uint8_t *)stream_state->rs.read_buffer,
parse_grpc_header((const uint8_t *)stream_state->rs.read_buffer); &stream_state->rs.length_field,
&stream_state->rs.compressed);
CRONET_LOG(GPR_DEBUG, "length field = %d", CRONET_LOG(GPR_DEBUG, "length field = %d",
stream_state->rs.length_field); stream_state->rs.length_field);
if (stream_state->rs.length_field > 0) { if (stream_state->rs.length_field > 0) {
@ -1082,6 +1105,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer); grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
grpc_slice_buffer_stream_init(&stream_state->rs.sbs, grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
&stream_state->rs.read_slice_buffer, 0); &stream_state->rs.read_slice_buffer, 0);
if (stream_state->rs.compressed) {
stream_state->rs.sbs.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
}
*((grpc_byte_buffer **)stream_op->recv_message) = *((grpc_byte_buffer **)stream_op->recv_message) =
(grpc_byte_buffer *)&stream_state->rs.sbs; (grpc_byte_buffer *)&stream_state->rs.sbs;
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready, grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
@ -1093,6 +1119,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes; stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0; stream_state->rs.received_bytes = 0;
stream_state->rs.compressed = false;
stream_state->rs.length_field_received = false; stream_state->rs.length_field_received = false;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs); CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] = stream_state->state_op_done[OP_READ_REQ_MADE] =
@ -1107,6 +1134,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes; stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0; stream_state->rs.received_bytes = 0;
stream_state->rs.compressed = false;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs); CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] = stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */ true; /* Indicates that at least one read request has been made */
@ -1130,6 +1158,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
read_data_slice); read_data_slice);
grpc_slice_buffer_stream_init(&stream_state->rs.sbs, grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
&stream_state->rs.read_slice_buffer, 0); &stream_state->rs.read_slice_buffer, 0);
if (stream_state->rs.compressed) {
stream_state->rs.sbs.base.flags = GRPC_WRITE_INTERNAL_COMPRESS;
}
*((grpc_byte_buffer **)stream_op->recv_message) = *((grpc_byte_buffer **)stream_op->recv_message) =
(grpc_byte_buffer *)&stream_state->rs.sbs; (grpc_byte_buffer *)&stream_state->rs.sbs;
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready, grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
@ -1139,6 +1170,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
/* Do an extra read to trigger on_succeeded() callback in case connection /* Do an extra read to trigger on_succeeded() callback in case connection
is closed */ is closed */
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes; stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.compressed = false;
stream_state->rs.received_bytes = 0; stream_state->rs.received_bytes = 0;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.length_field_received = false; stream_state->rs.length_field_received = false;
@ -1215,7 +1247,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount, grpc_stream *gs, grpc_stream_refcount *refcount,
const void *server_data) { const void *server_data, gpr_arena *arena) {
stream_obj *s = (stream_obj *)gs; stream_obj *s = (stream_obj *)gs;
memset(&s->storage, 0, sizeof(s->storage)); memset(&s->storage, 0, sizeof(s->storage));
s->storage.head = NULL; s->storage.head = NULL;
@ -1237,6 +1269,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
s->curr_gs = gs; s->curr_gs = gs;
s->curr_ct = (grpc_cronet_transport *)gt; s->curr_ct = (grpc_cronet_transport *)gt;
s->arena = arena;
gpr_mu_init(&s->mu); gpr_mu_init(&s->mu);
return 0; return 0;
@ -1273,10 +1306,12 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
} }
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, void *and_free_memory) { grpc_stream *gs,
grpc_closure *then_schedule_closure) {
stream_obj *s = (stream_obj *)gs; stream_obj *s = (stream_obj *)gs;
null_and_maybe_free_read_buffer(s); null_and_maybe_free_read_buffer(s);
GRPC_ERROR_UNREF(s->state.cancel_error); GRPC_ERROR_UNREF(s->state.cancel_error);
grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
} }
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {} static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {}

@ -166,41 +166,32 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
} }
} }
grpc_error *grpc_call_stack_init( grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, int initial_refs, grpc_iomgr_cb_func destroy,
grpc_call_context_element *context, const void *transport_server_data, void *destroy_arg,
grpc_slice path, gpr_timespec start_time, gpr_timespec deadline, const grpc_call_element_args *elem_args) {
grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
size_t count = channel_stack->count; size_t count = channel_stack->count;
grpc_call_element *call_elems; grpc_call_element *call_elems;
char *user_data; char *user_data;
size_t i; size_t i;
call_stack->count = count; elem_args->call_stack->count = count;
GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy, GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
destroy_arg, "CALL_STACK"); destroy_arg, "CALL_STACK");
call_elems = CALL_ELEMS_FROM_STACK(call_stack); call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack);
user_data = ((char *)call_elems) + user_data = ((char *)call_elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */ /* init per-filter data */
grpc_error *first_error = GRPC_ERROR_NONE; grpc_error *first_error = GRPC_ERROR_NONE;
const grpc_call_element_args args = {
.start_time = start_time,
.call_stack = call_stack,
.server_transport_data = transport_server_data,
.context = context,
.path = path,
.deadline = deadline,
};
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
call_elems[i].filter = channel_elems[i].filter; call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data; call_elems[i].call_data = user_data;
grpc_error *error = grpc_error *error = call_elems[i].filter->init_call_elem(
call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args); exec_ctx, &call_elems[i], elem_args);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
if (first_error == GRPC_ERROR_NONE) { if (first_error == GRPC_ERROR_NONE) {
first_error = error; first_error = error;
@ -241,15 +232,16 @@ void grpc_call_stack_ignore_set_pollset_or_pollset_set(
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack, void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *and_free_memory) { grpc_closure *then_schedule_closure) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack); grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count; size_t count = stack->count;
size_t i; size_t i;
/* destroy per-filter data */ /* destroy per-filter data */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], final_info, elems[i].filter->destroy_call_elem(
i == count - 1 ? and_free_memory : NULL); exec_ctx, &elems[i], final_info,
i == count - 1 ? then_schedule_closure : NULL);
} }
} }

@ -56,6 +56,7 @@
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/support/arena.h"
#include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -84,6 +85,7 @@ typedef struct {
grpc_slice path; grpc_slice path;
gpr_timespec start_time; gpr_timespec start_time;
gpr_timespec deadline; gpr_timespec deadline;
gpr_arena *arena;
} grpc_call_element_args; } grpc_call_element_args;
typedef struct { typedef struct {
@ -139,12 +141,12 @@ typedef struct {
/* Destroy per call data. /* Destroy per call data.
The filter does not need to do any chaining. The filter does not need to do any chaining.
The bottom filter of a stack will be passed a non-NULL pointer to The bottom filter of a stack will be passed a non-NULL pointer to
\a and_free_memory that should be passed to gpr_free when destruction \a then_schedule_closure that should be passed to grpc_closure_sched when
is complete. \a final_info contains data about the completed call, mainly destruction is complete. \a final_info contains data about the completed
for reporting purposes. */ call, mainly for reporting purposes. */
void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *and_free_memory); grpc_closure *then_schedule_closure);
/* sizeof(per channel data) */ /* sizeof(per channel data) */
size_t sizeof_channel_data; size_t sizeof_channel_data;
@ -236,12 +238,11 @@ void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
/* Initialize a call stack given a channel stack. transport_server_data is /* Initialize a call stack given a channel stack. transport_server_data is
expected to be NULL on a client, or an opaque transport owned pointer on the expected to be NULL on a client, or an opaque transport owned pointer on the
server. */ server. */
grpc_error *grpc_call_stack_init( grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, int initial_refs, grpc_iomgr_cb_func destroy,
grpc_call_context_element *context, const void *transport_server_data, void *destroy_arg,
grpc_slice path, gpr_timespec start_time, gpr_timespec deadline, const grpc_call_element_args *elem_args);
grpc_call_stack *call_stack);
/* Set a pollset or a pollset_set for a call stack: must occur before the first /* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */ * op is started */
void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@ -271,7 +272,7 @@ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
/* Destroy a call stack */ /* Destroy a call stack */
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack, void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *and_free_memory); grpc_closure *then_schedule_closure);
/* Ignore set pollset{_set} - used by filters if they don't care about pollsets /* Ignore set pollset{_set} - used by filters if they don't care about pollsets
* at all. Does nothing. */ * at all. Does nothing. */

@ -292,7 +292,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */ /* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
/* grab pointers to our data from the call element */ /* grab pointers to our data from the call element */
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices); grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);

@ -88,9 +88,10 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
int r = grpc_transport_init_stream( int r = grpc_transport_init_stream(
exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
&args->call_stack->refcount, args->server_transport_data); &args->call_stack->refcount, args->server_transport_data, args->arena);
return r == 0 ? GRPC_ERROR_NONE return r == 0 ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("transport stream initialization failed"); : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"transport stream initialization failed");
} }
static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@ -105,12 +106,12 @@ static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */ /* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *and_free_memory) { grpc_closure *then_schedule_closure) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_transport_destroy_stream(exec_ctx, chand->transport, grpc_transport_destroy_stream(exec_ctx, chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld), TRANSPORT_STREAM_FROM_CALL_DATA(calld),
and_free_memory); then_schedule_closure);
} }
/* Constructor for channel_data */ /* Constructor for channel_data */

@ -55,9 +55,9 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg,
if (error != GRPC_ERROR_CANCELLED) { if (error != GRPC_ERROR_CANCELLED) {
grpc_call_element_signal_error( grpc_call_element_signal_error(
exec_ctx, elem, exec_ctx, elem,
grpc_error_set_int(GRPC_ERROR_CREATE("Deadline Exceeded"), grpc_error_set_int(
GRPC_ERROR_INT_GRPC_STATUS, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"),
GRPC_STATUS_DEADLINE_EXCEEDED)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_DEADLINE_EXCEEDED));
} }
GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer"); GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer");
} }
@ -256,7 +256,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
// Destructor for call_data. Used for both client and server filters. // Destructor for call_data. Used for both client and server filters.
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info, const grpc_call_final_info* final_info,
void* and_free_memory) { grpc_closure* ignored) {
grpc_deadline_state_destroy(exec_ctx, elem); grpc_deadline_state_destroy(exec_ctx, elem);
} }

@ -236,8 +236,9 @@ static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg,
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
grpc_handshake_manager* mgr = arg; grpc_handshake_manager* mgr = arg;
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled. if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
grpc_handshake_manager_shutdown(exec_ctx, mgr, grpc_handshake_manager_shutdown(
GRPC_ERROR_CREATE("Handshake timed out")); exec_ctx, mgr,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out"));
} }
grpc_handshake_manager_unref(exec_ctx, mgr); grpc_handshake_manager_unref(exec_ctx, mgr);
} }

@ -108,11 +108,11 @@ static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
grpc_error *e = grpc_error_set_str( grpc_error *e = grpc_error_set_str(
grpc_error_set_int( grpc_error_set_int(
grpc_error_set_str( grpc_error_set_str(
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Received http2 :status header with non-200 OK status"), "Received http2 :status header with non-200 OK status"),
GRPC_ERROR_STR_VALUE, val), GRPC_ERROR_STR_VALUE, grpc_slice_from_copied_string(val)),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED),
GRPC_ERROR_STR_GRPC_MESSAGE, msg); GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_copied_string(msg));
gpr_free(val); gpr_free(val);
gpr_free(msg); gpr_free(msg);
return e; return e;
@ -412,7 +412,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */ /* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices); grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
} }

@ -101,7 +101,7 @@ static void add_error(const char *error_name, grpc_error **cumulative,
grpc_error *new) { grpc_error *new) {
if (new == GRPC_ERROR_NONE) return; if (new == GRPC_ERROR_NONE) return;
if (*cumulative == GRPC_ERROR_NONE) { if (*cumulative == GRPC_ERROR_NONE) {
*cumulative = GRPC_ERROR_CREATE(error_name); *cumulative = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_name);
} }
*cumulative = grpc_error_add_child(*cumulative, new); *cumulative = grpc_error_add_child(*cumulative, new);
} }
@ -125,27 +125,32 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
*calld->recv_cacheable_request = true; *calld->recv_cacheable_request = true;
} else { } else {
add_error(error_name, &error, add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"), grpc_attach_md_to_error(
b->idx.named.method->md)); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.method->md));
} }
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.method); grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.method);
} else { } else {
add_error(error_name, &error, add_error(
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"), error_name, &error,
GRPC_ERROR_STR_KEY, ":method")); grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":method")));
} }
if (b->idx.named.te != NULL) { if (b->idx.named.te != NULL) {
if (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) { if (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) {
add_error(error_name, &error, add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"), grpc_attach_md_to_error(
b->idx.named.te->md)); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.te->md));
} }
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.te); grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.te);
} else { } else {
add_error(error_name, &error, add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"), grpc_error_set_str(
GRPC_ERROR_STR_KEY, "te")); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string("te")));
} }
if (b->idx.named.scheme != NULL) { if (b->idx.named.scheme != NULL) {
@ -153,14 +158,17 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTPS) && !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTPS) &&
!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_GRPC)) { !grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_GRPC)) {
add_error(error_name, &error, add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"), grpc_attach_md_to_error(
b->idx.named.scheme->md)); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.scheme->md));
} }
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.scheme); grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.scheme);
} else { } else {
add_error(error_name, &error, add_error(
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"), error_name, &error,
GRPC_ERROR_STR_KEY, ":scheme")); grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":scheme")));
} }
if (b->idx.named.content_type != NULL) { if (b->idx.named.content_type != NULL) {
@ -194,8 +202,9 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
if (b->idx.named.path == NULL) { if (b->idx.named.path == NULL) {
add_error(error_name, &error, add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"), grpc_error_set_str(
GRPC_ERROR_STR_KEY, ":path")); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path")));
} }
if (b->idx.named.host != NULL && b->idx.named.authority == NULL) { if (b->idx.named.host != NULL && b->idx.named.authority == NULL) {
@ -212,9 +221,11 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
} }
if (b->idx.named.authority == NULL) { if (b->idx.named.authority == NULL) {
add_error(error_name, &error, add_error(
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"), error_name, &error,
GRPC_ERROR_STR_KEY, ":authority")); grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority")));
} }
if (b->idx.named.grpc_payload_bin != NULL) { if (b->idx.named.grpc_payload_bin != NULL) {
@ -358,7 +369,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for call_data */ /* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info, const grpc_call_final_info *final_info,
void *ignored) { grpc_closure *ignored) {
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->read_slice_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &calld->read_slice_buffer);
} }

@ -121,8 +121,8 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data,
"Received message larger than max (%u vs. %d)", "Received message larger than max (%u vs. %d)",
(*calld->recv_message)->length, calld->max_recv_size); (*calld->recv_message)->length, calld->max_recv_size);
grpc_error* new_error = grpc_error_set_int( grpc_error* new_error = grpc_error_set_int(
GRPC_ERROR_CREATE(message_string), GRPC_ERROR_INT_GRPC_STATUS, GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_STATUS_INVALID_ARGUMENT); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INVALID_ARGUMENT);
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
error = new_error; error = new_error;
} else { } else {
@ -147,9 +147,10 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
op->send_message->length, calld->max_send_size); op->send_message->length, calld->max_send_size);
grpc_transport_stream_op_finish_with_failure( grpc_transport_stream_op_finish_with_failure(
exec_ctx, op, grpc_error_set_int(GRPC_ERROR_CREATE(message_string), exec_ctx, op,
GRPC_ERROR_INT_GRPC_STATUS, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_STATUS_INVALID_ARGUMENT)); GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_INVALID_ARGUMENT));
gpr_free(message_string); gpr_free(message_string);
return; return;
} }
@ -200,7 +201,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
// Destructor for call_data. // Destructor for call_data.
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info, const grpc_call_final_info* final_info,
void* ignored) {} grpc_closure* ignored) {}
// Constructor for channel_data. // Constructor for channel_data.
static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,

@ -126,13 +126,15 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
static void append_error(internal_request *req, grpc_error *error) { static void append_error(internal_request *req, grpc_error *error) {
if (req->overall_error == GRPC_ERROR_NONE) { if (req->overall_error == GRPC_ERROR_NONE) {
req->overall_error = GRPC_ERROR_CREATE("Failed HTTP/1 client request"); req->overall_error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request");
} }
grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1]; grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1];
char *addr_text = grpc_sockaddr_to_uri(addr); char *addr_text = grpc_sockaddr_to_uri(addr);
req->overall_error = grpc_error_add_child( req->overall_error = grpc_error_add_child(
req->overall_error, req->overall_error,
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text)); grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(addr_text)));
gpr_free(addr_text); gpr_free(addr_text);
} }
@ -190,8 +192,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
internal_request *req = arg; internal_request *req = arg;
if (!ep) { if (!ep) {
next_address(exec_ctx, req, next_address(exec_ctx, req, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Unexplained handshake failure")); "Unexplained handshake failure"));
return; return;
} }
@ -221,8 +223,8 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
} }
if (req->next_address == req->addresses->naddrs) { if (req->next_address == req->addresses->naddrs) {
finish(exec_ctx, req, finish(exec_ctx, req,
GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets", GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
&req->overall_error, 1)); "Failed HTTP requests to all targets", &req->overall_error, 1));
return; return;
} }
addr = &req->addresses->addrs[req->next_address++]; addr = &req->addresses->addrs[req->next_address++];

@ -95,7 +95,7 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
char *msg; char *msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate", gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
c->secure_peer_name); c->secure_peer_name);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
} }
grpc_closure_sched(exec_ctx, on_peer_checked, error); grpc_closure_sched(exec_ctx, on_peer_checked, error);

@ -54,26 +54,36 @@ static grpc_error *handle_response_line(grpc_http_parser *parser) {
uint8_t *cur = beg; uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length; uint8_t *end = beg + parser->cur_line_length;
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); if (cur == end || *cur++ != 'H')
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); if (cur == end || *cur++ != 'T')
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); if (cur == end || *cur++ != 'T')
if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'"); if (cur == end || *cur++ != 'P')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
if (cur == end || *cur++ != '/')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
if (cur == end || *cur++ != '1')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '1'");
if (cur == end || *cur++ != '.')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '.'");
if (cur == end || *cur < '0' || *cur++ > '1') { if (cur == end || *cur < '0' || *cur++ > '1') {
return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Expected HTTP/1.0 or HTTP/1.1");
} }
if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); if (cur == end || *cur++ != ' ')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
if (cur == end || *cur < '1' || *cur++ > '9') if (cur == end || *cur < '1' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9') if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9') if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
parser->http.response->status = parser->http.response->status =
(cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); if (cur == end || *cur++ != ' ')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
/* we don't really care about the status code message */ /* we don't really care about the status code message */
@ -89,24 +99,33 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) {
while (cur != end && *cur++ != ' ') while (cur != end && *cur++ != ' ')
; ;
if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line"); if (cur == end)
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No method on HTTP request line");
parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1)); parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
beg = cur; beg = cur;
while (cur != end && *cur++ != ' ') while (cur != end && *cur++ != ' ')
; ;
if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line"); if (cur == end)
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No path on HTTP request line");
parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1)); parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); if (cur == end || *cur++ != 'H')
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); if (cur == end || *cur++ != 'T')
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); if (cur == end || *cur++ != 'T')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
if (cur == end || *cur++ != 'P')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
if (cur == end || *cur++ != '/')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
vers_major = (uint8_t)(*cur++ - '1' + 1); vers_major = (uint8_t)(*cur++ - '1' + 1);
++cur; ++cur;
if (cur == end) if (cur == end)
return GRPC_ERROR_CREATE("End of line in HTTP version string"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"End of line in HTTP version string");
vers_minor = (uint8_t)(*cur++ - '1' + 1); vers_minor = (uint8_t)(*cur++ - '1' + 1);
if (vers_major == 1) { if (vers_major == 1) {
@ -115,18 +134,19 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) {
} else if (vers_minor == 1) { } else if (vers_minor == 1) {
parser->http.request->version = GRPC_HTTP_HTTP11; parser->http.request->version = GRPC_HTTP_HTTP11;
} else { } else {
return GRPC_ERROR_CREATE( return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
} else if (vers_major == 2) { } else if (vers_major == 2) {
if (vers_minor == 0) { if (vers_minor == 0) {
parser->http.request->version = GRPC_HTTP_HTTP20; parser->http.request->version = GRPC_HTTP_HTTP20;
} else { } else {
return GRPC_ERROR_CREATE( return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
} else { } else {
return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
@ -139,7 +159,8 @@ static grpc_error *handle_first_line(grpc_http_parser *parser) {
case GRPC_HTTP_RESPONSE: case GRPC_HTTP_RESPONSE:
return handle_response_line(parser); return handle_response_line(parser);
} }
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); GPR_UNREACHABLE_CODE(
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
} }
static grpc_error *add_header(grpc_http_parser *parser) { static grpc_error *add_header(grpc_http_parser *parser) {
@ -154,7 +175,8 @@ static grpc_error *add_header(grpc_http_parser *parser) {
GPR_ASSERT(cur != end); GPR_ASSERT(cur != end);
if (*cur == ' ' || *cur == '\t') { if (*cur == ' ' || *cur == '\t') {
error = GRPC_ERROR_CREATE("Continued header lines not supported yet"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Continued header lines not supported yet");
goto done; goto done;
} }
@ -162,7 +184,8 @@ static grpc_error *add_header(grpc_http_parser *parser) {
cur++; cur++;
} }
if (cur == end) { if (cur == end) {
error = GRPC_ERROR_CREATE("Didn't find ':' in header string"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Didn't find ':' in header string");
goto done; goto done;
} }
GPR_ASSERT(cur >= beg); GPR_ASSERT(cur >= beg);
@ -222,7 +245,8 @@ static grpc_error *finish_line(grpc_http_parser *parser,
} }
break; break;
case GRPC_HTTP_BODY: case GRPC_HTTP_BODY:
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Should never reach here"));
} }
parser->cur_line_length = 0; parser->cur_line_length = 0;
@ -240,7 +264,8 @@ static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
body_length = &parser->http.request->body_length; body_length = &parser->http.request->body_length;
body = &parser->http.request->body; body = &parser->http.request->body;
} else { } else {
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); GPR_UNREACHABLE_CODE(
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
} }
if (*body_length == parser->body_capacity) { if (*body_length == parser->body_capacity) {
@ -286,7 +311,8 @@ static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte,
if (grpc_http1_trace) if (grpc_http1_trace)
gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded", gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
return GRPC_ERROR_CREATE("HTTP header max line length exceeded"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"HTTP header max line length exceeded");
} }
parser->cur_line[parser->cur_line_length] = byte; parser->cur_line[parser->cur_line_length] = byte;
parser->cur_line_length++; parser->cur_line_length++;
@ -347,7 +373,7 @@ grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, grpc_slice slice,
grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) { grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
if (parser->state != GRPC_HTTP_BODY) { if (parser->state != GRPC_HTTP_BODY) {
return GRPC_ERROR_CREATE("Did not finish headers"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }

@ -33,6 +33,7 @@
#include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/closure.h"
#include <assert.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
@ -124,6 +125,7 @@ void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *c,
grpc_error *error) { grpc_error *error) {
GPR_TIMER_BEGIN("grpc_closure_run", 0); GPR_TIMER_BEGIN("grpc_closure_run", 0);
if (c != NULL) { if (c != NULL) {
assert(c->cb);
c->scheduler->vtable->run(exec_ctx, c, error); c->scheduler->vtable->run(exec_ctx, c, error);
} else { } else {
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
@ -135,6 +137,7 @@ void grpc_closure_sched(grpc_exec_ctx *exec_ctx, grpc_closure *c,
grpc_error *error) { grpc_error *error) {
GPR_TIMER_BEGIN("grpc_closure_sched", 0); GPR_TIMER_BEGIN("grpc_closure_sched", 0);
if (c != NULL) { if (c != NULL) {
assert(c->cb);
c->scheduler->vtable->sched(exec_ctx, c, error); c->scheduler->vtable->sched(exec_ctx, c, error);
} else { } else {
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
@ -146,6 +149,7 @@ void grpc_closure_list_sched(grpc_exec_ctx *exec_ctx, grpc_closure_list *list) {
grpc_closure *c = list->head; grpc_closure *c = list->head;
while (c != NULL) { while (c != NULL) {
grpc_closure *next = c->next_data.next; grpc_closure *next = c->next_data.next;
assert(c->cb);
c->scheduler->vtable->sched(exec_ctx, c, c->error_data.error); c->scheduler->vtable->sched(exec_ctx, c, c->error_data.error);
c = next; c = next;
} }

@ -33,6 +33,7 @@
#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/combiner.h"
#include <assert.h>
#include <string.h> #include <string.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
@ -216,6 +217,7 @@ static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
GPR_DEBUG, "C:%p grpc_combiner_execute c=%p cov=%d last=%" PRIdPTR, lock, GPR_DEBUG, "C:%p grpc_combiner_execute c=%p cov=%d last=%" PRIdPTR, lock,
cl, covered_by_poller, last)); cl, covered_by_poller, last));
GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed
assert(cl->cb);
cl->error_data.scratch = cl->error_data.scratch =
pack_error_data((error_data){error, covered_by_poller}); pack_error_data((error_data){error, covered_by_poller});
if (covered_by_poller) { if (covered_by_poller) {

@ -35,7 +35,6 @@
#include <string.h> #include <string.h>
#include <grpc/slice.h>
#include <grpc/status.h> #include <grpc/status.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
@ -287,7 +286,7 @@ static void internal_add_error(grpc_error **err, grpc_error *new) {
// It is very common to include and extra int and string in an error // It is very common to include and extra int and string in an error
#define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME) #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
grpc_error *grpc_error_create(const char *file, int line, const char *desc, grpc_error *grpc_error_create(grpc_slice file, int line, grpc_slice desc,
grpc_error **referencing, grpc_error **referencing,
size_t num_referencing) { size_t num_referencing) {
GPR_TIMER_BEGIN("grpc_error_create", 0); GPR_TIMER_BEGIN("grpc_error_create", 0);
@ -313,14 +312,8 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc,
memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX); memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX);
internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line); internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
internal_set_str(&err, GRPC_ERROR_STR_FILE, internal_set_str(&err, GRPC_ERROR_STR_FILE, file);
grpc_slice_from_static_string(file)); internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc);
internal_set_str(
&err, GRPC_ERROR_STR_DESCRIPTION,
grpc_slice_from_copied_buffer(
desc,
strlen(desc) +
1)); // TODO, pull this up. // TODO(ncteisen), pull this up.
for (size_t i = 0; i < num_referencing; ++i) { for (size_t i = 0; i < num_referencing; ++i) {
if (referencing[i] == GRPC_ERROR_NONE) continue; if (referencing[i] == GRPC_ERROR_NONE) continue;
@ -360,7 +353,7 @@ static grpc_error *copy_error_and_unref(grpc_error *in) {
GPR_TIMER_BEGIN("copy_error_and_unref", 0); GPR_TIMER_BEGIN("copy_error_and_unref", 0);
grpc_error *out; grpc_error *out;
if (grpc_error_is_special(in)) { if (grpc_error_is_special(in)) {
out = GRPC_ERROR_CREATE("unknown"); out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
if (in == GRPC_ERROR_NONE) { if (in == GRPC_ERROR_NONE) {
internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION, internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
grpc_slice_from_static_string("no error")); grpc_slice_from_static_string("no error"));
@ -417,7 +410,7 @@ typedef struct {
const char *msg; const char *msg;
} special_error_status_map; } special_error_status_map;
static special_error_status_map error_status_map[] = { static special_error_status_map error_status_map[] = {
{GRPC_ERROR_NONE, GRPC_STATUS_OK, NULL}, {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""},
{GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"}, {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"},
{GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"},
}; };
@ -448,33 +441,33 @@ bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
} }
grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which, grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value) { grpc_slice str) {
GPR_TIMER_BEGIN("grpc_error_set_str", 0); GPR_TIMER_BEGIN("grpc_error_set_str", 0);
grpc_error *new = copy_error_and_unref(src); grpc_error *new = copy_error_and_unref(src);
internal_set_str(&new, which, internal_set_str(&new, which, str);
grpc_slice_from_copied_buffer(
value, strlen(value) + 1)); // TODO, pull this up.
GPR_TIMER_END("grpc_error_set_str", 0); GPR_TIMER_END("grpc_error_set_str", 0);
return new; return new;
} }
const char *grpc_error_get_str(grpc_error *err, grpc_error_strs which) { bool grpc_error_get_str(grpc_error *err, grpc_error_strs which,
grpc_slice *str) {
if (grpc_error_is_special(err)) { if (grpc_error_is_special(err)) {
if (which == GRPC_ERROR_STR_GRPC_MESSAGE) { if (which == GRPC_ERROR_STR_GRPC_MESSAGE) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) { for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
if (error_status_map[i].error == err) { if (error_status_map[i].error == err) {
return error_status_map[i].msg; *str = grpc_slice_from_static_string(error_status_map[i].msg);
return true;
} }
} }
} }
return NULL; return false;
} }
uint8_t slot = err->strs[which]; uint8_t slot = err->strs[which];
if (slot != UINT8_MAX) { if (slot != UINT8_MAX) {
return (const char *)GRPC_SLICE_START_PTR( *str = *(grpc_slice *)(err->arena + slot);
*(grpc_slice *)(err->arena + slot)); return true;
} else { } else {
return NULL; return false;
} }
} }
@ -515,13 +508,14 @@ static void append_str(const char *str, char **s, size_t *sz, size_t *cap) {
} }
} }
static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) { static void append_esc_str(const uint8_t *str, size_t len, char **s, size_t *sz,
size_t *cap) {
static const char *hex = "0123456789abcdef"; static const char *hex = "0123456789abcdef";
append_chr('"', s, sz, cap); append_chr('"', s, sz, cap);
for (const uint8_t *c = (const uint8_t *)str; *c; c++) { for (size_t i = 0; i < len; i++, str++) {
if (*c < 32 || *c >= 127) { if (*str < 32 || *str >= 127) {
append_chr('\\', s, sz, cap); append_chr('\\', s, sz, cap);
switch (*c) { switch (*str) {
case '\b': case '\b':
append_chr('b', s, sz, cap); append_chr('b', s, sz, cap);
break; break;
@ -541,12 +535,12 @@ static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) {
append_chr('u', s, sz, cap); append_chr('u', s, sz, cap);
append_chr('0', s, sz, cap); append_chr('0', s, sz, cap);
append_chr('0', s, sz, cap); append_chr('0', s, sz, cap);
append_chr(hex[*c >> 4], s, sz, cap); append_chr(hex[*str >> 4], s, sz, cap);
append_chr(hex[*c & 0x0f], s, sz, cap); append_chr(hex[*str & 0x0f], s, sz, cap);
break; break;
} }
} else { } else {
append_chr((char)*c, s, sz, cap); append_chr((char)*str, s, sz, cap);
} }
} }
append_chr('"', s, sz, cap); append_chr('"', s, sz, cap);
@ -586,11 +580,12 @@ static char *key_str(grpc_error_strs which) {
return gpr_strdup(error_str_name(which)); return gpr_strdup(error_str_name(which));
} }
static char *fmt_str(void *p) { static char *fmt_str(grpc_slice slice) {
char *s = NULL; char *s = NULL;
size_t sz = 0; size_t sz = 0;
size_t cap = 0; size_t cap = 0;
append_esc_str(p, &s, &sz, &cap); append_esc_str((const uint8_t *)GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_LENGTH(slice), &s, &sz, &cap);
append_chr(0, &s, &sz, &cap); append_chr(0, &s, &sz, &cap);
return s; return s;
} }
@ -599,9 +594,8 @@ static void collect_strs_kvs(grpc_error *err, kv_pairs *kvs) {
for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) { for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
uint8_t slot = err->strs[which]; uint8_t slot = err->strs[which];
if (slot != UINT8_MAX) { if (slot != UINT8_MAX) {
append_kv( append_kv(kvs, key_str((grpc_error_strs)which),
kvs, key_str((grpc_error_strs)which), fmt_str(*(grpc_slice *)(err->arena + slot)));
fmt_str(GRPC_SLICE_START_PTR(*(grpc_slice *)(err->arena + slot))));
} }
} }
} }
@ -681,7 +675,8 @@ static char *finish_kvs(kv_pairs *kvs) {
append_chr('{', &s, &sz, &cap); append_chr('{', &s, &sz, &cap);
for (size_t i = 0; i < kvs->num_kvs; i++) { for (size_t i = 0; i < kvs->num_kvs; i++) {
if (i != 0) append_chr(',', &s, &sz, &cap); if (i != 0) append_chr(',', &s, &sz, &cap);
append_esc_str(kvs->kvs[i].key, &s, &sz, &cap); append_esc_str((const uint8_t *)kvs->kvs[i].key, strlen(kvs->kvs[i].key),
&s, &sz, &cap);
gpr_free(kvs->kvs[i].key); gpr_free(kvs->kvs[i].key);
append_chr(':', &s, &sz, &cap); append_chr(':', &s, &sz, &cap);
append_str(kvs->kvs[i].value, &s, &sz, &cap); append_str(kvs->kvs[i].value, &s, &sz, &cap);
@ -733,10 +728,14 @@ grpc_error *grpc_os_error(const char *file, int line, int err,
const char *call_name) { const char *call_name) {
return grpc_error_set_str( return grpc_error_set_str(
grpc_error_set_str( grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0), grpc_error_set_int(
GRPC_ERROR_INT_ERRNO, err), grpc_error_create(grpc_slice_from_static_string(file), line,
GRPC_ERROR_STR_OS_ERROR, strerror(err)), grpc_slice_from_static_string("OS Error"), NULL,
GRPC_ERROR_STR_SYSCALL, call_name); 0),
GRPC_ERROR_INT_ERRNO, err),
GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(strerror(err))),
GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name));
} }
#ifdef GPR_WINDOWS #ifdef GPR_WINDOWS
@ -745,10 +744,13 @@ grpc_error *grpc_wsa_error(const char *file, int line, int err,
char *utf8_message = gpr_format_message(err); char *utf8_message = gpr_format_message(err);
grpc_error *error = grpc_error_set_str( grpc_error *error = grpc_error_set_str(
grpc_error_set_str( grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0), grpc_error_set_int(
GRPC_ERROR_INT_WSA_ERROR, err), grpc_error_create(grpc_slice_from_static_string(file), line,
GRPC_ERROR_STR_OS_ERROR, utf8_message), grpc_slice_from_static_string("OS Error"), NULL,
GRPC_ERROR_STR_SYSCALL, call_name); 0),
GRPC_ERROR_INT_WSA_ERROR, err),
GRPC_ERROR_STR_OS_ERROR, grpc_slice_from_copied_string(utf8_message)),
GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name));
gpr_free(utf8_message); gpr_free(utf8_message);
return error; return error;
} }

@ -37,6 +37,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <grpc/slice.h>
#include <grpc/status.h> #include <grpc/status.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
@ -45,28 +46,9 @@ extern "C" {
#endif #endif
/// Opaque representation of an error. /// Opaque representation of an error.
/// Errors are refcounted objects that represent the result of an operation. /// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
/// Ownership laws: /// full write up of this object.
/// if a grpc_error is returned by a function, the caller owns a ref to that
/// instance
/// if a grpc_error is passed to a grpc_closure callback function (functions
/// with the signature:
/// void (*f)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error))
/// then those functions do not own a ref to error (but are free to manually
/// take a reference).
/// if a grpc_error is passed to *ANY OTHER FUNCTION* then that function takes
/// ownership of the error
/// Errors have:
/// a set of ints, strings, and timestamps that describe the error
/// always present are:
/// GRPC_ERROR_STR_FILE, GRPC_ERROR_INT_FILE_LINE - source location the error
/// was generated
/// GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error
/// GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened
/// an error can also have children; these are other errors that are believed
/// to have contributed to this one. By accumulating children, we can begin
/// to root cause high level failures from low level failures, without having
/// to derive execution paths from log lines
typedef struct grpc_error grpc_error; typedef struct grpc_error grpc_error;
typedef enum { typedef enum {
@ -156,7 +138,7 @@ typedef enum {
const char *grpc_error_string(grpc_error *error); const char *grpc_error_string(grpc_error *error);
/// Create an error - but use GRPC_ERROR_CREATE instead /// Create an error - but use GRPC_ERROR_CREATE instead
grpc_error *grpc_error_create(const char *file, int line, const char *desc, grpc_error *grpc_error_create(grpc_slice file, int line, grpc_slice desc,
grpc_error **referencing, size_t num_referencing); grpc_error **referencing, size_t num_referencing);
/// Create an error (this is the preferred way of generating an error that is /// Create an error (this is the preferred way of generating an error that is
/// not due to a system call - for system calls, use GRPC_OS_ERROR or /// not due to a system call - for system calls, use GRPC_OS_ERROR or
@ -166,13 +148,21 @@ grpc_error *grpc_error_create(const char *file, int line, const char *desc,
/// err = grpc_error_create(x, y, z, r, nr) is equivalent to: /// err = grpc_error_create(x, y, z, r, nr) is equivalent to:
/// err = grpc_error_create(x, y, z, NULL, 0); /// err = grpc_error_create(x, y, z, NULL, 0);
/// for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]); /// for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]);
#define GRPC_ERROR_CREATE(desc) \ #define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc) \
grpc_error_create(__FILE__, __LINE__, desc, NULL, 0) grpc_error_create(grpc_slice_from_static_string(__FILE__), __LINE__, \
grpc_slice_from_static_string(desc), NULL, 0)
#define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc) \
grpc_error_create(grpc_slice_from_static_string(__FILE__), __LINE__, \
grpc_slice_from_copied_string(desc), NULL, 0)
// Create an error that references some other errors. This function adds a // Create an error that references some other errors. This function adds a
// reference to each error in errs - it does not consume an existing reference // reference to each error in errs - it does not consume an existing reference
#define GRPC_ERROR_CREATE_REFERENCING(desc, errs, count) \ #define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count) \
grpc_error_create(__FILE__, __LINE__, desc, errs, count) grpc_error_create(grpc_slice_from_static_string(__FILE__), __LINE__, \
grpc_slice_from_static_string(desc), errs, count)
#define GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(desc, errs, count) \
grpc_error_create(grpc_slice_from_static_string(__FILE__), __LINE__, \
grpc_slice_from_copied_string(desc), errs, count)
//#define GRPC_ERROR_REFCOUNT_DEBUG //#define GRPC_ERROR_REFCOUNT_DEBUG
#ifdef GRPC_ERROR_REFCOUNT_DEBUG #ifdef GRPC_ERROR_REFCOUNT_DEBUG
@ -194,10 +184,11 @@ grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
intptr_t value) GRPC_MUST_USE_RESULT; intptr_t value) GRPC_MUST_USE_RESULT;
bool grpc_error_get_int(grpc_error *error, grpc_error_ints which, intptr_t *p); bool grpc_error_get_int(grpc_error *error, grpc_error_ints which, intptr_t *p);
grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which, grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value) GRPC_MUST_USE_RESULT; grpc_slice str) GRPC_MUST_USE_RESULT;
/// Returns NULL if the specified string is not set. /// Returns false if the specified string is not set.
/// Caller does NOT own return value. /// Caller does NOT own the slice.
const char *grpc_error_get_str(grpc_error *error, grpc_error_strs which); bool grpc_error_get_str(grpc_error *error, grpc_error_strs which,
grpc_slice *s);
/// Add a child error: an error that is believed to have contributed to this /// Add a child error: an error that is believed to have contributed to this
/// error occurring. Allows root causing high level errors from lower level /// error occurring. Allows root causing high level errors from lower level

@ -321,7 +321,7 @@ static bool append_error(grpc_error **composite, grpc_error *error,
const char *desc) { const char *desc) {
if (error == GRPC_ERROR_NONE) return true; if (error == GRPC_ERROR_NONE) return true;
if (*composite == GRPC_ERROR_NONE) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE(desc); *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
} }
*composite = grpc_error_add_child(*composite, error); *composite = grpc_error_add_child(*composite, error);
return false; return false;
@ -1146,9 +1146,9 @@ static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
schedule the closure with the shutdown error */ schedule the closure with the shutdown error */
if ((curr & FD_SHUTDOWN_BIT) > 0) { if ((curr & FD_SHUTDOWN_BIT) > 0) {
grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT); grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT);
grpc_closure_sched( grpc_closure_sched(exec_ctx, closure,
exec_ctx, closure, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("FD Shutdown", &shutdown_err, 1)); "FD Shutdown", &shutdown_err, 1));
return; return;
} }
@ -1203,9 +1203,9 @@ static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
notify_on to ensure that the closure it schedules 'happens-after' notify_on to ensure that the closure it schedules 'happens-after'
the set_shutdown is called on the fd */ the set_shutdown is called on the fd */
if (gpr_atm_rel_cas(state, curr, new_state)) { if (gpr_atm_rel_cas(state, curr, new_state)) {
grpc_closure_sched( grpc_closure_sched(exec_ctx, (grpc_closure *)curr,
exec_ctx, (grpc_closure *)curr, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_CREATE_REFERENCING("FD Shutdown", &shutdown_err, 1)); "FD Shutdown", &shutdown_err, 1));
return; return;
} }

@ -451,14 +451,16 @@ static grpc_error *fd_shutdown_error(grpc_fd *fd) {
if (!fd->shutdown) { if (!fd->shutdown) {
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} else { } else {
return GRPC_ERROR_CREATE_REFERENCING("FD shutdown", &fd->shutdown_error, 1); return GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"FD shutdown", &fd->shutdown_error, 1);
} }
} }
static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure **st, grpc_closure *closure) { grpc_closure **st, grpc_closure *closure) {
if (fd->shutdown) { if (fd->shutdown) {
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown")); grpc_closure_sched(exec_ctx, closure,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("FD shutdown"));
} else if (*st == CLOSURE_NOT_READY) { } else if (*st == CLOSURE_NOT_READY) {
/* not ready ==> switch to a waiting state by setting the closure */ /* not ready ==> switch to a waiting state by setting the closure */
*st = closure; *st = closure;
@ -696,7 +698,7 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
static void kick_append_error(grpc_error **composite, grpc_error *error) { static void kick_append_error(grpc_error **composite, grpc_error *error) {
if (error == GRPC_ERROR_NONE) return; if (error == GRPC_ERROR_NONE) return;
if (*composite == GRPC_ERROR_NONE) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("Kick Failure"); *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Kick Failure");
} }
*composite = grpc_error_add_child(*composite, error); *composite = grpc_error_add_child(*composite, error);
} }
@ -859,7 +861,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
static void work_combine_error(grpc_error **composite, grpc_error *error) { static void work_combine_error(grpc_error **composite, grpc_error *error) {
if (error == GRPC_ERROR_NONE) return; if (error == GRPC_ERROR_NONE) return;
if (*composite == GRPC_ERROR_NONE) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("pollset_work"); *composite = GRPC_ERROR_CREATE_FROM_STATIC_STRING("pollset_work");
} }
*composite = grpc_error_add_child(*composite, error); *composite = grpc_error_add_child(*composite, error);
} }
@ -1421,7 +1423,7 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
g_cvfds.pollcount++; g_cvfds.pollcount++;
opt = gpr_thd_options_default(); opt = gpr_thd_options_default();
gpr_thd_options_set_detached(&opt); gpr_thd_options_set_detached(&opt);
gpr_thd_new(&t_id, &run_poll, pargs, &opt); GPR_ASSERT(gpr_thd_new(&t_id, &run_poll, pargs, &opt));
// We want the poll() thread to trigger the deadline, so wait forever here // We want the poll() thread to trigger the deadline, so wait forever here
gpr_cv_wait(pollcv, &g_cvfds.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC)); gpr_cv_wait(pollcv, &g_cvfds.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
if (gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) { if (gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) {

@ -115,8 +115,8 @@ static void maybe_spawn_locked() {
/* All previous instances of the thread should have been joined at this point. /* All previous instances of the thread should have been joined at this point.
* Spawn time! */ * Spawn time! */
g_executor.busy = 1; g_executor.busy = 1;
gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL, GPR_ASSERT(gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
&g_executor.options); &g_executor.options));
g_executor.pending_join = 1; g_executor.pending_join = 1;
} }

@ -78,9 +78,12 @@ end:
*output = result; *output = result;
if (file != NULL) fclose(file); if (file != NULL) fclose(file);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
grpc_error *error_out = grpc_error_set_str( grpc_error *error_out =
GRPC_ERROR_CREATE_REFERENCING("Failed to load file", &error, 1), grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
GRPC_ERROR_STR_FILENAME, filename); "Failed to load file", &error, 1),
GRPC_ERROR_STR_FILENAME,
grpc_slice_from_copied_string(
filename)); // TODO(ncteisen), always static?
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
error = error_out; error = error_out;
} }

@ -39,6 +39,7 @@
#if defined(GRPC_UV) #if defined(GRPC_UV)
// Do nothing // Do nothing
#elif defined(GPR_MANYLINUX1) #elif defined(GPR_MANYLINUX1)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1 #define GRPC_HAVE_MSG_NOSIGNAL 1
@ -65,6 +66,7 @@
#define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1 #define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_LINUX) #elif defined(GPR_LINUX)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1 #define GRPC_HAVE_MSG_NOSIGNAL 1
@ -90,6 +92,7 @@
#define GRPC_POSIX_SOCKETUTILS #define GRPC_POSIX_SOCKETUTILS
#endif #endif
#elif defined(GPR_APPLE) #elif defined(GPR_APPLE)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_SO_NOSIGPIPE 1 #define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1 #define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_MSG_IOVLEN_TYPE int #define GRPC_MSG_IOVLEN_TYPE int
@ -100,6 +103,7 @@
#define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1 #define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_FREEBSD) #elif defined(GPR_FREEBSD)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_SO_NOSIGPIPE 1 #define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1 #define GRPC_HAVE_UNIX_SOCKET 1

@ -73,14 +73,16 @@ static grpc_error *blocking_resolve_address_impl(
/* parse name, splitting it into host and port parts */ /* parse name, splitting it into host and port parts */
gpr_split_host_port(name, &host, &port); gpr_split_host_port(name, &host, &port);
if (host == NULL) { if (host == NULL) {
err = grpc_error_set_str(GRPC_ERROR_CREATE("unparseable host:port"), err = grpc_error_set_str(
GRPC_ERROR_STR_TARGET_ADDRESS, name); GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
goto done; goto done;
} }
if (port == NULL) { if (port == NULL) {
if (default_port == NULL) { if (default_port == NULL) {
err = grpc_error_set_str(GRPC_ERROR_CREATE("no port in name"), err = grpc_error_set_str(
GRPC_ERROR_STR_TARGET_ADDRESS, name); GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
goto done; goto done;
} }
port = gpr_strdup(default_port); port = gpr_strdup(default_port);
@ -112,11 +114,15 @@ static grpc_error *blocking_resolve_address_impl(
if (s != 0) { if (s != 0) {
err = grpc_error_set_str( err = grpc_error_set_str(
grpc_error_set_str( grpc_error_set_str(
grpc_error_set_str(grpc_error_set_int(GRPC_ERROR_CREATE("OS Error"), grpc_error_set_str(
GRPC_ERROR_INT_ERRNO, s), grpc_error_set_int(
GRPC_ERROR_STR_OS_ERROR, gai_strerror(s)), GRPC_ERROR_CREATE_FROM_STATIC_STRING("OS Error"),
GRPC_ERROR_STR_SYSCALL, "getaddrinfo"), GRPC_ERROR_INT_ERRNO, s),
GRPC_ERROR_STR_TARGET_ADDRESS, name); GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(gai_strerror(s))),
GRPC_ERROR_STR_SYSCALL,
grpc_slice_from_static_string("getaddrinfo")),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
goto done; goto done;
} }

@ -92,9 +92,10 @@ static grpc_error *handle_addrinfo_result(int status, struct addrinfo *result,
if (status != 0) { if (status != 0) {
grpc_error *error; grpc_error *error;
*addresses = NULL; *addresses = NULL;
error = GRPC_ERROR_CREATE("getaddrinfo failed"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
error = error =
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(status)));
return error; return error;
} }
(*addresses) = gpr_malloc(sizeof(grpc_resolved_addresses)); (*addresses) = gpr_malloc(sizeof(grpc_resolved_addresses));
@ -153,7 +154,7 @@ static grpc_error *try_split_host_port(const char *name,
if (*host == NULL) { if (*host == NULL) {
char *msg; char *msg;
gpr_asprintf(&msg, "unparseable host:port: '%s'", name); gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return error; return error;
} }
@ -162,7 +163,7 @@ static grpc_error *try_split_host_port(const char *name,
if (default_port == NULL) { if (default_port == NULL) {
char *msg; char *msg;
gpr_asprintf(&msg, "no port in name '%s'", name); gpr_asprintf(&msg, "no port in name '%s'", name);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return error; return error;
} }
@ -262,8 +263,9 @@ static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
if (s != 0) { if (s != 0) {
*addrs = NULL; *addrs = NULL;
err = GRPC_ERROR_CREATE("getaddrinfo failed"); err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR, uv_strerror(s)); err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(s)));
grpc_closure_sched(exec_ctx, on_done, err); grpc_closure_sched(exec_ctx, on_done, err);
gpr_free(r); gpr_free(r);
gpr_free(req); gpr_free(req);

@ -78,7 +78,7 @@ static grpc_error *blocking_resolve_address_impl(
if (host == NULL) { if (host == NULL) {
char *msg; char *msg;
gpr_asprintf(&msg, "unparseable host:port: '%s'", name); gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
goto done; goto done;
} }
@ -86,7 +86,7 @@ static grpc_error *blocking_resolve_address_impl(
if (default_port == NULL) { if (default_port == NULL) {
char *msg; char *msg;
gpr_asprintf(&msg, "no port in name '%s'", name); gpr_asprintf(&msg, "no port in name '%s'", name);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
goto done; goto done;
} }

@ -0,0 +1,110 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_POSIX_SOCKET
#include "src/core/lib/iomgr/socket_factory_posix.h"
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
void grpc_socket_factory_init(grpc_socket_factory *factory,
const grpc_socket_factory_vtable *vtable) {
factory->vtable = vtable;
gpr_ref_init(&factory->refcount, 1);
}
int grpc_socket_factory_socket(grpc_socket_factory *factory, int domain,
int type, int protocol) {
return factory->vtable->socket(factory, domain, type, protocol);
}
int grpc_socket_factory_bind(grpc_socket_factory *factory, int sockfd,
const grpc_resolved_address *addr) {
return factory->vtable->bind(factory, sockfd, addr);
}
int grpc_socket_factory_compare(grpc_socket_factory *a,
grpc_socket_factory *b) {
int c = GPR_ICMP(a, b);
if (c != 0) {
grpc_socket_factory *sma = a;
grpc_socket_factory *smb = b;
c = GPR_ICMP(sma->vtable, smb->vtable);
if (c == 0) {
c = sma->vtable->compare(sma, smb);
}
}
return c;
}
grpc_socket_factory *grpc_socket_factory_ref(grpc_socket_factory *factory) {
gpr_ref(&factory->refcount);
return factory;
}
void grpc_socket_factory_unref(grpc_socket_factory *factory) {
if (gpr_unref(&factory->refcount)) {
factory->vtable->destroy(factory);
}
}
static void *socket_factory_arg_copy(void *p) {
return grpc_socket_factory_ref(p);
}
static void socket_factory_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
grpc_socket_factory_unref(p);
}
static int socket_factory_cmp(void *a, void *b) {
return grpc_socket_factory_compare((grpc_socket_factory *)a,
(grpc_socket_factory *)b);
}
static const grpc_arg_pointer_vtable socket_factory_arg_vtable = {
socket_factory_arg_copy, socket_factory_arg_destroy, socket_factory_cmp};
grpc_arg grpc_socket_factory_to_arg(grpc_socket_factory *factory) {
grpc_arg arg;
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_ARG_SOCKET_FACTORY;
arg.value.pointer.vtable = &socket_factory_arg_vtable;
arg.value.pointer.p = factory;
return arg;
}
#endif

@ -0,0 +1,90 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H
#define GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/sync.h>
#include "src/core/lib/iomgr/resolve_address.h"
#ifdef __cplusplus
extern "C" {
#endif
/** The virtual table of grpc_socket_factory */
typedef struct {
/** Replacement for socket(2) */
int (*socket)(grpc_socket_factory *factory, int domain, int type,
int protocol);
/** Replacement for bind(2) */
int (*bind)(grpc_socket_factory *factory, int sockfd,
const grpc_resolved_address *addr);
/** Compare socket factory \a a and \a b */
int (*compare)(grpc_socket_factory *a, grpc_socket_factory *b);
/** Destroys the socket factory instance */
void (*destroy)(grpc_socket_factory *factory);
} grpc_socket_factory_vtable;
/** The Socket Factory interface allows changes on socket options */
struct grpc_socket_factory {
const grpc_socket_factory_vtable *vtable;
gpr_refcount refcount;
};
/** called by concrete implementations to initialize the base struct */
void grpc_socket_factory_init(grpc_socket_factory *factory,
const grpc_socket_factory_vtable *vtable);
/** Wrap \a factory as a grpc_arg */
grpc_arg grpc_socket_factory_to_arg(grpc_socket_factory *factory);
/** Perform the equivalent of a socket(2) operation using \a factory */
int grpc_socket_factory_socket(grpc_socket_factory *factory, int domain,
int type, int protocol);
/** Perform the equivalent of a bind(2) operation using \a factory */
int grpc_socket_factory_bind(grpc_socket_factory *factory, int sockfd,
const grpc_resolved_address *addr);
/** Compare if \a a and \a b are the same factory or have same settings */
int grpc_socket_factory_compare(grpc_socket_factory *a, grpc_socket_factory *b);
grpc_socket_factory *grpc_socket_factory_ref(grpc_socket_factory *factory);
void grpc_socket_factory_unref(grpc_socket_factory *factory);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H */

@ -90,7 +90,7 @@ grpc_error *grpc_set_socket_no_sigpipe_if_possible(int fd) {
return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)"); return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)");
} }
if ((newval != 0) != (val != 0)) { if ((newval != 0) != (val != 0)) {
return GRPC_ERROR_CREATE("Failed to set SO_NOSIGPIPE"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_NOSIGPIPE");
} }
#endif #endif
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
@ -164,7 +164,7 @@ grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) {
return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)"); return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)");
} }
if ((newval != 0) != val) { if ((newval != 0) != val) {
return GRPC_ERROR_CREATE("Failed to set SO_REUSEADDR"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEADDR");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
@ -173,7 +173,8 @@ grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) {
/* set a socket to reuse old addresses */ /* set a socket to reuse old addresses */
grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) { grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) {
#ifndef SO_REUSEPORT #ifndef SO_REUSEPORT
return GRPC_ERROR_CREATE("SO_REUSEPORT unavailable on compiling system"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"SO_REUSEPORT unavailable on compiling system");
#else #else
int val = (reuse != 0); int val = (reuse != 0);
int newval; int newval;
@ -185,7 +186,7 @@ grpc_error *grpc_set_socket_reuse_port(int fd, int reuse) {
return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)"); return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEPORT)");
} }
if ((newval != 0) != val) { if ((newval != 0) != val) {
return GRPC_ERROR_CREATE("Failed to set SO_REUSEPORT"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set SO_REUSEPORT");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
@ -204,7 +205,7 @@ grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) {
return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)"); return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)");
} }
if ((newval != 0) != val) { if ((newval != 0) != val) {
return GRPC_ERROR_CREATE("Failed to set TCP_NODELAY"); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set TCP_NODELAY");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -213,7 +214,7 @@ grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) {
grpc_error *grpc_set_socket_with_mutator(int fd, grpc_socket_mutator *mutator) { grpc_error *grpc_set_socket_with_mutator(int fd, grpc_socket_mutator *mutator) {
GPR_ASSERT(mutator); GPR_ASSERT(mutator);
if (!grpc_socket_mutator_mutate_fd(mutator, fd)) { if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
return GRPC_ERROR_CREATE("grpc_socket_mutator failed."); return GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_socket_mutator failed.");
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
@ -268,7 +269,8 @@ static grpc_error *error_for_fd(int fd, const grpc_resolved_address *addr) {
char *addr_str; char *addr_str;
grpc_sockaddr_to_string(&addr_str, addr, 0); grpc_sockaddr_to_string(&addr_str, addr, 0);
grpc_error *err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"), grpc_error *err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"),
GRPC_ERROR_STR_TARGET_ADDRESS, addr_str); GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(addr_str));
gpr_free(addr_str); gpr_free(addr_str);
return err; return err;
} }
@ -276,11 +278,25 @@ static grpc_error *error_for_fd(int fd, const grpc_resolved_address *addr) {
grpc_error *grpc_create_dualstack_socket( grpc_error *grpc_create_dualstack_socket(
const grpc_resolved_address *resolved_addr, int type, int protocol, const grpc_resolved_address *resolved_addr, int type, int protocol,
grpc_dualstack_mode *dsmode, int *newfd) { grpc_dualstack_mode *dsmode, int *newfd) {
return grpc_create_dualstack_socket_using_factory(NULL, resolved_addr, type,
protocol, dsmode, newfd);
}
static int create_socket(grpc_socket_factory *factory, int domain, int type,
int protocol) {
return (factory != NULL)
? grpc_socket_factory_socket(factory, domain, type, protocol)
: socket(domain, type, protocol);
}
grpc_error *grpc_create_dualstack_socket_using_factory(
grpc_socket_factory *factory, const grpc_resolved_address *resolved_addr,
int type, int protocol, grpc_dualstack_mode *dsmode, int *newfd) {
const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr; const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr;
int family = addr->sa_family; int family = addr->sa_family;
if (family == AF_INET6) { if (family == AF_INET6) {
if (grpc_ipv6_loopback_available()) { if (grpc_ipv6_loopback_available()) {
*newfd = socket(family, type, protocol); *newfd = create_socket(factory, family, type, protocol);
} else { } else {
*newfd = -1; *newfd = -1;
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;
@ -302,7 +318,7 @@ grpc_error *grpc_create_dualstack_socket(
family = AF_INET; family = AF_INET;
} }
*dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE; *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
*newfd = socket(family, type, protocol); *newfd = create_socket(factory, family, type, protocol);
return error_for_fd(*newfd, resolved_addr); return error_for_fd(*newfd, resolved_addr);
} }

@ -41,6 +41,7 @@
#include <grpc/impl/codegen/grpc_types.h> #include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/socket_factory_posix.h"
#include "src/core/lib/iomgr/socket_mutator.h" #include "src/core/lib/iomgr/socket_mutator.h"
/* a wrapper for accept or accept4 */ /* a wrapper for accept or accept4 */
@ -137,4 +138,10 @@ grpc_error *grpc_create_dualstack_socket(const grpc_resolved_address *addr,
grpc_dualstack_mode *dsmode, grpc_dualstack_mode *dsmode,
int *newfd); int *newfd);
/* Same as grpc_create_dualstack_socket(), but use the given socket factory (if
non-null) to create the socket, rather than calling socket() directly. */
grpc_error *grpc_create_dualstack_socket_using_factory(
grpc_socket_factory *factory, const grpc_resolved_address *addr, int type,
int protocol, grpc_dualstack_mode *dsmode, int *newfd);
#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */ #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */

@ -121,8 +121,8 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
} }
gpr_mu_lock(&ac->mu); gpr_mu_lock(&ac->mu);
if (ac->fd != NULL) { if (ac->fd != NULL) {
grpc_fd_shutdown(exec_ctx, ac->fd, grpc_fd_shutdown(exec_ctx, ac->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("connect() timed out")); "connect() timed out"));
} }
done = (--ac->refs == 0); done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu); gpr_mu_unlock(&ac->mu);
@ -191,7 +191,8 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
gpr_mu_lock(&ac->mu); gpr_mu_lock(&ac->mu);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
error = error =
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, "Timeout occurred"); grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string("Timeout occurred"));
goto finish; goto finish;
} }
@ -252,12 +253,17 @@ finish:
gpr_mu_unlock(&ac->mu); gpr_mu_unlock(&ac->mu);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
char *error_descr; char *error_descr;
gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", grpc_slice str;
grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION)); bool ret = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &str);
error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION, error_descr); GPR_ASSERT(ret);
char *desc = grpc_slice_to_c_string(str);
gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", desc);
error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION,
grpc_slice_from_copied_string(error_descr));
gpr_free(error_descr); gpr_free(error_descr);
error = gpr_free(desc);
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, ac->addr_str); error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(ac->addr_str));
} }
if (done) { if (done) {
gpr_mu_destroy(&ac->mu); gpr_mu_destroy(&ac->mu);

@ -100,17 +100,21 @@ static void uv_tc_on_connect(uv_connect_t *req, int status) {
*connect->endpoint = grpc_tcp_create( *connect->endpoint = grpc_tcp_create(
connect->tcp_handle, connect->resource_quota, connect->addr_name); connect->tcp_handle, connect->resource_quota, connect->addr_name);
} else { } else {
error = GRPC_ERROR_CREATE("Failed to connect to remote host"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Failed to connect to remote host");
error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status); error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status);
error = error =
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status)); grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(status)));
if (status == UV_ECANCELED) { if (status == UV_ECANCELED) {
error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, error =
"Timeout occurred"); grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string("Timeout occurred"));
// This should only happen if the handle is already closed // This should only happen if the handle is already closed
} else { } else {
error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, error = grpc_error_set_str(
uv_strerror(status)); error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(status)));
uv_close((uv_handle_t *)connect->tcp_handle, tcp_close_callback); uv_close((uv_handle_t *)connect->tcp_handle, tcp_close_callback);
} }
} }

@ -123,7 +123,7 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
socket = NULL; socket = NULL;
} }
} else { } else {
error = GRPC_ERROR_CREATE("socket is null"); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket is null");
} }
} }
@ -238,8 +238,9 @@ failure:
GPR_ASSERT(error != GRPC_ERROR_NONE); GPR_ASSERT(error != GRPC_ERROR_NONE);
char *target_uri = grpc_sockaddr_to_uri(addr); char *target_uri = grpc_sockaddr_to_uri(addr);
grpc_error *final_error = grpc_error_set_str( grpc_error *final_error = grpc_error_set_str(
GRPC_ERROR_CREATE_REFERENCING("Failed to connect", &error, 1), GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Failed to connect",
GRPC_ERROR_STR_TARGET_ADDRESS, target_uri); &error, 1),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(target_uri));
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
if (socket != NULL) { if (socket != NULL) {
grpc_winsocket_destroy(socket); grpc_winsocket_destroy(socket);

@ -111,7 +111,8 @@ typedef struct {
static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) { static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) {
return grpc_error_set_str( return grpc_error_set_str(
grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd), grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
GRPC_ERROR_STR_TARGET_ADDRESS, tcp->peer_string); GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(tcp->peer_string));
} }
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
@ -246,8 +247,10 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
} else if (read_bytes == 0) { } else if (read_bytes == 0) {
/* 0 read size ==> end of stream */ /* 0 read size ==> end of stream */
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer); grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer);
call_read_cb(exec_ctx, tcp, call_read_cb(
tcp_annotate_error(GRPC_ERROR_CREATE("Socket closed"), tcp)); exec_ctx, tcp,
tcp_annotate_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp));
TCP_UNREF(exec_ctx, tcp, "read"); TCP_UNREF(exec_ctx, tcp, "read");
} else { } else {
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length); GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
@ -464,10 +467,12 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
if (buf->length == 0) { if (buf->length == 0) {
GPR_TIMER_END("tcp_write", 0); GPR_TIMER_END("tcp_write", 0);
grpc_closure_sched(exec_ctx, cb, grpc_closure_sched(
grpc_fd_is_shutdown(tcp->em_fd) exec_ctx, cb,
? tcp_annotate_error(GRPC_ERROR_CREATE("EOF"), tcp) grpc_fd_is_shutdown(tcp->em_fd)
: GRPC_ERROR_NONE); ? tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"),
tcp)
: GRPC_ERROR_NONE);
return; return;
} }
tcp->outgoing_buffer = buf; tcp->outgoing_buffer = buf;

@ -44,11 +44,8 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <ifaddrs.h>
#include <limits.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -67,82 +64,10 @@
#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils_posix.h" #include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h" #include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h" #include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
static gpr_once s_init_max_accept_queue_size;
static int s_max_accept_queue_size;
/* one listening port */
typedef struct grpc_tcp_listener grpc_tcp_listener;
struct grpc_tcp_listener {
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
grpc_resolved_address addr;
int port;
unsigned port_index;
unsigned fd_index;
grpc_closure read_closure;
grpc_closure destroyed_closure;
struct grpc_tcp_listener *next;
/* sibling is a linked list of all listeners for a given port. add_port and
clone_port place all new listeners in the same sibling list. A member of
the 'sibling' list is also a member of the 'next' list. The head of each
sibling list has is_sibling==0, and subsequent members of sibling lists
have is_sibling==1. is_sibling allows separate sibling lists to be
identified while iterating through 'next'. */
struct grpc_tcp_listener *sibling;
int is_sibling;
};
/* the overall server */
struct grpc_tcp_server {
gpr_refcount refs;
/* Called whenever accept() succeeds on a server port. */
grpc_tcp_server_cb on_accept_cb;
void *on_accept_cb_arg;
gpr_mu mu;
/* active port count: how many ports are actually still listening */
size_t active_ports;
/* destroyed port count: how many ports are completely destroyed */
size_t destroyed_ports;
/* is this server shutting down? */
bool shutdown;
/* have listeners been shutdown? */
bool shutdown_listeners;
/* use SO_REUSEPORT */
bool so_reuseport;
/* expand wildcard addresses to a list of all local addresses */
bool expand_wildcard_addrs;
/* linked list of server ports */
grpc_tcp_listener *head;
grpc_tcp_listener *tail;
unsigned nports;
/* List of closures passed to shutdown_starting_add(). */
grpc_closure_list shutdown_starting;
/* shutdown callback */
grpc_closure *shutdown_complete;
/* all pollsets interested in new connections */
grpc_pollset **pollsets;
/* number of pollsets in the pollsets array */
size_t pollset_count;
/* next pollset to assign a channel to */
gpr_atm next_pollset_to_assign;
grpc_resource_quota *resource_quota;
};
static gpr_once check_init = GPR_ONCE_INIT; static gpr_once check_init = GPR_ONCE_INIT;
static bool has_so_reuseport = false; static bool has_so_reuseport = false;
@ -175,8 +100,8 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
} else { } else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s); gpr_free(s);
return GRPC_ERROR_CREATE(GRPC_ARG_ALLOW_REUSEPORT return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT
" must be an integer"); " must be an integer");
} }
} else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_POINTER) { if (args->args[i].type == GRPC_ARG_POINTER) {
@ -186,8 +111,8 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
} else { } else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s); gpr_free(s);
return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
" must be a pointer to a buffer pool"); GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
} }
} else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) { } else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) {
if (args->args[i].type == GRPC_ARG_INTEGER) { if (args->args[i].type == GRPC_ARG_INTEGER) {
@ -195,8 +120,8 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
} else { } else {
grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota); grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
gpr_free(s); gpr_free(s);
return GRPC_ERROR_CREATE(GRPC_ARG_EXPAND_WILDCARD_ADDRS return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
" must be an integer"); GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer");
} }
} }
} }
@ -260,10 +185,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
/* delete ALL the things */ /* delete ALL the things */
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
if (!s->shutdown) { GPR_ASSERT(s->shutdown);
gpr_mu_unlock(&s->mu);
return;
}
if (s->head) { if (s->head) {
grpc_tcp_listener *sp; grpc_tcp_listener *sp;
@ -291,8 +213,8 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
if (s->active_ports) { if (s->active_ports) {
grpc_tcp_listener *sp; grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) { for (sp = s->head; sp; sp = sp->next) {
grpc_fd_shutdown(exec_ctx, sp->emfd, grpc_fd_shutdown(exec_ctx, sp->emfd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Server destroyed")); "Server destroyed"));
} }
gpr_mu_unlock(&s->mu); gpr_mu_unlock(&s->mu);
} else { } else {
@ -301,99 +223,6 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
} }
} }
/* get max listen queue size on linux */
static void init_max_accept_queue_size(void) {
int n = SOMAXCONN;
char buf[64];
FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
if (fp == NULL) {
/* 2.4 kernel. */
s_max_accept_queue_size = SOMAXCONN;
return;
}
if (fgets(buf, sizeof buf, fp)) {
char *end;
long i = strtol(buf, &end, 10);
if (i > 0 && i <= INT_MAX && end && *end == 0) {
n = (int)i;
}
}
fclose(fp);
s_max_accept_queue_size = n;
if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
gpr_log(GPR_INFO,
"Suspiciously small accept queue (%d) will probably lead to "
"connection drops",
s_max_accept_queue_size);
}
}
static int get_max_accept_queue_size(void) {
gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
return s_max_accept_queue_size;
}
/* Prepare a recently-created socket for listening. */
static grpc_error *prepare_socket(int fd, const grpc_resolved_address *addr,
bool so_reuseport, int *port) {
grpc_resolved_address sockname_temp;
grpc_error *err = GRPC_ERROR_NONE;
GPR_ASSERT(fd >= 0);
if (so_reuseport && !grpc_is_unix_socket(addr)) {
err = grpc_set_socket_reuse_port(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_nonblocking(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_cloexec(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_reuse_addr(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
GPR_ASSERT(addr->len < ~(socklen_t)0);
if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
err = GRPC_OS_ERROR(errno, "bind");
goto error;
}
if (listen(fd, get_max_accept_queue_size()) < 0) {
err = GRPC_OS_ERROR(errno, "listen");
goto error;
}
sockname_temp.len = sizeof(struct sockaddr_storage);
if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
(socklen_t *)&sockname_temp.len) < 0) {
err = GRPC_OS_ERROR(errno, "getsockname");
goto error;
}
*port = grpc_sockaddr_get_port(&sockname_temp);
return GRPC_ERROR_NONE;
error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (fd >= 0) {
close(fd);
}
grpc_error *ret = grpc_error_set_int(
GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
GRPC_ERROR_INT_FD, fd);
GRPC_ERROR_UNREF(err);
return ret;
}
/* event manager callback when reads are ready */ /* event manager callback when reads are ready */
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) { static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
grpc_tcp_listener *sp = arg; grpc_tcp_listener *sp = arg;
@ -469,7 +298,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
error: error:
gpr_mu_lock(&sp->server->mu); gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) { if (0 == --sp->server->active_ports && sp->server->shutdown) {
gpr_mu_unlock(&sp->server->mu); gpr_mu_unlock(&sp->server->mu);
deactivated_all_ports(exec_ctx, sp->server); deactivated_all_ports(exec_ctx, sp->server);
} else { } else {
@ -477,216 +306,6 @@ error:
} }
} }
static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
const grpc_resolved_address *addr,
unsigned port_index, unsigned fd_index,
grpc_tcp_listener **listener) {
grpc_tcp_listener *sp = NULL;
int port = -1;
char *addr_str;
char *name;
grpc_error *err = prepare_socket(fd, addr, s->so_reuseport, &port);
if (err == GRPC_ERROR_NONE) {
GPR_ASSERT(port > 0);
grpc_sockaddr_to_string(&addr_str, addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
s->nports++;
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
sp = gpr_malloc(sizeof(grpc_tcp_listener));
sp->next = NULL;
if (s->head == NULL) {
s->head = sp;
} else {
s->tail->next = sp;
}
s->tail = sp;
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd, name);
memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
sp->port = port;
sp->port_index = port_index;
sp->fd_index = fd_index;
sp->is_sibling = 0;
sp->sibling = NULL;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
gpr_free(addr_str);
gpr_free(name);
}
*listener = sp;
return err;
}
/* If successful, add a listener to s for addr, set *dsmode for the socket, and
return the *listener. */
static grpc_error *add_addr_to_server(grpc_tcp_server *s,
const grpc_resolved_address *addr,
unsigned port_index, unsigned fd_index,
grpc_dualstack_mode *dsmode,
grpc_tcp_listener **listener) {
grpc_resolved_address addr4_copy;
int fd;
grpc_error *err =
grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
if (err != GRPC_ERROR_NONE) {
return err;
}
if (*dsmode == GRPC_DSMODE_IPV4 &&
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
addr = &addr4_copy;
}
return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
}
/* Bind to "::" to get a port number not used by any address. */
static grpc_error *get_unused_port(int *port) {
grpc_resolved_address wild;
grpc_sockaddr_make_wildcard6(0, &wild);
grpc_dualstack_mode dsmode;
int fd;
grpc_error *err =
grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
if (err != GRPC_ERROR_NONE) {
return err;
}
if (dsmode == GRPC_DSMODE_IPV4) {
grpc_sockaddr_make_wildcard4(0, &wild);
}
if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) {
err = GRPC_OS_ERROR(errno, "bind");
close(fd);
return err;
}
if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) !=
0) {
err = GRPC_OS_ERROR(errno, "getsockname");
close(fd);
return err;
}
close(fd);
*port = grpc_sockaddr_get_port(&wild);
return *port <= 0 ? GRPC_ERROR_CREATE("Bad port") : GRPC_ERROR_NONE;
}
/* Return the listener in s with address addr or NULL. */
static grpc_tcp_listener *find_listener_with_addr(grpc_tcp_server *s,
grpc_resolved_address *addr) {
grpc_tcp_listener *l;
gpr_mu_lock(&s->mu);
for (l = s->head; l != NULL; l = l->next) {
if (l->addr.len != addr->len) {
continue;
}
if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
break;
}
}
gpr_mu_unlock(&s->mu);
return l;
}
/* Get all addresses assigned to network interfaces on the machine and create a
listener for each. requested_port is the port to use for every listener, or 0
to select one random port that will be used for every listener. Set *out_port
to the port selected. Return GRPC_ERROR_NONE only if all listeners were
added. */
static grpc_error *add_all_local_addrs_to_server(grpc_tcp_server *s,
unsigned port_index,
int requested_port,
int *out_port) {
struct ifaddrs *ifa = NULL;
struct ifaddrs *ifa_it;
unsigned fd_index = 0;
grpc_tcp_listener *sp = NULL;
grpc_error *err = GRPC_ERROR_NONE;
if (requested_port == 0) {
/* Note: There could be a race where some local addrs can listen on the
selected port and some can't. The sane way to handle this would be to
retry by recreating the whole grpc_tcp_server. Backing out individual
listeners and orphaning the FDs looks like too much trouble. */
if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
return err;
} else if (requested_port <= 0) {
return GRPC_ERROR_CREATE("Bad get_unused_port()");
}
gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
}
if (getifaddrs(&ifa) != 0 || ifa == NULL) {
return GRPC_OS_ERROR(errno, "getifaddrs");
}
for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) {
grpc_resolved_address addr;
char *addr_str = NULL;
grpc_dualstack_mode dsmode;
grpc_tcp_listener *new_sp = NULL;
const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
if (ifa_it->ifa_addr == NULL) {
continue;
} else if (ifa_it->ifa_addr->sa_family == AF_INET) {
addr.len = sizeof(struct sockaddr_in);
} else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
addr.len = sizeof(struct sockaddr_in6);
} else {
continue;
}
memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
if (!grpc_sockaddr_set_port(&addr, requested_port)) {
/* Should never happen, because we check sa_family above. */
err = GRPC_ERROR_CREATE("Failed to set port");
break;
}
if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
addr_str = gpr_strdup("<error>");
}
gpr_log(GPR_DEBUG,
"Adding local addr from interface %s flags 0x%x to server: %s",
ifa_name, ifa_it->ifa_flags, addr_str);
/* We could have multiple interfaces with the same address (e.g., bonding),
so look for duplicates. */
if (find_listener_with_addr(s, &addr) != NULL) {
gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
ifa_name);
gpr_free(addr_str);
continue;
}
if ((err = add_addr_to_server(s, &addr, port_index, fd_index, &dsmode,
&new_sp)) != GRPC_ERROR_NONE) {
char *err_str = NULL;
grpc_error *root_err;
if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
err_str = gpr_strdup("Failed to add listener");
}
root_err = GRPC_ERROR_CREATE(err_str);
gpr_free(err_str);
gpr_free(addr_str);
err = grpc_error_add_child(root_err, err);
break;
} else {
GPR_ASSERT(requested_port == new_sp->port);
++fd_index;
if (sp != NULL) {
new_sp->is_sibling = 1;
sp->sibling = new_sp;
}
sp = new_sp;
}
gpr_free(addr_str);
}
freeifaddrs(ifa);
if (err != GRPC_ERROR_NONE) {
return err;
} else if (sp == NULL) {
return GRPC_ERROR_CREATE("No local addresses");
} else {
*out_port = sp->port;
return GRPC_ERROR_NONE;
}
}
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s, static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
unsigned port_index, unsigned port_index,
@ -701,14 +320,16 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
grpc_error *v6_err = GRPC_ERROR_NONE; grpc_error *v6_err = GRPC_ERROR_NONE;
grpc_error *v4_err = GRPC_ERROR_NONE; grpc_error *v4_err = GRPC_ERROR_NONE;
*out_port = -1; *out_port = -1;
if (s->expand_wildcard_addrs) {
return add_all_local_addrs_to_server(s, port_index, requested_port, if (grpc_tcp_server_have_ifaddrs() && s->expand_wildcard_addrs) {
out_port); return grpc_tcp_server_add_all_local_addrs(s, port_index, requested_port,
out_port);
} }
grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6); grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6);
/* Try listening on IPv6 first. */ /* Try listening on IPv6 first. */
if ((v6_err = add_addr_to_server(s, &wild6, port_index, fd_index, &dsmode, if ((v6_err = grpc_tcp_server_add_addr(s, &wild6, port_index, fd_index,
&sp)) == GRPC_ERROR_NONE) { &dsmode, &sp)) == GRPC_ERROR_NONE) {
++fd_index; ++fd_index;
requested_port = *out_port = sp->port; requested_port = *out_port = sp->port;
if (dsmode == GRPC_DSMODE_DUALSTACK || dsmode == GRPC_DSMODE_IPV4) { if (dsmode == GRPC_DSMODE_DUALSTACK || dsmode == GRPC_DSMODE_IPV4) {
@ -717,8 +338,8 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
} }
/* If we got a v6-only socket or nothing, try adding 0.0.0.0. */ /* If we got a v6-only socket or nothing, try adding 0.0.0.0. */
grpc_sockaddr_set_port(&wild4, requested_port); grpc_sockaddr_set_port(&wild4, requested_port);
if ((v4_err = add_addr_to_server(s, &wild4, port_index, fd_index, &dsmode, if ((v4_err = grpc_tcp_server_add_addr(s, &wild4, port_index, fd_index,
&sp2)) == GRPC_ERROR_NONE) { &dsmode, &sp2)) == GRPC_ERROR_NONE) {
*out_port = sp2->port; *out_port = sp2->port;
if (sp != NULL) { if (sp != NULL) {
sp2->is_sibling = 1; sp2->is_sibling = 1;
@ -726,12 +347,24 @@ static grpc_error *add_wildcard_addrs_to_server(grpc_tcp_server *s,
} }
} }
if (*out_port > 0) { if (*out_port > 0) {
GRPC_LOG_IF_ERROR("Failed to add :: listener", v6_err); if (v6_err != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("Failed to add 0.0.0.0 listener", v4_err); gpr_log(GPR_INFO,
"Failed to add :: listener, "
"the environment may not support IPv6: %s",
grpc_error_string(v6_err));
GRPC_ERROR_UNREF(v6_err);
}
if (v4_err != GRPC_ERROR_NONE) {
gpr_log(GPR_INFO,
"Failed to add 0.0.0.0 listener, "
"the environment may not support IPv4: %s",
grpc_error_string(v4_err));
GRPC_ERROR_UNREF(v4_err);
}
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} else { } else {
grpc_error *root_err = grpc_error *root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
GRPC_ERROR_CREATE("Failed to add any wildcard listeners"); "Failed to add any wildcard listeners");
GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE); GPR_ASSERT(v6_err != GRPC_ERROR_NONE && v4_err != GRPC_ERROR_NONE);
root_err = grpc_error_add_child(root_err, v6_err); root_err = grpc_error_add_child(root_err, v6_err);
root_err = grpc_error_add_child(root_err, v4_err); root_err = grpc_error_add_child(root_err, v4_err);
@ -756,7 +389,7 @@ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode, err = grpc_create_dualstack_socket(&listener->addr, SOCK_STREAM, 0, &dsmode,
&fd); &fd);
if (err != GRPC_ERROR_NONE) return err; if (err != GRPC_ERROR_NONE) return err;
err = prepare_socket(fd, &listener->addr, true, &port); err = grpc_tcp_server_prepare_socket(fd, &listener->addr, true, &port);
if (err != GRPC_ERROR_NONE) return err; if (err != GRPC_ERROR_NONE) return err;
listener->server->nports++; listener->server->nports++;
grpc_sockaddr_to_string(&addr_str, &listener->addr, 1); grpc_sockaddr_to_string(&addr_str, &listener->addr, 1);
@ -828,7 +461,7 @@ grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s,
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
addr = &addr6_v4mapped; addr = &addr6_v4mapped;
} }
if ((err = add_addr_to_server(s, addr, port_index, 0, &dsmode, &sp)) == if ((err = grpc_tcp_server_add_addr(s, addr, port_index, 0, &dsmode, &sp)) ==
GRPC_ERROR_NONE) { GRPC_ERROR_NONE) {
*out_port = sp->port; *out_port = sp->port;
} }
@ -951,7 +584,7 @@ void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
grpc_tcp_listener *sp; grpc_tcp_listener *sp;
for (sp = s->head; sp; sp = sp->next) { for (sp = s->head; sp; sp = sp->next) {
grpc_fd_shutdown(exec_ctx, sp->emfd, grpc_fd_shutdown(exec_ctx, sp->emfd,
GRPC_ERROR_CREATE("Server shutdown")); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server shutdown"));
} }
} }
gpr_mu_unlock(&s->mu); gpr_mu_unlock(&s->mu);

@ -0,0 +1,134 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
#define GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_server.h"
/* one listening port */
typedef struct grpc_tcp_listener {
int fd;
grpc_fd *emfd;
grpc_tcp_server *server;
grpc_resolved_address addr;
int port;
unsigned port_index;
unsigned fd_index;
grpc_closure read_closure;
grpc_closure destroyed_closure;
struct grpc_tcp_listener *next;
/* sibling is a linked list of all listeners for a given port. add_port and
clone_port place all new listeners in the same sibling list. A member of
the 'sibling' list is also a member of the 'next' list. The head of each
sibling list has is_sibling==0, and subsequent members of sibling lists
have is_sibling==1. is_sibling allows separate sibling lists to be
identified while iterating through 'next'. */
struct grpc_tcp_listener *sibling;
int is_sibling;
} grpc_tcp_listener;
/* the overall server */
struct grpc_tcp_server {
gpr_refcount refs;
/* Called whenever accept() succeeds on a server port. */
grpc_tcp_server_cb on_accept_cb;
void *on_accept_cb_arg;
gpr_mu mu;
/* active port count: how many ports are actually still listening */
size_t active_ports;
/* destroyed port count: how many ports are completely destroyed */
size_t destroyed_ports;
/* is this server shutting down? */
bool shutdown;
/* have listeners been shutdown? */
bool shutdown_listeners;
/* use SO_REUSEPORT */
bool so_reuseport;
/* expand wildcard addresses to a list of all local addresses */
bool expand_wildcard_addrs;
/* linked list of server ports */
grpc_tcp_listener *head;
grpc_tcp_listener *tail;
unsigned nports;
/* List of closures passed to shutdown_starting_add(). */
grpc_closure_list shutdown_starting;
/* shutdown callback */
grpc_closure *shutdown_complete;
/* all pollsets interested in new connections */
grpc_pollset **pollsets;
/* number of pollsets in the pollsets array */
size_t pollset_count;
/* next pollset to assign a channel to */
gpr_atm next_pollset_to_assign;
grpc_resource_quota *resource_quota;
};
/* If successful, add a listener to \a s for \a addr, set \a dsmode for the
socket, and return the \a listener. */
grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s,
const grpc_resolved_address *addr,
unsigned port_index, unsigned fd_index,
grpc_dualstack_mode *dsmode,
grpc_tcp_listener **listener);
/* Get all addresses assigned to network interfaces on the machine and create a
listener for each. requested_port is the port to use for every listener, or 0
to select one random port that will be used for every listener. Set *out_port
to the port selected. Return GRPC_ERROR_NONE only if all listeners were
added. */
grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
unsigned port_index,
int requested_port,
int *out_port);
/* Prepare a recently-created socket for listening. */
grpc_error *grpc_tcp_server_prepare_socket(int fd,
const grpc_resolved_address *addr,
bool so_reuseport, int *port);
/* Ruturn true if the platform supports ifaddrs */
bool grpc_tcp_server_have_ifaddrs(void);
#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H */

@ -0,0 +1,221 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_POSIX_SOCKET
#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
static gpr_once s_init_max_accept_queue_size;
static int s_max_accept_queue_size;
/* get max listen queue size on linux */
static void init_max_accept_queue_size(void) {
int n = SOMAXCONN;
char buf[64];
FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
if (fp == NULL) {
/* 2.4 kernel. */
s_max_accept_queue_size = SOMAXCONN;
return;
}
if (fgets(buf, sizeof buf, fp)) {
char *end;
long i = strtol(buf, &end, 10);
if (i > 0 && i <= INT_MAX && end && *end == 0) {
n = (int)i;
}
}
fclose(fp);
s_max_accept_queue_size = n;
if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
gpr_log(GPR_INFO,
"Suspiciously small accept queue (%d) will probably lead to "
"connection drops",
s_max_accept_queue_size);
}
}
static int get_max_accept_queue_size(void) {
gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
return s_max_accept_queue_size;
}
static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
const grpc_resolved_address *addr,
unsigned port_index, unsigned fd_index,
grpc_tcp_listener **listener) {
grpc_tcp_listener *sp = NULL;
int port = -1;
char *addr_str;
char *name;
grpc_error *err =
grpc_tcp_server_prepare_socket(fd, addr, s->so_reuseport, &port);
if (err == GRPC_ERROR_NONE) {
GPR_ASSERT(port > 0);
grpc_sockaddr_to_string(&addr_str, addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
s->nports++;
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
sp = gpr_malloc(sizeof(grpc_tcp_listener));
sp->next = NULL;
if (s->head == NULL) {
s->head = sp;
} else {
s->tail->next = sp;
}
s->tail = sp;
sp->server = s;
sp->fd = fd;
sp->emfd = grpc_fd_create(fd, name);
memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
sp->port = port;
sp->port_index = port_index;
sp->fd_index = fd_index;
sp->is_sibling = 0;
sp->sibling = NULL;
GPR_ASSERT(sp->emfd);
gpr_mu_unlock(&s->mu);
gpr_free(addr_str);
gpr_free(name);
}
*listener = sp;
return err;
}
/* If successful, add a listener to s for addr, set *dsmode for the socket, and
return the *listener. */
grpc_error *grpc_tcp_server_add_addr(grpc_tcp_server *s,
const grpc_resolved_address *addr,
unsigned port_index, unsigned fd_index,
grpc_dualstack_mode *dsmode,
grpc_tcp_listener **listener) {
grpc_resolved_address addr4_copy;
int fd;
grpc_error *err =
grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, dsmode, &fd);
if (err != GRPC_ERROR_NONE) {
return err;
}
if (*dsmode == GRPC_DSMODE_IPV4 &&
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
addr = &addr4_copy;
}
return add_socket_to_server(s, fd, addr, port_index, fd_index, listener);
}
/* Prepare a recently-created socket for listening. */
grpc_error *grpc_tcp_server_prepare_socket(int fd,
const grpc_resolved_address *addr,
bool so_reuseport, int *port) {
grpc_resolved_address sockname_temp;
grpc_error *err = GRPC_ERROR_NONE;
GPR_ASSERT(fd >= 0);
if (so_reuseport && !grpc_is_unix_socket(addr)) {
err = grpc_set_socket_reuse_port(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_nonblocking(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_cloexec(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_reuse_addr(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
GPR_ASSERT(addr->len < ~(socklen_t)0);
if (bind(fd, (struct sockaddr *)addr->addr, (socklen_t)addr->len) < 0) {
err = GRPC_OS_ERROR(errno, "bind");
goto error;
}
if (listen(fd, get_max_accept_queue_size()) < 0) {
err = GRPC_OS_ERROR(errno, "listen");
goto error;
}
sockname_temp.len = sizeof(struct sockaddr_storage);
if (getsockname(fd, (struct sockaddr *)sockname_temp.addr,
(socklen_t *)&sockname_temp.len) < 0) {
err = GRPC_OS_ERROR(errno, "getsockname");
goto error;
}
*port = grpc_sockaddr_get_port(&sockname_temp);
return GRPC_ERROR_NONE;
error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (fd >= 0) {
close(fd);
}
grpc_error *ret =
grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Unable to configure socket", &err, 1),
GRPC_ERROR_INT_FD, fd);
GRPC_ERROR_UNREF(err);
return ret;
}
#endif /* GRPC_POSIX_SOCKET */

@ -0,0 +1,196 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_HAVE_IFADDRS
#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
#include <errno.h>
#include <ifaddrs.h>
#include <stddef.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
/* Return the listener in s with address addr or NULL. */
static grpc_tcp_listener *find_listener_with_addr(grpc_tcp_server *s,
grpc_resolved_address *addr) {
grpc_tcp_listener *l;
gpr_mu_lock(&s->mu);
for (l = s->head; l != NULL; l = l->next) {
if (l->addr.len != addr->len) {
continue;
}
if (memcmp(l->addr.addr, addr->addr, addr->len) == 0) {
break;
}
}
gpr_mu_unlock(&s->mu);
return l;
}
/* Bind to "::" to get a port number not used by any address. */
static grpc_error *get_unused_port(int *port) {
grpc_resolved_address wild;
grpc_sockaddr_make_wildcard6(0, &wild);
grpc_dualstack_mode dsmode;
int fd;
grpc_error *err =
grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd);
if (err != GRPC_ERROR_NONE) {
return err;
}
if (dsmode == GRPC_DSMODE_IPV4) {
grpc_sockaddr_make_wildcard4(0, &wild);
}
if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) {
err = GRPC_OS_ERROR(errno, "bind");
close(fd);
return err;
}
if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) !=
0) {
err = GRPC_OS_ERROR(errno, "getsockname");
close(fd);
return err;
}
close(fd);
*port = grpc_sockaddr_get_port(&wild);
return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port")
: GRPC_ERROR_NONE;
}
grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
unsigned port_index,
int requested_port,
int *out_port) {
struct ifaddrs *ifa = NULL;
struct ifaddrs *ifa_it;
unsigned fd_index = 0;
grpc_tcp_listener *sp = NULL;
grpc_error *err = GRPC_ERROR_NONE;
if (requested_port == 0) {
/* Note: There could be a race where some local addrs can listen on the
selected port and some can't. The sane way to handle this would be to
retry by recreating the whole grpc_tcp_server. Backing out individual
listeners and orphaning the FDs looks like too much trouble. */
if ((err = get_unused_port(&requested_port)) != GRPC_ERROR_NONE) {
return err;
} else if (requested_port <= 0) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad get_unused_port()");
}
gpr_log(GPR_DEBUG, "Picked unused port %d", requested_port);
}
if (getifaddrs(&ifa) != 0 || ifa == NULL) {
return GRPC_OS_ERROR(errno, "getifaddrs");
}
for (ifa_it = ifa; ifa_it != NULL; ifa_it = ifa_it->ifa_next) {
grpc_resolved_address addr;
char *addr_str = NULL;
grpc_dualstack_mode dsmode;
grpc_tcp_listener *new_sp = NULL;
const char *ifa_name = (ifa_it->ifa_name ? ifa_it->ifa_name : "<unknown>");
if (ifa_it->ifa_addr == NULL) {
continue;
} else if (ifa_it->ifa_addr->sa_family == AF_INET) {
addr.len = sizeof(struct sockaddr_in);
} else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
addr.len = sizeof(struct sockaddr_in6);
} else {
continue;
}
memcpy(addr.addr, ifa_it->ifa_addr, addr.len);
if (!grpc_sockaddr_set_port(&addr, requested_port)) {
/* Should never happen, because we check sa_family above. */
err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to set port");
break;
}
if (grpc_sockaddr_to_string(&addr_str, &addr, 0) < 0) {
addr_str = gpr_strdup("<error>");
}
gpr_log(GPR_DEBUG,
"Adding local addr from interface %s flags 0x%x to server: %s",
ifa_name, ifa_it->ifa_flags, addr_str);
/* We could have multiple interfaces with the same address (e.g., bonding),
so look for duplicates. */
if (find_listener_with_addr(s, &addr) != NULL) {
gpr_log(GPR_DEBUG, "Skipping duplicate addr %s on interface %s", addr_str,
ifa_name);
gpr_free(addr_str);
continue;
}
if ((err = grpc_tcp_server_add_addr(s, &addr, port_index, fd_index, &dsmode,
&new_sp)) != GRPC_ERROR_NONE) {
char *err_str = NULL;
grpc_error *root_err;
if (gpr_asprintf(&err_str, "Failed to add listener: %s", addr_str) < 0) {
err_str = gpr_strdup("Failed to add listener");
}
root_err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_str);
gpr_free(err_str);
gpr_free(addr_str);
err = grpc_error_add_child(root_err, err);
break;
} else {
GPR_ASSERT(requested_port == new_sp->port);
++fd_index;
if (sp != NULL) {
new_sp->is_sibling = 1;
sp->sibling = new_sp;
}
sp = new_sp;
}
gpr_free(addr_str);
}
freeifaddrs(ifa);
if (err != GRPC_ERROR_NONE) {
return err;
} else if (sp == NULL) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No local addresses");
} else {
*out_port = sp->port;
return GRPC_ERROR_NONE;
}
}
bool grpc_tcp_server_have_ifaddrs(void) { return true; }
#endif /* GRPC_HAVE_IFADDRS */

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2017, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,22 +31,19 @@
* *
*/ */
#include "src/core/ext/client_channel/initial_connect_string.h" #include "src/core/lib/iomgr/port.h"
#include <stddef.h> #if defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS)
extern void grpc_set_default_initial_connect_string( #include "src/core/lib/iomgr/tcp_server_utils_posix.h"
grpc_resolved_address **addr, grpc_slice *initial_str);
static grpc_set_initial_connect_string_func g_set_initial_connect_string_func = grpc_error *grpc_tcp_server_add_all_local_addrs(grpc_tcp_server *s,
grpc_set_default_initial_connect_string; unsigned port_index,
int requested_port,
void grpc_test_set_initial_connect_string_function( int *out_port) {
grpc_set_initial_connect_string_func func) { return GRPC_ERROR_CREATE_FROM_STATIC_STRING("no ifaddrs available");
g_set_initial_connect_string_func = func;
} }
void grpc_set_initial_connect_string(grpc_resolved_address **addr, bool grpc_tcp_server_have_ifaddrs(void) { return false; }
grpc_slice *initial_str) {
g_set_initial_connect_string_func(addr, initial_str); #endif /* defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS) */
}

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

Loading…
Cancel
Save