Merge github.com:grpc/grpc into bugscrub1-proposedfix1

pull/10218/head
Craig Tiller 8 years ago
commit 21947d33a0
  1. 4
      .gitmodules
  2. 30
      .vscode/launch.json
  3. 48
      BUILD
  4. 1422
      CMakeLists.txt
  5. 24
      INSTALL.md
  6. 490
      Makefile
  7. 1
      PYTHON-MANIFEST.in
  8. 18
      README.md
  9. 3
      Rakefile
  10. 17
      WORKSPACE
  11. 34
      binding.gyp
  12. 71
      build.yaml
  13. 15
      config.m4
  14. 158
      doc/combiner-explainer.md
  15. 160
      doc/core/grpc-error.md
  16. 8
      doc/environment_variables.md
  17. 76
      doc/http2-interop-test-descriptions.md
  18. 9
      examples/node/static_codegen/README.md
  19. 25
      examples/ruby/errors_and_cancellation/README.md
  20. 117
      examples/ruby/errors_and_cancellation/error_examples_client.rb
  21. 76
      examples/ruby/errors_and_cancellation/error_examples_server.rb
  22. 38
      gRPC-Core.podspec
  23. 2
      gRPC-ProtoRPC.podspec
  24. 2
      gRPC-RxLibrary.podspec
  25. 2
      gRPC.podspec
  26. 3
      grpc.def
  27. 94
      grpc.gemspec
  28. 247
      include/grpc++/impl/codegen/async_stream.h
  29. 48
      include/grpc++/impl/codegen/call.h
  30. 15
      include/grpc++/impl/codegen/client_context.h
  31. 106
      include/grpc++/impl/codegen/sync_stream.h
  32. 6
      include/grpc++/support/channel_arguments.h
  33. 65
      include/grpc/grpc.h
  34. 5
      include/grpc/impl/codegen/atm.h
  35. 26
      include/grpc/impl/codegen/grpc_types.h
  36. 8
      include/grpc/impl/codegen/port_platform.h
  37. 7
      package.json
  38. 21
      package.xml
  39. 21
      setup.py
  40. 49
      src/c-ares/CMakeLists.txt
  41. 149
      src/c-ares/gen_build_yaml.py
  42. 2
      src/compiler/README.md
  43. 77
      src/compiler/csharp_generator.cc
  44. 2
      src/compiler/php_generator.cc
  45. 8
      src/compiler/python_generator.cc
  46. 2
      src/core/README.md
  47. 2
      src/core/ext/census/gen/README.md
  48. 4
      src/core/ext/client_channel/channel_connectivity.c
  49. 162
      src/core/ext/client_channel/client_channel.c
  50. 3
      src/core/ext/client_channel/client_channel_plugin.c
  51. 2
      src/core/ext/client_channel/connector.h
  52. 4
      src/core/ext/client_channel/http_connect_handshaker.c
  53. 1
      src/core/ext/client_channel/resolver_registry.c
  54. 210
      src/core/ext/client_channel/retry_throttle.c
  55. 65
      src/core/ext/client_channel/retry_throttle.h
  56. 21
      src/core/ext/client_channel/subchannel.c
  57. 22
      src/core/ext/lb_policy/grpclb/grpclb.c
  58. 27
      src/core/ext/lb_policy/pick_first/pick_first.c
  59. 29
      src/core/ext/lb_policy/round_robin/round_robin.c
  60. 4
      src/core/ext/load_reporting/load_reporting_filter.c
  61. 350
      src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
  62. 65
      src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h
  63. 319
      src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
  64. 289
      src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
  65. 63
      src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h
  66. 22
      src/core/ext/resolver/dns/native/dns_resolver.c
  67. 41
      src/core/ext/transport/chttp2/client/chttp2_connector.c
  68. 4
      src/core/ext/transport/chttp2/server/chttp2_server.c
  69. 4
      src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
  70. 314
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  71. 17
      src/core/ext/transport/chttp2/transport/frame_data.c
  72. 5
      src/core/ext/transport/chttp2/transport/frame_goaway.c
  73. 22
      src/core/ext/transport/chttp2/transport/frame_ping.c
  74. 3
      src/core/ext/transport/chttp2/transport/frame_ping.h
  75. 7
      src/core/ext/transport/chttp2/transport/frame_rst_stream.c
  76. 11
      src/core/ext/transport/chttp2/transport/frame_settings.c
  77. 4
      src/core/ext/transport/chttp2/transport/frame_window_update.c
  78. 73
      src/core/ext/transport/chttp2/transport/hpack_parser.c
  79. 4
      src/core/ext/transport/chttp2/transport/hpack_table.c
  80. 7
      src/core/ext/transport/chttp2/transport/internal.h
  81. 30
      src/core/ext/transport/chttp2/transport/parsing.c
  82. 8
      src/core/ext/transport/chttp2/transport/writing.c
  83. 67
      src/core/ext/transport/cronet/transport/cronet_transport.c
  84. 3
      src/core/lib/channel/connected_channel.c
  85. 6
      src/core/lib/channel/deadline_filter.c
  86. 5
      src/core/lib/channel/handshaker.c
  87. 65
      src/core/lib/channel/http_client_filter.c
  88. 111
      src/core/lib/channel/http_server_filter.c
  89. 11
      src/core/lib/channel/message_size_filter.c
  90. 14
      src/core/lib/http/httpcli.c
  91. 2
      src/core/lib/http/httpcli_security_connector.c
  92. 88
      src/core/lib/http/parser.c
  93. 4
      src/core/lib/iomgr/closure.c
  94. 2
      src/core/lib/iomgr/combiner.c
  95. 88
      src/core/lib/iomgr/error.c
  96. 53
      src/core/lib/iomgr/error.h
  97. 39
      src/core/lib/iomgr/ev_epoll_linux.c
  98. 12
      src/core/lib/iomgr/ev_poll_posix.c
  99. 4
      src/core/lib/iomgr/executor.c
  100. 9
      src/core/lib/iomgr/load_file.c
  101. Some files were not shown because too many files have changed in this diff Show More

4
.gitmodules vendored

@ -23,3 +23,7 @@
[submodule "third_party/boringssl-with-bazel"]
path = third_party/boringssl-with-bazel
url = https://boringssl.googlesource.com/boringssl
[submodule "third_party/cares/cares"]
path = third_party/cares/cares
url = https://github.com/c-ares/c-ares.git
branch = cares-1_12_0

@ -0,0 +1,30 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha Tests",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd"
},
"runtimeArgs": [
"-u",
"tdd",
"--timeout",
"999999",
"--colors",
"${workspaceRoot}/src/node/test"
],
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Process",
"port": 5858
}
]
}

48
BUILD

@ -37,11 +37,11 @@ package(default_visibility = ["//visibility:public"])
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(
name = "gpr",
@ -67,6 +67,7 @@ grpc_cc_library(
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
"grpc_resolver_dns_ares",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
"grpc_secure",
@ -308,8 +309,9 @@ grpc_cc_library(
srcs = [
"src/core/lib/profiling/basic_timers.c",
"src/core/lib/profiling/stap_timers.c",
"src/core/lib/support/arena.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/backoff.c",
"src/core/lib/support/cmdline.c",
@ -353,8 +355,8 @@ grpc_cc_library(
"src/core/lib/support/wrap_memcpy.c",
],
hdrs = [
"src/core/lib/support/arena.h",
"src/core/lib/profiling/timers.h",
"src/core/lib/support/arena.h",
"src/core/lib/support/backoff.h",
"src/core/lib/support/block_annotate.h",
"src/core/lib/support/env.h",
@ -471,6 +473,7 @@ grpc_cc_library(
"src/core/lib/iomgr/resolve_address_windows.c",
"src/core/lib/iomgr/resource_quota.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_utils_common_posix.c",
"src/core/lib/iomgr/socket_utils_linux.c",
@ -483,6 +486,9 @@ grpc_cc_library(
"src/core/lib/iomgr/tcp_client_windows.c",
"src/core/lib/iomgr/tcp_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_windows.c",
"src/core/lib/iomgr/tcp_uv.c",
@ -505,6 +511,7 @@ grpc_cc_library(
"src/core/lib/json/json_reader.c",
"src/core/lib/json/json_string.c",
"src/core/lib/json/json_writer.c",
"src/core/lib/security/util/b64.c",
"src/core/lib/slice/percent_encoding.c",
"src/core/lib/slice/slice.c",
"src/core/lib/slice/slice_buffer.c",
@ -523,6 +530,7 @@ grpc_cc_library(
"src/core/lib/surface/channel_ping.c",
"src/core/lib/surface/channel_stack_type.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/lame_client.c",
"src/core/lib/surface/metadata_array.c",
@ -593,6 +601,7 @@ grpc_cc_library(
"src/core/lib/iomgr/sockaddr_posix.h",
"src/core/lib/iomgr/sockaddr_utils.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_utils.h",
"src/core/lib/iomgr/socket_utils_posix.h",
@ -601,6 +610,7 @@ grpc_cc_library(
"src/core/lib/iomgr/tcp_client_posix.h",
"src/core/lib/iomgr/tcp_posix.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_windows.h",
"src/core/lib/iomgr/time_averaged_stats.h",
@ -620,6 +630,7 @@ grpc_cc_library(
"src/core/lib/json/json_common.h",
"src/core/lib/json/json_reader.h",
"src/core/lib/json/json_writer.h",
"src/core/lib/security/util/b64.h",
"src/core/lib/slice/percent_encoding.h",
"src/core/lib/slice/slice_hash_table.h",
"src/core/lib/slice/slice_internal.h",
@ -631,6 +642,7 @@ grpc_cc_library(
"src/core/lib/surface/channel_init.h",
"src/core/lib/surface/channel_stack_type.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/init.h",
"src/core/lib/surface/lame_client.h",
@ -681,10 +693,8 @@ grpc_cc_library(
"src/core/ext/client_channel/client_channel_factory.c",
"src/core/ext/client_channel/client_channel_plugin.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_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_factory.c",
"src/core/ext/client_channel/lb_policy_registry.c",
@ -694,6 +704,7 @@ grpc_cc_library(
"src/core/ext/client_channel/resolver.c",
"src/core/ext/client_channel/resolver_factory.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_index.c",
"src/core/ext/client_channel/uri_parser.c",
@ -704,7 +715,6 @@ grpc_cc_library(
"src/core/ext/client_channel/connector.h",
"src/core/ext/client_channel/http_connect_handshaker.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_factory.h",
"src/core/ext/client_channel/lb_policy_registry.h",
@ -714,6 +724,7 @@ grpc_cc_library(
"src/core/ext/client_channel/resolver.h",
"src/core/ext/client_channel/resolver_factory.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_index.h",
"src/core/ext/client_channel/uri_parser.h",
@ -842,6 +853,27 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_resolver_dns_ares",
srcs = [
"src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c",
"src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c",
"src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c",
],
hdrs = [
"src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h",
],
language = "c",
deps = [
"grpc_base",
"grpc_client_channel",
],
external_deps = [
"cares",
],
)
grpc_cc_library(
name = "grpc_resolver_sockaddr",
srcs = [

File diff suppressed because it is too large Load Diff

@ -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
refer to these documents
@ -14,15 +14,15 @@ refer to these documents
* [Ruby](src/ruby): `gem install grpc`
#Pre-requisites
# Pre-requisites
##Linux
## Linux
```sh
$ [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
install Xcode from the Mac AppStore and then run the following command from a
@ -32,7 +32,7 @@ terminal:
$ [sudo] xcode-select --install
```
##Protoc
## Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
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.
#Build from Source
# Build from Source
For developers who are interested to contribute, here is how to compile the
gRPC C Core library.
@ -56,16 +56,16 @@ gRPC C Core library.
$ [sudo] make install
```
##Windows
## Windows
There are several ways to build under Windows, of varying complexity depending
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.
###Building using CMake (with BoringSSL)
### Building using CMake (with BoringSSL)
- Install [CMake](https://cmake.org/download/).
- Install [Active State Perl](http://www.activestate.com/activeperl/) (`choco install activeperl`)
- 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).
###msys2 (with mingw)
### msys2 (with mingw)
The Makefile (and source code) should support msys2's mingw32 and mingw64
compilers. Building with msys2's native compiler is also possible, but
difficult.
This approach requires having [msys2](https://msys2.github.io/) installed.
```
# Install prerequisites
MSYS2$ pacman -S autoconf automake gcc libtool mingw-w64-x86_64-toolchain perl pkg-config zlib

File diff suppressed because it is too large Load Diff

@ -7,6 +7,7 @@ graft include/grpc
graft third_party/boringssl
graft third_party/nanopb
graft third_party/zlib
graft third_party/c-ares
include src/python/grpcio/_spawn_patch.py
include src/python/grpcio/commands.py
include src/python/grpcio/grpc_version.py

@ -7,11 +7,11 @@
Copyright 2015 Google Inc.
#Documentation
# Documentation
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.
@ -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.
#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).
@ -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 |
<small>
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.
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.
</small>
See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
repository.
#Overview
# Overview
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.
##Interface
## Interface
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
alternatives if desired.
###Surface API
### Surface API
Starting from an interface definition in a .proto file, gRPC provides
Protocol Compiler plugins that generate Client- and Server-side APIs.
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.
#Protocol
# Protocol
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

@ -12,7 +12,8 @@ load 'tools/distrib/docker_for_windows.rb'
# Add rubocop style checking tasks
RuboCop::RakeTask.new(:rubocop) do |task|
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
spec = Gem::Specification.load('grpc.gemspec')

@ -28,6 +28,11 @@ bind(
actual = "@submodule_protobuf//:protoc",
)
bind(
name = "cares",
actual = "@submodule_cares//:ares",
)
bind(
name = "gtest",
actual = "@submodule_gtest//:gtest",
@ -66,3 +71,15 @@ local_repository(
name = "com_github_gflags_gflags",
path = "third_party/gflags",
)
git_repository(
name = "mongoose_repo",
commit = "4120a97945b41195a6223a600dae8e3b19bed19e",
remote = "https://github.com/makdharma/mongoose.git"
)
new_local_repository(
name = "submodule_cares",
path = "third_party/cares",
build_file = "third_party/cares/cares.BUILD",
)

@ -39,11 +39,9 @@
{
'variables': {
'runtime%': 'node',
# UV integration in C core is disabled by default while bugs are ironed
# out. It can be re-enabled for one build by setting the npm config
# variable grpc_uv to true, and it can be re-enabled permanently by
# setting it to true here.
'grpc_uv%': 'false',
# UV integration in C core is enabled by default. It can be disabled
# by setting this argument to anything else.
'grpc_uv%': 'true',
# Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN.
@ -60,6 +58,9 @@
'conditions': [
['grpc_uv=="true"', {
'defines': [
'GRPC_ARES=0',
# Disabling this while bugs are ironed out. Uncomment this to
# re-enable libuv integration in C core.
'GRPC_UV'
]
}],
@ -105,7 +106,8 @@
}],
['OS == "win"', {
"include_dirs": [
"third_party/zlib"
"third_party/zlib",
"third_party/cares/cares"
],
"defines": [
'_WIN32_WINNT=0x0600',
@ -128,7 +130,8 @@
'config': '<!(echo $CONFIG)',
},
'include_dirs': [
'<(node_root_dir)/deps/zlib'
'<(node_root_dir)/deps/zlib',
'<(node_root_dir)/deps/cares/include',
],
'conditions': [
['config=="gcov"', {
@ -529,6 +532,7 @@
}]
],
'targets': [
{
'cflags': [
'-std=c99',
@ -545,6 +549,7 @@
'src/core/lib/profiling/stap_timers.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/backoff.c',
'src/core/lib/support/cmdline.c',
@ -606,6 +611,7 @@
'type': 'static_library',
'dependencies': [
'gpr',
'node_modules/cares/deps/cares/cares.gyp:cares',
],
'sources': [
'src/core/lib/surface/init.c',
@ -656,6 +662,7 @@
'src/core/lib/iomgr/resolve_address_windows.c',
'src/core/lib/iomgr/resource_quota.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_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
@ -668,6 +675,9 @@
'src/core/lib/iomgr/tcp_client_windows.c',
'src/core/lib/iomgr/tcp_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_windows.c',
'src/core/lib/iomgr/tcp_uv.c',
@ -690,6 +700,7 @@
'src/core/lib/json/json_reader.c',
'src/core/lib/json/json_string.c',
'src/core/lib/json/json_writer.c',
'src/core/lib/security/util/b64.c',
'src/core/lib/slice/percent_encoding.c',
'src/core/lib/slice/slice.c',
'src/core/lib/slice/slice_buffer.c',
@ -708,6 +719,7 @@
'src/core/lib/surface/channel_ping.c',
'src/core/lib/surface/channel_stack_type.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/lame_client.c',
'src/core/lib/surface/metadata_array.c',
@ -771,7 +783,6 @@
'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c',
'src/core/lib/security/util/json_util.c',
'src/core/lib/surface/init_secure.c',
'src/core/lib/tsi/fake_transport_security.c',
@ -784,10 +795,8 @@
'src/core/ext/client_channel/client_channel_factory.c',
'src/core/ext/client_channel/client_channel_plugin.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_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_factory.c',
'src/core/ext/client_channel/lb_policy_registry.c',
@ -797,6 +806,7 @@
'src/core/ext/client_channel/resolver.c',
'src/core/ext/client_channel/resolver_factory.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_index.c',
'src/core/ext/client_channel/uri_parser.c',
@ -814,6 +824,9 @@
'third_party/nanopb/pb_encode.c',
'src/core/ext/lb_policy/pick_first/pick_first.c',
'src/core/ext/lb_policy/round_robin/round_robin.c',
'src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c',
'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c',
'src/core/ext/resolver/dns/native/dns_resolver.c',
'src/core/ext/resolver/sockaddr/sockaddr_resolver.c',
'src/core/ext/load_reporting/load_reporting.c',
@ -904,6 +917,7 @@
"dependencies": [
"grpc",
"gpr",
"node_modules/cares/deps/cares/cares.gyp:cares",
]
},
{

@ -103,6 +103,7 @@ filegroups:
- src/core/lib/profiling/stap_timers.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/backoff.c
- src/core/lib/support/cmdline.c
@ -222,6 +223,7 @@ filegroups:
- src/core/lib/iomgr/sockaddr_posix.h
- src/core/lib/iomgr/sockaddr_utils.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_utils.h
- src/core/lib/iomgr/socket_utils_posix.h
@ -230,6 +232,7 @@ filegroups:
- src/core/lib/iomgr/tcp_client_posix.h
- src/core/lib/iomgr/tcp_posix.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_windows.h
- src/core/lib/iomgr/time_averaged_stats.h
@ -260,6 +263,7 @@ filegroups:
- src/core/lib/surface/channel_init.h
- src/core/lib/surface/channel_stack_type.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/init.h
- src/core/lib/surface/lame_client.h
@ -327,6 +331,7 @@ filegroups:
- src/core/lib/iomgr/resolve_address_windows.c
- src/core/lib/iomgr/resource_quota.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_utils_common_posix.c
- src/core/lib/iomgr/socket_utils_linux.c
@ -339,6 +344,9 @@ filegroups:
- src/core/lib/iomgr/tcp_client_windows.c
- src/core/lib/iomgr/tcp_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_windows.c
- src/core/lib/iomgr/tcp_uv.c
@ -361,6 +369,7 @@ filegroups:
- src/core/lib/json/json_reader.c
- src/core/lib/json/json_string.c
- src/core/lib/json/json_writer.c
- src/core/lib/security/util/b64.c
- src/core/lib/slice/percent_encoding.c
- src/core/lib/slice/slice.c
- src/core/lib/slice/slice_buffer.c
@ -379,6 +388,7 @@ filegroups:
- src/core/lib/surface/channel_ping.c
- src/core/lib/surface/channel_stack_type.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/lame_client.c
- src/core/lib/surface/metadata_array.c
@ -409,7 +419,6 @@ filegroups:
- src/core/ext/client_channel/connector.h
- src/core/ext/client_channel/http_connect_handshaker.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_factory.h
- src/core/ext/client_channel/lb_policy_registry.h
@ -419,6 +428,7 @@ filegroups:
- src/core/ext/client_channel/resolver.h
- src/core/ext/client_channel/resolver_factory.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_index.h
- src/core/ext/client_channel/uri_parser.h
@ -428,10 +438,8 @@ filegroups:
- src/core/ext/client_channel/client_channel_factory.c
- src/core/ext/client_channel/client_channel_plugin.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_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_factory.c
- src/core/ext/client_channel/lb_policy_registry.c
@ -441,6 +449,7 @@ filegroups:
- src/core/ext/client_channel/resolver.c
- src/core/ext/client_channel/resolver_factory.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_index.c
- src/core/ext/client_channel/uri_parser.c
@ -514,6 +523,18 @@ filegroups:
plugin: grpc_load_reporting_plugin
uses:
- grpc_base
- name: grpc_resolver_dns_ares
headers:
- src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h
- src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h
src:
- src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
- src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
- src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
plugin: grpc_resolver_dns_ares
uses:
- grpc_base
- grpc_client_channel
- name: grpc_resolver_dns_native
src:
- src/core/ext/resolver/dns/native/dns_resolver.c
@ -958,6 +979,7 @@ libs:
- grpc_lb_policy_grpclb_secure
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
- grpc_resolver_dns_ares
- grpc_resolver_dns_native
- grpc_resolver_sockaddr
- grpc_load_reporting
@ -1051,6 +1073,7 @@ libs:
- grpc_base
- grpc_transport_chttp2_server_insecure
- grpc_transport_chttp2_client_insecure
- grpc_resolver_dns_ares
- grpc_resolver_dns_native
- grpc_resolver_sockaddr
- grpc_load_reporting
@ -2694,20 +2717,6 @@ targets:
- grpc
- gpr_test_util
- 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
build: test
language: c
@ -3124,6 +3133,26 @@ targets:
- mac
- linux
- 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
build: test
language: c++
@ -4107,7 +4136,6 @@ targets:
- test/cpp/interop/interop_client.cc
- test/cpp/interop/stress_interop_client.cc
- test/cpp/interop/stress_test.cc
- test/cpp/util/create_test_channel.cc
- test/cpp/util/metrics_server.cc
deps:
- grpc++_test_util
@ -4296,6 +4324,11 @@ configs:
test_environ:
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt
defaults:
ares:
CFLAGS: -Wno-sign-conversion -Wno-invalid-source-encoding
CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
$(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden
-D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DHAVE_CONFIG_H
benchmark:
CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
boringssl:
@ -4386,11 +4419,13 @@ python_dependencies:
deps:
- grpc
- gpr
- ares
- boringssl
- z
ruby_gem:
deps:
- grpc
- gpr
- ares
- boringssl
- z

@ -40,6 +40,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/profiling/stap_timers.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/backoff.c \
src/core/lib/support/cmdline.c \
@ -129,6 +130,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/resolve_address_windows.c \
src/core/lib/iomgr/resource_quota.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_utils_common_posix.c \
src/core/lib/iomgr/socket_utils_linux.c \
@ -141,6 +143,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/tcp_client_windows.c \
src/core/lib/iomgr/tcp_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_windows.c \
src/core/lib/iomgr/tcp_uv.c \
@ -163,6 +168,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/json/json_reader.c \
src/core/lib/json/json_string.c \
src/core/lib/json/json_writer.c \
src/core/lib/security/util/b64.c \
src/core/lib/slice/percent_encoding.c \
src/core/lib/slice/slice.c \
src/core/lib/slice/slice_buffer.c \
@ -181,6 +187,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/surface/channel_ping.c \
src/core/lib/surface/channel_stack_type.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/lame_client.c \
src/core/lib/surface/metadata_array.c \
@ -244,7 +251,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/transport/security_handshaker.c \
src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.c \
src/core/lib/security/util/json_util.c \
src/core/lib/surface/init_secure.c \
src/core/lib/tsi/fake_transport_security.c \
@ -257,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_plugin.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_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_factory.c \
src/core/ext/client_channel/lb_policy_registry.c \
@ -270,6 +274,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_channel/resolver.c \
src/core/ext/client_channel/resolver_factory.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_index.c \
src/core/ext/client_channel/uri_parser.c \
@ -287,6 +292,9 @@ if test "$PHP_GRPC" != "no"; then
third_party/nanopb/pb_encode.c \
src/core/ext/lb_policy/pick_first/pick_first.c \
src/core/ext/lb_policy/round_robin/round_robin.c \
src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c \
src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c \
src/core/ext/resolver/dns/native/dns_resolver.c \
src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
src/core/ext/load_reporting/load_reporting.c \
@ -626,6 +634,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/pick_first)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/round_robin)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/load_reporting)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/dns/c_ares)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/dns/native)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/sockaddr)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/alpn)

@ -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.

@ -69,3 +69,11 @@ some configuration as environment variables that can be set.
- DEBUG - log all gRPC messages
- INFO - log INFO and ERROR message
- ERROR - log only errors
* GRPC_DNS_RESOLVER
Declares which DNS resolver to use. The default is ares if gRPC is built with
c-ares support. Otherwise, the value of this environment variable is ignored.
Available DNS resolver include:
- native (default)- a DNS resolver based around getaddrinfo(), creates a new thread to
perform name resolution
- ares - a DNS resolver based around the c-ares library

@ -193,3 +193,79 @@ Server Procedure:
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.*
### 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
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
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
cd ../../protos
npm install -g grpc-tools
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
```

@ -0,0 +1,25 @@
#Errors and Cancelletion code samples for grpc-ruby
The examples in this directory show use of grpc errors.
On the server side, errors are returned from service
implementations by raising a certain `GRPC::BadStatus` exception.
On the client side, GRPC errors get raised when either:
* the call completes (unary and client-streaming call types)
* the response `Enumerable` is iterated through (server-streaming and
bidi call types).
## To run the examples here:
Start the server:
```
> ruby error_examples_server.rb
```
Then run the client:
```
> ruby error_examples_client.rb
```

@ -0,0 +1,117 @@
#!/usr/bin/env ruby
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Sample app that connects to an error-throwing implementation of
# Route Guide service.
#
# Usage: $ path/to/route_guide_client.rb
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(File.dirname(this_dir), 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
require 'grpc'
require 'route_guide_services_pb'
include Routeguide
def run_get_feature_expect_error(stub)
resp = stub.get_feature(Point.new)
end
def run_list_features_expect_error(stub)
resps = stub.list_features(Rectangle.new)
# NOOP iteration to pick up error
resps.each { }
end
def run_record_route_expect_error(stub)
stub.record_route([])
end
def run_route_chat_expect_error(stub)
resps = stub.route_chat([])
# NOOP iteration to pick up error
resps.each { }
end
def main
stub = RouteGuide::Stub.new('localhost:50051', :this_channel_is_insecure)
begin
run_get_feature_expect_error(stub)
rescue GRPC::BadStatus => e
puts "===== GetFeature exception: ====="
puts e.inspect
puts "e.code: #{e.code}"
puts "e.details: #{e.details}"
puts "e.metadata: #{e.metadata}"
puts "================================="
end
begin
run_list_features_expect_error(stub)
rescue GRPC::BadStatus => e
error = true
puts "===== ListFeatures exception: ====="
puts e.inspect
puts "e.code: #{e.code}"
puts "e.details: #{e.details}"
puts "e.metadata: #{e.metadata}"
puts "================================="
end
begin
run_route_chat_expect_error(stub)
rescue GRPC::BadStatus => e
puts "==== RouteChat exception: ===="
puts e.inspect
puts "e.code: #{e.code}"
puts "e.details: #{e.details}"
puts "e.metadata: #{e.metadata}"
puts "================================="
end
begin
run_record_route_expect_error(stub)
rescue GRPC::BadStatus => e
puts "==== RecordRoute exception: ===="
puts e.inspect
puts "e.code: #{e.code}"
puts "e.details: #{e.details}"
puts "e.metadata: #{e.metadata}"
puts "================================="
end
end
main

@ -0,0 +1,76 @@
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Error-throwing implementation of Route Guide service.
#
# Usage: $ path/to/route_guide_server.rb
this_dir = File.expand_path(File.dirname(__FILE__))
lib_dir = File.join(File.dirname(this_dir), 'lib')
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
require 'grpc'
require 'route_guide_services_pb'
include Routeguide
include GRPC::Core::StatusCodes
# CanellingandErrorReturningServiceImpl provides an implementation of the RouteGuide service.
class CancellingAndErrorReturningServerImpl < RouteGuide::Service
# def get_feature
# Note get_feature isn't implemented in this subclass, so the server
# will get a gRPC UNIMPLEMENTED error when it's called.
def list_features(rectangle, _call)
raise "string appears on the client in the 'details' field of a 'GRPC::Unknown' exception"
end
def record_route(call)
raise GRPC::BadStatus.new_status_exception(CANCELLED)
end
def route_chat(notes)
raise GRPC::BadStatus.new_status_exception(ABORTED, details = 'arbitrary', metadata = {somekey: 'val'})
end
end
def main
port = '0.0.0.0:50051'
s = GRPC::RpcServer.new
s.add_http2_port(port, :this_port_is_insecure)
GRPC.logger.info("... running insecurely on #{port}")
s.handle(CancellingAndErrorReturningServerImpl.new)
s.run_till_terminated
end
main

@ -51,7 +51,7 @@ Pod::Spec.new do |s|
:submodules => true,
}
s.ios.deployment_target = '7.1'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'
s.requires_arc = false
@ -104,6 +104,7 @@ Pod::Spec.new do |s|
}
s.default_subspecs = 'Interface', 'Implementation'
s.compiler_flags = '-DGRPC_ARES=0'
# Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
# sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't
@ -213,6 +214,7 @@ Pod::Spec.new do |s|
'src/core/lib/profiling/stap_timers.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/backoff.c',
'src/core/lib/support/cmdline.c',
@ -303,6 +305,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/sockaddr_posix.h',
'src/core/lib/iomgr/sockaddr_utils.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_utils.h',
'src/core/lib/iomgr/socket_utils_posix.h',
@ -311,6 +314,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_posix.h',
'src/core/lib/iomgr/tcp_posix.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_windows.h',
'src/core/lib/iomgr/time_averaged_stats.h',
@ -341,6 +345,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_init.h',
'src/core/lib/surface/channel_stack_type.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/init.h',
'src/core/lib/surface/lame_client.h',
@ -410,7 +415,6 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/connector.h',
'src/core/ext/client_channel/http_connect_handshaker.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_factory.h',
'src/core/ext/client_channel/lb_policy_registry.h',
@ -420,6 +424,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.h',
'src/core/ext/client_channel/resolver_factory.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_index.h',
'src/core/ext/client_channel/uri_parser.h',
@ -432,6 +437,8 @@ Pod::Spec.new do |s|
'third_party/nanopb/pb_common.h',
'third_party/nanopb/pb_decode.h',
'third_party/nanopb/pb_encode.h',
'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/load_reporting/load_reporting.h',
'src/core/ext/load_reporting/load_reporting_filter.h',
'src/core/ext/census/aggregation.h',
@ -498,6 +505,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/resolve_address_windows.c',
'src/core/lib/iomgr/resource_quota.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_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
@ -510,6 +518,9 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_windows.c',
'src/core/lib/iomgr/tcp_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_windows.c',
'src/core/lib/iomgr/tcp_uv.c',
@ -532,6 +543,7 @@ Pod::Spec.new do |s|
'src/core/lib/json/json_reader.c',
'src/core/lib/json/json_string.c',
'src/core/lib/json/json_writer.c',
'src/core/lib/security/util/b64.c',
'src/core/lib/slice/percent_encoding.c',
'src/core/lib/slice/slice.c',
'src/core/lib/slice/slice_buffer.c',
@ -550,6 +562,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_ping.c',
'src/core/lib/surface/channel_stack_type.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/lame_client.c',
'src/core/lib/surface/metadata_array.c',
@ -613,7 +626,6 @@ Pod::Spec.new do |s|
'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c',
'src/core/lib/security/util/json_util.c',
'src/core/lib/surface/init_secure.c',
'src/core/lib/tsi/fake_transport_security.c',
@ -626,10 +638,8 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/client_channel_factory.c',
'src/core/ext/client_channel/client_channel_plugin.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_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_factory.c',
'src/core/ext/client_channel/lb_policy_registry.c',
@ -639,6 +649,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.c',
'src/core/ext/client_channel/resolver_factory.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_index.c',
'src/core/ext/client_channel/uri_parser.c',
@ -656,6 +667,9 @@ Pod::Spec.new do |s|
'third_party/nanopb/pb_encode.c',
'src/core/ext/lb_policy/pick_first/pick_first.c',
'src/core/ext/lb_policy/round_robin/round_robin.c',
'src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c',
'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c',
'src/core/ext/resolver/dns/native/dns_resolver.c',
'src/core/ext/resolver/sockaddr/sockaddr_resolver.c',
'src/core/ext/load_reporting/load_reporting.c',
@ -739,6 +753,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/sockaddr_posix.h',
'src/core/lib/iomgr/sockaddr_utils.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_utils.h',
'src/core/lib/iomgr/socket_utils_posix.h',
@ -747,6 +762,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/tcp_client_posix.h',
'src/core/lib/iomgr/tcp_posix.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_windows.h',
'src/core/lib/iomgr/time_averaged_stats.h',
@ -777,6 +793,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/channel_init.h',
'src/core/lib/surface/channel_stack_type.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/init.h',
'src/core/lib/surface/lame_client.h',
@ -846,7 +863,6 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/connector.h',
'src/core/ext/client_channel/http_connect_handshaker.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_factory.h',
'src/core/ext/client_channel/lb_policy_registry.h',
@ -856,6 +872,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/resolver.h',
'src/core/ext/client_channel/resolver_factory.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_index.h',
'src/core/ext/client_channel/uri_parser.h',
@ -868,6 +885,8 @@ Pod::Spec.new do |s|
'third_party/nanopb/pb_common.h',
'third_party/nanopb/pb_decode.h',
'third_party/nanopb/pb_encode.h',
'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/load_reporting/load_reporting.h',
'src/core/ext/load_reporting/load_reporting_filter.h',
'src/core/ext/census/aggregation.h',
@ -890,8 +909,7 @@ Pod::Spec.new do |s|
s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpc'
ss.source_files = 'include/grpc/grpc_cronet.h',
'src/core/ext/transport/cronet/transport/cronet_transport.h'
ss.source_files = 'include/grpc/grpc_cronet.h'
end
s.subspec 'Cronet-Implementation' do |ss|
@ -902,7 +920,7 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Cronet-Interface", version
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'
end
@ -917,7 +935,7 @@ Pod::Spec.new do |s|
'test/core/end2end/end2end_test_utils.c',
'test/core/end2end/tests/*.{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/port.h',
'test/core/util/port.c',

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

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

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

@ -53,6 +53,9 @@ EXPORTS
grpc_shutdown
grpc_version_string
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_next
grpc_completion_queue_pluck

@ -99,6 +99,7 @@ Gem::Specification.new do |s|
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/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/backoff.c )
s.files += %w( src/core/lib/support/cmdline.c )
@ -220,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_utils.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_utils.h )
s.files += %w( src/core/lib/iomgr/socket_utils_posix.h )
@ -228,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_posix.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_windows.h )
s.files += %w( src/core/lib/iomgr/time_averaged_stats.h )
@ -258,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_stack_type.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/init.h )
s.files += %w( src/core/lib/surface/lame_client.h )
@ -327,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/http_connect_handshaker.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_factory.h )
s.files += %w( src/core/ext/client_channel/lb_policy_registry.h )
@ -337,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_factory.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_index.h )
s.files += %w( src/core/ext/client_channel/uri_parser.h )
@ -349,6 +353,8 @@ Gem::Specification.new do |s|
s.files += %w( third_party/nanopb/pb_common.h )
s.files += %w( third_party/nanopb/pb_decode.h )
s.files += %w( third_party/nanopb/pb_encode.h )
s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h )
s.files += %w( src/core/ext/load_reporting/load_reporting.h )
s.files += %w( src/core/ext/load_reporting/load_reporting_filter.h )
s.files += %w( src/core/ext/census/aggregation.h )
@ -415,6 +421,7 @@ Gem::Specification.new do |s|
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/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_utils_common_posix.c )
s.files += %w( src/core/lib/iomgr/socket_utils_linux.c )
@ -427,6 +434,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_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_windows.c )
s.files += %w( src/core/lib/iomgr/tcp_uv.c )
@ -449,6 +459,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/json/json_reader.c )
s.files += %w( src/core/lib/json/json_string.c )
s.files += %w( src/core/lib/json/json_writer.c )
s.files += %w( src/core/lib/security/util/b64.c )
s.files += %w( src/core/lib/slice/percent_encoding.c )
s.files += %w( src/core/lib/slice/slice.c )
s.files += %w( src/core/lib/slice/slice_buffer.c )
@ -467,6 +478,7 @@ Gem::Specification.new do |s|
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/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/lame_client.c )
s.files += %w( src/core/lib/surface/metadata_array.c )
@ -530,7 +542,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/transport/security_handshaker.c )
s.files += %w( src/core/lib/security/transport/server_auth_filter.c )
s.files += %w( src/core/lib/security/transport/tsi_error.c )
s.files += %w( src/core/lib/security/util/b64.c )
s.files += %w( src/core/lib/security/util/json_util.c )
s.files += %w( src/core/lib/surface/init_secure.c )
s.files += %w( src/core/lib/tsi/fake_transport_security.c )
@ -543,10 +554,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_plugin.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_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_factory.c )
s.files += %w( src/core/ext/client_channel/lb_policy_registry.c )
@ -556,6 +565,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_factory.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_index.c )
s.files += %w( src/core/ext/client_channel/uri_parser.c )
@ -573,6 +583,9 @@ Gem::Specification.new do |s|
s.files += %w( third_party/nanopb/pb_encode.c )
s.files += %w( src/core/ext/lb_policy/pick_first/pick_first.c )
s.files += %w( src/core/ext/lb_policy/round_robin/round_robin.c )
s.files += %w( src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c )
s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c )
s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c )
s.files += %w( src/core/ext/resolver/dns/native/dns_resolver.c )
s.files += %w( src/core/ext/resolver/sockaddr/sockaddr_resolver.c )
s.files += %w( src/core/ext/load_reporting/load_reporting.c )
@ -1026,4 +1039,77 @@ Gem::Specification.new do |s|
s.files += %w( third_party/zlib/trees.c )
s.files += %w( third_party/zlib/uncompr.c )
s.files += %w( third_party/zlib/zutil.c )
s.files += %w( third_party/cares/cares/ares.h )
s.files += %w( third_party/cares/cares/ares_data.h )
s.files += %w( third_party/cares/cares/ares_dns.h )
s.files += %w( third_party/cares/cares/ares_getenv.h )
s.files += %w( third_party/cares/cares/ares_getopt.h )
s.files += %w( third_party/cares/cares/ares_inet_net_pton.h )
s.files += %w( third_party/cares/cares/ares_iphlpapi.h )
s.files += %w( third_party/cares/cares/ares_ipv6.h )
s.files += %w( third_party/cares/cares/ares_library_init.h )
s.files += %w( third_party/cares/cares/ares_llist.h )
s.files += %w( third_party/cares/cares/ares_nowarn.h )
s.files += %w( third_party/cares/cares/ares_platform.h )
s.files += %w( third_party/cares/cares/ares_private.h )
s.files += %w( third_party/cares/cares/ares_rules.h )
s.files += %w( third_party/cares/cares/ares_setup.h )
s.files += %w( third_party/cares/cares/ares_strcasecmp.h )
s.files += %w( third_party/cares/cares/ares_strdup.h )
s.files += %w( third_party/cares/cares/ares_version.h )
s.files += %w( third_party/cares/cares/bitncmp.h )
s.files += %w( third_party/cares/cares/config-win32.h )
s.files += %w( third_party/cares/cares/setup_once.h )
s.files += %w( third_party/cares/ares_build.h )
s.files += %w( third_party/cares/config_linux/ares_config.h )
s.files += %w( third_party/cares/config_darwin/ares_config.h )
s.files += %w( third_party/cares/cares/ares__close_sockets.c )
s.files += %w( third_party/cares/cares/ares__get_hostent.c )
s.files += %w( third_party/cares/cares/ares__read_line.c )
s.files += %w( third_party/cares/cares/ares__timeval.c )
s.files += %w( third_party/cares/cares/ares_cancel.c )
s.files += %w( third_party/cares/cares/ares_create_query.c )
s.files += %w( third_party/cares/cares/ares_data.c )
s.files += %w( third_party/cares/cares/ares_destroy.c )
s.files += %w( third_party/cares/cares/ares_expand_name.c )
s.files += %w( third_party/cares/cares/ares_expand_string.c )
s.files += %w( third_party/cares/cares/ares_fds.c )
s.files += %w( third_party/cares/cares/ares_free_hostent.c )
s.files += %w( third_party/cares/cares/ares_free_string.c )
s.files += %w( third_party/cares/cares/ares_getenv.c )
s.files += %w( third_party/cares/cares/ares_gethostbyaddr.c )
s.files += %w( third_party/cares/cares/ares_gethostbyname.c )
s.files += %w( third_party/cares/cares/ares_getnameinfo.c )
s.files += %w( third_party/cares/cares/ares_getopt.c )
s.files += %w( third_party/cares/cares/ares_getsock.c )
s.files += %w( third_party/cares/cares/ares_init.c )
s.files += %w( third_party/cares/cares/ares_library_init.c )
s.files += %w( third_party/cares/cares/ares_llist.c )
s.files += %w( third_party/cares/cares/ares_mkquery.c )
s.files += %w( third_party/cares/cares/ares_nowarn.c )
s.files += %w( third_party/cares/cares/ares_options.c )
s.files += %w( third_party/cares/cares/ares_parse_a_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_aaaa_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_mx_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_naptr_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_ns_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_ptr_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_soa_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_srv_reply.c )
s.files += %w( third_party/cares/cares/ares_parse_txt_reply.c )
s.files += %w( third_party/cares/cares/ares_platform.c )
s.files += %w( third_party/cares/cares/ares_process.c )
s.files += %w( third_party/cares/cares/ares_query.c )
s.files += %w( third_party/cares/cares/ares_search.c )
s.files += %w( third_party/cares/cares/ares_send.c )
s.files += %w( third_party/cares/cares/ares_strcasecmp.c )
s.files += %w( third_party/cares/cares/ares_strdup.c )
s.files += %w( third_party/cares/cares/ares_strerror.c )
s.files += %w( third_party/cares/cares/ares_timeout.c )
s.files += %w( third_party/cares/cares/ares_version.c )
s.files += %w( third_party/cares/cares/ares_writev.c )
s.files += %w( third_party/cares/cares/bitncmp.c )
s.files += %w( third_party/cares/cares/inet_net_pton.c )
s.files += %w( third_party/cares/cares/inet_ntop.c )
s.files += %w( third_party/cares/cares/windows_port.c )
end

@ -101,6 +101,39 @@ class AsyncWriterInterface {
/// \param[in] msg The message to be written.
/// \param[in] tag The tag identifying the operation.
virtual void Write(const W& msg, void* tag) = 0;
/// Request the writing of \a msg using WriteOptions \a options with
/// identifying tag \a tag.
///
/// Only one write may be outstanding at any given time. This means that
/// after calling Write, one must wait to receive \a tag from the completion
/// queue BEFORE calling Write again.
/// WriteOptions \a options is used to set the write options of this message.
/// This is thread-safe with respect to \a Read
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
virtual void Write(const W& msg, WriteOptions options, void* tag) = 0;
/// Request the writing of \a msg and coalesce it with the writing
/// of trailing metadata, using WriteOptions \a options with identifying tag
/// \a tag.
///
/// For client, WriteLast is equivalent of performing Write and WritesDone in
/// a single step.
/// For server, WriteLast buffers the \a msg. The writing of \a msg is held
/// until Finish is called, where \a msg and trailing metadata are coalesced
/// and write is initiated. Note that WriteLast can only buffer \a msg up to
/// the flow control window size. If \a msg size is larger than the window
/// size, it will be sent on wire without buffering.
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
void WriteLast(const W& msg, WriteOptions options, void* tag) {
Write(msg, options.set_last_message(), tag);
}
};
template <class R>
@ -183,11 +216,17 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
: context_(context), call_(channel->CreateCall(method, context, cq)) {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
init_ops_.set_output_tag(tag);
init_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&init_ops_);
// if corked bit is set in context, we buffer up the initial metadata to
// coalesce with later message to be sent. No op is performed.
if (context_->initial_metadata_corked_) {
write_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
} else {
write_ops_.set_output_tag(tag);
write_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&write_ops_);
}
}
void ReadInitialMetadata(void* tag) override {
@ -205,10 +244,21 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
call_.PerformOps(&write_ops_);
}
void Write(const W& msg, WriteOptions options, void* tag) override {
write_ops_.set_output_tag(tag);
if (options.is_last_message()) {
options.set_buffer_hint();
write_ops_.ClientSendClose();
}
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
call_.PerformOps(&write_ops_);
}
void WritesDone(void* tag) override {
writes_done_ops_.set_output_tag(tag);
writes_done_ops_.ClientSendClose();
call_.PerformOps(&writes_done_ops_);
write_ops_.set_output_tag(tag);
write_ops_.ClientSendClose();
call_.PerformOps(&write_ops_);
}
void Finish(Status* status, void* tag) override {
@ -223,10 +273,9 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
private:
ClientContext* context_;
Call call_;
CallOpSet<CallOpSendInitialMetadata> init_ops_;
CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
CallOpSet<CallOpSendMessage> write_ops_;
CallOpSet<CallOpClientSendClose> writes_done_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
write_ops_;
CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
CallOpClientRecvStatus>
finish_ops_;
@ -253,10 +302,17 @@ class ClientAsyncReaderWriter final
const RpcMethod& method, ClientContext* context,
void* tag)
: context_(context), call_(channel->CreateCall(method, context, cq)) {
init_ops_.set_output_tag(tag);
init_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&init_ops_);
if (context_->initial_metadata_corked_) {
// if corked bit is set in context, we buffer up the initial metadata to
// coalesce with later message to be sent. No op is performed.
write_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
} else {
write_ops_.set_output_tag(tag);
write_ops_.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&write_ops_);
}
}
void ReadInitialMetadata(void* tag) override {
@ -283,10 +339,21 @@ class ClientAsyncReaderWriter final
call_.PerformOps(&write_ops_);
}
void Write(const W& msg, WriteOptions options, void* tag) override {
write_ops_.set_output_tag(tag);
if (options.is_last_message()) {
options.set_buffer_hint();
write_ops_.ClientSendClose();
}
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
call_.PerformOps(&write_ops_);
}
void WritesDone(void* tag) override {
writes_done_ops_.set_output_tag(tag);
writes_done_ops_.ClientSendClose();
call_.PerformOps(&writes_done_ops_);
write_ops_.set_output_tag(tag);
write_ops_.ClientSendClose();
call_.PerformOps(&write_ops_);
}
void Finish(Status* status, void* tag) override {
@ -301,11 +368,10 @@ class ClientAsyncReaderWriter final
private:
ClientContext* context_;
Call call_;
CallOpSet<CallOpSendInitialMetadata> init_ops_;
CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
CallOpSet<CallOpSendMessage> write_ops_;
CallOpSet<CallOpClientSendClose> writes_done_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
write_ops_;
CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
};
@ -395,6 +461,20 @@ class ServerAsyncWriterInterface : public ServerAsyncStreamingInterface,
public AsyncWriterInterface<W> {
public:
virtual void Finish(const Status& status, void* tag) = 0;
/// Request the writing of \a msg and coalesce it with trailing metadata which
/// contains \a status, using WriteOptions options with identifying tag \a
/// tag.
///
/// WriteAndFinish is equivalent of performing WriteLast and Finish in a
/// single step.
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
/// \param[in] tag The tag identifying the operation.
virtual void WriteAndFinish(const W& msg, WriteOptions options,
const Status& status, void* tag) = 0;
};
template <class W>
@ -418,29 +498,37 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
void Write(const W& msg, void* tag) override {
write_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
EnsureInitialMetadataSent(&write_ops_);
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
call_.PerformOps(&write_ops_);
}
void Write(const W& msg, WriteOptions options, void* tag) override {
write_ops_.set_output_tag(tag);
if (options.is_last_message()) {
options.set_buffer_hint();
}
EnsureInitialMetadataSent(&write_ops_);
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
call_.PerformOps(&write_ops_);
}
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
EnsureInitialMetadataSent(&finish_ops_);
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@ -448,10 +536,24 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
private:
void BindCall(Call* call) override { call_ = *call; }
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
ops->SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
}
Call call_;
ServerContext* ctx_;
CallOpSet<CallOpSendInitialMetadata> meta_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpServerSendStatus>
write_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
};
@ -462,6 +564,20 @@ class ServerAsyncReaderWriterInterface : public ServerAsyncStreamingInterface,
public AsyncReaderInterface<R> {
public:
virtual void Finish(const Status& status, void* tag) = 0;
/// Request the writing of \a msg and coalesce it with trailing metadata which
/// contains \a status, using WriteOptions options with identifying tag \a
/// tag.
///
/// WriteAndFinish is equivalent of performing WriteLast and Finish in a
/// single step.
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
/// \param[in] tag The tag identifying the operation.
virtual void WriteAndFinish(const W& msg, WriteOptions options,
const Status& status, void* tag) = 0;
};
template <class W, class R>
@ -492,29 +608,36 @@ class ServerAsyncReaderWriter final
void Write(const W& msg, void* tag) override {
write_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
EnsureInitialMetadataSent(&write_ops_);
// TODO(ctiller): don't assert
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
call_.PerformOps(&write_ops_);
}
void Write(const W& msg, WriteOptions options, void* tag) override {
write_ops_.set_output_tag(tag);
if (options.is_last_message()) {
options.set_buffer_hint();
}
EnsureInitialMetadataSent(&write_ops_);
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
call_.PerformOps(&write_ops_);
}
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&write_ops_);
options.set_buffer_hint();
GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
call_.PerformOps(&write_ops_);
}
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
EnsureInitialMetadataSent(&finish_ops_);
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
call_.PerformOps(&finish_ops_);
}
@ -524,11 +647,25 @@ class ServerAsyncReaderWriter final
void BindCall(Call* call) override { call_ = *call; }
template <class T>
void EnsureInitialMetadataSent(T* ops) {
if (!ctx_->sent_initial_metadata_) {
ops->SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops->set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
}
Call call_;
ServerContext* ctx_;
CallOpSet<CallOpSendInitialMetadata> meta_ops_;
CallOpSet<CallOpRecvMessage<R>> read_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpServerSendStatus>
write_ops_;
CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
};

@ -84,8 +84,9 @@ inline grpc_metadata* FillMetadataArray(
/// Per-message write options.
class WriteOptions {
public:
WriteOptions() : flags_(0) {}
WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
WriteOptions() : flags_(0), last_message_(false) {}
WriteOptions(const WriteOptions& other)
: flags_(other.flags_), last_message_(other.last_message_) {}
/// Clear all flags.
inline void Clear() { flags_ = 0; }
@ -141,6 +142,43 @@ class WriteOptions {
/// \sa GRPC_WRITE_BUFFER_HINT
inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
/// corked bit: aliases set_buffer_hint currently, with the intent that
/// set_buffer_hint will be removed in the future
inline WriteOptions& set_corked() {
SetBit(GRPC_WRITE_BUFFER_HINT);
return *this;
}
inline WriteOptions& clear_corked() {
ClearBit(GRPC_WRITE_BUFFER_HINT);
return *this;
}
inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
/// last-message bit: indicates this is the last message in a stream
/// client-side: makes Write the equivalent of performing Write, WritesDone
/// in a single step
/// server-side: hold the Write until the service handler returns (sync api)
/// or until Finish is called (async api)
inline WriteOptions& set_last_message() {
last_message_ = true;
return *this;
}
/// Clears flag indicating that this is the last message in a stream,
/// disabling coalescing.
inline WriteOptions& clear_last_messsage() {
last_message_ = false;
return *this;
}
/// Get value for the flag indicating that this is the last message, and
/// should be coalesced with trailing metadata.
///
/// \sa GRPC_WRITE_LAST_MESSAGE
bool is_last_message() const { return last_message_; }
WriteOptions& operator=(const WriteOptions& rhs) {
flags_ = rhs.flags_;
return *this;
@ -154,6 +192,7 @@ class WriteOptions {
bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
uint32_t flags_;
bool last_message_;
};
/// Default argument for CallOpSet. I is unused by the class, but can be
@ -224,7 +263,7 @@ class CallOpSendMessage {
/// after use.
template <class M>
Status SendMessage(const M& message,
const WriteOptions& options) GRPC_MUST_USE_RESULT;
WriteOptions options) GRPC_MUST_USE_RESULT;
template <class M>
Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
@ -252,8 +291,7 @@ class CallOpSendMessage {
};
template <class M>
Status CallOpSendMessage::SendMessage(const M& message,
const WriteOptions& options) {
Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
write_options_ = options;
return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
}

@ -281,6 +281,17 @@ class ClientContext {
/// \param algorithm The compression algorithm used for the client call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Flag whether the initial metadata should be \a corked
///
/// If \a corked is true, then the initial metadata will be colasced with the
/// write of first message in the stream.
///
/// \param corked The flag indicating whether the initial metadata is to be
/// corked or not.
void set_initial_metadata_corked(bool corked) {
initial_metadata_corked_ = corked;
}
/// Return the peer uri in a string.
///
/// \warning This value is never authenticated or subject to any security
@ -357,7 +368,8 @@ class ClientContext {
(cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
(wait_for_ready_explicitly_set_
? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
: 0);
: 0) |
(initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
}
grpc::string authority() { return authority_; }
@ -384,6 +396,7 @@ class ClientContext {
PropagationOptions propagation_options_;
grpc_compression_algorithm compression_algorithm_;
bool initial_metadata_corked_;
};
} // namespace grpc

@ -100,22 +100,40 @@ class WriterInterface {
public:
virtual ~WriterInterface() {}
/// Blocking write \a msg to the stream with options.
/// Blocking write \a msg to the stream with WriteOptions \a options.
/// This is thread-safe with respect to \a Read
///
/// \param msg The message to be written to the stream.
/// \param options Options affecting the write operation.
/// \param options The WriteOptions affecting the write operation.
///
/// \return \a true on success, \a false when the stream has been closed.
virtual bool Write(const W& msg, const WriteOptions& options) = 0;
virtual bool Write(const W& msg, WriteOptions options) = 0;
/// Blocking write \a msg to the stream with default options.
/// Blocking write \a msg to the stream with default write options.
/// This is thread-safe with respect to \a Read
///
/// \param msg The message to be written to the stream.
///
/// \return \a true on success, \a false when the stream has been closed.
inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
/// Write \a msg and coalesce it with the writing of trailing metadata, using
/// WriteOptions \a options.
///
/// For client, WriteLast is equivalent of performing Write and WritesDone in
/// a single step. \a msg and trailing metadata are coalesced and sent on wire
/// by calling this function.
/// For server, WriteLast buffers the \a msg. The writing of \a msg is held
/// until the service handler returns, where \a msg and trailing metadata are
/// coalesced and sent on wire. Note that WriteLast can only buffer \a msg up
/// to the flow control window size. If \a msg size is larger than the window
/// size, it will be sent on wire without buffering.
///
/// \param[in] msg The message to be written to the stream.
/// \param[in] options The WriteOptions to be used to write this message.
void WriteLast(const W& msg, WriteOptions options) {
Write(msg, options.set_last_message());
}
};
/// Client-side interface for streaming reads of message of type \a R.
@ -213,11 +231,13 @@ class ClientWriter : public ClientWriterInterface<W> {
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
if (!context_->initial_metadata_corked_) {
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
void WaitForInitialMetadata() {
@ -230,11 +250,24 @@ class ClientWriter : public ClientWriterInterface<W> {
}
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) override {
CallOpSet<CallOpSendMessage> ops;
bool Write(const W& msg, WriteOptions options) override {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessage(msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
@ -293,11 +326,13 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context)
: context_(context), call_(channel->CreateCall(method, context, &cq_)) {
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
if (!context_->initial_metadata_corked_) {
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(context->send_initial_metadata_,
context->initial_metadata_flags());
call_.PerformOps(&ops);
cq_.Pluck(&ops);
}
}
void WaitForInitialMetadata() override {
@ -325,9 +360,24 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
}
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) override {
CallOpSet<CallOpSendMessage> ops;
if (!ops.SendMessage(msg, options).ok()) return false;
bool Write(const W& msg, WriteOptions options) override {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpClientSendClose>
ops;
if (options.is_last_message()) {
options.set_buffer_hint();
ops.ClientSendClose();
}
if (context_->initial_metadata_corked_) {
ops.SendInitialMetadata(context_->send_initial_metadata_,
context_->initial_metadata_flags());
context_->set_initial_metadata_corked(false);
}
if (!ops.SendMessage(msg, options).ok()) {
return false;
}
call_.PerformOps(&ops);
return cq_.Pluck(&ops);
}
@ -423,7 +473,10 @@ class ServerWriter final : public ServerWriterInterface<W> {
}
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) override {
bool Write(const W& msg, WriteOptions options) override {
if (options.is_last_message()) {
options.set_buffer_hint();
}
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
if (!ops.SendMessage(msg, options).ok()) {
return false;
@ -485,7 +538,10 @@ class ServerReaderWriterBody final {
return call_->cq()->Pluck(&ops) && ops.got_message;
}
bool Write(const W& msg, const WriteOptions& options) {
bool Write(const W& msg, WriteOptions options) {
if (options.is_last_message()) {
options.set_buffer_hint();
}
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
if (!ops.SendMessage(msg, options).ok()) {
return false;
@ -523,7 +579,7 @@ class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
bool Read(R* msg) override { return body_.Read(msg); }
using WriterInterface<W>::Write;
bool Write(const W& msg, const WriteOptions& options) override {
bool Write(const W& msg, WriteOptions options) override {
return body_.Write(msg, options);
}
@ -562,8 +618,7 @@ class ServerUnaryStreamer final
}
using WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
const WriteOptions& options) override {
bool Write(const ResponseType& response, WriteOptions options) override {
if (write_done_ || !read_done_) {
return false;
}
@ -604,8 +659,7 @@ class ServerSplitStreamer final
}
using WriterInterface<ResponseType>::Write;
bool Write(const ResponseType& response,
const WriteOptions& options) override {
bool Write(const ResponseType& response, WriteOptions options) override {
return read_done_ && body_.Write(response, options);
}

@ -54,7 +54,7 @@ class ResourceQuota;
class ChannelArguments {
public:
ChannelArguments();
~ChannelArguments() {}
~ChannelArguments();
ChannelArguments(const ChannelArguments& other);
ChannelArguments& operator=(ChannelArguments other) {
@ -117,10 +117,10 @@ class ChannelArguments {
/// Return (by value) a c grpc_channel_args structure which points to
/// arguments owned by this ChannelArguments instance
grpc_channel_args c_channel_args() {
grpc_channel_args c_channel_args() const {
grpc_channel_args out;
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;
}

@ -93,6 +93,71 @@ GRPCAPI const char *grpc_version_string(void);
/** Return a string specifying what the 'g' in gRPC stands for */
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 */
GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved);

@ -92,4 +92,9 @@
#error could not determine platform for atm
#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 */

@ -87,6 +87,9 @@ typedef struct grpc_call grpc_call;
/** The Socket Mutator interface allows changes on socket options */
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 */
typedef enum {
GRPC_ARG_STRING,
@ -195,14 +198,14 @@ typedef struct {
#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
/** After a duration of this time the client pings the server to see if the
transport is still alive. Int valued, seconds. */
#define GRPC_ARG_HTTP2_KEEPALIVE_TIME "grpc.http2.keepalive_time"
#define GRPC_ARG_CLIENT_KEEPALIVE_TIME_S "grpc.client_keepalive_time"
/** After waiting for a duration of this time, if the client does not receive
the ping ack, it will close the transport. Int valued, seconds. */
#define GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT "grpc.http2.keepalive_timeout"
#define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout"
/** Is it permissible to send keepalive pings without any outstanding streams.
Int valued, 0(false)/1(true). */
#define GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS \
"grpc.http2.keepalive_permit_without_calls"
#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \
"grpc.keepalive_permit_without_calls"
/** Default authority to pass if none specified on call construction. A string.
* */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
@ -240,6 +243,8 @@ typedef struct {
#define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name"
/** The grpc_socket_mutator instance that set the socket options. A pointer. */
#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
* possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
@ -311,13 +316,16 @@ typedef enum grpc_call_error {
/** Signal that GRPC_INITIAL_METADATA_WAIT_FOR_READY was explicitly set
by the calling application. */
#define GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET (0x00000080u)
/** Signal that the initial metadata should be corked */
#define GRPC_INITIAL_METADATA_CORKED (0x00000100u)
/** Mask of all valid flags */
#define GRPC_INITIAL_METADATA_USED_MASK \
(GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
GRPC_INITIAL_METADATA_WAIT_FOR_READY | \
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET)
#define GRPC_INITIAL_METADATA_USED_MASK \
(GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
GRPC_INITIAL_METADATA_WAIT_FOR_READY | \
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET | \
GRPC_INITIAL_METADATA_CORKED)
/** A single metadata element */
typedef struct grpc_metadata {

@ -364,6 +364,14 @@ typedef unsigned __int64 uint64_t;
power of two */
#define GPR_MAX_ALIGNMENT 16
#ifndef GRPC_ARES
#ifdef GPR_WINDOWS
#define GRPC_ARES 0
#else
#define GRPC_ARES 1
#endif
#endif
#ifndef GRPC_MUST_USE_RESULT
#if defined(__GNUC__) && !defined(__MINGW32__)
#define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))

@ -24,7 +24,7 @@
"electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell",
"gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
"coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
"install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build"
"install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library"
},
"bundledDependencies": [
"node-pre-gyp"
@ -34,7 +34,8 @@
"lodash": "^4.15.0",
"nan": "^2.0.0",
"node-pre-gyp": "^0.6.0",
"protobufjs": "^5.0.0"
"protobufjs": "^5.0.0",
"cares": "^1.1.5"
},
"devDependencies": {
"async": "^2.0.1",
@ -52,7 +53,7 @@
"poisson-process": "^0.2.1"
},
"engines": {
"node": ">=1.1.0"
"node": ">=4"
},
"binary": {
"module_name": "grpc_node",

@ -108,6 +108,7 @@
<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/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/backoff.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/cmdline.c" role="src" />
@ -229,6 +230,7 @@
<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_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_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.h" role="src" />
@ -237,6 +239,7 @@
<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_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_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.h" role="src" />
@ -267,6 +270,7 @@
<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/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/init.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/lame_client.h" role="src" />
@ -336,7 +340,6 @@
<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_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_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.h" role="src" />
@ -346,6 +349,7 @@
<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_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_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.h" role="src" />
@ -358,6 +362,8 @@
<file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/aggregation.h" role="src" />
@ -424,6 +430,7 @@
<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/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_utils_common_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_linux.c" role="src" />
@ -436,6 +443,9 @@
<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_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_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.c" role="src" />
@ -458,6 +468,7 @@
<file baseinstalldir="/" name="src/core/lib/json/json_reader.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_string.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/percent_encoding.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.c" role="src" />
@ -476,6 +487,7 @@
<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/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/lame_client.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/metadata_array.c" role="src" />
@ -539,7 +551,6 @@
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/server_auth_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/init_secure.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" />
@ -552,10 +563,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_plugin.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_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_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.c" role="src" />
@ -565,6 +574,7 @@
<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_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_index.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.c" role="src" />
@ -582,6 +592,9 @@
<file baseinstalldir="/" name="third_party/nanopb/pb_encode.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/pick_first/pick_first.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/round_robin/round_robin.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/dns/native/dns_resolver.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/resolver/sockaddr/sockaddr_resolver.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.c" role="src" />

@ -52,6 +52,13 @@ PYTHON_STEM = os.path.join('src', 'python', 'grpcio')
CORE_INCLUDE = ('include', '.',)
BORINGSSL_INCLUDE = (os.path.join('third_party', 'boringssl', 'include'),)
ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
CARES_INCLUDE = (
os.path.join('third_party', 'cares'),
os.path.join('third_party', 'cares', 'cares'),)
if 'linux' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
if 'darwin' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_darwin'),)
README = os.path.join(PYTHON_STEM, 'README.rst')
# Ensure we're in the proper directory whether or not we're being used by pip.
@ -136,7 +143,8 @@ CYTHON_HELPER_C_FILES = ()
CORE_C_FILES = tuple(grpc_core_dependencies.CORE_SOURCE_FILES)
EXTENSION_INCLUDE_DIRECTORIES = (
(PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE)
(PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE +
CARES_INCLUDE)
EXTENSION_LIBRARIES = ()
if "linux" in sys.platform:
@ -150,13 +158,15 @@ DEFINE_MACROS = (
('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
if "win32" in sys.platform:
DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1),)
DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1),)
if '64bit' in platform.architecture()[0]:
DEFINE_MACROS += (('MS_WIN64', 1),)
elif sys.version_info >= (3, 5):
# For some reason, this is needed to get access to inet_pton/inet_ntop
# on msvc, but only for 32 bits
DEFINE_MACROS += (('NTDDI_VERSION', 0x06000000),)
else:
DEFINE_MACROS += (('HAVE_CONFIG_H', 1),)
LDFLAGS = tuple(EXTRA_LINK_ARGS)
CFLAGS = tuple(EXTRA_COMPILE_ARGS)
@ -206,14 +216,13 @@ PACKAGE_DIRECTORIES = {
INSTALL_REQUIRES = (
'six>=1.5.2',
'enum34>=1.0.4',
# TODO(atash): eventually split the grpcio package into a metapackage
# depending on protobuf and the runtime component (independent of protobuf)
'protobuf>=3.2.0',
)
if not PY3:
INSTALL_REQUIRES += ('futures>=2.2.0',)
INSTALL_REQUIRES += ('futures>=2.2.0', 'enum34>=1.0.4')
SETUP_REQUIRES = INSTALL_REQUIRES + (
'sphinx>=1.3',
@ -265,6 +274,10 @@ PACKAGES = setuptools.find_packages(PYTHON_STEM)
setuptools.setup(
name='grpcio',
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,
long_description=open(README).read(),
ext_modules=CYTHON_EXTENSION_MODULES,

@ -0,0 +1,49 @@
# c-ares cmake file for gRPC
#
# This is currently very experimental, and unsupported.
#
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
string(TOLOWER ${CMAKE_SYSTEM_NAME} cares_system_name)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/cares)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/cares/cares)
if(${cares_system_name} MATCHES windows)
add_definitions(-DCARES_STATICLIB=1)
add_definitions(-DWIN32_LEAN_AND_MEAN=1)
else()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../third_party/cares/config_${cares_system_name})
add_definitions(-DHAVE_CONFIG_H=1)
add_definitions(-D_GNU_SOURCE=1)
endif()
file(GLOB lib_sources ../../third_party/cares/cares/*.c)
add_library(cares ${lib_sources})

@ -0,0 +1,149 @@
#!/usr/bin/env python2.7
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re
import os
import sys
import yaml
os.chdir(os.path.dirname(sys.argv[0])+'/../..')
out = {}
try:
def gen_ares_build(x):
subprocess.call("third_party/cares/cares/buildconf", shell=True)
subprocess.call("third_party/cares/cares/configure", shell=True)
def config_platform(x):
if 'linux' in sys.platform:
return 'src/cares/cares/config_linux/ares_config.h'
if 'darwin' in sys.platform:
return 'src/cares/cares/config_darwin/ares_config.h'
if not os.path.isfile('third_party/cares/cares/ares_config.h'):
gen_ares_build(x)
return 'third_party/cares/cares/ares_config.h'
def ares_build(x):
if os.path.isfile('src/cares/cares/ares_build.h'):
return 'src/cares/cares/ares_build.h'
if not os.path.isfile('third_party/cares/cares/ares_build.h'):
gen_ares_build(x)
return 'third_party/cares/cares/ares_build.h'
out['libs'] = [{
'name': 'ares',
'defaults': 'ares',
'build': 'private',
'language': 'c',
'secure': 'no',
'src': [
"third_party/cares/cares/ares__close_sockets.c",
"third_party/cares/cares/ares__get_hostent.c",
"third_party/cares/cares/ares__read_line.c",
"third_party/cares/cares/ares__timeval.c",
"third_party/cares/cares/ares_cancel.c",
"third_party/cares/cares/ares_create_query.c",
"third_party/cares/cares/ares_data.c",
"third_party/cares/cares/ares_destroy.c",
"third_party/cares/cares/ares_expand_name.c",
"third_party/cares/cares/ares_expand_string.c",
"third_party/cares/cares/ares_fds.c",
"third_party/cares/cares/ares_free_hostent.c",
"third_party/cares/cares/ares_free_string.c",
"third_party/cares/cares/ares_getenv.c",
"third_party/cares/cares/ares_gethostbyaddr.c",
"third_party/cares/cares/ares_gethostbyname.c",
"third_party/cares/cares/ares_getnameinfo.c",
"third_party/cares/cares/ares_getopt.c",
"third_party/cares/cares/ares_getsock.c",
"third_party/cares/cares/ares_init.c",
"third_party/cares/cares/ares_library_init.c",
"third_party/cares/cares/ares_llist.c",
"third_party/cares/cares/ares_mkquery.c",
"third_party/cares/cares/ares_nowarn.c",
"third_party/cares/cares/ares_options.c",
"third_party/cares/cares/ares_parse_a_reply.c",
"third_party/cares/cares/ares_parse_aaaa_reply.c",
"third_party/cares/cares/ares_parse_mx_reply.c",
"third_party/cares/cares/ares_parse_naptr_reply.c",
"third_party/cares/cares/ares_parse_ns_reply.c",
"third_party/cares/cares/ares_parse_ptr_reply.c",
"third_party/cares/cares/ares_parse_soa_reply.c",
"third_party/cares/cares/ares_parse_srv_reply.c",
"third_party/cares/cares/ares_parse_txt_reply.c",
"third_party/cares/cares/ares_platform.c",
"third_party/cares/cares/ares_process.c",
"third_party/cares/cares/ares_query.c",
"third_party/cares/cares/ares_search.c",
"third_party/cares/cares/ares_send.c",
"third_party/cares/cares/ares_strcasecmp.c",
"third_party/cares/cares/ares_strdup.c",
"third_party/cares/cares/ares_strerror.c",
"third_party/cares/cares/ares_timeout.c",
"third_party/cares/cares/ares_version.c",
"third_party/cares/cares/ares_writev.c",
"third_party/cares/cares/bitncmp.c",
"third_party/cares/cares/inet_net_pton.c",
"third_party/cares/cares/inet_ntop.c",
"third_party/cares/cares/windows_port.c",
],
'headers': [
"third_party/cares/cares/ares.h",
"third_party/cares/cares/ares_data.h",
"third_party/cares/cares/ares_dns.h",
"third_party/cares/cares/ares_getenv.h",
"third_party/cares/cares/ares_getopt.h",
"third_party/cares/cares/ares_inet_net_pton.h",
"third_party/cares/cares/ares_iphlpapi.h",
"third_party/cares/cares/ares_ipv6.h",
"third_party/cares/cares/ares_library_init.h",
"third_party/cares/cares/ares_llist.h",
"third_party/cares/cares/ares_nowarn.h",
"third_party/cares/cares/ares_platform.h",
"third_party/cares/cares/ares_private.h",
"third_party/cares/cares/ares_rules.h",
"third_party/cares/cares/ares_setup.h",
"third_party/cares/cares/ares_strcasecmp.h",
"third_party/cares/cares/ares_strdup.h",
"third_party/cares/cares/ares_version.h",
"third_party/cares/cares/bitncmp.h",
"third_party/cares/cares/config-win32.h",
"third_party/cares/cares/setup_once.h",
"third_party/cares/ares_build.h",
"third_party/cares/config_linux/ares_config.h",
"third_party/cares/config_darwin/ares_config.h"
],
}]
except:
pass
print yaml.dump(out)

@ -1,4 +1,4 @@
#Overview
# Overview
This directory contains source code for gRPC protocol buffer compiler (*protoc*) plugins. Along with `protoc`,
these plugins are used to generate gRPC client and server stubs from `.proto` files.

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

@ -118,7 +118,7 @@ void PrintService(const ServiceDescriptor *service, Printer *out) {
out->Print(
"/**\n * @param string $$hostname hostname\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"
"public function __construct($$hostname, $$opts, "
"$$channel = null) {\n");

@ -647,15 +647,15 @@ bool PrivateGenerator::PrintBetaPreamble() {
"Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
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;
}
bool PrivateGenerator::PrintPreamble() {
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) {
out->Print("\n");
StringPairSet imports_set;

@ -1,4 +1,4 @@
#Overview
# Overview
This directory contains source code for C library (a.k.a the *gRPC C core*) that provides all gRPC's core functionality through a low level API. Libraries in other languages in this repository (C++, Ruby,
Python, PHP, NodeJS, Objective-C) are layered on top of this library.

@ -1,6 +1,6 @@
Files generated for use by Census stats and trace recording subsystem.
#Files
# Files
* census.pb.{h,c} - Generated from src/core/ext/census/census.proto, using the
script `tools/codegen/core/gen_nano_proto.sh src/proto/census/census.proto
$PWD/src/core/ext/census/gen src/core/ext/census/gen`

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

@ -47,6 +47,7 @@
#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/resolver_registry.h"
#include "src/core/ext/client_channel/retry_throttle.h"
#include "src/core/ext/client_channel/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
@ -189,6 +190,8 @@ typedef struct client_channel_channel_data {
grpc_combiner *combiner;
/** currently active load balancer */
grpc_lb_policy *lb_policy;
/** retry throttle data */
grpc_server_retry_throttle_data *retry_throttle_data;
/** maps method names to method_parameters structs */
grpc_slice_hash_table *method_params_table;
/** 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);
}
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,
void *arg, grpc_error *error) {
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_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
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;
service_config_parsing_state parsing_state;
memset(&parsing_state, 0, sizeof(parsing_state));
if (chand->resolver_result != NULL) {
// 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_create(service_config_json);
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(
exec_ctx, service_config, method_parameters_create_from_json,
&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;
}
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) {
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) {
grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
} else if (chand->resolver == NULL /* disconnected */) {
grpc_closure_list_fail_all(
&chand->waiting_for_config_closures,
GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1));
grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Channel disconnected", &error, 1));
grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
}
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};
set_channel_connectivity_state_locked(
exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs,
GPR_ARRAY_SIZE(refs)),
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Got config after disconnection", refs, GPR_ARRAY_SIZE(refs)),
"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 (chand->lb_policy == NULL) {
grpc_closure_sched(exec_ctx, op->send_ping,
GRPC_ERROR_CREATE("Ping with no load balancing"));
grpc_closure_sched(
exec_ctx, op->send_ping,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
} else {
grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping);
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 (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args);
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;
}
@ -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_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) {
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.
gpr_timespec call_start_time;
gpr_timespec deadline;
grpc_server_retry_throttle_data *retry_throttle_data;
method_parameters *method_params;
grpc_error *cancel_error;
@ -676,6 +764,9 @@ typedef struct client_channel_call_data {
grpc_call_stack *owning_call;
grpc_linked_mdelem lb_token_mdelem;
grpc_closure on_complete;
grpc_closure *original_on_complete;
} call_data;
grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
@ -728,7 +819,7 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
gpr_free(ops);
}
// Sets calld->method_params.
// Sets calld->method_params and calld->retry_throttle_data.
// If the method params specify a timeout, populates
// *per_method_deadline and returns true.
static bool set_call_method_params_from_service_config_locked(
@ -736,6 +827,10 @@ static bool set_call_method_params_from_service_config_locked(
gpr_timespec *per_method_deadline) {
channel_data *chand = elem->channel_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) {
calld->method_params = grpc_method_config_table_get(
exec_ctx, chand->method_params_table, calld->path);
@ -781,12 +876,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (calld->connected_subchannel == NULL) {
gpr_atm_no_barrier_store(&calld->subchannel_call, 1);
fail_locked(exec_ctx, calld, GRPC_ERROR_CREATE_REFERENCING(
"Failed to create subchannel", &error, 1));
fail_locked(exec_ctx, calld,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed to create subchannel", &error, 1));
} else if (GET_CALL(calld) == CANCELLED_CALL) {
/* already cancelled before subchannel became ready */
grpc_error *cancellation_error = GRPC_ERROR_CREATE_REFERENCING(
"Cancelled before creating subchannel", &error, 1);
grpc_error *cancellation_error =
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 (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) {
cancellation_error =
@ -888,9 +985,9 @@ static bool pick_subchannel_locked(
cpa = closure->cb_arg;
if (cpa->connected_subchannel == connected_subchannel) {
cpa->connected_subchannel = NULL;
grpc_closure_sched(
exec_ctx, cpa->on_ready,
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
grpc_closure_sched(exec_ctx, cpa->on_ready,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick cancelled", &error, 1));
}
}
GPR_TIMER_END("pick_subchannel", 0);
@ -947,7 +1044,8 @@ static bool pick_subchannel_locked(
grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
GRPC_ERROR_NONE);
} 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);
@ -1056,6 +1154,26 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
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,
grpc_error *error_ignored) {
GPR_TIMER_BEGIN("start_transport_stream_op_locked", 0);
@ -1064,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];
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);
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,

@ -43,6 +43,7 @@
#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/resolver_registry.h"
#include "src/core/ext/client_channel/retry_throttle.h"
#include "src/core/ext/client_channel/subchannel_index.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) {
grpc_lb_policy_registry_init();
grpc_resolver_registry_init();
grpc_retry_throttle_map_init();
grpc_proxy_mapper_registry_init();
grpc_register_http_proxy_mapper();
grpc_subchannel_index_init();
@ -96,6 +98,7 @@ void grpc_client_channel_shutdown(void) {
grpc_subchannel_index_shutdown();
grpc_channel_init_shutdown();
grpc_proxy_mapper_registry_shutdown();
grpc_retry_throttle_map_shutdown();
grpc_resolver_registry_shutdown();
grpc_lb_policy_registry_shutdown();
}

@ -48,8 +48,6 @@ struct grpc_connector {
typedef struct {
/** set of pollsets interested in this connection */
grpc_pollset_set *interested_parties;
/** initial connect string to send */
grpc_slice initial_connect_string;
/** deadline for connection */
gpr_timespec deadline;
/** 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
// before the endpoint callback was invoked, we need to generate our
// own error.
error = GRPC_ERROR_CREATE("Handshaker shutdown");
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshaker shutdown");
}
if (!handshaker->shutdown) {
// 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;
gpr_asprintf(&msg, "HTTP proxy returned response code %d",
handshaker->http_response.status);
error = GRPC_ERROR_CREATE(msg);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
handshake_failed_locked(exec_ctx, handshaker, error);
goto done;

@ -93,7 +93,6 @@ static grpc_resolver_factory *lookup_factory(const char *name) {
return g_all_of_the_resolvers[i];
}
}
return NULL;
}

@ -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 "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/proxy_mapper_registry.h"
#include "src/core/ext/client_channel/subchannel_index.h"
@ -103,9 +102,6 @@ struct grpc_subchannel {
grpc_subchannel_key *key;
/** initial string to send to peer */
grpc_slice initial_connect_string;
/** set during connection */
grpc_connect_out_args connecting_result;
@ -215,7 +211,6 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel *c = arg;
gpr_free((void *)c->filters);
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_connector_unref(exec_ctx, c->connector);
grpc_pollset_set_destroy(exec_ctx, c->pollset_set);
@ -274,8 +269,9 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->disconnected);
c->disconnected = true;
grpc_connector_shutdown(exec_ctx, c->connector,
GRPC_ERROR_CREATE("Subchannel disconnected"));
grpc_connector_shutdown(
exec_ctx, c->connector,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Subchannel disconnected"));
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
@ -333,7 +329,6 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
c->pollset_set = grpc_pollset_set_create();
grpc_resolved_address *addr = gpr_malloc(sizeof(*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_channel_args *new_args = NULL;
if (grpc_proxy_mappers_map_address(exec_ctx, addr, args->args, &new_address,
@ -404,7 +399,6 @@ static void continue_connect_locked(grpc_exec_ctx *exec_ctx,
args.interested_parties = c->pollset_set;
args.deadline = c->next_attempt;
args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
@ -444,7 +438,8 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_mu_lock(&c->mu);
c->have_alarm = false;
if (c->disconnected) {
error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected",
&error, 1);
} else {
GRPC_ERROR_REF(error);
}
@ -695,9 +690,9 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
} else {
grpc_connectivity_state_set(
exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_int(
GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Connect Failed", &error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
"connect_failed");
const char *errmsg = grpc_error_string(error);

@ -925,7 +925,7 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
grpc_connectivity_state_set(
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
* while holding glb_policy->mu: lb_on_server_status_received, invoked due to
* 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;
if (pp->target == target) {
*target = NULL;
grpc_closure_sched(
exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
grpc_closure_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick Cancelled", &error, 1));
} else {
pp->next = glb_policy->pending_picks;
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;
if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) {
grpc_closure_sched(
exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
grpc_closure_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick Cancelled", &error, 1));
} else {
pp->next = glb_policy->pending_picks;
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) {
if (pick_args->lb_token_mdelem_storage == NULL) {
*target = NULL;
grpc_closure_sched(
exec_ctx, on_complete,
GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting "
"won't work without it. Failing"));
grpc_closure_sched(exec_ctx, on_complete,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No mdelem storage for the LB token. Load reporting "
"won't work without it. Failing"));
return 0;
}

@ -101,7 +101,7 @@ static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
p->pending_picks = NULL;
grpc_connectivity_state_set(
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 */
if (p->selected != NULL) {
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;
if (pp->target == target) {
*target = NULL;
grpc_closure_sched(
exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
grpc_closure_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick Cancelled", &error, 1));
gpr_free(pp);
} else {
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;
if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) {
grpc_closure_sched(
exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
grpc_closure_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick Cancelled", &error, 1));
gpr_free(pp);
} else {
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) {
grpc_connectivity_state_set(
exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels",
&error, 1),
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick first exhausted channels", &error, 1),
"no_more_channels");
while ((pp = p->pending_picks)) {
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) {
grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
} 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");
}
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
memset(&sc_args, 0, sizeof(grpc_subchannel_args));
grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args =
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
1);
gpr_free(addr_arg.value.string);
sc_args.args = new_args;
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)) {
p->pending_picks = pp->next;
*pp->target = NULL;
grpc_closure_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE("Channel Shutdown"));
grpc_closure_sched(
exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"));
gpr_free(pp);
}
grpc_connectivity_state_set(
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++) {
subchannel_data *sd = p->subchannels[i];
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;
if (pp->target == target) {
*target = NULL;
grpc_closure_sched(
exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
grpc_closure_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick cancelled", &error, 1));
gpr_free(pp);
} else {
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) ==
initial_metadata_flags_eq) {
*pp->target = NULL;
grpc_closure_sched(
exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
grpc_closure_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Pick cancelled", &error, 1));
gpr_free(pp);
} else {
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_UNREF(exec_ctx, target, "rr_picked");
} else {
grpc_closure_sched(exec_ctx, closure,
GRPC_ERROR_CREATE("Round Robin not connected"));
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"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. */
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));
grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args =
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
1);
gpr_free(addr_arg.value.string);
sc_args.args = new_args;
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));
calld->have_service_method = true;
} else {
err =
grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header"));
err = grpc_error_add_child(
err, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing :path header"));
}
if (calld->recv_initial_metadata->idx.named.lb_token != NULL) {
calld->initial_md_string = grpc_slice_ref_internal(

@ -0,0 +1,350 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/backoff.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1
#define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** name to resolve (usually the same as target_name) */
char *name_to_resolve;
/** default port to use */
char *default_port;
/** channel args. */
grpc_channel_args *channel_args;
/** pollset_set to drive the name resolution process */
grpc_pollset_set *interested_parties;
/** Closures used by the combiner */
grpc_closure dns_ares_on_retry_timer_locked;
grpc_closure dns_ares_on_resolved_locked;
/** Combiner guarding the rest of the state */
grpc_combiner *combiner;
/** are we currently resolving? */
bool resolving;
/** which version of the result have we published? */
int published_version;
/** which version of the result is current? */
int resolved_version;
/** pending next completion, or NULL */
grpc_closure *next_completion;
/** target result address for next completion */
grpc_channel_args **target_result;
/** current (fully resolved) result */
grpc_channel_args *resolved_result;
/** retry timer */
bool have_retry_timer;
grpc_timer retry_timer;
/** retry backoff state */
gpr_backoff backoff_state;
/** currently resolving addresses */
grpc_resolved_addresses *addresses;
} ares_dns_resolver;
static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void dns_ares_start_resolving_locked(grpc_exec_ctx *exec_ctx,
ares_dns_resolver *r);
static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
ares_dns_resolver *r);
static void dns_ares_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void dns_ares_channel_saw_error_locked(grpc_exec_ctx *exec_ctx,
grpc_resolver *r);
static void dns_ares_next_locked(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_channel_args **target_result,
grpc_closure *on_complete);
static const grpc_resolver_vtable dns_ares_resolver_vtable = {
dns_ares_destroy, dns_ares_shutdown_locked,
dns_ares_channel_saw_error_locked, dns_ares_next_locked};
static void dns_ares_shutdown_locked(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver) {
ares_dns_resolver *r = (ares_dns_resolver *)resolver;
if (r->have_retry_timer) {
grpc_timer_cancel(exec_ctx, &r->retry_timer);
}
if (r->next_completion != NULL) {
*r->target_result = NULL;
grpc_closure_sched(
exec_ctx, r->next_completion,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown"));
r->next_completion = NULL;
}
}
static void dns_ares_channel_saw_error_locked(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver) {
ares_dns_resolver *r = (ares_dns_resolver *)resolver;
if (!r->resolving) {
gpr_backoff_reset(&r->backoff_state);
dns_ares_start_resolving_locked(exec_ctx, r);
}
}
static void dns_ares_on_retry_timer_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
ares_dns_resolver *r = arg;
r->have_retry_timer = false;
if (error == GRPC_ERROR_NONE) {
if (!r->resolving) {
dns_ares_start_resolving_locked(exec_ctx, r);
}
}
GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer");
}
static void dns_ares_on_resolved_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
ares_dns_resolver *r = arg;
grpc_channel_args *result = NULL;
GPR_ASSERT(r->resolving);
r->resolving = false;
if (r->addresses != NULL) {
grpc_lb_addresses *addresses = grpc_lb_addresses_create(
r->addresses->naddrs, NULL /* user_data_vtable */);
for (size_t i = 0; i < r->addresses->naddrs; ++i) {
grpc_lb_addresses_set_address(
addresses, i, &r->addresses->addrs[i].addr,
r->addresses->addrs[i].len, false /* is_balancer */,
NULL /* balancer_name */, NULL /* user_data */);
}
grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
grpc_resolved_addresses_destroy(r->addresses);
grpc_lb_addresses_destroy(exec_ctx, addresses);
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now);
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
GRPC_RESOLVER_REF(&r->base, "retry-timer");
if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
timeout.tv_nsec);
} else {
gpr_log(GPR_DEBUG, "retrying immediately");
}
grpc_timer_init(exec_ctx, &r->retry_timer, next_try,
&r->dns_ares_on_retry_timer_locked, now);
}
if (r->resolved_result != NULL) {
grpc_channel_args_destroy(exec_ctx, r->resolved_result);
}
r->resolved_result = result;
r->resolved_version++;
dns_ares_maybe_finish_next_locked(exec_ctx, r);
GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "dns-resolving");
}
static void dns_ares_next_locked(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver,
grpc_channel_args **target_result,
grpc_closure *on_complete) {
gpr_log(GPR_DEBUG, "dns_ares_next is called.");
ares_dns_resolver *r = (ares_dns_resolver *)resolver;
GPR_ASSERT(!r->next_completion);
r->next_completion = on_complete;
r->target_result = target_result;
if (r->resolved_version == 0 && !r->resolving) {
gpr_backoff_reset(&r->backoff_state);
dns_ares_start_resolving_locked(exec_ctx, r);
} else {
dns_ares_maybe_finish_next_locked(exec_ctx, r);
}
}
static void dns_ares_start_resolving_locked(grpc_exec_ctx *exec_ctx,
ares_dns_resolver *r) {
GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving);
r->resolving = true;
r->addresses = NULL;
grpc_resolve_address(exec_ctx, r->name_to_resolve, r->default_port,
r->interested_parties, &r->dns_ares_on_resolved_locked,
&r->addresses);
}
static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
ares_dns_resolver *r) {
if (r->next_completion != NULL &&
r->resolved_version != r->published_version) {
*r->target_result = r->resolved_result == NULL
? NULL
: grpc_channel_args_copy(r->resolved_result);
grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
r->next_completion = NULL;
r->published_version = r->resolved_version;
}
}
static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
gpr_log(GPR_DEBUG, "dns_ares_destroy");
ares_dns_resolver *r = (ares_dns_resolver *)gr;
if (r->resolved_result != NULL) {
grpc_channel_args_destroy(exec_ctx, r->resolved_result);
}
grpc_pollset_set_destroy(exec_ctx, r->interested_parties);
gpr_free(r->name_to_resolve);
gpr_free(r->default_port);
grpc_channel_args_destroy(exec_ctx, r->channel_args);
gpr_free(r);
}
static grpc_resolver *dns_ares_create(grpc_exec_ctx *exec_ctx,
grpc_resolver_args *args,
const char *default_port) {
// Get name from args.
const char *path = args->uri->path;
if (0 != strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based dns uri's not supported");
return NULL;
}
if (path[0] == '/') ++path;
// Create resolver.
ares_dns_resolver *r = gpr_zalloc(sizeof(ares_dns_resolver));
grpc_resolver_init(&r->base, &dns_ares_resolver_vtable, args->combiner);
r->name_to_resolve = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
r->channel_args = grpc_channel_args_copy(args->args);
r->interested_parties = grpc_pollset_set_create();
if (args->pollset_set != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
args->pollset_set);
}
gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
GRPC_DNS_RECONNECT_JITTER,
GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
grpc_closure_init(&r->dns_ares_on_retry_timer_locked,
dns_ares_on_retry_timer_locked, r,
grpc_combiner_scheduler(r->base.combiner, false));
grpc_closure_init(&r->dns_ares_on_resolved_locked,
dns_ares_on_resolved_locked, r,
grpc_combiner_scheduler(r->base.combiner, false));
return &r->base;
}
/*
* FACTORY
*/
static void dns_ares_factory_ref(grpc_resolver_factory *factory) {}
static void dns_ares_factory_unref(grpc_resolver_factory *factory) {}
static grpc_resolver *dns_factory_create_resolver(
grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory,
grpc_resolver_args *args) {
return dns_ares_create(exec_ctx, args, "https");
}
static char *dns_ares_factory_get_default_host_name(
grpc_resolver_factory *factory, grpc_uri *uri) {
const char *path = uri->path;
if (path[0] == '/') ++path;
return gpr_strdup(path);
}
static const grpc_resolver_factory_vtable dns_ares_factory_vtable = {
dns_ares_factory_ref, dns_ares_factory_unref, dns_factory_create_resolver,
dns_ares_factory_get_default_host_name, "dns"};
static grpc_resolver_factory dns_resolver_factory = {&dns_ares_factory_vtable};
static grpc_resolver_factory *dns_ares_resolver_factory_create() {
return &dns_resolver_factory;
}
void grpc_resolver_dns_ares_init(void) {
char *resolver = gpr_getenv("GRPC_DNS_RESOLVER");
/* TODO(zyc): Turn on c-ares based resolver by default after the address
sorter and the CNAME support are added. */
if (resolver != NULL && gpr_stricmp(resolver, "ares") == 0) {
grpc_error *error = grpc_ares_init();
if (error != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("ares_library_init() failed", error);
return;
}
grpc_resolve_address = grpc_resolve_address_ares;
grpc_register_resolver_type(dns_ares_resolver_factory_create());
}
gpr_free(resolver);
}
void grpc_resolver_dns_ares_shutdown(void) {
char *resolver = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver != NULL && gpr_stricmp(resolver, "ares") == 0) {
grpc_ares_cleanup();
}
gpr_free(resolver);
}
#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */
void grpc_resolver_dns_ares_init(void) {}
void grpc_resolver_dns_ares_shutdown(void) {}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */

@ -0,0 +1,65 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
#define GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
#include <ares.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/pollset_set.h"
typedef struct grpc_ares_ev_driver grpc_ares_ev_driver;
/* Start \a ev_driver. It will keep working until all IO on its ares_channel is
done, or grpc_ares_ev_driver_destroy() is called. It may notify the callbacks
bound to its ares_channel when necessary. */
void grpc_ares_ev_driver_start(grpc_exec_ctx *exec_ctx,
grpc_ares_ev_driver *ev_driver);
/* Returns the ares_channel owned by \a ev_driver. To bind a c-ares query to
\a ev_driver, use the ares_channel owned by \a ev_driver as the arg of the
query. */
ares_channel *grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver *ev_driver);
/* Creates a new grpc_ares_ev_driver. Returns GRPC_ERROR_NONE if \a ev_driver is
created successfully. */
grpc_error *grpc_ares_ev_driver_create(grpc_ares_ev_driver **ev_driver,
grpc_pollset_set *pollset_set);
/* Destroys \a ev_driver asynchronously. Pending lookups made on \a ev_driver
will be cancelled and their on_done callbacks will be invoked with a status
of ARES_ECANCELLED. */
void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver);
#endif /* GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H */

@ -0,0 +1,319 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET)
#include "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"
typedef struct fd_node {
/** the owner of this fd node */
grpc_ares_ev_driver *ev_driver;
/** the grpc_fd owned by this fd node */
grpc_fd *grpc_fd;
/** a closure wrapping on_readable_cb, which should be invoked when the
grpc_fd in this node becomes readable. */
grpc_closure read_closure;
/** a closure wrapping on_writable_cb, which should be invoked when the
grpc_fd in this node becomes writable. */
grpc_closure write_closure;
/** next fd node in the list */
struct fd_node *next;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** if the readable closure has been registered */
bool readable_registered;
/** if the writable closure has been registered */
bool writable_registered;
} fd_node;
struct grpc_ares_ev_driver {
/** the ares_channel owned by this event driver */
ares_channel channel;
/** pollset set for driving the IO events of the channel */
grpc_pollset_set *pollset_set;
/** refcount of the event driver */
gpr_refcount refs;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** a list of grpc_fd that this event driver is currently using. */
fd_node *fds;
/** is this event driver currently working? */
bool working;
/** is this event driver being shut down */
bool shutting_down;
};
static void grpc_ares_notify_on_event_locked(grpc_exec_ctx *exec_ctx,
grpc_ares_ev_driver *ev_driver);
static grpc_ares_ev_driver *grpc_ares_ev_driver_ref(
grpc_ares_ev_driver *ev_driver) {
gpr_log(GPR_DEBUG, "Ref ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
gpr_ref(&ev_driver->refs);
return ev_driver;
}
static void grpc_ares_ev_driver_unref(grpc_ares_ev_driver *ev_driver) {
gpr_log(GPR_DEBUG, "Unref ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
if (gpr_unref(&ev_driver->refs)) {
gpr_log(GPR_DEBUG, "destroy ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
GPR_ASSERT(ev_driver->fds == NULL);
gpr_mu_destroy(&ev_driver->mu);
ares_destroy(ev_driver->channel);
gpr_free(ev_driver);
}
}
static void fd_node_destroy(grpc_exec_ctx *exec_ctx, fd_node *fdn) {
gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->grpc_fd));
GPR_ASSERT(!fdn->readable_registered);
GPR_ASSERT(!fdn->writable_registered);
gpr_mu_destroy(&fdn->mu);
grpc_pollset_set_del_fd(exec_ctx, fdn->ev_driver->pollset_set, fdn->grpc_fd);
grpc_fd_shutdown(exec_ctx, fdn->grpc_fd,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("fd node destroyed"));
grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, NULL, "c-ares query finished");
gpr_free(fdn);
}
grpc_error *grpc_ares_ev_driver_create(grpc_ares_ev_driver **ev_driver,
grpc_pollset_set *pollset_set) {
*ev_driver = gpr_malloc(sizeof(grpc_ares_ev_driver));
int status = ares_init(&(*ev_driver)->channel);
gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create");
if (status != ARES_SUCCESS) {
char *err_msg;
gpr_asprintf(&err_msg, "Failed to init ares channel. C-ares error: %s",
ares_strerror(status));
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_msg);
gpr_free(err_msg);
gpr_free(*ev_driver);
return err;
}
gpr_mu_init(&(*ev_driver)->mu);
gpr_ref_init(&(*ev_driver)->refs, 1);
(*ev_driver)->pollset_set = pollset_set;
(*ev_driver)->fds = NULL;
(*ev_driver)->working = false;
(*ev_driver)->shutting_down = false;
return GRPC_ERROR_NONE;
}
void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver) {
// It's not safe to shut down remaining fds here directly, becauses
// ares_host_callback does not provide an exec_ctx. We mark the event driver
// as being shut down. If the event driver is working,
// grpc_ares_notify_on_event_locked will shut down the fds; if it's not
// working, there are no fds to shut down.
gpr_mu_lock(&ev_driver->mu);
ev_driver->shutting_down = true;
gpr_mu_unlock(&ev_driver->mu);
grpc_ares_ev_driver_unref(ev_driver);
}
// Search fd in the fd_node list head. This is an O(n) search, the max possible
// value of n is ARES_GETSOCK_MAXNUM (16). n is typically 1 - 2 in our tests.
static fd_node *pop_fd_node(fd_node **head, int fd) {
fd_node dummy_head;
dummy_head.next = *head;
fd_node *node = &dummy_head;
while (node->next != NULL) {
if (grpc_fd_wrapped_fd(node->next->grpc_fd) == fd) {
fd_node *ret = node->next;
node->next = node->next->next;
*head = dummy_head.next;
return ret;
}
node = node->next;
}
return NULL;
}
static void on_readable_cb(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
fd_node *fdn = arg;
grpc_ares_ev_driver *ev_driver = fdn->ev_driver;
gpr_mu_lock(&fdn->mu);
fdn->readable_registered = false;
gpr_mu_unlock(&fdn->mu);
gpr_log(GPR_DEBUG, "readable on %d", grpc_fd_wrapped_fd(fdn->grpc_fd));
if (error == GRPC_ERROR_NONE) {
ares_process_fd(ev_driver->channel, grpc_fd_wrapped_fd(fdn->grpc_fd),
ARES_SOCKET_BAD);
} else {
// If error is not GRPC_ERROR_NONE, it means the fd has been shutdown or
// timed out. The pending lookups made on this ev_driver will be cancelled
// by the following ares_cancel() and the on_done callbacks will be invoked
// with a status of ARES_ECANCELLED. The remaining file descriptors in this
// ev_driver will be cleaned up in the follwing
// grpc_ares_notify_on_event_locked().
ares_cancel(ev_driver->channel);
}
gpr_mu_lock(&ev_driver->mu);
grpc_ares_notify_on_event_locked(exec_ctx, ev_driver);
gpr_mu_unlock(&ev_driver->mu);
grpc_ares_ev_driver_unref(ev_driver);
}
static void on_writable_cb(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
fd_node *fdn = arg;
grpc_ares_ev_driver *ev_driver = fdn->ev_driver;
gpr_mu_lock(&fdn->mu);
fdn->writable_registered = false;
gpr_mu_unlock(&fdn->mu);
gpr_log(GPR_DEBUG, "writable on %d", grpc_fd_wrapped_fd(fdn->grpc_fd));
if (error == GRPC_ERROR_NONE) {
ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD,
grpc_fd_wrapped_fd(fdn->grpc_fd));
} else {
// If error is not GRPC_ERROR_NONE, it means the fd has been shutdown or
// timed out. The pending lookups made on this ev_driver will be cancelled
// by the following ares_cancel() and the on_done callbacks will be invoked
// with a status of ARES_ECANCELLED. The remaining file descriptors in this
// ev_driver will be cleaned up in the follwing
// grpc_ares_notify_on_event_locked().
ares_cancel(ev_driver->channel);
}
gpr_mu_lock(&ev_driver->mu);
grpc_ares_notify_on_event_locked(exec_ctx, ev_driver);
gpr_mu_unlock(&ev_driver->mu);
grpc_ares_ev_driver_unref(ev_driver);
}
ares_channel *grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver *ev_driver) {
return &ev_driver->channel;
}
// Get the file descriptors used by the ev_driver's ares channel, register
// driver_closure with these filedescriptors.
static void grpc_ares_notify_on_event_locked(grpc_exec_ctx *exec_ctx,
grpc_ares_ev_driver *ev_driver) {
fd_node *new_list = NULL;
if (!ev_driver->shutting_down) {
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
int socks_bitmask =
ares_getsock(ev_driver->channel, socks, ARES_GETSOCK_MAXNUM);
for (size_t i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
if (ARES_GETSOCK_READABLE(socks_bitmask, i) ||
ARES_GETSOCK_WRITABLE(socks_bitmask, i)) {
fd_node *fdn = pop_fd_node(&ev_driver->fds, socks[i]);
// Create a new fd_node if sock[i] is not in the fd_node list.
if (fdn == NULL) {
char *fd_name;
gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
fdn = gpr_malloc(sizeof(fd_node));
gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
fdn->grpc_fd = grpc_fd_create(socks[i], fd_name);
fdn->ev_driver = ev_driver;
fdn->readable_registered = false;
fdn->writable_registered = false;
gpr_mu_init(&fdn->mu);
grpc_closure_init(&fdn->read_closure, on_readable_cb, fdn,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&fdn->write_closure, on_writable_cb, fdn,
grpc_schedule_on_exec_ctx);
grpc_pollset_set_add_fd(exec_ctx, ev_driver->pollset_set,
fdn->grpc_fd);
gpr_free(fd_name);
}
fdn->next = new_list;
new_list = fdn;
gpr_mu_lock(&fdn->mu);
// Register read_closure if the socket is readable and read_closure has
// not been registered with this socket.
if (ARES_GETSOCK_READABLE(socks_bitmask, i) &&
!fdn->readable_registered) {
grpc_ares_ev_driver_ref(ev_driver);
gpr_log(GPR_DEBUG, "notify read on: %d",
grpc_fd_wrapped_fd(fdn->grpc_fd));
grpc_fd_notify_on_read(exec_ctx, fdn->grpc_fd, &fdn->read_closure);
fdn->readable_registered = true;
}
// Register write_closure if the socket is writable and write_closure
// has not been registered with this socket.
if (ARES_GETSOCK_WRITABLE(socks_bitmask, i) &&
!fdn->writable_registered) {
gpr_log(GPR_DEBUG, "notify write on: %d",
grpc_fd_wrapped_fd(fdn->grpc_fd));
grpc_ares_ev_driver_ref(ev_driver);
grpc_fd_notify_on_write(exec_ctx, fdn->grpc_fd, &fdn->write_closure);
fdn->writable_registered = true;
}
gpr_mu_unlock(&fdn->mu);
}
}
}
// Any remaining fds in ev_driver->fds were not returned by ares_getsock() and
// are therefore no longer in use, so they can be shut down and removed from
// the list.
while (ev_driver->fds != NULL) {
fd_node *cur = ev_driver->fds;
ev_driver->fds = ev_driver->fds->next;
fd_node_destroy(exec_ctx, cur);
}
ev_driver->fds = new_list;
// If the ev driver has no working fd, all the tasks are done.
if (new_list == NULL) {
ev_driver->working = false;
gpr_log(GPR_DEBUG, "ev driver stop working");
}
}
void grpc_ares_ev_driver_start(grpc_exec_ctx *exec_ctx,
grpc_ares_ev_driver *ev_driver) {
gpr_mu_lock(&ev_driver->mu);
if (!ev_driver->working) {
ev_driver->working = true;
grpc_ares_notify_on_event_locked(exec_ctx, ev_driver);
}
gpr_mu_unlock(&ev_driver->mu);
}
#endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET) */

@ -0,0 +1,289 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include <string.h>
#include <sys/types.h>
#include <ares.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"
static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
typedef struct grpc_ares_request {
/** following members are set in grpc_resolve_address_ares_impl */
/** host to resolve, parsed from the name to resolve */
char *host;
/** port to fill in sockaddr_in, parsed from the name to resolve */
char *port;
/** default port to use */
char *default_port;
/** closure to call when the request completes */
grpc_closure *on_done;
/** the pointer to receive the resolved addresses */
grpc_resolved_addresses **addrs_out;
/** the evernt driver used by this request */
grpc_ares_ev_driver *ev_driver;
/** number of ongoing queries */
gpr_refcount pending_queries;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** is there at least one successful query, set in on_done_cb */
bool success;
/** the errors explaining the request failure, set in on_done_cb */
grpc_error *error;
} grpc_ares_request;
static void do_basic_init(void) { gpr_mu_init(&g_init_mu); }
static uint16_t strhtons(const char *port) {
if (strcmp(port, "http") == 0) {
return htons(80);
} else if (strcmp(port, "https") == 0) {
return htons(443);
}
return htons((unsigned short)atoi(port));
}
static void grpc_ares_request_unref(grpc_exec_ctx *exec_ctx,
grpc_ares_request *r) {
/* If there are no pending queries, invoke on_done callback and destroy the
request */
if (gpr_unref(&r->pending_queries)) {
/* TODO(zyc): Sort results with RFC6724 before invoking on_done. */
if (exec_ctx == NULL) {
/* A new exec_ctx is created here, as the c-ares interface does not
provide one in ares_host_callback. It's safe to schedule on_done with
the newly created exec_ctx, since the caller has been warned not to
acquire locks in on_done. ares_dns_resolver is using combiner to
protect resources needed by on_done. */
grpc_exec_ctx new_exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_closure_sched(&new_exec_ctx, r->on_done, r->error);
grpc_exec_ctx_finish(&new_exec_ctx);
} else {
grpc_closure_sched(exec_ctx, r->on_done, r->error);
}
gpr_mu_destroy(&r->mu);
grpc_ares_ev_driver_destroy(r->ev_driver);
gpr_free(r->host);
gpr_free(r->port);
gpr_free(r->default_port);
gpr_free(r);
}
}
static void on_done_cb(void *arg, int status, int timeouts,
struct hostent *hostent) {
grpc_ares_request *r = (grpc_ares_request *)arg;
gpr_mu_lock(&r->mu);
if (status == ARES_SUCCESS) {
GRPC_ERROR_UNREF(r->error);
r->error = GRPC_ERROR_NONE;
r->success = true;
grpc_resolved_addresses **addresses = r->addrs_out;
if (*addresses == NULL) {
*addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
(*addresses)->naddrs = 0;
(*addresses)->addrs = NULL;
}
size_t prev_naddr = (*addresses)->naddrs;
size_t i;
for (i = 0; hostent->h_addr_list[i] != NULL; i++) {
}
(*addresses)->naddrs += i;
(*addresses)->addrs =
gpr_realloc((*addresses)->addrs,
sizeof(grpc_resolved_address) * (*addresses)->naddrs);
for (i = prev_naddr; i < (*addresses)->naddrs; i++) {
memset(&(*addresses)->addrs[i], 0, sizeof(grpc_resolved_address));
if (hostent->h_addrtype == AF_INET6) {
(*addresses)->addrs[i].len = sizeof(struct sockaddr_in6);
struct sockaddr_in6 *addr =
(struct sockaddr_in6 *)&(*addresses)->addrs[i].addr;
addr->sin6_family = (sa_family_t)hostent->h_addrtype;
addr->sin6_port = strhtons(r->port);
char output[INET6_ADDRSTRLEN];
memcpy(&addr->sin6_addr, hostent->h_addr_list[i - prev_naddr],
sizeof(struct in6_addr));
ares_inet_ntop(AF_INET6, &addr->sin6_addr, output, INET6_ADDRSTRLEN);
gpr_log(GPR_DEBUG,
"c-ares resolver gets a AF_INET6 result: \n"
" addr: %s\n port: %s\n sin6_scope_id: %d\n",
output, r->port, addr->sin6_scope_id);
} else {
(*addresses)->addrs[i].len = sizeof(struct sockaddr_in);
struct sockaddr_in *addr =
(struct sockaddr_in *)&(*addresses)->addrs[i].addr;
memcpy(&addr->sin_addr, hostent->h_addr_list[i - prev_naddr],
sizeof(struct in_addr));
addr->sin_family = (sa_family_t)hostent->h_addrtype;
addr->sin_port = strhtons(r->port);
char output[INET_ADDRSTRLEN];
ares_inet_ntop(AF_INET, &addr->sin_addr, output, INET_ADDRSTRLEN);
gpr_log(GPR_DEBUG,
"c-ares resolver gets a AF_INET result: \n"
" addr: %s\n port: %s\n",
output, r->port);
}
}
} else if (!r->success) {
char *error_msg;
gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s",
ares_strerror(status));
grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
if (r->error == GRPC_ERROR_NONE) {
r->error = error;
} else {
r->error = grpc_error_add_child(error, r->error);
}
}
gpr_mu_unlock(&r->mu);
grpc_ares_request_unref(NULL, r);
}
void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx, const char *name,
const char *default_port,
grpc_pollset_set *interested_parties,
grpc_closure *on_done,
grpc_resolved_addresses **addrs) {
/* TODO(zyc): Enable tracing after #9603 is checked in */
/* if (grpc_dns_trace) {
gpr_log(GPR_DEBUG, "resolve_address (blocking): name=%s, default_port=%s",
name, default_port);
} */
/* parse name, splitting it into host and port parts */
char *host;
char *port;
gpr_split_host_port(name, &host, &port);
if (host == NULL) {
grpc_error *err = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("unparseable host:port"),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
grpc_closure_sched(exec_ctx, on_done, err);
goto error_cleanup;
} else if (port == NULL) {
if (default_port == NULL) {
grpc_error *err = grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("no port in name"),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
grpc_closure_sched(exec_ctx, on_done, err);
goto error_cleanup;
}
port = gpr_strdup(default_port);
}
grpc_ares_ev_driver *ev_driver;
grpc_error *err = grpc_ares_ev_driver_create(&ev_driver, interested_parties);
if (err != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("grpc_ares_ev_driver_create() failed", err);
goto error_cleanup;
}
grpc_ares_request *r = gpr_malloc(sizeof(grpc_ares_request));
gpr_mu_init(&r->mu);
r->ev_driver = ev_driver;
r->on_done = on_done;
r->addrs_out = addrs;
r->default_port = gpr_strdup(default_port);
r->port = port;
r->host = host;
r->success = false;
r->error = GRPC_ERROR_NONE;
ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
gpr_ref_init(&r->pending_queries, 2);
if (grpc_ipv6_loopback_available()) {
gpr_ref(&r->pending_queries);
ares_gethostbyname(*channel, r->host, AF_INET6, on_done_cb, r);
}
ares_gethostbyname(*channel, r->host, AF_INET, on_done_cb, r);
/* TODO(zyc): Handle CNAME records here. */
grpc_ares_ev_driver_start(exec_ctx, r->ev_driver);
grpc_ares_request_unref(exec_ctx, r);
return;
error_cleanup:
gpr_free(host);
gpr_free(port);
}
void (*grpc_resolve_address_ares)(
grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
grpc_pollset_set *interested_parties, grpc_closure *on_done,
grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl;
grpc_error *grpc_ares_init(void) {
gpr_once_init(&g_basic_init, do_basic_init);
gpr_mu_lock(&g_init_mu);
int status = ares_library_init(ARES_LIB_INIT_ALL);
gpr_mu_unlock(&g_init_mu);
if (status != ARES_SUCCESS) {
char *error_msg;
gpr_asprintf(&error_msg, "ares_library_init failed: %s",
ares_strerror(status));
grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return error;
}
return GRPC_ERROR_NONE;
}
void grpc_ares_cleanup(void) {
gpr_mu_lock(&g_init_mu);
ares_library_cleanup();
gpr_mu_unlock(&g_init_mu);
}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */

@ -0,0 +1,63 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
#define GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/resolve_address.h"
/* Asynchronously resolve addr. Use \a default_port if a port isn't designated
in addr, otherwise use the port in addr. grpc_ares_init() must be called at
least once before this function. \a on_done may be called directly in this
function without being scheduled with \a exec_ctx, it must not try to acquire
locks that are being held by the caller. */
extern void (*grpc_resolve_address_ares)(grpc_exec_ctx *exec_ctx,
const char *addr,
const char *default_port,
grpc_pollset_set *interested_parties,
grpc_closure *on_done,
grpc_resolved_addresses **addresses);
/* Initialize gRPC ares wrapper. Must be called at least once before
grpc_resolve_address_ares(). */
grpc_error *grpc_ares_init(void);
/* Uninitialized gRPC ares wrapper. If there was more than one previous call to
grpc_ares_init(), this function uninitializes the gRPC ares wrapper only if
it has been called the same number of times as grpc_ares_init(). */
void grpc_ares_cleanup(void);
#endif /* GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H */

@ -44,6 +44,7 @@
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/backoff.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1
@ -113,8 +114,9 @@ static void dns_shutdown_locked(grpc_exec_ctx *exec_ctx,
}
if (r->next_completion != NULL) {
*r->target_result = NULL;
grpc_closure_sched(exec_ctx, r->next_completion,
GRPC_ERROR_CREATE("Resolver Shutdown"));
grpc_closure_sched(
exec_ctx, r->next_completion,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver Shutdown"));
r->next_completion = NULL;
}
}
@ -303,7 +305,21 @@ static grpc_resolver_factory *dns_resolver_factory_create() {
}
void grpc_resolver_dns_native_init(void) {
grpc_register_resolver_type(dns_resolver_factory_create());
char *resolver = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver != NULL && gpr_stricmp(resolver, "native") == 0) {
gpr_log(GPR_DEBUG, "Using native dns resolver");
grpc_register_resolver_type(dns_resolver_factory_create());
} else {
grpc_resolver_factory *existing_factory =
grpc_resolver_factory_lookup("dns");
if (existing_factory == NULL) {
gpr_log(GPR_DEBUG, "Using native dns resolver");
grpc_register_resolver_type(dns_resolver_factory_create());
} else {
grpc_resolver_factory_unref(existing_factory);
}
}
gpr_free(resolver);
}
void grpc_resolver_dns_native_shutdown(void) {}

@ -63,8 +63,6 @@ typedef struct {
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
grpc_slice_buffer initial_string_buffer;
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) {
chttp2_connector *c = (chttp2_connector *)con;
if (gpr_unref(&c->refs)) {
/* c->initial_string_buffer does not need to be destroyed */
gpr_mu_destroy(&c->mu);
// If handshaking is not yet in progress, destroy the endpoint.
// 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);
if (error != GRPC_ERROR_NONE || c->shutdown) {
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
// destroy the endpoint here.
// 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.
}
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) {
chttp2_connector *c = arg;
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;
if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown");
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown");
} else {
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);
} else {
GPR_ASSERT(c->endpoint != NULL);
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
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);
}
start_handshake_locked(exec_ctx, c);
gpr_mu_unlock(&c->mu);
}
}

@ -256,7 +256,7 @@ grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
char *msg;
gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs);
gpr_free(msg);
goto error;
} 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
" addresses added out of total %" PRIuPTR " resolved",
count, naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
err = GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, errors, naddrs);
gpr_free(msg);
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));
// Create security context.
if (creds == NULL) {
err = GRPC_ERROR_CREATE(
err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"No credentials specified for secure server port (creds==NULL)");
goto done;
}
@ -72,7 +72,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
gpr_asprintf(&msg,
"Unable to create secure server with credentials of type %s.",
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);
gpr_free(msg);
goto done;

@ -69,10 +69,16 @@
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define DEFAULT_KEEPALIVE_TIME_SECOND INT_MAX
#define DEFAULT_KEEPALIVE_TIMEOUT_SECOND 20
#define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX
#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20
#define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false
static int g_default_client_keepalive_time_s = DEFAULT_CLIENT_KEEPALIVE_TIME_S;
static int g_default_client_keepalive_timeout_s =
DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S;
static bool g_default_keepalive_permit_without_calls =
DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS;
#define MAX_CLIENT_STREAM_ID 0x7fffffffu
int grpc_http_trace = 0;
int grpc_flowctl_trace = 0;
@ -142,6 +148,8 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_ping_type ping_type,
grpc_closure *on_initiate,
grpc_closure *on_complete);
static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error);
#define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0
#define DEFAULT_MAX_PINGS_BETWEEN_DATA 3
@ -187,7 +195,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
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) {
grpc_chttp2_write_cb *next = t->write_cb_pool->next;
@ -266,6 +275,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->destructive_reclaimer_locked,
destructive_reclaimer_locked, t,
grpc_combiner_scheduler(t->combiner, false));
grpc_closure_init(&t->retry_initiate_ping_locked, retry_initiate_ping_locked,
t, grpc_combiner_scheduler(t->combiner, false));
grpc_closure_init(&t->start_bdp_ping_locked, start_bdp_ping_locked, t,
grpc_combiner_scheduler(t->combiner, false));
grpc_closure_init(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
@ -344,15 +355,16 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* client-side keepalive setting */
t->keepalive_time =
DEFAULT_KEEPALIVE_TIME_SECOND == INT_MAX
g_default_client_keepalive_time_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIME_SECOND, GPR_TIMESPAN);
: gpr_time_from_seconds(g_default_client_keepalive_time_s,
GPR_TIMESPAN);
t->keepalive_timeout =
DEFAULT_KEEPALIVE_TIMEOUT_SECOND == INT_MAX
g_default_client_keepalive_timeout_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIMEOUT_SECOND,
: gpr_time_from_seconds(g_default_client_keepalive_timeout_s,
GPR_TIMESPAN);
t->keepalive_permit_without_calls = DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS;
t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls;
if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) {
@ -402,24 +414,25 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->enable_bdp_probe = grpc_channel_arg_get_integer(
&channel_args->args[i], (grpc_integer_options){1, 0, 1});
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_KEEPALIVE_TIME)) {
GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){DEFAULT_KEEPALIVE_TIME_SECOND, 1, INT_MAX});
(grpc_integer_options){g_default_client_keepalive_time_s, 1,
INT_MAX});
t->keepalive_time = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT)) {
GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
const int value = grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){DEFAULT_KEEPALIVE_TIMEOUT_SECOND, 0,
(grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
INT_MAX});
t->keepalive_timeout = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
t->keepalive_permit_without_calls =
(uint32_t)grpc_channel_arg_get_integer(
&channel_args->args[i], (grpc_integer_options){0, 0, 1});
@ -473,6 +486,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
t->ping_state.is_delayed_ping_timer_set = false;
/** Start client-side keepalive pings */
if (t->is_client) {
@ -494,8 +508,9 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp,
t->destroying = 1;
close_transport_locked(
exec_ctx, t,
grpc_error_set_int(GRPC_ERROR_CREATE("Transport destroyed"),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state));
grpc_error_set_int(
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");
}
@ -518,7 +533,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) {
if (t->close_transport_on_writes_finished == NULL) {
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 =
grpc_error_add_child(t->close_transport_on_writes_finished, error);
@ -834,7 +850,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SENT;
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"));
}
}
@ -898,22 +915,19 @@ void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
uint32_t goaway_error,
grpc_slice goaway_text) {
char *msg = grpc_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
grpc_slice_unref_internal(exec_ctx, goaway_text);
// GRPC_CHTTP2_IF_TRACING(
// gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
t->seen_goaway = 1;
/* lie: use transient failure from the transport to indicate goaway has been
* received */
connectivity_state_set(
exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_str(
grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
GRPC_ERROR_INT_HTTP2_ERROR,
(intptr_t)goaway_error),
GRPC_ERROR_STR_RAW_BYTES, msg),
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)goaway_error),
GRPC_ERROR_STR_RAW_BYTES, goaway_text),
"got_goaway");
gpr_free(msg);
}
static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
@ -936,9 +950,10 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
t->next_stream_id += 2;
if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) {
connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_CREATE("Stream IDs exhausted"),
"no_more_stream_ids");
connectivity_state_set(
exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"),
"no_more_stream_ids");
}
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
@ -952,9 +967,9 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) {
grpc_chttp2_cancel_stream(
exec_ctx, t, s,
grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE));
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
}
}
@ -1003,11 +1018,11 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
}
if (error != GRPC_ERROR_NONE) {
if (closure->error_data.error == GRPC_ERROR_NONE) {
closure->error_data.error =
GRPC_ERROR_CREATE("Error in HTTP transport completing operation");
closure->error_data.error =
grpc_error_set_str(closure->error_data.error,
GRPC_ERROR_STR_TARGET_ADDRESS, t->peer_string);
closure->error_data.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Error in HTTP transport completing operation");
closure->error_data.error = grpc_error_set_str(
closure->error_data.error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(t->peer_string));
}
closure->error_data.error =
grpc_error_add_child(closure->error_data.error, error);
@ -1182,10 +1197,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s,
grpc_error_set_int(
grpc_error_set_int(
grpc_error_set_int(
GRPC_ERROR_CREATE("to-be-sent initial metadata size "
"exceeds peer limit"),
GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size),
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"to-be-sent initial metadata size "
"exceeds peer limit"),
GRPC_ERROR_INT_SIZE,
(intptr_t)metadata_size),
GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
} else {
@ -1201,21 +1217,26 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} else {
grpc_chttp2_cancel_stream(
exec_ctx, t, s,
grpc_error_set_int(GRPC_ERROR_CREATE("Transport closed"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE));
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
}
} else {
GPR_ASSERT(s->id != 0);
grpc_chttp2_become_writable(exec_ctx, t, s,
GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED,
grpc_chttp2_stream_write_type write_type =
GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED;
if (op->send_message != NULL &&
(op->send_message->flags & GRPC_WRITE_BUFFER_HINT)) {
write_type = GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK;
}
grpc_chttp2_become_writable(exec_ctx, t, s, write_type,
"op.send_initial_metadata");
}
} else {
s->send_initial_metadata = NULL;
grpc_chttp2_complete_closure_step(
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",
&s->write_closed_error, 1),
"send_initial_metadata_finished");
@ -1229,7 +1250,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (s->write_closed) {
grpc_chttp2_complete_closure_step(
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",
&s->write_closed_error, 1),
"fetching_send_message_finished");
@ -1277,10 +1298,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s,
grpc_error_set_int(
grpc_error_set_int(
grpc_error_set_int(
GRPC_ERROR_CREATE("to-be-sent trailing metadata size "
"exceeds peer limit"),
GRPC_ERROR_INT_SIZE, (intptr_t)metadata_size),
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"to-be-sent trailing metadata size "
"exceeds peer limit"),
GRPC_ERROR_INT_SIZE,
(intptr_t)metadata_size),
GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
} else {
@ -1293,8 +1315,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
exec_ctx, t, s, &s->send_trailing_metadata_finished,
grpc_metadata_batch_is_empty(op->send_trailing_metadata)
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
"stream was closed"),
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Attempt to send trailing metadata after "
"stream was closed"),
"send_trailing_metadata_finished");
} else if (s->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
@ -1389,6 +1412,13 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
}
static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error) {
grpc_chttp2_transport *t = tp;
t->ping_state.is_delayed_ping_timer_set = false;
grpc_chttp2_initiate_write(exec_ctx, t, false, "retry_send_ping");
}
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint64_t id) {
grpc_chttp2_ping_queue *pq =
@ -1409,11 +1439,11 @@ static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
grpc_http2_error_code http_error;
const char *msg;
grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL, &msg,
&http_error);
grpc_slice slice;
grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL,
&slice, &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_ERROR_UNREF(error);
}
@ -1573,7 +1603,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (t->sent_goaway_state == GRPC_CHTTP2_GOAWAY_SENT) {
close_transport_locked(
exec_ctx, t,
GRPC_ERROR_CREATE_REFERENCING(
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Last stream closed after sending GOAWAY", &error, 1));
}
}
@ -1614,8 +1644,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,
grpc_chttp2_stream *s, grpc_error *error) {
grpc_status_code status;
const char *msg;
grpc_error_get_status(error, s->deadline, &status, &msg, NULL);
grpc_slice slice;
grpc_error_get_status(error, s->deadline, &status, &slice, NULL);
if (status != GRPC_STATUS_OK) {
s->seen_error = true;
@ -1636,13 +1666,13 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_GRPC_STATUS,
grpc_slice_from_copied_string(status_string))));
if (msg != NULL) {
if (!GRPC_SLICE_IS_EMPTY(slice)) {
GRPC_LOG_IF_ERROR(
"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_from_copied_string(msg))));
grpc_slice_ref_internal(slice))));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
@ -1671,7 +1701,8 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s,
add_error(extra_error, refs, &nrefs);
grpc_error *error = GRPC_ERROR_NONE;
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);
return error;
@ -1765,12 +1796,13 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error) {
grpc_slice hdr;
grpc_slice status_hdr;
grpc_slice http_status_hdr;
grpc_slice message_pfx;
uint8_t *p;
uint32_t len = 0;
grpc_status_code grpc_status;
const char *msg;
grpc_error_get_status(error, s->deadline, &grpc_status, &msg, NULL);
grpc_slice slice;
grpc_error_get_status(error, s->deadline, &grpc_status, &slice, NULL);
GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
@ -1780,6 +1812,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
the time we got around to sending this, so instead we ignore HPACK
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));
p = GRPC_SLICE_START_PTR(status_hdr);
*p++ = 0x00; /* literal header, not indexed */
@ -1806,32 +1858,30 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
if (msg != NULL) {
size_t msg_len = strlen(msg);
GPR_ASSERT(msg_len <= UINT32_MAX);
uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
message_pfx = grpc_slice_malloc(14 + msg_len_len);
p = GRPC_SLICE_START_PTR(message_pfx);
*p++ = 0x00; /* literal header, not indexed */
*p++ = 12; /* len(grpc-message) */
*p++ = 'g';
*p++ = 'r';
*p++ = 'p';
*p++ = 'c';
*p++ = '-';
*p++ = 'm';
*p++ = 'e';
*p++ = 's';
*p++ = 's';
*p++ = 'a';
*p++ = 'g';
*p++ = 'e';
GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, (uint32_t)msg_len_len);
p += msg_len_len;
GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
len += (uint32_t)msg_len;
}
size_t msg_len = GRPC_SLICE_LENGTH(slice);
GPR_ASSERT(msg_len <= UINT32_MAX);
uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 1);
message_pfx = grpc_slice_malloc(14 + msg_len_len);
p = GRPC_SLICE_START_PTR(message_pfx);
*p++ = 0x00; /* literal header, not indexed */
*p++ = 12; /* len(grpc-message) */
*p++ = 'g';
*p++ = 'r';
*p++ = 'p';
*p++ = 'c';
*p++ = '-';
*p++ = 'm';
*p++ = 'e';
*p++ = 's';
*p++ = 's';
*p++ = 'a';
*p++ = 'g';
*p++ = 'e';
GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 1, 0, p, (uint32_t)msg_len_len);
p += msg_len_len;
GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
len += (uint32_t)msg_len;
hdr = grpc_slice_malloc(9);
p = GRPC_SLICE_START_PTR(hdr);
@ -1847,11 +1897,12 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
grpc_slice_buffer_add(&t->qbuf, hdr);
grpc_slice_buffer_add(&t->qbuf, status_hdr);
if (msg != NULL) {
grpc_slice_buffer_add(&t->qbuf, message_pfx);
grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg));
if (!s->sent_initial_metadata) {
grpc_slice_buffer_add(&t->qbuf, http_status_hdr);
}
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(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
&s->stats.outgoing));
@ -1926,9 +1977,9 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
if (parse_error == GRPC_ERROR_NONE &&
(parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
error = grpc_error_set_int(
grpc_error_set_int(
GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
GRPC_ERROR_INT_HTTP_STATUS, response.status),
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Trying to connect an http1.x server"),
GRPC_ERROR_INT_HTTP_STATUS, response.status),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
}
GRPC_ERROR_UNREF(parse_error);
@ -1949,9 +2000,10 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *err = error;
if (err != GRPC_ERROR_NONE) {
err = grpc_error_set_int(
GRPC_ERROR_CREATE_REFERENCING("Endpoint read failed", &err, 1),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state);
err = grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Endpoint read failed", &err, 1),
GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
t->write_state);
}
GPR_SWAP(grpc_error *, err, error);
GRPC_ERROR_UNREF(err);
@ -1972,8 +2024,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (errors[1] != GRPC_ERROR_NONE) {
errors[2] = try_http_parsing(exec_ctx, t);
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
GPR_ARRAY_SIZE(errors));
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed parsing HTTP/2", errors, GPR_ARRAY_SIZE(errors));
}
for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
GRPC_ERROR_UNREF(errors[i]);
@ -1998,7 +2050,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_BEGIN("post_reading_action_locked", 0);
bool keep_reading = false;
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) {
close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
@ -2076,6 +2128,32 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
}
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) {
size_t i;
if (args) {
for (i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
g_default_client_keepalive_time_s = grpc_channel_arg_get_integer(
&args->args[i], (grpc_integer_options){
g_default_client_keepalive_time_s, 1, INT_MAX});
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
g_default_client_keepalive_timeout_s = grpc_channel_arg_get_integer(
&args->args[i],
(grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
INT_MAX});
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
g_default_keepalive_permit_without_calls =
(uint32_t)grpc_channel_arg_get_integer(
&args->args[i],
(grpc_integer_options){g_default_keepalive_permit_without_calls,
0, 1});
}
}
}
}
static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_chttp2_transport *t = arg;
@ -2119,9 +2197,7 @@ static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_timer_init(
exec_ctx, &t->keepalive_ping_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
grpc_closure_create(init_keepalive_ping_locked, t,
grpc_combiner_scheduler(t->combiner, false)),
gpr_now(GPR_CLOCK_MONOTONIC));
&t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
}
}
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive ping end");
@ -2133,8 +2209,8 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
if (error == GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
close_transport_locked(exec_ctx, t,
GRPC_ERROR_CREATE("keepalive watchdog timeout"));
close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"keepalive watchdog timeout"));
}
} else {
/** The watchdog timer should have been cancelled by
@ -2333,7 +2409,8 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&bs->slice_mu);
if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) {
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 {
bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
if (bs->on_next != NULL) {
@ -2353,7 +2430,7 @@ void grpc_chttp2_incoming_byte_stream_finished(
if (error == GRPC_ERROR_NONE) {
gpr_mu_lock(&bs->slice_mu);
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);
}
@ -2433,9 +2510,9 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
t->peer_string);
}
send_goaway(exec_ctx, t,
grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_ENHANCE_YOUR_CALM));
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
} else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG,
"HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
@ -2462,9 +2539,10 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
s->id);
}
grpc_chttp2_cancel_stream(
exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_ENHANCE_YOUR_CALM));
exec_ctx, t, s,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_ENHANCE_YOUR_CALM));
if (n > 1) {
/* Since we cancel one stream per destructive reclamation, if
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) {
if (parser->parsing_frame != NULL) {
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);
}
@ -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) {
char *msg;
gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
grpc_error *err = grpc_error_set_int(
GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
grpc_error *err =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg),
GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
gpr_free(msg);
return err;
}
@ -173,13 +175,13 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
break;
default:
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,
(intptr_t)s->id);
gpr_free(msg);
msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
p->error =
grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
grpc_slice_from_copied_string(msg));
gpr_free(msg);
p->error =
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,

@ -54,7 +54,7 @@ grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p,
if (length < 8) {
char *msg;
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);
return err;
}
@ -156,7 +156,8 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
}
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,

@ -40,6 +40,8 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
static bool g_disable_ping_ack = false;
grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) {
grpc_slice slice = grpc_slice_malloc(9 + 8);
uint8_t *p = GRPC_SLICE_START_PTR(slice);
@ -71,7 +73,7 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
if (flags & 0xfe || length != 8) {
char *msg;
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);
return error;
}
@ -101,15 +103,21 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
if (p->is_ack) {
grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
} else {
if (t->ping_ack_count == t->ping_ack_capacity) {
t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
t->ping_acks = gpr_realloc(
t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks));
if (!g_disable_ping_ack) {
if (t->ping_ack_count == t->ping_ack_capacity) {
t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
t->ping_acks = gpr_realloc(
t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks));
}
t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes;
grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
}
t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes;
grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
}
}
return GRPC_ERROR_NONE;
}
void grpc_set_disable_ping_ack(bool disable_ping_ack) {
g_disable_ping_ack = disable_ping_ack;
}

@ -53,4 +53,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_stream *s,
grpc_slice slice, int is_last);
/* Test-only function for disabling ping ack */
void grpc_set_disable_ping_ack(bool disable_ping_ack);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */

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

@ -131,13 +131,16 @@ grpc_error *grpc_chttp2_settings_parser_begin_frame(
if (flags == GRPC_CHTTP2_FLAG_ACK) {
parser->is_ack = 1;
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;
} 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) {
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 {
return GRPC_ERROR_NONE;
}
@ -229,7 +232,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
&t->qbuf);
gpr_asprintf(&msg, "invalid value %u passed for %s",
parser->value, sp->name);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}

@ -70,7 +70,7 @@ grpc_error *grpc_chttp2_window_update_parser_begin_frame(
char *msg;
gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length,
flags);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
@ -102,7 +102,7 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
if (received_update == 0 || (received_update & 0x80000000u)) {
char *msg;
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);
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) {
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);
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);
if (GRPC_MDISNULL(md)) {
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_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) {
return parse_error(
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"));
}
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) {
return parse_error(
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"));
}
p->dynamic_table_update_allowed--;
@ -1126,7 +1127,7 @@ static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(cur != end);
char *msg;
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);
return parse_error(exec_ctx, p, cur, end, err);
}
@ -1246,7 +1247,7 @@ error:
"integer overflow in hpack integer decoding: have 0x%08x, "
"got byte 0x%02x on byte 5",
*p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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, "
"got byte 0x%02x sometime after byte 5",
*p->parsing.value, *cur);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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];
++cur;
if (bits == 255)
return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character"));
return parse_error(
exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64)
goto b64_byte0;
p->base64_buffer = bits << 18;
@ -1348,8 +1350,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character"));
return parse_error(
exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64)
goto b64_byte1;
p->base64_buffer |= bits << 12;
@ -1363,8 +1366,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character"));
return parse_error(
exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64)
goto b64_byte2;
p->base64_buffer |= bits << 6;
@ -1378,8 +1382,9 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("Illegal base64 character"));
return parse_error(
exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal base64 character"));
else if (bits == 64)
goto b64_byte3;
p->base64_buffer |= bits;
@ -1391,7 +1396,8 @@ static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
goto b64_byte0;
}
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,
@ -1406,16 +1412,16 @@ static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
case B64_BYTE0:
break;
case B64_BYTE1:
return parse_error(
exec_ctx, p, cur, end,
GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */
return parse_error(exec_ctx, p, cur, end,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"illegal base64 encoding")); /* illegal encoding */
case B64_BYTE2:
bits = p->base64_buffer;
if (bits & 0xffff) {
char *msg;
gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x",
bits & 0xffff);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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;
gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x",
bits & 0xff);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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);
if (GRPC_MDISNULL(elem)) {
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_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_chttp2_hpack_parser *p,
grpc_slice slice) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple
steps in the event of a large chunk of data to limit
stack space usage when no tail call optimization is
available */
/* max number of bytes to parse at a time... limits call stack depth on
* compilers without TCO */
#define MAX_PARSE_LENGTH 1024
p->current_slice_refcount = slice.refcount;
grpc_error *error = p->state(exec_ctx, p, GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_END_PTR(slice));
uint8_t *start = GRPC_SLICE_START_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;
return error;
}
@ -1670,7 +1682,7 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
if (is_last) {
if (parser->is_boundary && parser->state != parse_begin) {
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");
}
/* 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 (parser->is_boundary) {
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] =
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,
"Attempt to make hpack table %d bytes when max is %d 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);
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 "
"stream (still at %d)",
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);
return err;
}

@ -102,6 +102,8 @@ typedef struct {
typedef struct {
gpr_timespec last_ping_sent_time;
int pings_before_data_required;
grpc_timer delayed_ping_timer;
bool is_delayed_ping_timer_set;
} grpc_chttp2_repeated_ping_state;
/* deframer state for the overall http2 stream of bytes */
@ -308,6 +310,7 @@ struct grpc_chttp2_transport {
grpc_chttp2_repeated_ping_policy ping_policy;
grpc_chttp2_repeated_ping_state ping_state;
uint64_t ping_ctr; /* unique id for pings */
grpc_closure retry_initiate_ping_locked;
/** ping acks */
size_t ping_ack_count;
@ -827,4 +830,8 @@ void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
uint32_t grpc_chttp2_target_incoming_window(grpc_chttp2_transport *t);
/** Set the default keepalive configurations, must only be called at
initialization */
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -116,7 +116,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
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);
err = GRPC_ERROR_CREATE(msg);
err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
@ -219,7 +219,7 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
t->incoming_frame_size,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]);
err = GRPC_ERROR_CREATE(msg);
err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
@ -278,7 +278,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
gpr_asprintf(
&msg, "Expected SETTINGS frame as the first frame, got frame type %d",
t->incoming_frame_type);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
@ -288,7 +288,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
char *msg;
gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
t->incoming_frame_type);
grpc_error *err = GRPC_ERROR_CREATE(msg);
grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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 "
"grpc_chttp2_stream %08x",
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);
return err;
}
@ -311,7 +311,8 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_HEADER:
return init_header_frame_parser(exec_ctx, t, 0);
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:
return init_rst_stream_parser(exec_ctx, t);
case GRPC_CHTTP2_FRAME_SETTINGS:
@ -371,7 +372,7 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
char *msg;
gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
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);
return err;
}
@ -409,7 +410,7 @@ static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
s->incoming_window_delta +
t->settings[GRPC_ACKED_SETTINGS]
[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);
return err;
}
@ -542,7 +543,8 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_chttp2_cancel_stream(
exec_ctx, t, s,
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_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true;
@ -598,9 +600,10 @@ static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
exec_ctx, t, s,
grpc_error_set_int(
GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
s->seen_error = true;
GRPC_MDELEM_UNREF(exec_ctx, md);
@ -771,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,
grpc_chttp2_transport *t) {
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(

@ -101,6 +101,14 @@ static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx,
"Ping delayed [%p]: not enough time elapsed since last ping",
t->peer_string);
}
if (!t->ping_state.is_delayed_ping_timer_set) {
t->ping_state.is_delayed_ping_timer_set = true;
grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer,
gpr_time_add(t->ping_state.last_ping_sent_time,
t->ping_policy.min_time_between_pings),
&t->retry_initiate_ping_locked,
gpr_now(GPR_CLOCK_MONOTONIC));
}
return;
}
/* coalesce equivalent pings into this one */

@ -128,6 +128,7 @@ struct read_state {
int received_bytes;
int remaining_bytes;
int length_field;
bool compressed;
char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES];
char *payload_field;
bool read_stream_closed;
@ -289,7 +290,7 @@ static void maybe_flush_read(stream_obj *s) {
}
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);
return error;
}
@ -484,6 +485,16 @@ static void on_response_headers_received(
CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
headers, negotiated_protocol);
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);
memset(&s->state.rs.initial_metadata, 0,
sizeof(s->state.rs.initial_metadata));
@ -507,6 +518,7 @@ static void on_response_headers_received(
is closed */
GPR_ASSERT(s->state.rs.length_field_received == false);
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.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
@ -641,7 +653,7 @@ static void on_response_trailers_received(
*/
static void create_grpc_frame(grpc_slice_buffer *write_slice_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);
size_t length = GRPC_SLICE_LENGTH(slice);
*p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
@ -650,7 +662,9 @@ static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer,
*pp_write_buffer = write_buffer;
uint8_t *p = (uint8_t *)write_buffer;
/* 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 >> 16);
*p++ = (uint8_t)(length >> 8);
@ -728,14 +742,16 @@ static void convert_metadata_to_cronet_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;
int length = 0;
length |= ((uint8_t)*p++) << 24;
length |= ((uint8_t)*p++) << 16;
length |= ((uint8_t)*p++) << 8;
length |= ((uint8_t)*p++);
return length;
*compressed = ((c & 0x01) == 0x01);
*length = 0;
*length |= ((uint8_t)*p++) << 24;
*length |= ((uint8_t)*p++) << 16;
*length |= ((uint8_t)*p++) << 8;
*length |= ((uint8_t)*p++);
}
static bool header_has_authority(grpc_linked_mdelem *head) {
@ -788,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])
result = false;
/* 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;
} else if (op_id == OP_SEND_MESSAGE) {
/* already executed (note we're checking op specific state, not stream
@ -801,7 +818,8 @@ static bool op_can_be_run(grpc_transport_stream_op *curr_op,
/* already executed */
if (op_state->state_op_done[OP_RECV_MESSAGE]) result = false;
/* 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;
} else if (op_id == OP_RECV_TRAILING_METADATA) {
/* already executed */
@ -955,12 +973,6 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_init(&write_slice_buffer);
grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
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);
if (write_slice_buffer.count != 1) {
/* Empty request not handled yet */
@ -970,7 +982,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
if (write_slice_buffer.count > 0) {
size_t write_buffer_size;
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,
stream_state->ws.write_buffer);
stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
@ -1022,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]) {
grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
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 {
grpc_chttp2_incoming_metadata_buffer_publish(
exec_ctx, &oas->s->state.rs.initial_metadata,
@ -1066,8 +1081,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.remaining_bytes == 0) {
/* Start a read operation for data */
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",
stream_state->rs.length_field);
if (stream_state->rs.length_field > 0) {
@ -1089,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_stream_init(&stream_state->rs.sbs,
&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_state->rs.sbs;
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
@ -1100,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.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0;
stream_state->rs.compressed = false;
stream_state->rs.length_field_received = false;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
@ -1114,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.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0;
stream_state->rs.compressed = false;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */
@ -1137,6 +1158,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
read_data_slice);
grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
&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_state->rs.sbs;
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
@ -1146,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
is closed */
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.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.length_field_received = false;

@ -90,7 +90,8 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
&args->call_stack->refcount, args->server_transport_data, args->arena);
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,

@ -55,9 +55,9 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg,
if (error != GRPC_ERROR_CANCELLED) {
grpc_call_element_signal_error(
exec_ctx, elem,
grpc_error_set_int(GRPC_ERROR_CREATE("Deadline Exceeded"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_DEADLINE_EXCEEDED));
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_DEADLINE_EXCEEDED));
}
GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer");
}

@ -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) {
grpc_handshake_manager* mgr = arg;
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
grpc_handshake_manager_shutdown(exec_ctx, mgr,
GRPC_ERROR_CREATE("Handshake timed out"));
grpc_handshake_manager_shutdown(
exec_ctx, mgr,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out"));
}
grpc_handshake_manager_unref(exec_ctx, mgr);
}

@ -36,6 +36,7 @@
#include <grpc/support/string_util.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/security/util/b64.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@ -56,7 +57,6 @@ typedef struct call_data {
grpc_linked_mdelem te_trailers;
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
grpc_linked_mdelem payload_bin;
grpc_metadata_batch *recv_initial_metadata;
grpc_metadata_batch *recv_trailing_metadata;
@ -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_set_int(
grpc_error_set_str(
GRPC_ERROR_CREATE(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"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_STR_GRPC_MESSAGE, msg);
GRPC_ERROR_STR_GRPC_MESSAGE, grpc_slice_from_copied_string(msg));
gpr_free(val);
gpr_free(msg);
return e;
@ -292,19 +292,58 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
continue_send_message(exec_ctx, elem);
if (calld->send_message_blocked == false) {
/* when all the send_message data is available, then create a MDELEM and
append to headers */
grpc_mdelem payload_bin = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_GRPC_PAYLOAD_BIN,
grpc_slice_from_copied_buffer((const char *)calld->payload_bytes,
op->send_message->length));
error =
grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
&calld->payload_bin, payload_bin);
/* when all the send_message data is available, then modify the path
* MDELEM by appending base64 encoded query to the path */
const int k_url_safe = 1;
const int k_multi_line = 0;
const unsigned char k_query_separator = '?';
grpc_slice path_slice =
GRPC_MDVALUE(op->send_initial_metadata->idx.named.path->md);
/* sum up individual component's lengths and allocate enough memory to
* hold combined path+query */
size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
estimated_len++; /* for the '?' */
estimated_len += grpc_base64_estimate_encoded_size(
op->send_message->length, k_url_safe, k_multi_line);
estimated_len += 1; /* for the trailing 0 */
grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len);
/* memcopy individual pieces into this slice */
uint8_t *write_ptr =
(uint8_t *)GRPC_SLICE_START_PTR(path_with_query_slice);
uint8_t *original_path = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
write_ptr += GRPC_SLICE_LENGTH(path_slice);
*write_ptr = k_query_separator;
write_ptr++; /* for the '?' */
grpc_base64_encode_core((char *)write_ptr, calld->payload_bytes,
op->send_message->length, k_url_safe,
k_multi_line);
/* remove trailing unused memory and add trailing 0 to terminate string
*/
char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
/* safe to use strlen since base64_encode will always add '\0' */
size_t path_length = strlen(t) + 1;
*(t + path_length) = '\0';
path_with_query_slice =
grpc_slice_sub(path_with_query_slice, 0, path_length);
/* substitute previous path with the new path+query */
grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
grpc_metadata_batch *b = op->send_initial_metadata;
error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_and_query);
if (error != GRPC_ERROR_NONE) return error;
calld->on_complete = op->on_complete;
op->on_complete = &calld->hc_on_complete;
op->send_message = NULL;
grpc_slice_unref_internal(exec_ctx, path_with_query_slice);
} else {
/* Not all data is available. Fall back to POST. */
gpr_log(GPR_DEBUG,

@ -37,6 +37,7 @@
#include <grpc/support/log.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/security/util/b64.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@ -51,8 +52,8 @@ typedef struct call_data {
grpc_linked_mdelem status;
grpc_linked_mdelem content_type;
/* did this request come with payload-bin */
bool seen_payload_bin;
/* did this request come with path query containing request payload */
bool seen_path_with_query;
/* flag to ensure payload_bin is delivered only once */
bool payload_bin_delivered;
@ -61,7 +62,7 @@ typedef struct call_data {
bool *recv_cacheable_request;
/** Closure to call when finished with the hs_on_recv hook */
grpc_closure *on_done_recv;
/** Closure to call when we retrieve read message from the payload-bin header
/** Closure to call when we retrieve read message from the path URI
*/
grpc_closure *recv_message_ready;
grpc_closure *on_complete;
@ -101,7 +102,7 @@ static void add_error(const char *error_name, grpc_error **cumulative,
grpc_error *new) {
if (new == GRPC_ERROR_NONE) return;
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);
}
@ -125,27 +126,32 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
*calld->recv_cacheable_request = true;
} else {
add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
b->idx.named.method->md));
grpc_attach_md_to_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.method->md));
}
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.method);
} else {
add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
GRPC_ERROR_STR_KEY, ":method"));
add_error(
error_name, &error,
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 (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) {
add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
b->idx.named.te->md));
grpc_attach_md_to_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.te->md));
}
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.te);
} else {
add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
GRPC_ERROR_STR_KEY, "te"));
grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string("te")));
}
if (b->idx.named.scheme != NULL) {
@ -153,14 +159,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_GRPC)) {
add_error(error_name, &error,
grpc_attach_md_to_error(GRPC_ERROR_CREATE("Bad header"),
b->idx.named.scheme->md));
grpc_attach_md_to_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
b->idx.named.scheme->md));
}
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.scheme);
} else {
add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
GRPC_ERROR_STR_KEY, ":scheme"));
add_error(
error_name, &error,
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) {
@ -194,8 +203,46 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
if (b->idx.named.path == NULL) {
add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
GRPC_ERROR_STR_KEY, ":path"));
grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path")));
} else if (*calld->recv_cacheable_request == true) {
/* We have a cacheable request made with GET verb. The path contains the
* query parameter which is base64 encoded request payload. */
const char k_query_separator = '?';
grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md);
uint8_t *path_ptr = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
size_t path_length = GRPC_SLICE_LENGTH(path_slice);
/* offset of the character '?' */
size_t offset = 0;
for (offset = 0; *path_ptr != k_query_separator && offset < path_length;
path_ptr++, offset++)
;
if (offset < path_length) {
grpc_slice query_slice =
grpc_slice_sub(path_slice, offset + 1, path_length);
/* substitute path metadata with just the path (not query) */
grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_PATH, grpc_slice_sub(path_slice, 0, offset));
grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_without_query);
/* decode payload from query and add to the slice buffer to be returned */
const int k_url_safe = 1;
grpc_slice_buffer_add(
&calld->read_slice_buffer,
grpc_base64_decode(exec_ctx,
(const char *)GRPC_SLICE_START_PTR(query_slice),
k_url_safe));
grpc_slice_buffer_stream_init(&calld->read_stream,
&calld->read_slice_buffer, 0);
calld->seen_path_with_query = true;
grpc_slice_unref_internal(exec_ctx, query_slice);
} else {
gpr_log(GPR_ERROR, "GET request without QUERY");
}
}
if (b->idx.named.host != NULL && b->idx.named.authority == NULL) {
@ -212,19 +259,11 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
}
if (b->idx.named.authority == NULL) {
add_error(error_name, &error,
grpc_error_set_str(GRPC_ERROR_CREATE("Missing header"),
GRPC_ERROR_STR_KEY, ":authority"));
}
if (b->idx.named.grpc_payload_bin != NULL) {
calld->seen_payload_bin = true;
grpc_slice_buffer_add(&calld->read_slice_buffer,
grpc_slice_ref_internal(
GRPC_MDVALUE(b->idx.named.grpc_payload_bin->md)));
grpc_slice_buffer_stream_init(&calld->read_stream,
&calld->read_slice_buffer, 0);
grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_payload_bin);
add_error(
error_name, &error,
grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority")));
}
return error;
@ -247,8 +286,8 @@ static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
/* Call recv_message_ready if we got the payload via the header field */
if (calld->seen_payload_bin && calld->recv_message_ready != NULL) {
/* Call recv_message_ready if we got the payload via the path field */
if (calld->seen_path_with_query && calld->recv_message_ready != NULL) {
*calld->pp_recv_message = calld->payload_bin_delivered
? NULL
: (grpc_byte_stream *)&calld->read_stream;
@ -263,7 +302,7 @@ static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
if (calld->seen_payload_bin) {
if (calld->seen_path_with_query) {
/* do nothing. This is probably a GET request, and payload will be returned
in hs_on_complete callback. */
} else {

@ -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)",
(*calld->recv_message)->length, calld->max_recv_size);
grpc_error* new_error = grpc_error_set_int(
GRPC_ERROR_CREATE(message_string), GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_INVALID_ARGUMENT);
GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INVALID_ARGUMENT);
if (error == GRPC_ERROR_NONE) {
error = new_error;
} 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)",
op->send_message->length, calld->max_send_size);
grpc_transport_stream_op_finish_with_failure(
exec_ctx, op, grpc_error_set_int(GRPC_ERROR_CREATE(message_string),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_INVALID_ARGUMENT));
exec_ctx, op,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_INVALID_ARGUMENT));
gpr_free(message_string);
return;
}

@ -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) {
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];
char *addr_text = grpc_sockaddr_to_uri(addr);
req->overall_error = grpc_error_add_child(
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);
}
@ -190,8 +192,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
internal_request *req = arg;
if (!ep) {
next_address(exec_ctx, req,
GRPC_ERROR_CREATE("Unexplained handshake failure"));
next_address(exec_ctx, req, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Unexplained handshake failure"));
return;
}
@ -221,8 +223,8 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
}
if (req->next_address == req->addresses->naddrs) {
finish(exec_ctx, req,
GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets",
&req->overall_error, 1));
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed HTTP requests to all targets", &req->overall_error, 1));
return;
}
addr = &req->addresses->addrs[req->next_address++];

@ -95,7 +95,7 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
char *msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
c->secure_peer_name);
error = GRPC_ERROR_CREATE(msg);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
}
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 *end = beg + parser->cur_line_length;
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
if (cur == end || *cur++ != 'H')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
if (cur == end || *cur++ != 'T')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
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 '/'");
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') {
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')
return GRPC_ERROR_CREATE("Expected status code");
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
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')
return GRPC_ERROR_CREATE("Expected status code");
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
parser->http.response->status =
(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 */
@ -89,24 +99,33 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) {
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));
beg = 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));
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
if (cur == end || *cur++ != 'H')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
if (cur == end || *cur++ != 'T')
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
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);
++cur;
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);
if (vers_major == 1) {
@ -115,18 +134,19 @@ static grpc_error *handle_request_line(grpc_http_parser *parser) {
} else if (vers_minor == 1) {
parser->http.request->version = GRPC_HTTP_HTTP11;
} 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");
}
} else if (vers_major == 2) {
if (vers_minor == 0) {
parser->http.request->version = GRPC_HTTP_HTTP20;
} 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");
}
} 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;
@ -139,7 +159,8 @@ static grpc_error *handle_first_line(grpc_http_parser *parser) {
case GRPC_HTTP_RESPONSE:
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) {
@ -154,7 +175,8 @@ static grpc_error *add_header(grpc_http_parser *parser) {
GPR_ASSERT(cur != end);
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;
}
@ -162,7 +184,8 @@ static grpc_error *add_header(grpc_http_parser *parser) {
cur++;
}
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;
}
GPR_ASSERT(cur >= beg);
@ -222,7 +245,8 @@ static grpc_error *finish_line(grpc_http_parser *parser,
}
break;
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;
@ -240,7 +264,8 @@ static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
body_length = &parser->http.request->body_length;
body = &parser->http.request->body;
} 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) {
@ -286,7 +311,8 @@ static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte,
if (grpc_http1_trace)
gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
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_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) {
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;
}

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

@ -33,6 +33,7 @@
#include "src/core/lib/iomgr/combiner.h"
#include <assert.h>
#include <string.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,
cl, covered_by_poller, last));
GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed
assert(cl->cb);
cl->error_data.scratch =
pack_error_data((error_data){error, covered_by_poller});
if (covered_by_poller) {

@ -35,7 +35,6 @@
#include <string.h>
#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/alloc.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
#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,
size_t num_referencing) {
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);
internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
internal_set_str(&err, GRPC_ERROR_STR_FILE,
grpc_slice_from_static_string(file));
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.
internal_set_str(&err, GRPC_ERROR_STR_FILE, file);
internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc);
for (size_t i = 0; i < num_referencing; ++i) {
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);
grpc_error *out;
if (grpc_error_is_special(in)) {
out = GRPC_ERROR_CREATE("unknown");
out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
if (in == GRPC_ERROR_NONE) {
internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
grpc_slice_from_static_string("no error"));
@ -417,7 +410,7 @@ typedef struct {
const char *msg;
} special_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_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,
const char *value) {
grpc_slice str) {
GPR_TIMER_BEGIN("grpc_error_set_str", 0);
grpc_error *new = copy_error_and_unref(src);
internal_set_str(&new, which,
grpc_slice_from_copied_buffer(
value, strlen(value) + 1)); // TODO, pull this up.
internal_set_str(&new, which, str);
GPR_TIMER_END("grpc_error_set_str", 0);
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 (which == GRPC_ERROR_STR_GRPC_MESSAGE) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
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];
if (slot != UINT8_MAX) {
return (const char *)GRPC_SLICE_START_PTR(
*(grpc_slice *)(err->arena + slot));
*str = *(grpc_slice *)(err->arena + slot);
return true;
} 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";
append_chr('"', s, sz, cap);
for (const uint8_t *c = (const uint8_t *)str; *c; c++) {
if (*c < 32 || *c >= 127) {
for (size_t i = 0; i < len; i++, str++) {
if (*str < 32 || *str >= 127) {
append_chr('\\', s, sz, cap);
switch (*c) {
switch (*str) {
case '\b':
append_chr('b', s, sz, cap);
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('0', s, sz, cap);
append_chr('0', s, sz, cap);
append_chr(hex[*c >> 4], s, sz, cap);
append_chr(hex[*c & 0x0f], s, sz, cap);
append_chr(hex[*str >> 4], s, sz, cap);
append_chr(hex[*str & 0x0f], s, sz, cap);
break;
}
} else {
append_chr((char)*c, s, sz, cap);
append_chr((char)*str, 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));
}
static char *fmt_str(void *p) {
static char *fmt_str(grpc_slice slice) {
char *s = NULL;
size_t sz = 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);
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) {
uint8_t slot = err->strs[which];
if (slot != UINT8_MAX) {
append_kv(
kvs, key_str((grpc_error_strs)which),
fmt_str(GRPC_SLICE_START_PTR(*(grpc_slice *)(err->arena + slot))));
append_kv(kvs, key_str((grpc_error_strs)which),
fmt_str(*(grpc_slice *)(err->arena + slot)));
}
}
}
@ -681,7 +675,8 @@ static char *finish_kvs(kv_pairs *kvs) {
append_chr('{', &s, &sz, &cap);
for (size_t i = 0; i < kvs->num_kvs; i++) {
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);
append_chr(':', &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) {
return grpc_error_set_str(
grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
GRPC_ERROR_INT_ERRNO, err),
GRPC_ERROR_STR_OS_ERROR, strerror(err)),
GRPC_ERROR_STR_SYSCALL, call_name);
grpc_error_set_int(
grpc_error_create(grpc_slice_from_static_string(file), line,
grpc_slice_from_static_string("OS Error"), NULL,
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
@ -745,10 +744,13 @@ grpc_error *grpc_wsa_error(const char *file, int line, int err,
char *utf8_message = gpr_format_message(err);
grpc_error *error = grpc_error_set_str(
grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
GRPC_ERROR_INT_WSA_ERROR, err),
GRPC_ERROR_STR_OS_ERROR, utf8_message),
GRPC_ERROR_STR_SYSCALL, call_name);
grpc_error_set_int(
grpc_error_create(grpc_slice_from_static_string(file), line,
grpc_slice_from_static_string("OS Error"), NULL,
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);
return error;
}

@ -37,6 +37,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/time.h>
@ -45,28 +46,9 @@ extern "C" {
#endif
/// Opaque representation of an error.
/// Errors are refcounted objects that represent the result of an operation.
/// Ownership laws:
/// 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
/// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
/// full write up of this object.
typedef struct grpc_error grpc_error;
typedef enum {
@ -156,7 +138,7 @@ typedef enum {
const char *grpc_error_string(grpc_error *error);
/// 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);
/// 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
@ -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, NULL, 0);
/// for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]);
#define GRPC_ERROR_CREATE(desc) \
grpc_error_create(__FILE__, __LINE__, desc, NULL, 0)
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc) \
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
// reference to each error in errs - it does not consume an existing reference
#define GRPC_ERROR_CREATE_REFERENCING(desc, errs, count) \
grpc_error_create(__FILE__, __LINE__, desc, errs, count)
#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(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
#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;
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,
const char *value) GRPC_MUST_USE_RESULT;
/// Returns NULL if the specified string is not set.
/// Caller does NOT own return value.
const char *grpc_error_get_str(grpc_error *error, grpc_error_strs which);
grpc_slice str) GRPC_MUST_USE_RESULT;
/// Returns false if the specified string is not set.
/// Caller does NOT own the slice.
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
/// 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) {
if (error == GRPC_ERROR_NONE) return true;
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);
return false;
@ -1110,7 +1110,13 @@ static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
gpr_atm curr = gpr_atm_no_barrier_load(state);
switch (curr) {
case CLOSURE_NOT_READY: {
/* CLOSURE_NOT_READY -> <closure>. */
/* CLOSURE_NOT_READY -> <closure>.
We're guaranteed by API that there's an acquire barrier before here,
so there's no need to double-dip and this can be a release-only.
The release itself pairs with the acquire half of a set_ready full
barrier. */
if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) {
return; /* Successful. Return */
}
@ -1141,9 +1147,9 @@ static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
schedule the closure with the shutdown error */
if ((curr & FD_SHUTDOWN_BIT) > 0) {
grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT);
grpc_closure_sched(
exec_ctx, closure,
GRPC_ERROR_CREATE_REFERENCING("FD Shutdown", &shutdown_err, 1));
grpc_closure_sched(exec_ctx, closure,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"FD Shutdown", &shutdown_err, 1));
return;
}
@ -1169,7 +1175,9 @@ static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
switch (curr) {
case CLOSURE_READY:
case CLOSURE_NOT_READY:
if (gpr_atm_full_cas(state, curr, new_state)) {
/* Release cas to pair with a set_ready performing a load of the
shutdown state later */
if (gpr_atm_rel_cas(state, curr, new_state)) {
return; /* early out */
}
break; /* retry */
@ -1183,11 +1191,14 @@ static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
}
/* Fd is not shutdown. Schedule the closure and move the state to
shutdown state. */
shutdown state.
Needs an acquire to pair with setting the closure (and get a
happens-after on that edge), and a release to pair with anything
loading the shutdown state. */
if (gpr_atm_full_cas(state, curr, new_state)) {
grpc_closure_sched(
exec_ctx, (grpc_closure *)curr,
GRPC_ERROR_CREATE_REFERENCING("FD Shutdown", &shutdown_err, 1));
grpc_closure_sched(exec_ctx, (grpc_closure *)curr,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"FD Shutdown", &shutdown_err, 1));
return;
}
@ -1212,6 +1223,8 @@ static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state) {
}
case CLOSURE_NOT_READY: {
/* No barrier required as we're transitioning to a state that does not
involve a closure */
if (gpr_atm_no_barrier_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) {
return; /* early out */
}
@ -1223,7 +1236,11 @@ static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state) {
if ((curr & FD_SHUTDOWN_BIT) > 0) {
/* The fd is shutdown. Do nothing */
return;
} else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) {
}
/* Full cas: acquire pairs with this cas' release in the event of a
spurious set_ready; release pairs with this or the acquire in
notify_on (or set_shutdown) */
else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) {
grpc_closure_sched(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE);
return;
}

@ -451,14 +451,16 @@ static grpc_error *fd_shutdown_error(grpc_fd *fd) {
if (!fd->shutdown) {
return GRPC_ERROR_NONE;
} 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,
grpc_closure **st, grpc_closure *closure) {
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) {
/* not ready ==> switch to a waiting state by setting the 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) {
if (error == GRPC_ERROR_NONE) return;
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);
}
@ -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) {
if (error == GRPC_ERROR_NONE) return;
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);
}
@ -1421,7 +1423,7 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
g_cvfds.pollcount++;
opt = gpr_thd_options_default();
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
gpr_cv_wait(pollcv, &g_cvfds.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
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.
* Spawn time! */
g_executor.busy = 1;
gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
&g_executor.options);
GPR_ASSERT(gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
&g_executor.options));
g_executor.pending_join = 1;
}

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

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

Loading…
Cancel
Save