Переглянути джерело

Merge remote-tracking branch 'upstream/master' into trailing_metadata_status

kpayson64 7 роки тому
батько
коміт
3c37b728a9
100 змінених файлів з 3901 додано та 964 видалено
  1. 2 2
      .clang-tidy
  2. 42 6
      BUILD
  3. 41 69
      BUILDING.md
  4. 119 51
      CMakeLists.txt
  5. 63 0
      CONCEPTS.md
  6. 26 5
      CONTRIBUTING.md
  7. 5 6
      Makefile
  8. 44 76
      README.md
  9. 4 22
      bazel/grpc_build_system.bzl
  10. 53 6
      bazel/grpc_deps.bzl
  11. 43 32
      build.yaml
  12. 15 0
      cmake/nanopb.cmake
  13. 7 4
      config.m4
  14. 10 4
      config.w32
  15. 1 1
      doc/PROTOCOL-WEB.md
  16. 1 1
      doc/command_line_tool.md
  17. 2 1
      doc/g_stands_for.md
  18. 1 1
      examples/cpp/README.md
  19. 2 2
      examples/cpp/cpptutorial.md
  20. 2 2
      examples/cpp/helloworld/README.md
  21. 6 0
      examples/cpp/route_guide/README.md
  22. 6 3
      examples/python/helloworld/greeter_client.py
  23. 8 4
      examples/python/interceptors/default_value/greeter_client.py
  24. 8 4
      examples/python/interceptors/headers/greeter_client.py
  25. 17 14
      examples/python/multiplex/multiplex_client.py
  26. 13 10
      examples/python/route_guide/route_guide_client.py
  27. 8 6
      gRPC-C++.podspec
  28. 9 3
      gRPC-Core.podspec
  29. 1 1
      gRPC-ProtoRPC.podspec
  30. 1 1
      gRPC-RxLibrary.podspec
  31. 1 1
      gRPC.podspec
  32. 0 2
      grpc.def
  33. 4 1
      grpc.gemspec
  34. 17 12
      grpc.gyp
  35. 0 8
      include/grpc/grpc.h
  36. 29 2
      include/grpc/grpc_security.h
  37. 4 0
      include/grpc/impl/codegen/grpc_types.h
  38. 2 2
      include/grpcpp/impl/codegen/call.h
  39. 41 0
      include/grpcpp/opencensus.h
  40. 2 2
      include/grpcpp/server_builder.h
  41. 6 3
      package.xml
  42. 2 1
      setup.py
  43. 72 57
      src/core/ext/filters/client_channel/client_channel.cc
  44. 9 5
      src/core/ext/filters/client_channel/http_proxy.cc
  45. 2 2
      src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
  46. 1 1
      src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
  47. 2 2
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  48. 311 0
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
  49. 44 6
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
  50. 38 289
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
  51. 88 67
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  52. 2 2
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
  53. 6 5
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
  54. 1 1
      src/core/ext/filters/http/server/http_server_filter.h
  55. 21 16
      src/core/ext/transport/chttp2/transport/writing.cc
  56. 23 26
      src/core/lib/channel/channel_trace.cc
  57. 13 17
      src/core/lib/channel/channel_trace.h
  58. 185 0
      src/core/lib/channel/channelz.cc
  59. 85 0
      src/core/lib/channel/channelz.h
  60. 17 12
      src/core/lib/channel/handshaker.cc
  61. 53 12
      src/core/lib/iomgr/ev_epollex_linux.cc
  62. 1 0
      src/core/lib/iomgr/is_epollexclusive_available.cc
  63. 9 0
      src/core/lib/iomgr/socket_utils.h
  64. 4 0
      src/core/lib/iomgr/socket_utils_common_posix.cc
  65. 4 0
      src/core/lib/iomgr/socket_utils_uv.cc
  66. 4 0
      src/core/lib/iomgr/socket_utils_windows.cc
  67. 2 1
      src/core/lib/security/credentials/google_default/google_default_credentials.cc
  68. 17 3
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  69. 30 5
      src/core/lib/security/security_connector/security_connector.cc
  70. 1 0
      src/core/lib/security/security_connector/security_connector.h
  71. 12 7
      src/core/lib/surface/call.cc
  72. 20 13
      src/core/lib/surface/channel.cc
  73. 4 0
      src/core/lib/surface/channel.h
  74. 1 1
      src/core/lib/surface/version.cc
  75. 2 2
      src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h
  76. 1 1
      src/core/tsi/alts/handshaker/altscontext.pb.h
  77. 1 1
      src/core/tsi/alts/handshaker/handshaker.pb.h
  78. 1 1
      src/core/tsi/alts/handshaker/transport_security_common.pb.h
  79. 2 2
      src/core/tsi/alts/handshaker/transport_security_common_api.h
  80. 2 3
      src/core/tsi/ssl_transport_security.cc
  81. 56 8
      src/cpp/README.md
  82. 2 1
      src/cpp/client/secure_credentials.cc
  83. 1 1
      src/cpp/common/version_cc.cc
  84. 9 10
      src/cpp/ext/filters/census/channel_filter.cc
  85. 16 11
      src/cpp/ext/filters/census/channel_filter.h
  86. 165 0
      src/cpp/ext/filters/census/client_filter.cc
  87. 104 0
      src/cpp/ext/filters/census/client_filter.h
  88. 132 0
      src/cpp/ext/filters/census/context.cc
  89. 126 0
      src/cpp/ext/filters/census/context.h
  90. 0 0
      src/cpp/ext/filters/census/grpc_context.cc
  91. 130 0
      src/cpp/ext/filters/census/grpc_plugin.cc
  92. 111 0
      src/cpp/ext/filters/census/grpc_plugin.h
  93. 129 0
      src/cpp/ext/filters/census/measures.cc
  94. 46 0
      src/cpp/ext/filters/census/measures.h
  95. 39 0
      src/cpp/ext/filters/census/rpc_encoding.cc
  96. 284 0
      src/cpp/ext/filters/census/rpc_encoding.h
  97. 198 0
      src/cpp/ext/filters/census/server_filter.cc
  98. 101 0
      src/cpp/ext/filters/census/server_filter.h
  99. 491 0
      src/cpp/ext/filters/census/views.cc
  100. 2 2
      src/cpp/server/health/default_health_check_service.cc

+ 2 - 2
.clang-tidy

@@ -1,6 +1,6 @@
 ---
 ---
-Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
-WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
+Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*'
+WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size,performance-*'
 CheckOptions:
 CheckOptions:
   - key:    readability-function-size.StatementThreshold
   - key:    readability-function-size.StatementThreshold
     value:  '450'
     value:  '450'

+ 42 - 6
BUILD

@@ -64,11 +64,11 @@ config_setting(
 )
 )
 
 
 # This should be updated along with build.yaml
 # This should be updated along with build.yaml
-g_stands_for = "gloriosa"
+g_stands_for = "gladiolus"
 
 
 core_version = "6.0.0-dev"
 core_version = "6.0.0-dev"
 
 
-version = "1.13.0-dev"
+version = "1.14.0-dev"
 
 
 GPR_PUBLIC_HDRS = [
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
     "include/grpc/support/alloc.h",
@@ -485,10 +485,7 @@ grpc_cc_library(
 grpc_cc_library(
 grpc_cc_library(
     name = "census",
     name = "census",
     srcs = [
     srcs = [
-        "src/core/ext/census/grpc_context.cc",
-    ],
-    external_deps = [
-        "nanopb",
+        "src/cpp/ext/filters/census/grpc_context.cc",
     ],
     ],
     language = "c++",
     language = "c++",
     public_hdrs = [
     public_hdrs = [
@@ -679,6 +676,7 @@ grpc_cc_library(
         "src/core/lib/channel/channel_stack_builder.cc",
         "src/core/lib/channel/channel_stack_builder.cc",
         "src/core/lib/channel/channel_trace.cc",
         "src/core/lib/channel/channel_trace.cc",
         "src/core/lib/channel/channelz_registry.cc",
         "src/core/lib/channel/channelz_registry.cc",
+        "src/core/lib/channel/channelz.cc",
         "src/core/lib/channel/connected_channel.cc",
         "src/core/lib/channel/connected_channel.cc",
         "src/core/lib/channel/handshaker.cc",
         "src/core/lib/channel/handshaker.cc",
         "src/core/lib/channel/handshaker_factory.cc",
         "src/core/lib/channel/handshaker_factory.cc",
@@ -826,6 +824,7 @@ grpc_cc_library(
         "src/core/lib/channel/channel_stack_builder.h",
         "src/core/lib/channel/channel_stack_builder.h",
         "src/core/lib/channel/channel_trace.h",
         "src/core/lib/channel/channel_trace.h",
         "src/core/lib/channel/channelz_registry.h",
         "src/core/lib/channel/channelz_registry.h",
+        "src/core/lib/channel/channelz.h",
         "src/core/lib/channel/connected_channel.h",
         "src/core/lib/channel/connected_channel.h",
         "src/core/lib/channel/context.h",
         "src/core/lib/channel/context.h",
         "src/core/lib/channel/handshaker.h",
         "src/core/lib/channel/handshaker.h",
@@ -1333,6 +1332,7 @@ grpc_cc_library(
     name = "grpc_resolver_dns_ares",
     name = "grpc_resolver_dns_ares",
     srcs = [
     srcs = [
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
@@ -1989,4 +1989,40 @@ grpc_cc_library(
     ],
     ],
 )
 )
 
 
+grpc_cc_library(
+    name = "grpc_opencensus_plugin",
+    srcs = [
+        "src/cpp/ext/filters/census/client_filter.cc",
+        "src/cpp/ext/filters/census/server_filter.cc",
+        "src/cpp/ext/filters/census/channel_filter.cc",
+        "src/cpp/ext/filters/census/context.cc",
+        "src/cpp/ext/filters/census/grpc_context.cc",
+        "src/cpp/ext/filters/census/grpc_plugin.cc",
+        "src/cpp/ext/filters/census/measures.cc",
+        "src/cpp/ext/filters/census/rpc_encoding.cc",
+        "src/cpp/ext/filters/census/views.cc",
+    ],
+    hdrs = [
+        "include/grpcpp/opencensus.h",
+        "src/cpp/ext/filters/census/client_filter.h",
+        "src/cpp/ext/filters/census/server_filter.h",
+        "src/cpp/ext/filters/census/channel_filter.h",
+        "src/cpp/ext/filters/census/context.h",
+        "src/cpp/ext/filters/census/grpc_plugin.h",
+        "src/cpp/ext/filters/census/measures.h",
+        "src/cpp/ext/filters/census/rpc_encoding.h",
+    ],
+    language = "c++",
+    external_deps = [
+        "absl-base",
+        "absl-time",
+        "opencensus-trace",
+        "opencensus-stats",
+    ],
+    deps = [
+        ":census",
+        ":grpc++",
+    ],
+)
+
 grpc_generate_one_off_targets()
 grpc_generate_one_off_targets()

+ 41 - 69
INSTALL.md → BUILDING.md

@@ -1,18 +1,5 @@
-# If you are in a hurry
-
-For language-specific installation instructions for gRPC runtime, please
-refer to these documents
-
- * [C++](examples/cpp): Currently to install gRPC for C++, you need to build from source as described below.
- * [C#](src/csharp): NuGet package `Grpc`
- * [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc`
- * [Java](https://github.com/grpc/grpc-java)
- * [Node](src/node): `npm install grpc`
- * [Objective-C](src/objective-c)
- * [PHP](src/php): `pecl install grpc`
- * [Python](src/python/grpcio): `pip install grpcio`
- * [Ruby](src/ruby): `gem install grpc`
-
+gRPC C++ - Building from source
+===========================
 
 
 # Pre-requisites
 # Pre-requisites
 
 
@@ -28,7 +15,7 @@ If you plan to build from source and run tests, install the following as well:
  $ [sudo] apt-get install clang libc++-dev
  $ [sudo] apt-get install clang libc++-dev
 ```
 ```
 
 
-## macOS 
+## MacOS
 
 
 On a Mac, you will first need to
 On a Mac, you will first need to
 install Xcode or
 install Xcode or
@@ -60,6 +47,17 @@ installed by `brew` is being used:
  $ LIBTOOL=glibtool LIBTOOLIZE=glibtoolize make
  $ LIBTOOL=glibtool LIBTOOLIZE=glibtoolize make
 ```
 ```
 
 
+## Windows
+
+To prepare for cmake + Microsoft Visual C++ compiler build
+- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used).
+- Install [Git](https://git-scm.com/).
+- Install [CMake](https://cmake.org/download/).
+- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`) - *required by boringssl*
+- Install [Go](https://golang.org/dl/) (`choco install golang`) - *required by boringssl*
+- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`) - *required by boringssl*
+- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
+
 ## Protoc
 ## Protoc
 
 
 By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
 By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
@@ -77,48 +75,49 @@ $ cd grpc/third_party/protobuf
 $ sudo make install   # 'make' should have been run by core grpc
 $ sudo make install   # 'make' should have been run by core grpc
 ```
 ```
 
 
-# Build from Source
+# Clone the repository (including submodules)
 
 
-For developers who are interested to contribute, the following commands show how to compile the
-gRPC C Core library.
+Before building, you need to clone the gRPC github repository and download submodules containing source code 
+for gRPC's dependencies (that's done by the `submodule` command or `--recursive` flag). The following commands will clone the gRPC
+repository at the latest stable version.
+
+## Unix
 
 
 ```sh
 ```sh
  $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
  $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
  $ cd grpc
  $ cd grpc
  $ git submodule update --init
  $ git submodule update --init
- $ make
- $ [sudo] make install
-```
+ ```
 
 
 ## Windows
 ## Windows
 
 
-There are several ways to build under Windows, of varying complexity depending
-on experience with the tools involved.
+```
+> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc"
+> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc
+> cd grpc
+> @rem To update submodules at later time, run "git submodule update --init"
+```
 
 
+# Build from source
 
 
+In the C++ world, there's no "standard" build system that would work for in all supported use cases and on all supported platforms.
+Therefore, gRPC supports several major build systems, which should satisfy most users.
 
 
-### Building using CMake (RECOMMENDED)
+## make (on UNIX systems)
 
 
-Builds gRPC C and C++ with boringssl.
-- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used).
-- Install [Git](https://git-scm.com/).
-- Install [CMake](https://cmake.org/download/).
-- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`) - *required by boringssl*
-- Install [Go](https://golang.org/dl/) (`choco install golang`) - *required by boringssl*
-- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`) - *required by boringssl*
-- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
+From the grpc repository root
+```sh
+ $ make
+```
 
 
-#### Clone grpc sources including submodules
-Before building, you need to clone the gRPC github repository and download submodules containing source code 
-for gRPC's dependencies (that's done by the `submodule` command).
+## bazel
+
+From the grpc repository root
 ```
 ```
-> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc"
-> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc
-> cd grpc
-> @rem To update submodules at later time, run "git submodule update --init"
+bazel build :all
 ```
 ```
 
 
-#### cmake: Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM).
+## cmake: Windows, Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM).
 When using the "Visual Studio" generator,
 When using the "Visual Studio" generator,
 cmake will generate a solution (`grpc.sln`) that contains a VS project for 
 cmake will generate a solution (`grpc.sln`) that contains a VS project for 
 every target defined in `CMakeLists.txt` (+ few extra convenience projects
 every target defined in `CMakeLists.txt` (+ few extra convenience projects
@@ -132,7 +131,7 @@ you will be able to browse and build the code.
 > cmake --build .
 > cmake --build .
 ```
 ```
 
 
-#### cmake: Using Ninja (faster build, supports boringssl's assembly optimizations).
+## cmake: Windows, Using Ninja (faster build, supports boringssl's assembly optimizations).
 Please note that when using Ninja, you will still need Visual C++ (part of Visual Studio)
 Please note that when using Ninja, you will still need Visual C++ (part of Visual Studio)
 installed to be able to compile the C/C++ sources.
 installed to be able to compile the C/C++ sources.
 ```
 ```
@@ -143,30 +142,3 @@ installed to be able to compile the C/C++ sources.
 > cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
 > cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
 > cmake --build .
 > cmake --build .
 ```
 ```
-
-### msys2 (with mingw)
-
-The Makefile (and source code) should support msys2's mingw32 and mingw64
-compilers. Building with msys2's native compiler is 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
-MSYS2$ pacman -S mingw-w64-x86_64-gflags
-```
-
-```
-# From mingw shell
-MINGW64$ export CPPFLAGS="-D_WIN32_WINNT=0x0600"
-MINGW64$ make
-```
-
-NOTE: Though most of the make targets are buildable under Mingw, some haven't been ported to Windows yet
-and may fail to build (mostly trying to include POSIX headers not available on Mingw).
-
-### Pre-generated Visual Studio solution (DELETED)
-
-*WARNING: This used to be the recommended way to build on Windows, but because of significant limitations (hard to build dependencies including boringssl, .proto codegen is hard to support, ..) we are no longer providing them. Use cmake to build on Windows instead.*

Різницю між файлами не показано, бо вона завелика
+ 119 - 51
CMakeLists.txt


+ 63 - 0
CONCEPTS.md

@@ -0,0 +1,63 @@
+# gRPC Concepts Overview
+
+Remote Procedure Calls (RPCs) provide a useful abstraction for building
+distributed applications and services. The libraries in this repository
+provide a concrete implementation of the gRPC protocol, layered over HTTP/2.
+These libraries enable communication between clients and servers using any
+combination of the supported languages.
+
+
+## Interface
+
+Developers using gRPC start with a language agnostic description of an RPC service (a collection
+of methods). From this description, gRPC will generate client and server side interfaces
+in any of the supported languages. The server implements
+the service interface, which can be remotely invoked by the client interface.
+
+By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the
+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.
+
+### Invoking & handling remote calls
+Starting from an interface definition in a .proto file, gRPC provides
+Protocol Compiler plugins that generate Client- and Server-side APIs.
+gRPC users call into these APIs on the Client side and implement
+the corresponding API on the server side.
+
+#### Synchronous vs. asynchronous
+Synchronous RPC calls, that block until a response arrives from the server, are
+the closest approximation to the abstraction of a procedure call that RPC
+aspires to.
+
+On the other hand, networks are inherently asynchronous and in many scenarios,
+it is desirable to have the ability to start RPCs without blocking the current
+thread.
+
+The gRPC programming surface in most languages comes in both synchronous and
+asynchronous flavors.
+
+
+## Streaming
+
+gRPC supports streaming semantics, where either the client or the server (or both)
+send a stream of messages on a single RPC call. The most general case is
+Bidirectional Streaming where a single gRPC call establishes a stream in which both
+the client and the server can send a stream of messages to each other. The streamed
+messages are delivered in the order they were sent.
+
+
+# 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
+fleshing out the details of each of the required operations.
+
+## Abstract gRPC protocol
+A gRPC call comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`).
+
+## Implementation over HTTP/2
+The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPACK compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers).
+
+## Flow Control
+gRPC uses the flow control mechanism in HTTP/2. This enables fine-grained control of memory used for buffering in-flight messages.

+ 26 - 5
CONTRIBUTING.md

@@ -11,13 +11,34 @@ In order to protect both you and ourselves, you will need to sign the
 [Contributor License
 [Contributor License
 Agreement](https://identity.linuxfoundation.org/projects/cncf).
 Agreement](https://identity.linuxfoundation.org/projects/cncf).
 
 
-## Running tests
+## Cloning the repository
 
 
-Use `tools/run_tests/run_tests.py` script to run the unit tests.  See
-[tools/run_tests](tools/run_tests) for how to run tests for a given language.
+Before starting any development work you will need a local copy of the gRPC repository.
+Please follow the instructions in [Building gRPC C++: Clone the repository](BUILDING.md#clone-the-repository-including-submodules).
 
 
-Prerequisites for building and running tests are listed in
-[INSTALL.md](INSTALL.md) and in `src/YOUR-LANGUAGE` (e.g. `src/csharp`)
+## Building & Running tests
+
+Different languages use different build systems. To hide the complexity
+of needing to build with many different build systems, a portable python
+script that unifies the experience of building and testing gRPC in different
+languages and on different platforms is provided.
+
+To build gRPC in the language of choice (e.g. `c++`, `csharp`, `php`, `python`, `ruby`, ...)
+- Prepare you development environment based on language-specific instructions in `src/YOUR-LANGUAGE` directory.
+- The language-specific instructions might involve installing C/C++ prerequisites listed in
+  [Building gRPC C++: Prerequisites](BUILDING.md#pre-requisites) as gRPC implementations
+  in this repository are using the native gRPC "core" library internally.
+- Run
+  ```
+  python tools/run_tests/run_tests.py -l YOUR_LANGUAGE --build_only
+  ```
+- To also run all the unit tests after building
+  ```
+  python tools/run_tests/run_tests.py -l YOUR_LANGUAGE
+  ```
+
+You can also run `python tools/run_tests/run_tests.py --help` to discover useful command line flags supported. For more details,
+see [tools/run_tests](tools/run_tests) where you will also find guidance on how to run various other test suites (e.g. interop tests, benchmarks)
 
 
 ## Generated project files
 ## Generated project files
 
 

Різницю між файлами не показано, бо вона завелика
+ 5 - 6
Makefile


+ 44 - 76
README.md

@@ -1,24 +1,59 @@
-[gRPC - An RPC library and framework](http://github.com/grpc/grpc)
+gRPC - An RPC library and framework
 ===================================
 ===================================
 
 
+gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. It enables client and server applications to communicate transparently, and makes it easier to build connected systems.
+
+<table>
+  <tr>
+    <td><b>Homepage:</b></td>
+    <td><a href="https://grpc.io/">grpc.io</a></td>
+  </tr>
+  <tr>
+    <td><b>Mailing List:</b></td>
+    <td><a href="https://groups.google.com/forum/#!forum/grpc-io">grpc-io@googlegroups.com</a></td>
+  </tr>
+</table>
+
 [![Join the chat at https://gitter.im/grpc/grpc](https://badges.gitter.im/grpc/grpc.svg)](https://gitter.im/grpc/grpc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![Join the chat at https://gitter.im/grpc/grpc](https://badges.gitter.im/grpc/grpc.svg)](https://gitter.im/grpc/grpc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 
-Copyright 2015
-[The gRPC Authors](https://github.com/grpc/grpc/blob/master/AUTHORS)
+# To start using gRPC
+
+To maximize usability, gRPC supports the standard way of adding dependencies in your language of choice (if there is one).
+In most languages, the gRPC runtime comes in form of a package available in your language's package manager.
+
+For instructions on how to use the language-specific gRPC runtime in your project, please refer to these documents
 
 
-# Documentation
+ * [C++](src/cpp): follow the instructions under the `src/cpp` directory
+ * [C#](src/csharp): NuGet package `Grpc`
+ * [Dart](https://github.com/grpc/grpc-dart): pub package `grpc`
+ * [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc`
+ * [Java](https://github.com/grpc/grpc-java): Use JARs from Maven Central Repository
+ * [Node](https://github.com/grpc/grpc-node): `npm install grpc`
+ * [Objective-C](src/objective-c): Add `gRPC-ProtoRPC` dependency to podspec
+ * [PHP](src/php): `pecl install grpc`
+ * [Python](src/python/grpcio): `pip install grpcio`
+ * [Ruby](src/ruby): `gem install grpc`
+ * [WebJS](https://github.com/grpc/grpc-web): follow the grpc-web instructions
 
 
-You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively.
+You can find per-language quickstart guides and tutorials in [Documentation section on grpc.io website](https://grpc.io/docs/). The code examples are available in the [examples](examples) directory.
 
 
-# Installation & Testing
+# To start developing gRPC
 
 
-See [INSTALL](INSTALL.md) for installation instructions for various platforms.
+Contributions are welcome!
 
 
-See [tools/run_tests](tools/run_tests) for more guidance on how to run various test suites (e.g. unit tests, interop tests, benchmarks)
+Please read [How to contribute](CONTRIBUTING.md) which will guide you through the entire workflow of how to build the source code, how to run the tests and how to contribute your changes to
+the gRPC codebase.
+The document also contains info on how the contributing process works and contains best practices for creating contributions.
+
+# Performance 
 
 
 See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for the performance numbers for the latest released version.
 See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for the performance numbers for the latest released version.
 
 
-# Repository Structure & Status
+# Concepts
+
+See [gRPC Concepts](CONCEPTS.md)
+
+# About This Repository
 
 
 This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core](src/core).
 This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core](src/core).
 
 
@@ -42,70 +77,3 @@ Libraries in different languages may be in different states of development. We a
 | WebJS                   | [grpc-web](https://github.com/grpc/grpc-web)         |
 | WebJS                   | [grpc-web](https://github.com/grpc/grpc-web)         |
 | Dart                    | [grpc-dart](https://github.com/grpc/grpc-dart)       |
 | Dart                    | [grpc-dart](https://github.com/grpc/grpc-dart)       |
 
 
-See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
-repository.
-
-# Overview
-
-
-Remote Procedure Calls (RPCs) provide a useful abstraction for building
-distributed applications and services. The libraries in this repository
-provide a concrete implementation of the gRPC protocol, layered over HTTP/2.
-These libraries enable communication between clients and servers using any
-combination of the supported languages.
-
-
-## Interface
-
-
-Developers using gRPC typically start with the description of an RPC service
-(a collection of methods), and generate client and server side interfaces
-which they use on the client-side and implement on the server side.
-
-By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the
-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
-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
-the corresponding API on the server side.
-
-#### Synchronous vs. asynchronous
-Synchronous RPC calls, that block until a response arrives from the server, are
-the closest approximation to the abstraction of a procedure call that RPC
-aspires to.
-
-On the other hand, networks are inherently asynchronous and in many scenarios,
-it is desirable to have the ability to start RPCs without blocking the current
-thread.
-
-The gRPC programming surface in most languages comes in both synchronous and
-asynchronous flavors.
-
-
-## Streaming
-
-gRPC supports streaming semantics, where either the client or the server (or both)
-send a stream of messages on a single RPC call. The most general case is
-Bidirectional Streaming where a single gRPC call establishes a stream where both
-the client and the server can send a stream of messages to each other. The streamed
-messages are delivered in the order they were sent.
-
-
-# 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
-fleshing out the details of each of the required operations.
-
-## Abstract gRPC protocol
-A gRPC RPC comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`).
-
-## Implementation over HTTP/2
-The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPACK compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers).
-
-## Flow Control
-gRPC inherits the flow control mechanisms in HTTP/2 and uses them to enable fine-grained control of the amount of memory used for buffering in-flight messages.

+ 4 - 22
bazel/grpc_build_system.bzl

@@ -36,9 +36,7 @@ def if_not_windows(a):
 def _get_external_deps(external_deps):
 def _get_external_deps(external_deps):
   ret = []
   ret = []
   for dep in external_deps:
   for dep in external_deps:
-    if dep == "nanopb":
-      ret += ["grpc_nanopb"]
-    elif dep == "address_sorting":
+    if dep == "address_sorting":
       ret += ["//third_party/address_sorting"]
       ret += ["//third_party/address_sorting"]
     elif dep == "cares":
     elif dep == "cares":
       ret += select({"//:grpc_no_ares": [],
       ret += select({"//:grpc_no_ares": [],
@@ -62,7 +60,7 @@ def _maybe_update_cc_library_hdrs(hdrs):
 def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
 def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
                     external_deps = [], deps = [], standalone = False,
                     external_deps = [], deps = [], standalone = False,
                     language = "C++", testonly = False, visibility = None,
                     language = "C++", testonly = False, visibility = None,
-                    alwayslink = 0):
+                    alwayslink = 0, data = []):
   copts = []
   copts = []
   if language.upper() == "C":
   if language.upper() == "C":
     copts = if_not_windows(["-std=c99"])
     copts = if_not_windows(["-std=c99"])
@@ -87,6 +85,7 @@ def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
         "include"
         "include"
     ],
     ],
     alwayslink = alwayslink,
     alwayslink = alwayslink,
+    data = data,
   )
   )
 
 
 def grpc_proto_plugin(name, srcs = [], deps = []):
 def grpc_proto_plugin(name, srcs = [], deps = []):
@@ -161,24 +160,7 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da
     linkopts = if_not_windows(["-pthread"]) + linkopts,
     linkopts = if_not_windows(["-pthread"]) + linkopts,
   )
   )
 
 
-def grpc_generate_one_off_targets():
-  native.cc_library(
-    name = "grpc_nanopb",
-    hdrs = [
-      "//third_party/nanopb:pb.h",
-      "//third_party/nanopb:pb_common.h",
-      "//third_party/nanopb:pb_decode.h",
-      "//third_party/nanopb:pb_encode.h",
-    ],
-    srcs = [
-      "//third_party/nanopb:pb_common.c",
-      "//third_party/nanopb:pb_decode.c",
-      "//third_party/nanopb:pb_encode.c",
-    ],
-    defines = [
-      "PB_FIELD_16BIT=1",
-    ],
-  )
+def grpc_generate_one_off_targets(): pass
 
 
 def grpc_sh_test(name, srcs, args = [], data = []):
 def grpc_sh_test(name, srcs, args = [], data = []):
   native.sh_test(
   native.sh_test(

+ 53 - 6
bazel/grpc_deps.bzl

@@ -2,6 +2,22 @@
 
 
 def grpc_deps():
 def grpc_deps():
     """Loads dependencies need to compile and test the grpc library."""
     """Loads dependencies need to compile and test the grpc library."""
+
+    native.bind(
+        name = "nanopb",
+        actual = "@com_github_nanopb_nanopb//:nanopb",
+    )
+
+    native.bind(
+        name = "absl-base",
+        actual = "@com_google_absl//absl/base",
+    )
+
+    native.bind(
+        name = "absl-time",
+        actual = "@com_google_absl//absl/time:time",
+    )
+
     native.bind(
     native.bind(
         name = "libssl",
         name = "libssl",
         actual = "@boringssl//:ssl",
         actual = "@boringssl//:ssl",
@@ -59,12 +75,27 @@ def grpc_deps():
 
 
     native.bind(
     native.bind(
         name = "grpc_cpp_plugin",
         name = "grpc_cpp_plugin",
-        actual = "@com_github_grpc_grpc//:grpc_cpp_plugin"
+        actual = "@com_github_grpc_grpc//:grpc_cpp_plugin",
     )
     )
 
 
     native.bind(
     native.bind(
         name = "grpc++_codegen_proto",
         name = "grpc++_codegen_proto",
-        actual = "@com_github_grpc_grpc//:grpc++_codegen_proto"
+        actual = "@com_github_grpc_grpc//:grpc++_codegen_proto",
+    )
+
+    native.bind(
+        name = "opencensus-trace",
+        actual = "@io_opencensus_cpp//opencensus/trace:trace"
+    )
+
+    native.bind(
+        name = "opencensus-stats",
+        actual = "@io_opencensus_cpp//opencensus/stats:stats"
+    )
+
+    native.bind(
+        name = "opencensus-stats-test",
+        actual = "@io_opencensus_cpp//opencensus/stats:test_utils"
     )
     )
 
 
     if "boringssl" not in native.existing_rules():
     if "boringssl" not in native.existing_rules():
@@ -87,6 +118,14 @@ def grpc_deps():
             name = "com_google_protobuf",
             name = "com_google_protobuf",
             strip_prefix = "protobuf-b5fbb742af122b565925987e65c08957739976a7",
             strip_prefix = "protobuf-b5fbb742af122b565925987e65c08957739976a7",
             url = "https://github.com/google/protobuf/archive/b5fbb742af122b565925987e65c08957739976a7.tar.gz",
             url = "https://github.com/google/protobuf/archive/b5fbb742af122b565925987e65c08957739976a7.tar.gz",
+            )
+
+    if "com_github_nanopb_nanopb" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_nanopb_nanopb",
+            build_file = "@com_github_grpc_grpc//third_party:nanopb.BUILD",
+            strip_prefix = "nanopb-f8ac463766281625ad710900479130c7fcb4d63b",
+            url = "https://github.com/nanopb/nanopb/archive/f8ac463766281625ad710900479130c7fcb4d63b.tar.gz",
         )
         )
 
 
     if "com_github_google_googletest" not in native.existing_rules():
     if "com_github_google_googletest" not in native.existing_rules():
@@ -108,8 +147,8 @@ def grpc_deps():
         native.new_http_archive(
         native.new_http_archive(
             name = "com_github_google_benchmark",
             name = "com_github_google_benchmark",
             build_file = "@com_github_grpc_grpc//third_party:benchmark.BUILD",
             build_file = "@com_github_grpc_grpc//third_party:benchmark.BUILD",
-            strip_prefix = "benchmark-5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8",
-            url = "https://github.com/google/benchmark/archive/5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8.tar.gz",
+            strip_prefix = "benchmark-9913418d323e64a0111ca0da81388260c2bbe1e9",
+            url = "https://github.com/google/benchmark/archive/9913418d323e64a0111ca0da81388260c2bbe1e9.tar.gz",
         )
         )
 
 
     if "com_github_cares_cares" not in native.existing_rules():
     if "com_github_cares_cares" not in native.existing_rules():
@@ -123,8 +162,8 @@ def grpc_deps():
     if "com_google_absl" not in native.existing_rules():
     if "com_google_absl" not in native.existing_rules():
         native.http_archive(
         native.http_archive(
             name = "com_google_absl",
             name = "com_google_absl",
-            strip_prefix = "abseil-cpp-cc4bed2d74f7c8717e31f9579214ab52a9c9c610",
-            url = "https://github.com/abseil/abseil-cpp/archive/cc4bed2d74f7c8717e31f9579214ab52a9c9c610.tar.gz",
+            strip_prefix = "abseil-cpp-cd95e71df6eaf8f2a282b1da556c2cf1c9b09207",
+            url = "https://github.com/abseil/abseil-cpp/archive/cd95e71df6eaf8f2a282b1da556c2cf1c9b09207.tar.gz",
         )
         )
 
 
     if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
     if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
@@ -138,6 +177,14 @@ def grpc_deps():
             sha256 = "1c4a532b396c698e6467a1548554571cb85fa091e472b05e398ebc836c315d77",
             sha256 = "1c4a532b396c698e6467a1548554571cb85fa091e472b05e398ebc836c315d77",
         )
         )
 
 
+    if "io_opencensus_cpp" not in native.existing_rules():
+      native.http_archive(
+            name = "io_opencensus_cpp",
+            strip_prefix = "opencensus-cpp-fdf0f308b1631bb4a942e32ba5d22536a6170274",
+            url = "https://github.com/census-instrumentation/opencensus-cpp/archive/fdf0f308b1631bb4a942e32ba5d22536a6170274.tar.gz",
+        )
+
+
 # TODO: move some dependencies from "grpc_deps" here?
 # TODO: move some dependencies from "grpc_deps" here?
 def grpc_test_only_deps():
 def grpc_test_only_deps():
     """Internal, not intended for use by packages that are consuming grpc.
     """Internal, not intended for use by packages that are consuming grpc.

+ 43 - 32
build.yaml

@@ -13,8 +13,8 @@ settings:
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
   '#10': See the expand_version.py for all the quirks here
   core_version: 6.0.0-dev
   core_version: 6.0.0-dev
-  g_stands_for: gloriosa
-  version: 1.13.0-dev
+  g_stands_for: gladiolus
+  version: 1.14.0-dev
 filegroups:
 filegroups:
 - name: alts_proto
 - name: alts_proto
   headers:
   headers:
@@ -100,10 +100,9 @@ filegroups:
   public_headers:
   public_headers:
   - include/grpc/census.h
   - include/grpc/census.h
   src:
   src:
-  - src/core/ext/census/grpc_context.cc
+  - src/cpp/ext/filters/census/grpc_context.cc
   uses:
   uses:
   - grpc_base
   - grpc_base
-  - nanopb
 - name: cmdline
 - name: cmdline
   headers:
   headers:
   - test/core/util/cmdline.h
   - test/core/util/cmdline.h
@@ -235,6 +234,7 @@ filegroups:
   - src/core/lib/channel/channel_stack.cc
   - src/core/lib/channel/channel_stack.cc
   - src/core/lib/channel/channel_stack_builder.cc
   - src/core/lib/channel/channel_stack_builder.cc
   - src/core/lib/channel/channel_trace.cc
   - src/core/lib/channel/channel_trace.cc
+  - src/core/lib/channel/channelz.cc
   - src/core/lib/channel/channelz_registry.cc
   - src/core/lib/channel/channelz_registry.cc
   - src/core/lib/channel/connected_channel.cc
   - src/core/lib/channel/connected_channel.cc
   - src/core/lib/channel/handshaker.cc
   - src/core/lib/channel/handshaker.cc
@@ -405,6 +405,7 @@ filegroups:
   - src/core/lib/channel/channel_stack.h
   - src/core/lib/channel/channel_stack.h
   - src/core/lib/channel/channel_stack_builder.h
   - src/core/lib/channel/channel_stack_builder.h
   - src/core/lib/channel/channel_trace.h
   - src/core/lib/channel/channel_trace.h
+  - src/core/lib/channel/channelz.h
   - src/core/lib/channel/channelz_registry.h
   - src/core/lib/channel/channelz_registry.h
   - src/core/lib/channel/connected_channel.h
   - src/core/lib/channel/connected_channel.h
   - src/core/lib/channel/context.h
   - src/core/lib/channel/context.h
@@ -725,6 +726,7 @@ filegroups:
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
   src:
   src:
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
@@ -1904,15 +1906,6 @@ libs:
   - test/cpp/interop/interop_server_bootstrap.cc
   - test/cpp/interop/interop_server_bootstrap.cc
   deps:
   deps:
   - interop_server_lib
   - interop_server_lib
-- name: lb_load_data_store
-  build: private
-  language: c++
-  headers:
-  - src/cpp/server/load_reporter/load_data_store.h
-  src:
-  - src/cpp/server/load_reporter/load_data_store.cc
-  deps:
-  - grpc++
 - name: qps
 - name: qps
   build: private
   build: private
   language: c++
   language: c++
@@ -2792,6 +2785,21 @@ targets:
   platforms:
   platforms:
   - linux
   - linux
   secure: true
   secure: true
+- name: handshake_verify_peer_options
+  build: test
+  language: c
+  src:
+  - test/core/handshake/verify_peer_options.cc
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  exclude_iomgrs:
+  - uv
+  platforms:
+  - linux
+  secure: true
 - name: histogram_test
 - name: histogram_test
   build: test
   build: test
   language: c
   language: c
@@ -4237,6 +4245,23 @@ targets:
   uses:
   uses:
   - grpc++_test
   - grpc++_test
   uses_polling: false
   uses_polling: false
+- name: channelz_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/channel/channelz_test.cc
+  deps:
+  - grpc_test_util
+  - grpc++_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  filegroups:
+  - grpc++_channelz_proto
+  uses:
+  - grpc++_test
 - name: check_gcp_environment_linux_test
 - name: check_gcp_environment_linux_test
   build: test
   build: test
   language: c++
   language: c++
@@ -4830,20 +4855,6 @@ targets:
   - mac
   - mac
   - linux
   - linux
   - posix
   - posix
-- name: lb_load_data_store_test
-  gtest: true
-  build: test
-  language: c++
-  src:
-  - test/cpp/server/load_reporter/load_data_store_test.cc
-  deps:
-  - lb_load_data_store
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr_test_util
-  - gpr
 - name: memory_test
 - name: memory_test
   gtest: true
   gtest: true
   build: test
   build: test
@@ -5493,7 +5504,7 @@ configs:
     compile_the_world: true
     compile_the_world: true
     test_environ:
     test_environ:
       ASAN_OPTIONS: detect_leaks=1:color=always
       ASAN_OPTIONS: detect_leaks=1:color=always
-      LSAN_OPTIONS: suppressions=tools/lsan_suppressions.txt:report_objects=1
+      LSAN_OPTIONS: suppressions=test/core/util/lsan_suppressions.txt:report_objects=1
   asan-noleaks:
   asan-noleaks:
     CC: clang
     CC: clang
     CPPFLAGS: -O0 -fsanitize-coverage=edge,trace-pc-guard -fsanitize=address -fno-omit-frame-pointer
     CPPFLAGS: -O0 -fsanitize-coverage=edge,trace-pc-guard -fsanitize=address -fno-omit-frame-pointer
@@ -5517,7 +5528,7 @@ configs:
     compile_the_world: true
     compile_the_world: true
     test_environ:
     test_environ:
       ASAN_OPTIONS: detect_leaks=1:color=always
       ASAN_OPTIONS: detect_leaks=1:color=always
-      LSAN_OPTIONS: suppressions=tools/lsan_suppressions.txt:report_objects=1
+      LSAN_OPTIONS: suppressions=test/core/util/lsan_suppressions.txt:report_objects=1
   basicprof:
   basicprof:
     CPPFLAGS: -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
     CPPFLAGS: -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
     DEFINES: NDEBUG
     DEFINES: NDEBUG
@@ -5591,7 +5602,7 @@ configs:
     LDXX: clang++
     LDXX: clang++
     compile_the_world: true
     compile_the_world: true
     test_environ:
     test_environ:
-      TSAN_OPTIONS: suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
+      TSAN_OPTIONS: suppressions=test/core/util/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
   ubsan:
   ubsan:
     CC: clang
     CC: clang
     CPPFLAGS: -O0 -fsanitize-coverage=edge,trace-pc-guard -fsanitize=undefined -fno-omit-frame-pointer
     CPPFLAGS: -O0 -fsanitize-coverage=edge,trace-pc-guard -fsanitize=undefined -fno-omit-frame-pointer
@@ -5603,7 +5614,7 @@ configs:
     LDXX: clang++
     LDXX: clang++
     compile_the_world: true
     compile_the_world: true
     test_environ:
     test_environ:
-      UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt
+      UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1:suppressions=test/core/util/ubsan_suppressions.txt
 defaults:
 defaults:
   ares:
   ares:
     CFLAGS: -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32)
     CFLAGS: -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32)
@@ -5625,7 +5636,7 @@ defaults:
   global:
   global:
     COREFLAGS: -fno-rtti -fno-exceptions
     COREFLAGS: -fno-rtti -fno-exceptions
     CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
     CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-      -Wno-deprecated-declarations
+      -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
     LDFLAGS: -g
     LDFLAGS: -g
   zlib:
   zlib:
     CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration
     CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration

+ 15 - 0
cmake/nanopb.cmake

@@ -0,0 +1,15 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(_gRPC_NANOPB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/nanopb")

+ 7 - 4
config.m4

@@ -9,11 +9,12 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include)
   PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/nanopb)
 
 
   LIBS="-lpthread $LIBS"
   LIBS="-lpthread $LIBS"
 
 
-  CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_16BIT=1"
-  CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_16BIT=1"
+  CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_32BIT=1"
+  CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_32BIT=1"
   GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
   GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
   PHP_REQUIRE_CXX()
   PHP_REQUIRE_CXX()
   PHP_ADD_LIBRARY(pthread)
   PHP_ADD_LIBRARY(pthread)
@@ -89,6 +90,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
     src/core/lib/channel/channel_stack_builder.cc \
     src/core/lib/channel/channel_trace.cc \
     src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channelz.cc \
     src/core/lib/channel/channelz_registry.cc \
     src/core/lib/channel/channelz_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker.cc \
@@ -370,6 +372,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
     src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
     src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
     src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
@@ -377,7 +380,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
     src/core/ext/filters/load_reporting/server_load_reporting_filter.cc \
     src/core/ext/filters/load_reporting/server_load_reporting_filter.cc \
     src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc \
     src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc \
-    src/core/ext/census/grpc_context.cc \
+    src/cpp/ext/filters/census/grpc_context.cc \
     src/core/ext/filters/max_age/max_age_filter.cc \
     src/core/ext/filters/max_age/max_age_filter.cc \
     src/core/ext/filters/message_size/message_size_filter.cc \
     src/core/ext/filters/message_size/message_size_filter.cc \
     src/core/ext/filters/http/client_authority_filter.cc \
     src/core/ext/filters/http/client_authority_filter.cc \
@@ -648,7 +651,6 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
   PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
 
 
   PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl)
   PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/census)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1)
@@ -711,6 +713,7 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/handshaker)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/handshaker)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/zero_copy_frame_protector)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/zero_copy_frame_protector)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/cpp/ext/filters/census)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/address_sorting)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/address_sorting)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1)

+ 10 - 4
config.w32

@@ -65,6 +65,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\channel\\channel_stack.cc " +
     "src\\core\\lib\\channel\\channel_stack.cc " +
     "src\\core\\lib\\channel\\channel_stack_builder.cc " +
     "src\\core\\lib\\channel\\channel_stack_builder.cc " +
     "src\\core\\lib\\channel\\channel_trace.cc " +
     "src\\core\\lib\\channel\\channel_trace.cc " +
+    "src\\core\\lib\\channel\\channelz.cc " +
     "src\\core\\lib\\channel\\channelz_registry.cc " +
     "src\\core\\lib\\channel\\channelz_registry.cc " +
     "src\\core\\lib\\channel\\connected_channel.cc " +
     "src\\core\\lib\\channel\\connected_channel.cc " +
     "src\\core\\lib\\channel\\handshaker.cc " +
     "src\\core\\lib\\channel\\handshaker.cc " +
@@ -346,6 +347,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
+    "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.cc " +
@@ -353,7 +355,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " +
     "src\\core\\ext\\filters\\load_reporting\\server_load_reporting_filter.cc " +
     "src\\core\\ext\\filters\\load_reporting\\server_load_reporting_filter.cc " +
     "src\\core\\ext\\filters\\load_reporting\\server_load_reporting_plugin.cc " +
     "src\\core\\ext\\filters\\load_reporting\\server_load_reporting_plugin.cc " +
-    "src\\core\\ext\\census\\grpc_context.cc " +
+    "src\\cpp\\ext\\filters\\census\\grpc_context.cc " +
     "src\\core\\ext\\filters\\max_age\\max_age_filter.cc " +
     "src\\core\\ext\\filters\\max_age\\max_age_filter.cc " +
     "src\\core\\ext\\filters\\message_size\\message_size_filter.cc " +
     "src\\core\\ext\\filters\\message_size\\message_size_filter.cc " +
     "src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
     "src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
@@ -637,13 +639,14 @@ if (PHP_GRPC != "no") {
   EXTENSION("grpc", grpc_source, null,
   EXTENSION("grpc", grpc_source, null,
     "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+
     "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+
     "/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+
     "/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+
-    "/DPB_FIELD_16BIT "+
+    "/DPB_FIELD_32BIT "+
     "/I"+configure_module_dirname+" "+
     "/I"+configure_module_dirname+" "+
     "/I"+configure_module_dirname+"\\include "+
     "/I"+configure_module_dirname+"\\include "+
     "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+
     "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+
     "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+
     "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+
     "/I"+configure_module_dirname+"\\third_party\\zlib "+
     "/I"+configure_module_dirname+"\\third_party\\zlib "+
-    "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include");
+    "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include "+
+    "/I"+configure_module_dirname+"\\third_party\\nanopb");
 
 
   base_dir = get_define('BUILD_DIR');
   base_dir = get_define('BUILD_DIR');
   FSO.CreateFolder(base_dir+"\\ext");
   FSO.CreateFolder(base_dir+"\\ext");
@@ -652,7 +655,6 @@ if (PHP_GRPC != "no") {
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\boringssl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\boringssl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext");
-  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\census");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy");
@@ -728,6 +730,10 @@ if (PHP_GRPC != "no") {
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\zero_copy_frame_protector");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\zero_copy_frame_protector");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl\\session_cache");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl\\session_cache");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\cpp");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\cpp\\ext");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\cpp\\ext\\filters");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\cpp\\ext\\filters\\census");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext\\grpc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext\\grpc");

+ 1 - 1
doc/PROTOCOL-WEB.md

@@ -138,4 +138,4 @@ Versioning
 
 
 Browser-specific features
 Browser-specific features
 
 
-* For features that are unique to browser or HTML clients, check the [spec doc](https://github.com/grpc/grpc-web/blob/master/PROTOCOL-WEB.md) published in the grpc/grpc-web repo.
+* For features that are unique to browser or HTML clients, check the [spec doc](https://github.com/grpc/grpc-web/blob/master/BROWSER-FEATURES.md) published in the grpc/grpc-web repo.

+ 1 - 1
doc/command_line_tool.md

@@ -32,7 +32,7 @@ The command line tool should support the following things:
 
 
 To use the tool, you need to get the grpc repository and make sure your system
 To use the tool, you need to get the grpc repository and make sure your system
 has the prerequisites for building grpc from source, given in the [installation
 has the prerequisites for building grpc from source, given in the [installation
-instructions](https://github.com/grpc/grpc/blob/master/INSTALL.md).
+instructions](../BUILDING.md).
 
 
 In order to build the grpc command line tool from a fresh clone of the grpc
 In order to build the grpc command line tool from a fresh clone of the grpc
 repository, you need to run the following command to update submodules:
 repository, you need to run the following command to update submodules:

+ 2 - 1
doc/g_stands_for.md

@@ -12,4 +12,5 @@
 - 1.10 'g' stands for ['glamorous'](https://github.com/grpc/grpc/tree/v1.10.x)
 - 1.10 'g' stands for ['glamorous'](https://github.com/grpc/grpc/tree/v1.10.x)
 - 1.11 'g' stands for ['gorgeous'](https://github.com/grpc/grpc/tree/v1.11.x)
 - 1.11 'g' stands for ['gorgeous'](https://github.com/grpc/grpc/tree/v1.11.x)
 - 1.12 'g' stands for ['glorious'](https://github.com/grpc/grpc/tree/v1.12.x)
 - 1.12 'g' stands for ['glorious'](https://github.com/grpc/grpc/tree/v1.12.x)
-- 1.13 'g' stands for ['gloriosa'](https://github.com/grpc/grpc/tree/master)
+- 1.13 'g' stands for ['gloriosa'](https://github.com/grpc/grpc/tree/v1.13.x)
+- 1.14 'g' stands for ['gladiolus'](https://github.com/grpc/grpc/tree/master)

+ 1 - 1
examples/cpp/README.md

@@ -3,7 +3,7 @@
 ## Installation
 ## Installation
 
 
 To install gRPC on your system, follow the instructions to build from source
 To install gRPC on your system, follow the instructions to build from source
-[here](../../INSTALL.md). This also installs the protocol buffer compiler
+[here](../../BUILDING.md). This also installs the protocol buffer compiler
 `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
 `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
 
 
 ## Hello C++ gRPC!
 ## Hello C++ gRPC!

+ 2 - 2
examples/cpp/cpptutorial.md

@@ -35,7 +35,7 @@ updating.
 The example code for our tutorial is in [examples/cpp/route_guide](route_guide).
 The example code for our tutorial is in [examples/cpp/route_guide](route_guide).
 You also should have the relevant tools installed to generate the server and
 You also should have the relevant tools installed to generate the server and
 client interface code - if you don't already, follow the setup instructions in
 client interface code - if you don't already, follow the setup instructions in
-[INSTALL.md](../../INSTALL.md).
+[BUILDING.md](../../BUILDING.md).
 
 
 ## Defining the service
 ## Defining the service
 
 
@@ -130,7 +130,7 @@ a special gRPC C++ plugin.
 For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs
 For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs
 `protoc` for you with the appropriate plugin, input, and output (if you want to
 `protoc` for you with the appropriate plugin, input, and output (if you want to
 run this yourself, make sure you've installed protoc and followed the gRPC code
 run this yourself, make sure you've installed protoc and followed the gRPC code
-[installation instructions](../../INSTALL.md) first):
+[installation instructions](../../BUILDING.md) first):
 
 
 ```shell
 ```shell
 $ make route_guide.grpc.pb.cc route_guide.pb.cc
 $ make route_guide.grpc.pb.cc route_guide.pb.cc

+ 2 - 2
examples/cpp/helloworld/README.md

@@ -1,8 +1,8 @@
 # gRPC C++ Hello World Tutorial
 # gRPC C++ Hello World Tutorial
 
 
 ### Install gRPC
 ### Install gRPC
-Make sure you have installed gRPC on your system. Follow the instructions here:
-[https://github.com/grpc/grpc/blob/master/INSTALL](../../../INSTALL.md).
+Make sure you have installed gRPC on your system. Follow the
+[BUILDING.md](../../../BUILDING.md) instructions.
 
 
 ### Get the tutorial source code
 ### Get the tutorial source code
 
 

+ 6 - 0
examples/cpp/route_guide/README.md

@@ -0,0 +1,6 @@
+# gRPC Basics: C++ sample code
+
+The files in this folder are the samples used in [gRPC Basics: C++][],
+a detailed tutorial for using gRPC in C++.
+
+[gRPC Basics: C++]:https://grpc.io/docs/tutorials/basic/c.html

+ 6 - 3
examples/python/helloworld/greeter_client.py

@@ -22,9 +22,12 @@ import helloworld_pb2_grpc
 
 
 
 
 def run():
 def run():
-    channel = grpc.insecure_channel('localhost:50051')
-    stub = helloworld_pb2_grpc.GreeterStub(channel)
-    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
+    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+    # used in circumstances in which the with statement does not fit the needs
+    # of the code.
+    with grpc.insecure_channel('localhost:50051') as channel:
+        stub = helloworld_pb2_grpc.GreeterStub(channel)
+        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
     print("Greeter client received: " + response.message)
     print("Greeter client received: " + response.message)
 
 
 
 

+ 8 - 4
examples/python/interceptors/default_value/greeter_client.py

@@ -27,10 +27,14 @@ def run():
         message='Hello from your local interceptor!')
         message='Hello from your local interceptor!')
     default_value_interceptor = default_value_client_interceptor.DefaultValueClientInterceptor(
     default_value_interceptor = default_value_client_interceptor.DefaultValueClientInterceptor(
         default_value)
         default_value)
-    channel = grpc.insecure_channel('localhost:50051')
-    channel = grpc.intercept_channel(channel, default_value_interceptor)
-    stub = helloworld_pb2_grpc.GreeterStub(channel)
-    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
+    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+    # used in circumstances in which the with statement does not fit the needs
+    # of the code.
+    with grpc.insecure_channel('localhost:50051') as channel:
+        intercept_channel = grpc.intercept_channel(channel,
+                                                   default_value_interceptor)
+        stub = helloworld_pb2_grpc.GreeterStub(intercept_channel)
+        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
     print("Greeter client received: " + response.message)
     print("Greeter client received: " + response.message)
 
 
 
 

+ 8 - 4
examples/python/interceptors/headers/greeter_client.py

@@ -25,10 +25,14 @@ import header_manipulator_client_interceptor
 def run():
 def run():
     header_adder_interceptor = header_manipulator_client_interceptor.header_adder_interceptor(
     header_adder_interceptor = header_manipulator_client_interceptor.header_adder_interceptor(
         'one-time-password', '42')
         'one-time-password', '42')
-    channel = grpc.insecure_channel('localhost:50051')
-    channel = grpc.intercept_channel(channel, header_adder_interceptor)
-    stub = helloworld_pb2_grpc.GreeterStub(channel)
-    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
+    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+    # used in circumstances in which the with statement does not fit the needs
+    # of the code.
+    with grpc.insecure_channel('localhost:50051') as channel:
+        intercept_channel = grpc.intercept_channel(channel,
+                                                   header_adder_interceptor)
+        stub = helloworld_pb2_grpc.GreeterStub(intercept_channel)
+        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
     print("Greeter client received: " + response.message)
     print("Greeter client received: " + response.message)
 
 
 
 

+ 17 - 14
examples/python/multiplex/multiplex_client.py

@@ -106,20 +106,23 @@ def guide_route_chat(route_guide_stub):
 
 
 
 
 def run():
 def run():
-    channel = grpc.insecure_channel('localhost:50051')
-    greeter_stub = helloworld_pb2_grpc.GreeterStub(channel)
-    route_guide_stub = route_guide_pb2_grpc.RouteGuideStub(channel)
-    greeter_response = greeter_stub.SayHello(
-        helloworld_pb2.HelloRequest(name='you'))
-    print("Greeter client received: " + greeter_response.message)
-    print("-------------- GetFeature --------------")
-    guide_get_feature(route_guide_stub)
-    print("-------------- ListFeatures --------------")
-    guide_list_features(route_guide_stub)
-    print("-------------- RecordRoute --------------")
-    guide_record_route(route_guide_stub)
-    print("-------------- RouteChat --------------")
-    guide_route_chat(route_guide_stub)
+    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+    # used in circumstances in which the with statement does not fit the needs
+    # of the code.
+    with grpc.insecure_channel('localhost:50051') as channel:
+        greeter_stub = helloworld_pb2_grpc.GreeterStub(channel)
+        route_guide_stub = route_guide_pb2_grpc.RouteGuideStub(channel)
+        greeter_response = greeter_stub.SayHello(
+            helloworld_pb2.HelloRequest(name='you'))
+        print("Greeter client received: " + greeter_response.message)
+        print("-------------- GetFeature --------------")
+        guide_get_feature(route_guide_stub)
+        print("-------------- ListFeatures --------------")
+        guide_list_features(route_guide_stub)
+        print("-------------- RecordRoute --------------")
+        guide_record_route(route_guide_stub)
+        print("-------------- RouteChat --------------")
+        guide_route_chat(route_guide_stub)
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':

+ 13 - 10
examples/python/route_guide/route_guide_client.py

@@ -100,16 +100,19 @@ def guide_route_chat(stub):
 
 
 
 
 def run():
 def run():
-    channel = grpc.insecure_channel('localhost:50051')
-    stub = route_guide_pb2_grpc.RouteGuideStub(channel)
-    print("-------------- GetFeature --------------")
-    guide_get_feature(stub)
-    print("-------------- ListFeatures --------------")
-    guide_list_features(stub)
-    print("-------------- RecordRoute --------------")
-    guide_record_route(stub)
-    print("-------------- RouteChat --------------")
-    guide_route_chat(stub)
+    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
+    # used in circumstances in which the with statement does not fit the needs
+    # of the code.
+    with grpc.insecure_channel('localhost:50051') as channel:
+        stub = route_guide_pb2_grpc.RouteGuideStub(channel)
+        print("-------------- GetFeature --------------")
+        guide_get_feature(stub)
+        print("-------------- ListFeatures --------------")
+        guide_list_features(stub)
+        print("-------------- RecordRoute --------------")
+        guide_record_route(stub)
+        print("-------------- RouteChat --------------")
+        guide_route_chat(stub)
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':

+ 8 - 6
gRPC-C++.podspec

@@ -23,7 +23,7 @@
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  # version = '1.13.0-dev'
+  # version = '1.14.0-dev'
   version = '0.0.2'
   version = '0.0.2'
   s.version  = version
   s.version  = version
   s.summary  = 'gRPC C++ library'
   s.summary  = 'gRPC C++ library'
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
   s.license  = 'Apache License, Version 2.0'
   s.license  = 'Apache License, Version 2.0'
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
 
-  grpc_version = '1.13.0-dev'
+  grpc_version = '1.14.0-dev'
 
 
   s.source = {
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
     :git => 'https://github.com/grpc/grpc.git',
@@ -347,6 +347,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
                       'src/core/lib/channel/channel_stack_builder.h',
                       'src/core/lib/channel/channel_trace.h',
                       'src/core/lib/channel/channel_trace.h',
+                      'src/core/lib/channel/channelz.h',
                       'src/core/lib/channel/channelz_registry.h',
                       'src/core/lib/channel/channelz_registry.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.h',
                       'src/core/lib/channel/context.h',
@@ -532,6 +533,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
                               'src/core/lib/channel/channel_stack_builder.h',
                               'src/core/lib/channel/channel_trace.h',
                               'src/core/lib/channel/channel_trace.h',
+                              'src/core/lib/channel/channelz.h',
                               'src/core/lib/channel/channelz_registry.h',
                               'src/core/lib/channel/channelz_registry.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.h',
                               'src/core/lib/channel/context.h',
@@ -663,9 +665,9 @@ Pod::Spec.new do |s|
   end
   end
 
 
   s.prepare_command = <<-END_OF_COMMAND
   s.prepare_command = <<-END_OF_COMMAND
-    find src/cpp/ -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
-    find src/cpp/ -name "*.back" -type f -delete
-    find src/core/ -regex ".*\.h" -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
-    find src/core/ -name "*.back" -type f -delete
+    find src/cpp/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
+    find src/cpp/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
+    find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
+    find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
   END_OF_COMMAND
   END_OF_COMMAND
 end
 end

+ 9 - 3
gRPC-Core.podspec

@@ -22,7 +22,7 @@
 
 
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
   s.name     = 'gRPC-Core'
-  version = '1.13.0-dev'
+  version = '1.14.0-dev'
   s.version  = version
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
   s.homepage = 'https://grpc.io'
@@ -357,6 +357,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
                       'src/core/lib/channel/channel_stack_builder.h',
                       'src/core/lib/channel/channel_trace.h',
                       'src/core/lib/channel/channel_trace.h',
+                      'src/core/lib/channel/channelz.h',
                       'src/core/lib/channel/channelz_registry.h',
                       'src/core/lib/channel/channelz_registry.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.h',
                       'src/core/lib/channel/context.h',
@@ -507,6 +508,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/channel/channel_stack.cc',
                       'src/core/lib/channel/channel_stack.cc',
                       'src/core/lib/channel/channel_stack_builder.cc',
                       'src/core/lib/channel/channel_stack_builder.cc',
                       'src/core/lib/channel/channel_trace.cc',
                       'src/core/lib/channel/channel_trace.cc',
+                      'src/core/lib/channel/channelz.cc',
                       'src/core/lib/channel/channelz_registry.cc',
                       'src/core/lib/channel/channelz_registry.cc',
                       'src/core/lib/channel/connected_channel.cc',
                       'src/core/lib/channel/connected_channel.cc',
                       'src/core/lib/channel/handshaker.cc',
                       'src/core/lib/channel/handshaker.cc',
@@ -785,6 +787,7 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
                       'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
                       'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
                       'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
@@ -792,7 +795,7 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
                       'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
                       'src/core/ext/filters/load_reporting/server_load_reporting_filter.cc',
                       'src/core/ext/filters/load_reporting/server_load_reporting_filter.cc',
                       'src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc',
                       'src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc',
-                      'src/core/ext/census/grpc_context.cc',
+                      'src/cpp/ext/filters/census/grpc_context.cc',
                       'src/core/ext/filters/max_age/max_age_filter.cc',
                       'src/core/ext/filters/max_age/max_age_filter.cc',
                       'src/core/ext/filters/message_size/message_size_filter.cc',
                       'src/core/ext/filters/message_size/message_size_filter.cc',
                       'src/core/ext/filters/http/client_authority_filter.cc',
                       'src/core/ext/filters/http/client_authority_filter.cc',
@@ -935,6 +938,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
                               'src/core/lib/channel/channel_stack_builder.h',
                               'src/core/lib/channel/channel_trace.h',
                               'src/core/lib/channel/channel_trace.h',
+                              'src/core/lib/channel/channelz.h',
                               'src/core/lib/channel/channelz_registry.h',
                               'src/core/lib/channel/channelz_registry.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.h',
                               'src/core/lib/channel/context.h',
@@ -1193,6 +1197,7 @@ Pod::Spec.new do |s|
                       'test/core/end2end/tests/cancel_before_invoke.cc',
                       'test/core/end2end/tests/cancel_before_invoke.cc',
                       'test/core/end2end/tests/cancel_in_a_vacuum.cc',
                       'test/core/end2end/tests/cancel_in_a_vacuum.cc',
                       'test/core/end2end/tests/cancel_with_status.cc',
                       'test/core/end2end/tests/cancel_with_status.cc',
+                      'test/core/end2end/tests/channelz.cc',
                       'test/core/end2end/tests/compressed_payload.cc',
                       'test/core/end2end/tests/compressed_payload.cc',
                       'test/core/end2end/tests/connectivity.cc',
                       'test/core/end2end/tests/connectivity.cc',
                       'test/core/end2end/tests/default_host.cc',
                       'test/core/end2end/tests/default_host.cc',
@@ -1264,6 +1269,7 @@ Pod::Spec.new do |s|
 
 
   # TODO (mxyan): Instead of this hack, add include path "third_party" to C core's include path?
   # TODO (mxyan): Instead of this hack, add include path "third_party" to C core's include path?
   s.prepare_command = <<-END_OF_COMMAND
   s.prepare_command = <<-END_OF_COMMAND
-    find src/core/ -type f ! -path '*.back*' -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
+    find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
+    find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
   END_OF_COMMAND
   END_OF_COMMAND
 end
 end

+ 1 - 1
gRPC-ProtoRPC.podspec

@@ -21,7 +21,7 @@
 
 
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.13.0-dev'
+  version = '1.14.0-dev'
   s.version  = version
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
   s.homepage = 'https://grpc.io'

+ 1 - 1
gRPC-RxLibrary.podspec

@@ -21,7 +21,7 @@
 
 
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
   s.name     = 'gRPC-RxLibrary'
-  version = '1.13.0-dev'
+  version = '1.14.0-dev'
   s.version  = version
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
   s.homepage = 'https://grpc.io'

+ 1 - 1
gRPC.podspec

@@ -20,7 +20,7 @@
 
 
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
   s.name     = 'gRPC'
-  version = '1.13.0-dev'
+  version = '1.14.0-dev'
   s.version  = version
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
   s.homepage = 'https://grpc.io'

+ 0 - 2
grpc.def

@@ -45,8 +45,6 @@ EXPORTS
     grpc_insecure_channel_create
     grpc_insecure_channel_create
     grpc_lame_client_channel_create
     grpc_lame_client_channel_create
     grpc_channel_destroy
     grpc_channel_destroy
-    grpc_channel_get_trace
-    grpc_channel_get_uuid
     grpc_call_cancel
     grpc_call_cancel
     grpc_call_cancel_with_status
     grpc_call_cancel_with_status
     grpc_call_ref
     grpc_call_ref

+ 4 - 1
grpc.gemspec

@@ -294,6 +294,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/channel/channel_stack.h )
   s.files += %w( src/core/lib/channel/channel_stack.h )
   s.files += %w( src/core/lib/channel/channel_stack_builder.h )
   s.files += %w( src/core/lib/channel/channel_stack_builder.h )
   s.files += %w( src/core/lib/channel/channel_trace.h )
   s.files += %w( src/core/lib/channel/channel_trace.h )
+  s.files += %w( src/core/lib/channel/channelz.h )
   s.files += %w( src/core/lib/channel/channelz_registry.h )
   s.files += %w( src/core/lib/channel/channelz_registry.h )
   s.files += %w( src/core/lib/channel/connected_channel.h )
   s.files += %w( src/core/lib/channel/connected_channel.h )
   s.files += %w( src/core/lib/channel/context.h )
   s.files += %w( src/core/lib/channel/context.h )
@@ -444,6 +445,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/channel/channel_stack.cc )
   s.files += %w( src/core/lib/channel/channel_stack.cc )
   s.files += %w( src/core/lib/channel/channel_stack_builder.cc )
   s.files += %w( src/core/lib/channel/channel_stack_builder.cc )
   s.files += %w( src/core/lib/channel/channel_trace.cc )
   s.files += %w( src/core/lib/channel/channel_trace.cc )
+  s.files += %w( src/core/lib/channel/channelz.cc )
   s.files += %w( src/core/lib/channel/channelz_registry.cc )
   s.files += %w( src/core/lib/channel/channelz_registry.cc )
   s.files += %w( src/core/lib/channel/connected_channel.cc )
   s.files += %w( src/core/lib/channel/connected_channel.cc )
   s.files += %w( src/core/lib/channel/handshaker.cc )
   s.files += %w( src/core/lib/channel/handshaker.cc )
@@ -725,6 +727,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc )
@@ -732,7 +735,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc )
   s.files += %w( src/core/ext/filters/load_reporting/server_load_reporting_filter.cc )
   s.files += %w( src/core/ext/filters/load_reporting/server_load_reporting_filter.cc )
   s.files += %w( src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc )
   s.files += %w( src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc )
-  s.files += %w( src/core/ext/census/grpc_context.cc )
+  s.files += %w( src/cpp/ext/filters/census/grpc_context.cc )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.cc )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.cc )
   s.files += %w( src/core/ext/filters/message_size/message_size_filter.cc )
   s.files += %w( src/core/ext/filters/message_size/message_size_filter.cc )
   s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )
   s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )

+ 17 - 12
grpc.gyp

@@ -59,6 +59,8 @@
       '-Wno-unused-parameter',
       '-Wno-unused-parameter',
       '-DOSATOMIC_USE_INLINED=1',
       '-DOSATOMIC_USE_INLINED=1',
       '-Wno-deprecated-declarations',
       '-Wno-deprecated-declarations',
+      '-Ithird_party/nanopb',
+      '-DPB_FIELD_32BIT',
     ],
     ],
     'ldflags': [
     'ldflags': [
       '-g',
       '-g',
@@ -75,6 +77,7 @@
       '.',
       '.',
       '../..',
       '../..',
       'include',
       'include',
+      '../../third_party/nanopb',
     ],
     ],
     'defines': [
     'defines': [
       'GRPC_ARES=0',
       'GRPC_ARES=0',
@@ -137,6 +140,8 @@
             '-Wno-unused-parameter',
             '-Wno-unused-parameter',
             '-DOSATOMIC_USE_INLINED=1',
             '-DOSATOMIC_USE_INLINED=1',
             '-Wno-deprecated-declarations',
             '-Wno-deprecated-declarations',
+            '-Ithird_party/nanopb',
+            '-DPB_FIELD_32BIT',
           ],
           ],
           'OTHER_CPLUSPLUSFLAGS': [
           'OTHER_CPLUSPLUSFLAGS': [
             '-g',
             '-g',
@@ -147,6 +152,8 @@
             '-Wno-unused-parameter',
             '-Wno-unused-parameter',
             '-DOSATOMIC_USE_INLINED=1',
             '-DOSATOMIC_USE_INLINED=1',
             '-Wno-deprecated-declarations',
             '-Wno-deprecated-declarations',
+            '-Ithird_party/nanopb',
+            '-DPB_FIELD_32BIT',
             '-stdlib=libc++',
             '-stdlib=libc++',
             '-std=c++11',
             '-std=c++11',
             '-Wno-error=deprecated-declarations',
             '-Wno-error=deprecated-declarations',
@@ -249,6 +256,7 @@
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_trace.cc',
         'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channelz.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker.cc',
@@ -530,6 +538,7 @@
         'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
         'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
         'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
         'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
@@ -537,7 +546,7 @@
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
         'src/core/ext/filters/load_reporting/server_load_reporting_filter.cc',
         'src/core/ext/filters/load_reporting/server_load_reporting_filter.cc',
         'src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc',
         'src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc',
-        'src/core/ext/census/grpc_context.cc',
+        'src/cpp/ext/filters/census/grpc_context.cc',
         'src/core/ext/filters/max_age/max_age_filter.cc',
         'src/core/ext/filters/max_age/max_age_filter.cc',
         'src/core/ext/filters/message_size/message_size_filter.cc',
         'src/core/ext/filters/message_size/message_size_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
@@ -598,6 +607,7 @@
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_trace.cc',
         'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channelz.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker.cc',
@@ -829,6 +839,7 @@
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_trace.cc',
         'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channelz.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker.cc',
@@ -1038,6 +1049,7 @@
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
         'src/core/lib/channel/channel_trace.cc',
         'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channelz.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/channelz_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker.cc',
@@ -1240,6 +1252,7 @@
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
@@ -1259,7 +1272,7 @@
         'third_party/nanopb/pb_encode.c',
         'third_party/nanopb/pb_encode.c',
         'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
         'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
         'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
         'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
-        'src/core/ext/census/grpc_context.cc',
+        'src/cpp/ext/filters/census/grpc_context.cc',
         'src/core/ext/filters/max_age/max_age_filter.cc',
         'src/core/ext/filters/max_age/max_age_filter.cc',
         'src/core/ext/filters/message_size/message_size_filter.cc',
         'src/core/ext/filters/message_size/message_size_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
         'src/core/ext/filters/http/client_authority_filter.cc',
@@ -1636,16 +1649,6 @@
         'test/cpp/interop/interop_server_bootstrap.cc',
         'test/cpp/interop/interop_server_bootstrap.cc',
       ],
       ],
     },
     },
-    {
-      'target_name': 'lb_load_data_store',
-      'type': 'static_library',
-      'dependencies': [
-        'grpc++',
-      ],
-      'sources': [
-        'src/cpp/server/load_reporter/load_data_store.cc',
-      ],
-    },
     {
     {
       'target_name': 'qps',
       'target_name': 'qps',
       'type': 'static_library',
       'type': 'static_library',
@@ -2607,6 +2610,7 @@
         'test/core/end2end/tests/cancel_before_invoke.cc',
         'test/core/end2end/tests/cancel_before_invoke.cc',
         'test/core/end2end/tests/cancel_in_a_vacuum.cc',
         'test/core/end2end/tests/cancel_in_a_vacuum.cc',
         'test/core/end2end/tests/cancel_with_status.cc',
         'test/core/end2end/tests/cancel_with_status.cc',
+        'test/core/end2end/tests/channelz.cc',
         'test/core/end2end/tests/compressed_payload.cc',
         'test/core/end2end/tests/compressed_payload.cc',
         'test/core/end2end/tests/connectivity.cc',
         'test/core/end2end/tests/connectivity.cc',
         'test/core/end2end/tests/default_host.cc',
         'test/core/end2end/tests/default_host.cc',
@@ -2698,6 +2702,7 @@
         'test/core/end2end/tests/cancel_before_invoke.cc',
         'test/core/end2end/tests/cancel_before_invoke.cc',
         'test/core/end2end/tests/cancel_in_a_vacuum.cc',
         'test/core/end2end/tests/cancel_in_a_vacuum.cc',
         'test/core/end2end/tests/cancel_with_status.cc',
         'test/core/end2end/tests/cancel_with_status.cc',
+        'test/core/end2end/tests/channelz.cc',
         'test/core/end2end/tests/compressed_payload.cc',
         'test/core/end2end/tests/compressed_payload.cc',
         'test/core/end2end/tests/connectivity.cc',
         'test/core/end2end/tests/connectivity.cc',
         'test/core/end2end/tests/default_host.cc',
         'test/core/end2end/tests/default_host.cc',

+ 0 - 8
include/grpc/grpc.h

@@ -286,14 +286,6 @@ GRPCAPI grpc_channel* grpc_lame_client_channel_create(
 /** Close and destroy a grpc channel */
 /** Close and destroy a grpc channel */
 GRPCAPI void grpc_channel_destroy(grpc_channel* channel);
 GRPCAPI void grpc_channel_destroy(grpc_channel* channel);
 
 
-/** Returns the JSON formatted channel trace for this channel. The caller
-    owns the returned string and is responsible for freeing it. */
-GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel);
-
-/** Returns the channel uuid, which can be used to look up its trace at a
-    later time. */
-GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel);
-
 /** Error handling for grpc_call
 /** Error handling for grpc_call
    Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
    Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
    then the operation failed due to some unsatisfied precondition.
    then the operation failed due to some unsatisfied precondition.

+ 29 - 2
include/grpc/grpc_security.h

@@ -163,6 +163,26 @@ typedef struct {
   const char* cert_chain;
   const char* cert_chain;
 } grpc_ssl_pem_key_cert_pair;
 } grpc_ssl_pem_key_cert_pair;
 
 
+/** Object that holds additional peer-verification options on a secure
+   channel. */
+typedef struct {
+  /** If non-NULL this callback will be invoked with the expected
+     target_name, the peer's certificate (in PEM format), and whatever
+     userdata pointer is set below. If a non-zero value is returned by this
+     callback then it is treated as a verification failure. Invocation of
+     the callback is blocking, so any implementation should be light-weight.
+     */
+  int (*verify_peer_callback)(const char* target_name, const char* peer_pem,
+                              void* userdata);
+  /** Arbitrary userdata that will be passed as the last argument to
+     verify_peer_callback. */
+  void* verify_peer_callback_userdata;
+  /** A destruct callback that will be invoked when the channel is being
+     cleaned up. The userdata argument will be passed to it. The intent is
+     to perform any cleanup associated with that userdata. */
+  void (*verify_peer_destruct)(void* userdata);
+} verify_peer_options;
+
 /** Creates an SSL credentials object.
 /** Creates an SSL credentials object.
    - pem_root_certs is the NULL-terminated string containing the PEM encoding
    - pem_root_certs is the NULL-terminated string containing the PEM encoding
      of the server root certificates. If this parameter is NULL, the
      of the server root certificates. If this parameter is NULL, the
@@ -173,10 +193,17 @@ typedef struct {
      disk (in the grpc install directory).
      disk (in the grpc install directory).
    - pem_key_cert_pair is a pointer on the object containing client's private
    - pem_key_cert_pair is a pointer on the object containing client's private
      key and certificate chain. This parameter can be NULL if the client does
      key and certificate chain. This parameter can be NULL if the client does
-     not have such a key/cert pair. */
+     not have such a key/cert pair.
+   - verify_options is an optional verify_peer_options object which holds
+     additional options controlling how peer certificates are verified. For
+     example, you can supply a callback which receives the peer's certificate
+     with which you can do additional verification. Can be NULL, in which
+     case verification will retain default behavior. Any settings in
+     verify_options are copied during this call, so the verify_options
+     object can be released afterwards. */
 GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create(
 GRPCAPI grpc_channel_credentials* grpc_ssl_credentials_create(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-    void* reserved);
+    const verify_peer_options* verify_options, void* reserved);
 
 
 /** --- grpc_call_credentials object.
 /** --- grpc_call_credentials object.
 
 

+ 4 - 0
include/grpc/impl/codegen/grpc_types.h

@@ -289,6 +289,10 @@ typedef struct {
  * subchannel. The default is 10. If set to 0, channel tracing is disabled. */
  * subchannel. The default is 10. If set to 0, channel tracing is disabled. */
 #define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
 #define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
   "grpc.max_channel_trace_events_per_node"
   "grpc.max_channel_trace_events_per_node"
+/** If non-zero, gRPC library will track stats and information at at per channel
+ * level. Disabling channelz naturally disables channel tracing. The default
+ * is for channelz to be disabled. */
+#define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz"
 /** If non-zero, Cronet transport will coalesce packets to fewer frames
 /** If non-zero, Cronet transport will coalesce packets to fewer frames
  * when possible. */
  * when possible. */
 #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
 #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \

+ 2 - 2
include/grpcpp/impl/codegen/call.h

@@ -171,8 +171,8 @@ class WriteOptions {
     return *this;
     return *this;
   }
   }
 
 
-  /// Guarantee that all bytes have been written to the wire before completing
-  /// this write (usually writes are completed when they pass flow control)
+  /// Guarantee that all bytes have been written to the socket before completing
+  /// this write (usually writes are completed when they pass flow control).
   inline WriteOptions& set_write_through() {
   inline WriteOptions& set_write_through() {
     SetBit(GRPC_WRITE_THROUGH);
     SetBit(GRPC_WRITE_THROUGH);
     return *this;
     return *this;

+ 41 - 0
include/grpcpp/opencensus.h

@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_OPENCENSUS_H
+#define GRPCPP_OPENCENSUS_H
+
+namespace grpc {
+// These symbols in this file will not be included in the binary unless
+// grpc_opencensus_plugin build target was added as a dependency. At the moment
+// it is only setup to be built with Bazel.
+
+// Registers the OpenCensus plugin with gRPC, so that it will be used for future
+// RPCs. This must be called before any views are created.
+void RegisterOpenCensusPlugin();
+
+// RPC stats definitions, defined by
+// https://github.com/census-instrumentation/opencensus-specs/blob/master/stats/gRPC.md
+
+// Registers the cumulative gRPC views so that they will be exported by any
+// registered stats exporter. For on-task stats, construct a View using the
+// ViewDescriptors below.
+void RegisterOpenCensusViewsForExport();
+
+}  // namespace grpc
+
+#endif  // GRPCPP_OPENCENSUS_H

+ 2 - 2
include/grpcpp/server_builder.h

@@ -86,8 +86,8 @@ class ServerBuilder {
   /// \param creds The credentials associated with the server.
   /// \param creds The credentials associated with the server.
   /// \param selected_port[out] If not `nullptr`, gets populated with the port
   /// \param selected_port[out] If not `nullptr`, gets populated with the port
   /// number bound to the \a grpc::Server for the corresponding endpoint after
   /// number bound to the \a grpc::Server for the corresponding endpoint after
-  /// it is successfully bound, 0 otherwise.
-  ///
+  /// it is successfully bound by BuildAndStart(), 0 otherwise. AddListeningPort
+  /// does not modify this pointer.
   ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
   ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
                                   std::shared_ptr<ServerCredentials> creds,
                                   std::shared_ptr<ServerCredentials> creds,
                                   int* selected_port = nullptr);
                                   int* selected_port = nullptr);

+ 6 - 3
package.xml

@@ -13,8 +13,8 @@
  <date>2018-01-19</date>
  <date>2018-01-19</date>
  <time>16:06:07</time>
  <time>16:06:07</time>
  <version>
  <version>
-  <release>1.13.0dev</release>
-  <api>1.13.0dev</api>
+  <release>1.14.0dev</release>
+  <api>1.14.0dev</api>
  </version>
  </version>
  <stability>
  <stability>
   <release>beta</release>
   <release>beta</release>
@@ -299,6 +299,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channelz.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
@@ -449,6 +450,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channelz.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" />
@@ -730,6 +732,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc" role="src" />
@@ -737,7 +740,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/server_load_reporting_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/server_load_reporting_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/census/grpc_context.cc" role="src" />
+    <file baseinstalldir="/" name="src/cpp/ext/filters/census/grpc_context.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" />

+ 2 - 1
setup.py

@@ -37,6 +37,7 @@ PYTHON_STEM = os.path.join('src', 'python', 'grpcio')
 CORE_INCLUDE = ('include', '.',)
 CORE_INCLUDE = ('include', '.',)
 SSL_INCLUDE = (os.path.join('third_party', 'boringssl', 'include'),)
 SSL_INCLUDE = (os.path.join('third_party', 'boringssl', 'include'),)
 ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
 ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
+NANOPB_INCLUDE = (os.path.join('third_party', 'nanopb'),)
 CARES_INCLUDE = (
 CARES_INCLUDE = (
     os.path.join('third_party', 'cares'),
     os.path.join('third_party', 'cares'),
     os.path.join('third_party', 'cares', 'cares'),)
     os.path.join('third_party', 'cares', 'cares'),)
@@ -181,7 +182,7 @@ if BUILD_WITH_SYSTEM_CARES:
 
 
 EXTENSION_INCLUDE_DIRECTORIES = (
 EXTENSION_INCLUDE_DIRECTORIES = (
     (PYTHON_STEM,) + CORE_INCLUDE + SSL_INCLUDE + ZLIB_INCLUDE +
     (PYTHON_STEM,) + CORE_INCLUDE + SSL_INCLUDE + ZLIB_INCLUDE +
-    CARES_INCLUDE + ADDRESS_SORTING_INCLUDE)
+    NANOPB_INCLUDE + CARES_INCLUDE + ADDRESS_SORTING_INCLUDE)
 
 
 EXTENSION_LIBRARIES = ()
 EXTENSION_LIBRARIES = ()
 if "linux" in sys.platform:
 if "linux" in sys.platform:

+ 72 - 57
src/core/ext/filters/client_channel/client_channel.cc

@@ -794,6 +794,15 @@ typedef struct {
   // The batch to use in the subchannel call.
   // The batch to use in the subchannel call.
   // Its payload field points to subchannel_call_retry_state.batch_payload.
   // Its payload field points to subchannel_call_retry_state.batch_payload.
   grpc_transport_stream_op_batch batch;
   grpc_transport_stream_op_batch batch;
+  // For intercepting on_complete.
+  grpc_closure on_complete;
+} subchannel_batch_data;
+
+// Retry state associated with a subchannel call.
+// Stored in the parent_data of the subchannel call object.
+typedef struct {
+  // subchannel_batch_data.batch.payload points to this.
+  grpc_transport_stream_op_batch_payload batch_payload;
   // For send_initial_metadata.
   // For send_initial_metadata.
   // Note that we need to make a copy of the initial metadata for each
   // Note that we need to make a copy of the initial metadata for each
   // subchannel call instead of just referring to the copy in call_data,
   // subchannel call instead of just referring to the copy in call_data,
@@ -818,15 +827,6 @@ typedef struct {
   grpc_metadata_batch recv_trailing_metadata;
   grpc_metadata_batch recv_trailing_metadata;
   grpc_transport_stream_stats collect_stats;
   grpc_transport_stream_stats collect_stats;
   grpc_closure recv_trailing_metadata_ready;
   grpc_closure recv_trailing_metadata_ready;
-  // For intercepting on_complete.
-  grpc_closure on_complete;
-} subchannel_batch_data;
-
-// Retry state associated with a subchannel call.
-// Stored in the parent_data of the subchannel call object.
-typedef struct {
-  // subchannel_batch_data.batch.payload points to this.
-  grpc_transport_stream_op_batch_payload batch_payload;
   // These fields indicate which ops have been started and completed on
   // These fields indicate which ops have been started and completed on
   // this subchannel call.
   // this subchannel call.
   size_t started_send_message_count;
   size_t started_send_message_count;
@@ -1524,17 +1524,21 @@ static subchannel_batch_data* batch_data_create(grpc_call_element* elem,
 
 
 static void batch_data_unref(subchannel_batch_data* batch_data) {
 static void batch_data_unref(subchannel_batch_data* batch_data) {
   if (gpr_unref(&batch_data->refs)) {
   if (gpr_unref(&batch_data->refs)) {
-    if (batch_data->send_initial_metadata_storage != nullptr) {
-      grpc_metadata_batch_destroy(&batch_data->send_initial_metadata);
+    subchannel_call_retry_state* retry_state =
+        static_cast<subchannel_call_retry_state*>(
+            grpc_connected_subchannel_call_get_parent_data(
+                batch_data->subchannel_call));
+    if (batch_data->batch.send_initial_metadata) {
+      grpc_metadata_batch_destroy(&retry_state->send_initial_metadata);
     }
     }
-    if (batch_data->send_trailing_metadata_storage != nullptr) {
-      grpc_metadata_batch_destroy(&batch_data->send_trailing_metadata);
+    if (batch_data->batch.send_trailing_metadata) {
+      grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
     }
     }
     if (batch_data->batch.recv_initial_metadata) {
     if (batch_data->batch.recv_initial_metadata) {
-      grpc_metadata_batch_destroy(&batch_data->recv_initial_metadata);
+      grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata);
     }
     }
     if (batch_data->batch.recv_trailing_metadata) {
     if (batch_data->batch.recv_trailing_metadata) {
-      grpc_metadata_batch_destroy(&batch_data->recv_trailing_metadata);
+      grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata);
     }
     }
     GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref");
     GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref");
     call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
     call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
@@ -1560,8 +1564,12 @@ static void invoke_recv_initial_metadata_callback(void* arg,
       });
       });
   GPR_ASSERT(pending != nullptr);
   GPR_ASSERT(pending != nullptr);
   // Return metadata.
   // Return metadata.
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
   grpc_metadata_batch_move(
   grpc_metadata_batch_move(
-      &batch_data->recv_initial_metadata,
+      &retry_state->recv_initial_metadata,
       pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
       pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
   // Update bookkeeping.
   // Update bookkeeping.
   // Note: Need to do this before invoking the callback, since invoking
   // Note: Need to do this before invoking the callback, since invoking
@@ -1606,7 +1614,7 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
   // the recv_trailing_metadata_ready callback, then defer propagating this
   // the recv_trailing_metadata_ready callback, then defer propagating this
   // callback back to the surface.  We can evaluate whether to retry when
   // callback back to the surface.  We can evaluate whether to retry when
   // recv_trailing_metadata comes back.
   // recv_trailing_metadata comes back.
-  if (GPR_UNLIKELY((batch_data->trailing_metadata_available ||
+  if (GPR_UNLIKELY((retry_state->trailing_metadata_available ||
                     error != GRPC_ERROR_NONE) &&
                     error != GRPC_ERROR_NONE) &&
                    !retry_state->completed_recv_trailing_metadata)) {
                    !retry_state->completed_recv_trailing_metadata)) {
     if (grpc_client_channel_trace.enabled()) {
     if (grpc_client_channel_trace.enabled()) {
@@ -1651,8 +1659,12 @@ static void invoke_recv_message_callback(void* arg, grpc_error* error) {
       });
       });
   GPR_ASSERT(pending != nullptr);
   GPR_ASSERT(pending != nullptr);
   // Return payload.
   // Return payload.
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
   *pending->batch->payload->recv_message.recv_message =
   *pending->batch->payload->recv_message.recv_message =
-      std::move(batch_data->recv_message);
+      std::move(retry_state->recv_message);
   // Update bookkeeping.
   // Update bookkeeping.
   // Note: Need to do this before invoking the callback, since invoking
   // Note: Need to do this before invoking the callback, since invoking
   // the callback will result in yielding the call combiner.
   // the callback will result in yielding the call combiner.
@@ -1693,7 +1705,7 @@ static void recv_message_ready(void* arg, grpc_error* error) {
   // callback back to the surface.  We can evaluate whether to retry when
   // callback back to the surface.  We can evaluate whether to retry when
   // recv_trailing_metadata comes back.
   // recv_trailing_metadata comes back.
   if (GPR_UNLIKELY(
   if (GPR_UNLIKELY(
-          (batch_data->recv_message == nullptr || error != GRPC_ERROR_NONE) &&
+          (retry_state->recv_message == nullptr || error != GRPC_ERROR_NONE) &&
           !retry_state->completed_recv_trailing_metadata)) {
           !retry_state->completed_recv_trailing_metadata)) {
     if (grpc_client_channel_trace.enabled()) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_INFO,
       gpr_log(GPR_INFO,
@@ -1766,8 +1778,12 @@ static void add_closure_for_recv_trailing_metadata_ready(
     return;
     return;
   }
   }
   // Return metadata.
   // Return metadata.
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
   grpc_metadata_batch_move(
   grpc_metadata_batch_move(
-      &batch_data->recv_trailing_metadata,
+      &retry_state->recv_trailing_metadata,
       pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
       pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
   // Add closure.
   // Add closure.
   closures->Add(pending->batch->payload->recv_trailing_metadata
   closures->Add(pending->batch->payload->recv_trailing_metadata
@@ -1788,11 +1804,11 @@ static void add_closures_for_deferred_recv_callbacks(
     // Add closure for deferred recv_initial_metadata_ready.
     // Add closure for deferred recv_initial_metadata_ready.
     if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch !=
     if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch !=
                      nullptr)) {
                      nullptr)) {
-      GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready,
+      GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
                         invoke_recv_initial_metadata_callback,
                         invoke_recv_initial_metadata_callback,
                         retry_state->recv_initial_metadata_ready_deferred_batch,
                         retry_state->recv_initial_metadata_ready_deferred_batch,
                         grpc_schedule_on_exec_ctx);
                         grpc_schedule_on_exec_ctx);
-      closures->Add(&batch_data->recv_initial_metadata_ready,
+      closures->Add(&retry_state->recv_initial_metadata_ready,
                     retry_state->recv_initial_metadata_error,
                     retry_state->recv_initial_metadata_error,
                     "resuming recv_initial_metadata_ready");
                     "resuming recv_initial_metadata_ready");
       retry_state->recv_initial_metadata_ready_deferred_batch = nullptr;
       retry_state->recv_initial_metadata_ready_deferred_batch = nullptr;
@@ -1800,11 +1816,11 @@ static void add_closures_for_deferred_recv_callbacks(
     // Add closure for deferred recv_message_ready.
     // Add closure for deferred recv_message_ready.
     if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch !=
     if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch !=
                      nullptr)) {
                      nullptr)) {
-      GRPC_CLOSURE_INIT(&batch_data->recv_message_ready,
+      GRPC_CLOSURE_INIT(&retry_state->recv_message_ready,
                         invoke_recv_message_callback,
                         invoke_recv_message_callback,
                         retry_state->recv_message_ready_deferred_batch,
                         retry_state->recv_message_ready_deferred_batch,
                         grpc_schedule_on_exec_ctx);
                         grpc_schedule_on_exec_ctx);
-      closures->Add(&batch_data->recv_message_ready,
+      closures->Add(&retry_state->recv_message_ready,
                     retry_state->recv_message_error,
                     retry_state->recv_message_error,
                     "resuming recv_message_ready");
                     "resuming recv_message_ready");
       retry_state->recv_message_ready_deferred_batch = nullptr;
       retry_state->recv_message_ready_deferred_batch = nullptr;
@@ -2120,28 +2136,28 @@ static void add_retriable_send_initial_metadata_op(
   //
   //
   // If we've already completed one or more attempts, add the
   // If we've already completed one or more attempts, add the
   // grpc-retry-attempts header.
   // grpc-retry-attempts header.
-  batch_data->send_initial_metadata_storage =
+  retry_state->send_initial_metadata_storage =
       static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
       static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
           calld->arena, sizeof(grpc_linked_mdelem) *
           calld->arena, sizeof(grpc_linked_mdelem) *
                             (calld->send_initial_metadata.list.count +
                             (calld->send_initial_metadata.list.count +
                              (calld->num_attempts_completed > 0))));
                              (calld->num_attempts_completed > 0))));
   grpc_metadata_batch_copy(&calld->send_initial_metadata,
   grpc_metadata_batch_copy(&calld->send_initial_metadata,
-                           &batch_data->send_initial_metadata,
-                           batch_data->send_initial_metadata_storage);
-  if (GPR_UNLIKELY(batch_data->send_initial_metadata.idx.named
+                           &retry_state->send_initial_metadata,
+                           retry_state->send_initial_metadata_storage);
+  if (GPR_UNLIKELY(retry_state->send_initial_metadata.idx.named
                        .grpc_previous_rpc_attempts != nullptr)) {
                        .grpc_previous_rpc_attempts != nullptr)) {
-    grpc_metadata_batch_remove(
-        &batch_data->send_initial_metadata,
-        batch_data->send_initial_metadata.idx.named.grpc_previous_rpc_attempts);
+    grpc_metadata_batch_remove(&retry_state->send_initial_metadata,
+                               retry_state->send_initial_metadata.idx.named
+                                   .grpc_previous_rpc_attempts);
   }
   }
   if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) {
   if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) {
     grpc_mdelem retry_md = grpc_mdelem_from_slices(
     grpc_mdelem retry_md = grpc_mdelem_from_slices(
         GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
         GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
         *retry_count_strings[calld->num_attempts_completed - 1]);
         *retry_count_strings[calld->num_attempts_completed - 1]);
     grpc_error* error = grpc_metadata_batch_add_tail(
     grpc_error* error = grpc_metadata_batch_add_tail(
-        &batch_data->send_initial_metadata,
-        &batch_data->send_initial_metadata_storage[calld->send_initial_metadata
-                                                       .list.count],
+        &retry_state->send_initial_metadata,
+        &retry_state->send_initial_metadata_storage[calld->send_initial_metadata
+                                                        .list.count],
         retry_md);
         retry_md);
     if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
     if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
       gpr_log(GPR_ERROR, "error adding retry metadata: %s",
       gpr_log(GPR_ERROR, "error adding retry metadata: %s",
@@ -2152,7 +2168,7 @@ static void add_retriable_send_initial_metadata_op(
   retry_state->started_send_initial_metadata = true;
   retry_state->started_send_initial_metadata = true;
   batch_data->batch.send_initial_metadata = true;
   batch_data->batch.send_initial_metadata = true;
   batch_data->batch.payload->send_initial_metadata.send_initial_metadata =
   batch_data->batch.payload->send_initial_metadata.send_initial_metadata =
-      &batch_data->send_initial_metadata;
+      &retry_state->send_initial_metadata;
   batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
   batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
       calld->send_initial_metadata_flags;
       calld->send_initial_metadata_flags;
   batch_data->batch.payload->send_initial_metadata.peer_string =
   batch_data->batch.payload->send_initial_metadata.peer_string =
@@ -2173,10 +2189,10 @@ static void add_retriable_send_message_op(
   grpc_core::ByteStreamCache* cache =
   grpc_core::ByteStreamCache* cache =
       (*calld->send_messages)[retry_state->started_send_message_count];
       (*calld->send_messages)[retry_state->started_send_message_count];
   ++retry_state->started_send_message_count;
   ++retry_state->started_send_message_count;
-  batch_data->send_message.Init(cache);
+  retry_state->send_message.Init(cache);
   batch_data->batch.send_message = true;
   batch_data->batch.send_message = true;
   batch_data->batch.payload->send_message.send_message.reset(
   batch_data->batch.payload->send_message.send_message.reset(
-      batch_data->send_message.get());
+      retry_state->send_message.get());
 }
 }
 
 
 // Adds retriable send_trailing_metadata op to batch_data.
 // Adds retriable send_trailing_metadata op to batch_data.
@@ -2186,17 +2202,17 @@ static void add_retriable_send_trailing_metadata_op(
   // We need to make a copy of the metadata batch for each attempt, since
   // We need to make a copy of the metadata batch for each attempt, since
   // the filters in the subchannel stack may modify this batch, and we don't
   // the filters in the subchannel stack may modify this batch, and we don't
   // want those modifications to be passed forward to subsequent attempts.
   // want those modifications to be passed forward to subsequent attempts.
-  batch_data->send_trailing_metadata_storage =
+  retry_state->send_trailing_metadata_storage =
       static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
       static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
           calld->arena, sizeof(grpc_linked_mdelem) *
           calld->arena, sizeof(grpc_linked_mdelem) *
                             calld->send_trailing_metadata.list.count));
                             calld->send_trailing_metadata.list.count));
   grpc_metadata_batch_copy(&calld->send_trailing_metadata,
   grpc_metadata_batch_copy(&calld->send_trailing_metadata,
-                           &batch_data->send_trailing_metadata,
-                           batch_data->send_trailing_metadata_storage);
+                           &retry_state->send_trailing_metadata,
+                           retry_state->send_trailing_metadata_storage);
   retry_state->started_send_trailing_metadata = true;
   retry_state->started_send_trailing_metadata = true;
   batch_data->batch.send_trailing_metadata = true;
   batch_data->batch.send_trailing_metadata = true;
   batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata =
   batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata =
-      &batch_data->send_trailing_metadata;
+      &retry_state->send_trailing_metadata;
 }
 }
 
 
 // Adds retriable recv_initial_metadata op to batch_data.
 // Adds retriable recv_initial_metadata op to batch_data.
@@ -2205,16 +2221,16 @@ static void add_retriable_recv_initial_metadata_op(
     subchannel_batch_data* batch_data) {
     subchannel_batch_data* batch_data) {
   retry_state->started_recv_initial_metadata = true;
   retry_state->started_recv_initial_metadata = true;
   batch_data->batch.recv_initial_metadata = true;
   batch_data->batch.recv_initial_metadata = true;
-  grpc_metadata_batch_init(&batch_data->recv_initial_metadata);
+  grpc_metadata_batch_init(&retry_state->recv_initial_metadata);
   batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata =
   batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata =
-      &batch_data->recv_initial_metadata;
+      &retry_state->recv_initial_metadata;
   batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available =
   batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available =
-      &batch_data->trailing_metadata_available;
-  GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready,
+      &retry_state->trailing_metadata_available;
+  GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
                     recv_initial_metadata_ready, batch_data,
                     recv_initial_metadata_ready, batch_data,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
   batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready =
   batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready =
-      &batch_data->recv_initial_metadata_ready;
+      &retry_state->recv_initial_metadata_ready;
 }
 }
 
 
 // Adds retriable recv_message op to batch_data.
 // Adds retriable recv_message op to batch_data.
@@ -2224,11 +2240,11 @@ static void add_retriable_recv_message_op(
   ++retry_state->started_recv_message_count;
   ++retry_state->started_recv_message_count;
   batch_data->batch.recv_message = true;
   batch_data->batch.recv_message = true;
   batch_data->batch.payload->recv_message.recv_message =
   batch_data->batch.payload->recv_message.recv_message =
-      &batch_data->recv_message;
-  GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, recv_message_ready,
+      &retry_state->recv_message;
+  GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, recv_message_ready,
                     batch_data, grpc_schedule_on_exec_ctx);
                     batch_data, grpc_schedule_on_exec_ctx);
   batch_data->batch.payload->recv_message.recv_message_ready =
   batch_data->batch.payload->recv_message.recv_message_ready =
-      &batch_data->recv_message_ready;
+      &retry_state->recv_message_ready;
 }
 }
 
 
 // Adds retriable recv_trailing_metadata op to batch_data.
 // Adds retriable recv_trailing_metadata op to batch_data.
@@ -2237,16 +2253,17 @@ static void add_retriable_recv_trailing_metadata_op(
     subchannel_batch_data* batch_data) {
     subchannel_batch_data* batch_data) {
   retry_state->started_recv_trailing_metadata = true;
   retry_state->started_recv_trailing_metadata = true;
   batch_data->batch.recv_trailing_metadata = true;
   batch_data->batch.recv_trailing_metadata = true;
-  grpc_metadata_batch_init(&batch_data->recv_trailing_metadata);
+  grpc_metadata_batch_init(&retry_state->recv_trailing_metadata);
   batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata =
   batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata =
-      &batch_data->recv_trailing_metadata;
+      &retry_state->recv_trailing_metadata;
   batch_data->batch.payload->recv_trailing_metadata.collect_stats =
   batch_data->batch.payload->recv_trailing_metadata.collect_stats =
-      &batch_data->collect_stats;
-  GRPC_CLOSURE_INIT(&batch_data->recv_trailing_metadata_ready,
+      &retry_state->collect_stats;
+  GRPC_CLOSURE_INIT(&retry_state->recv_trailing_metadata_ready,
                     recv_trailing_metadata_ready, batch_data,
                     recv_trailing_metadata_ready, batch_data,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
   batch_data->batch.payload->recv_trailing_metadata
   batch_data->batch.payload->recv_trailing_metadata
-      .recv_trailing_metadata_ready = &batch_data->recv_trailing_metadata_ready;
+      .recv_trailing_metadata_ready =
+      &retry_state->recv_trailing_metadata_ready;
 }
 }
 
 
 // Helper function used to start a recv_trailing_metadata batch.  This
 // Helper function used to start a recv_trailing_metadata batch.  This
@@ -2400,11 +2417,9 @@ static void add_subchannel_batches_for_pending_batches(
         // started subchannel batch, since we'll propagate the
         // started subchannel batch, since we'll propagate the
         // completion when it completes.
         // completion when it completes.
         if (retry_state->completed_recv_trailing_metadata) {
         if (retry_state->completed_recv_trailing_metadata) {
-          subchannel_batch_data* batch_data =
-              retry_state->recv_trailing_metadata_internal_batch;
           // Batches containing recv_trailing_metadata always succeed.
           // Batches containing recv_trailing_metadata always succeed.
           closures->Add(
           closures->Add(
-              &batch_data->recv_trailing_metadata_ready, GRPC_ERROR_NONE,
+              &retry_state->recv_trailing_metadata_ready, GRPC_ERROR_NONE,
               "re-executing recv_trailing_metadata_ready to propagate "
               "re-executing recv_trailing_metadata_ready to propagate "
               "internally triggered result");
               "internally triggered result");
         } else {
         } else {

+ 9 - 5
src/core/ext/filters/client_channel/http_proxy.cc

@@ -37,17 +37,21 @@
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/b64.h"
 
 
 /**
 /**
- * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or
- * nullptr on error. Also sets 'user_cred' to user credentials if present in the
- * 'http_proxy' env var, otherwise leaves it unchanged. It is caller's
- * responsibility to gpr_free user_cred.
+ * Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the
+ * proxy hostname to resolve or nullptr on error. Also sets 'user_cred' to user
+ * credentials if present in the 'http_proxy' env var, otherwise leaves it
+ * unchanged. It is caller's responsibility to gpr_free user_cred.
  */
  */
 static char* get_http_proxy_server(char** user_cred) {
 static char* get_http_proxy_server(char** user_cred) {
   GPR_ASSERT(user_cred != nullptr);
   GPR_ASSERT(user_cred != nullptr);
   char* proxy_name = nullptr;
   char* proxy_name = nullptr;
-  char* uri_str = gpr_getenv("http_proxy");
   char** authority_strs = nullptr;
   char** authority_strs = nullptr;
   size_t authority_nstrs;
   size_t authority_nstrs;
+  /* Prefer using 'https_proxy'. Fallback on 'http_proxy' if it is not set. The
+   * fallback behavior can be removed if there's a demand for it.
+   */
+  char* uri_str = gpr_getenv("https_proxy");
+  if (uri_str == nullptr) uri_str = gpr_getenv("http_proxy");
   if (uri_str == nullptr) return nullptr;
   if (uri_str == nullptr) return nullptr;
   grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
   grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
   if (uri == nullptr || uri->authority == nullptr) {
   if (uri == nullptr || uri->authority == nullptr) {

+ 2 - 2
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc

@@ -18,9 +18,9 @@
 
 
 #include <grpc/support/port_platform.h>
 #include <grpc/support/port_platform.h>
 
 
+#include "pb_decode.h"
+#include "pb_encode.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
-#include "third_party/nanopb/pb_decode.h"
-#include "third_party/nanopb/pb_encode.h"
 
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/alloc.h>
 
 

+ 1 - 1
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h

@@ -3,7 +3,7 @@
 
 
 #ifndef PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
 #ifndef PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
 #define PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
 #define PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
-#include "third_party/nanopb/pb.h"
+#include "pb.h"
 /* @@protoc_insertion_point(includes) */
 /* @@protoc_insertion_point(includes) */
 #if PB_PROTO_HEADER_VERSION != 30
 #if PB_PROTO_HEADER_VERSION != 30
 #error Regenerate this file with the current version of nanopb generator.
 #error Regenerate this file with the current version of nanopb generator.

+ 2 - 2
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc

@@ -414,10 +414,10 @@ void AresDnsResolver::StartResolvingLocked() {
   resolving_ = true;
   resolving_ = true;
   lb_addresses_ = nullptr;
   lb_addresses_ = nullptr;
   service_config_json_ = nullptr;
   service_config_json_ = nullptr;
-  pending_request_ = grpc_dns_lookup_ares(
+  pending_request_ = grpc_dns_lookup_ares_locked(
       dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
       dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
       &on_resolved_, &lb_addresses_, true /* check_grpclb */,
       &on_resolved_, &lb_addresses_, true /* check_grpclb */,
-      request_service_config_ ? &service_config_json_ : nullptr);
+      request_service_config_ ? &service_config_json_ : nullptr, combiner());
   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
   last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
 }
 }
 
 

+ 311 - 0
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc

@@ -0,0 +1,311 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER)
+
+#include <ares.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "src/core/ext/filters/client_channel/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 "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/lib/gpr/string.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"
+
+typedef struct fd_node {
+  /** the owner of this fd node */
+  grpc_ares_ev_driver* ev_driver;
+  /** a closure wrapping on_readable_locked, which should be
+     invoked when the grpc_fd in this node becomes readable. */
+  grpc_closure read_closure;
+  /** a closure wrapping on_writable_locked, 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;
+
+  /** wrapped fd that's polled by grpc's poller for the current platform */
+  grpc_core::GrpcPolledFd* grpc_polled_fd;
+  /** if the readable closure has been registered */
+  bool readable_registered;
+  /** if the writable closure has been registered */
+  bool writable_registered;
+  /** if the fd has been shutdown yet from grpc iomgr perspective */
+  bool already_shutdown;
+} 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;
+
+  /** combiner to synchronize c-ares and I/O callbacks on */
+  grpc_combiner* combiner;
+  /** 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_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 == nullptr);
+    GRPC_COMBINER_UNREF(ev_driver->combiner, "free ares event driver");
+    ares_destroy(ev_driver->channel);
+    gpr_free(ev_driver);
+  }
+}
+
+static void fd_node_destroy_locked(fd_node* fdn) {
+  gpr_log(GPR_DEBUG, "delete fd: %s", fdn->grpc_polled_fd->GetName());
+  GPR_ASSERT(!fdn->readable_registered);
+  GPR_ASSERT(!fdn->writable_registered);
+  GPR_ASSERT(fdn->already_shutdown);
+  grpc_core::Delete(fdn->grpc_polled_fd);
+  gpr_free(fdn);
+}
+
+static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) {
+  if (!fdn->already_shutdown) {
+    fdn->already_shutdown = true;
+    fdn->grpc_polled_fd->ShutdownLocked(
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING(reason));
+  }
+}
+
+grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
+                                              grpc_pollset_set* pollset_set,
+                                              grpc_combiner* combiner) {
+  *ev_driver = static_cast<grpc_ares_ev_driver*>(
+      gpr_malloc(sizeof(grpc_ares_ev_driver)));
+  ares_options opts;
+  memset(&opts, 0, sizeof(opts));
+  opts.flags |= ARES_FLAG_STAYOPEN;
+  int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS);
+  grpc_core::ConfigureAresChannelLocked(&(*ev_driver)->channel);
+  gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create_locked");
+  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;
+  }
+  (*ev_driver)->combiner = GRPC_COMBINER_REF(combiner, "ares event driver");
+  gpr_ref_init(&(*ev_driver)->refs, 1);
+  (*ev_driver)->pollset_set = pollset_set;
+  (*ev_driver)->fds = nullptr;
+  (*ev_driver)->working = false;
+  (*ev_driver)->shutting_down = false;
+  return GRPC_ERROR_NONE;
+}
+
+void grpc_ares_ev_driver_destroy_locked(grpc_ares_ev_driver* ev_driver) {
+  // 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.
+  ev_driver->shutting_down = true;
+  grpc_ares_ev_driver_unref(ev_driver);
+}
+
+void grpc_ares_ev_driver_shutdown_locked(grpc_ares_ev_driver* ev_driver) {
+  ev_driver->shutting_down = true;
+  fd_node* fn = ev_driver->fds;
+  while (fn != nullptr) {
+    fd_node_shutdown_locked(fn, "grpc_ares_ev_driver_shutdown");
+    fn = fn->next;
+  }
+}
+
+// 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_locked(fd_node** head, ares_socket_t as) {
+  fd_node dummy_head;
+  dummy_head.next = *head;
+  fd_node* node = &dummy_head;
+  while (node->next != nullptr) {
+    if (node->next->grpc_polled_fd->GetWrappedAresSocketLocked() == as) {
+      fd_node* ret = node->next;
+      node->next = node->next->next;
+      *head = dummy_head.next;
+      return ret;
+    }
+    node = node->next;
+  }
+  return nullptr;
+}
+
+static void on_readable_locked(void* arg, grpc_error* error) {
+  fd_node* fdn = static_cast<fd_node*>(arg);
+  grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
+  const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
+  fdn->readable_registered = false;
+  gpr_log(GPR_DEBUG, "readable on %s", fdn->grpc_polled_fd->GetName());
+  if (error == GRPC_ERROR_NONE) {
+    do {
+      ares_process_fd(ev_driver->channel, as, ARES_SOCKET_BAD);
+    } while (fdn->grpc_polled_fd->IsFdStillReadableLocked());
+  } 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);
+  }
+  grpc_ares_notify_on_event_locked(ev_driver);
+  grpc_ares_ev_driver_unref(ev_driver);
+}
+
+static void on_writable_locked(void* arg, grpc_error* error) {
+  fd_node* fdn = static_cast<fd_node*>(arg);
+  grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
+  const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
+  fdn->writable_registered = false;
+  gpr_log(GPR_DEBUG, "writable on %s", fdn->grpc_polled_fd->GetName());
+  if (error == GRPC_ERROR_NONE) {
+    ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, as);
+  } 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);
+  }
+  grpc_ares_notify_on_event_locked(ev_driver);
+  grpc_ares_ev_driver_unref(ev_driver);
+}
+
+ares_channel* grpc_ares_ev_driver_get_channel_locked(
+    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_ares_ev_driver* ev_driver) {
+  fd_node* new_list = nullptr;
+  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_locked(&ev_driver->fds, socks[i]);
+        // Create a new fd_node if sock[i] is not in the fd_node list.
+        if (fdn == nullptr) {
+          fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
+          fdn->grpc_polled_fd = grpc_core::NewGrpcPolledFdLocked(
+              socks[i], ev_driver->pollset_set);
+          gpr_log(GPR_DEBUG, "new fd: %s", fdn->grpc_polled_fd->GetName());
+          fdn->ev_driver = ev_driver;
+          fdn->readable_registered = false;
+          fdn->writable_registered = false;
+          fdn->already_shutdown = false;
+          GRPC_CLOSURE_INIT(&fdn->read_closure, on_readable_locked, fdn,
+                            grpc_combiner_scheduler(ev_driver->combiner));
+          GRPC_CLOSURE_INIT(&fdn->write_closure, on_writable_locked, fdn,
+                            grpc_combiner_scheduler(ev_driver->combiner));
+        }
+        fdn->next = new_list;
+        new_list = fdn;
+        // 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: %s",
+                  fdn->grpc_polled_fd->GetName());
+          fdn->grpc_polled_fd->RegisterForOnReadableLocked(&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: %s",
+                  fdn->grpc_polled_fd->GetName());
+          grpc_ares_ev_driver_ref(ev_driver);
+          fdn->grpc_polled_fd->RegisterForOnWriteableLocked(
+              &fdn->write_closure);
+          fdn->writable_registered = true;
+        }
+      }
+    }
+  }
+  // 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 != nullptr) {
+    fd_node* cur = ev_driver->fds;
+    ev_driver->fds = ev_driver->fds->next;
+    fd_node_shutdown_locked(cur, "c-ares fd shutdown");
+    if (!cur->readable_registered && !cur->writable_registered) {
+      fd_node_destroy_locked(cur);
+    } else {
+      cur->next = new_list;
+      new_list = cur;
+    }
+  }
+  ev_driver->fds = new_list;
+  // If the ev driver has no working fd, all the tasks are done.
+  if (new_list == nullptr) {
+    ev_driver->working = false;
+    gpr_log(GPR_DEBUG, "ev driver stop working");
+  }
+}
+
+void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
+  if (!ev_driver->working) {
+    ev_driver->working = true;
+    grpc_ares_notify_on_event_locked(ev_driver);
+  }
+}
+
+#endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */

+ 44 - 6
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h

@@ -22,6 +22,7 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/port_platform.h>
 
 
 #include <ares.h>
 #include <ares.h>
+#include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
 
 typedef struct grpc_ares_ev_driver grpc_ares_ev_driver;
 typedef struct grpc_ares_ev_driver grpc_ares_ev_driver;
@@ -29,25 +30,62 @@ 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
 /* 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
    done, or grpc_ares_ev_driver_destroy() is called. It may notify the callbacks
    bound to its ares_channel when necessary. */
    bound to its ares_channel when necessary. */
-void grpc_ares_ev_driver_start(grpc_ares_ev_driver* ev_driver);
+void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver);
 
 
 /* Returns the ares_channel owned by \a ev_driver. To bind a c-ares query to
 /* 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
    \a ev_driver, use the ares_channel owned by \a ev_driver as the arg of the
    query. */
    query. */
-ares_channel* grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver* ev_driver);
+ares_channel* grpc_ares_ev_driver_get_channel_locked(
+    grpc_ares_ev_driver* ev_driver);
 
 
 /* Creates a new grpc_ares_ev_driver. Returns GRPC_ERROR_NONE if \a ev_driver is
 /* Creates a new grpc_ares_ev_driver. Returns GRPC_ERROR_NONE if \a ev_driver is
    created successfully. */
    created successfully. */
-grpc_error* grpc_ares_ev_driver_create(grpc_ares_ev_driver** ev_driver,
-                                       grpc_pollset_set* pollset_set);
+grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
+                                              grpc_pollset_set* pollset_set,
+                                              grpc_combiner* combiner);
 
 
 /* Destroys \a ev_driver asynchronously. Pending lookups made on \a ev_driver
 /* 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
    will be cancelled and their on_done callbacks will be invoked with a status
    of ARES_ECANCELLED. */
    of ARES_ECANCELLED. */
-void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver* ev_driver);
+void grpc_ares_ev_driver_destroy_locked(grpc_ares_ev_driver* ev_driver);
 
 
 /* Shutdown all the grpc_fds used by \a ev_driver */
 /* Shutdown all the grpc_fds used by \a ev_driver */
-void grpc_ares_ev_driver_shutdown(grpc_ares_ev_driver* ev_driver);
+void grpc_ares_ev_driver_shutdown_locked(grpc_ares_ev_driver* ev_driver);
+
+namespace grpc_core {
+
+/* A wrapped fd that integrates with the grpc iomgr of the current platform.
+ * A GrpcPolledFd knows how to create grpc platform-specific iomgr endpoints
+ * from "ares_socket_t" sockets, and then sign up for readability/writeability
+ * with that poller, and do shutdown and destruction. */
+class GrpcPolledFd {
+ public:
+  virtual ~GrpcPolledFd() {}
+  /* Called when c-ares library is interested and there's no pending callback */
+  virtual void RegisterForOnReadableLocked(grpc_closure* read_closure)
+      GRPC_ABSTRACT;
+  /* Called when c-ares library is interested and there's no pending callback */
+  virtual void RegisterForOnWriteableLocked(grpc_closure* write_closure)
+      GRPC_ABSTRACT;
+  /* Indicates if there is data left even after just being read from */
+  virtual bool IsFdStillReadableLocked() GRPC_ABSTRACT;
+  /* Called once and only once. Must cause cancellation of any pending
+   * read/write callbacks. */
+  virtual void ShutdownLocked(grpc_error* error) GRPC_ABSTRACT;
+  /* Get the underlying ares_socket_t that this was created from */
+  virtual ares_socket_t GetWrappedAresSocketLocked() GRPC_ABSTRACT;
+  /* A unique name, for logging */
+  virtual const char* GetName() GRPC_ABSTRACT;
+
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+/* Creates a new wrapped fd for the current platform */
+GrpcPolledFd* NewGrpcPolledFdLocked(ares_socket_t as,
+                                    grpc_pollset_set* driver_pollset_set);
+void ConfigureAresChannelLocked(ares_channel* channel);
+
+}  // namespace grpc_core
 
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \
         */
         */

+ 38 - 289
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc

@@ -36,311 +36,60 @@
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 
 
-typedef struct fd_node {
-  /** the owner of this fd node */
-  grpc_ares_ev_driver* ev_driver;
-  /** 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;
-  /** the grpc_fd owned by this fd node */
-  grpc_fd* fd;
-  /** if the readable closure has been registered */
-  bool readable_registered;
-  /** if the writable closure has been registered */
-  bool writable_registered;
-  /** if the fd has been shutdown yet from grpc iomgr perspective */
-  bool already_shutdown;
-} 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_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 == nullptr);
-    gpr_mu_destroy(&ev_driver->mu);
-    ares_destroy(ev_driver->channel);
-    gpr_free(ev_driver);
+namespace grpc_core {
+
+class GrpcPolledFdPosix : public GrpcPolledFd {
+ public:
+  GrpcPolledFdPosix(ares_socket_t as, grpc_pollset_set* driver_pollset_set)
+      : as_(as) {
+    gpr_asprintf(&name_, "c-ares fd: %d", (int)as);
+    fd_ = grpc_fd_create((int)as, name_, false);
+    grpc_pollset_set_add_fd(driver_pollset_set, fd_);
   }
   }
-}
-
-static void fd_node_destroy(fd_node* fdn) {
-  gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->fd));
-  GPR_ASSERT(!fdn->readable_registered);
-  GPR_ASSERT(!fdn->writable_registered);
-  GPR_ASSERT(fdn->already_shutdown);
-  gpr_mu_destroy(&fdn->mu);
-  /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up
-     immediately by another thread, and should not be closed by the following
-     grpc_fd_orphan. */
-  int dummy_release_fd;
-  grpc_fd_orphan(fdn->fd, nullptr, &dummy_release_fd, "c-ares query finished");
-  gpr_free(fdn);
-}
 
 
-static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) {
-  if (!fdn->already_shutdown) {
-    fdn->already_shutdown = true;
-    grpc_fd_shutdown(fdn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(reason));
+  ~GrpcPolledFdPosix() {
+    gpr_free(name_);
+    /* c-ares library will close the fd inside grpc_fd. This fd may be picked up
+       immediately by another thread, and should not be closed by the following
+       grpc_fd_orphan. */
+    int dummy_release_fd;
+    grpc_fd_orphan(fd_, nullptr, &dummy_release_fd, "c-ares query finished");
   }
   }
-}
 
 
-grpc_error* grpc_ares_ev_driver_create(grpc_ares_ev_driver** ev_driver,
-                                       grpc_pollset_set* pollset_set) {
-  *ev_driver = static_cast<grpc_ares_ev_driver*>(
-      gpr_malloc(sizeof(grpc_ares_ev_driver)));
-  ares_options opts;
-  memset(&opts, 0, sizeof(opts));
-  opts.flags |= ARES_FLAG_STAYOPEN;
-  int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS);
-  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;
+  void RegisterForOnReadableLocked(grpc_closure* read_closure) override {
+    grpc_fd_notify_on_read(fd_, read_closure);
   }
   }
-  gpr_mu_init(&(*ev_driver)->mu);
-  gpr_ref_init(&(*ev_driver)->refs, 1);
-  (*ev_driver)->pollset_set = pollset_set;
-  (*ev_driver)->fds = nullptr;
-  (*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);
-}
+  void RegisterForOnWriteableLocked(grpc_closure* write_closure) override {
+    grpc_fd_notify_on_write(fd_, write_closure);
+  }
 
 
-void grpc_ares_ev_driver_shutdown(grpc_ares_ev_driver* ev_driver) {
-  gpr_mu_lock(&ev_driver->mu);
-  ev_driver->shutting_down = true;
-  fd_node* fn = ev_driver->fds;
-  while (fn != nullptr) {
-    gpr_mu_lock(&fn->mu);
-    fd_node_shutdown_locked(fn, "grpc_ares_ev_driver_shutdown");
-    gpr_mu_unlock(&fn->mu);
-    fn = fn->next;
+  bool IsFdStillReadableLocked() override {
+    size_t bytes_available = 0;
+    return ioctl(grpc_fd_wrapped_fd(fd_), FIONREAD, &bytes_available) == 0 &&
+           bytes_available > 0;
   }
   }
-  gpr_mu_unlock(&ev_driver->mu);
-}
 
 
-// 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 != nullptr) {
-    if (grpc_fd_wrapped_fd(node->next->fd) == fd) {
-      fd_node* ret = node->next;
-      node->next = node->next->next;
-      *head = dummy_head.next;
-      return ret;
-    }
-    node = node->next;
+  void ShutdownLocked(grpc_error* error) override {
+    grpc_fd_shutdown(fd_, error);
   }
   }
-  return nullptr;
-}
 
 
-/* Check if \a fd is still readable */
-static bool grpc_ares_is_fd_still_readable(grpc_ares_ev_driver* ev_driver,
-                                           int fd) {
-  size_t bytes_available = 0;
-  return ioctl(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0;
-}
+  ares_socket_t GetWrappedAresSocketLocked() override { return as_; }
 
 
-static void on_readable_cb(void* arg, grpc_error* error) {
-  fd_node* fdn = static_cast<fd_node*>(arg);
-  grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
-  gpr_mu_lock(&fdn->mu);
-  const int fd = grpc_fd_wrapped_fd(fdn->fd);
-  fdn->readable_registered = false;
-  gpr_mu_unlock(&fdn->mu);
-  gpr_log(GPR_DEBUG, "readable on %d", fd);
-  if (error == GRPC_ERROR_NONE) {
-    do {
-      ares_process_fd(ev_driver->channel, fd, ARES_SOCKET_BAD);
-    } while (grpc_ares_is_fd_still_readable(ev_driver, 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(ev_driver);
-  gpr_mu_unlock(&ev_driver->mu);
-  grpc_ares_ev_driver_unref(ev_driver);
-}
+  const char* GetName() override { return name_; }
 
 
-static void on_writable_cb(void* arg, grpc_error* error) {
-  fd_node* fdn = static_cast<fd_node*>(arg);
-  grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
-  gpr_mu_lock(&fdn->mu);
-  const int fd = grpc_fd_wrapped_fd(fdn->fd);
-  fdn->writable_registered = false;
-  gpr_mu_unlock(&fdn->mu);
-  gpr_log(GPR_DEBUG, "writable on %d", fd);
-  if (error == GRPC_ERROR_NONE) {
-    ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, 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(ev_driver);
-  gpr_mu_unlock(&ev_driver->mu);
-  grpc_ares_ev_driver_unref(ev_driver);
-}
+  char* name_;
+  ares_socket_t as_;
+  grpc_fd* fd_;
+};
 
 
-ares_channel* grpc_ares_ev_driver_get_channel(grpc_ares_ev_driver* ev_driver) {
-  return &ev_driver->channel;
+GrpcPolledFd* NewGrpcPolledFdLocked(ares_socket_t as,
+                                    grpc_pollset_set* driver_pollset_set) {
+  return grpc_core::New<GrpcPolledFdPosix>(as, driver_pollset_set);
 }
 }
 
 
-// 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_ares_ev_driver* ev_driver) {
-  fd_node* new_list = nullptr;
-  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 == nullptr) {
-          char* fd_name;
-          gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
-          fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
-          gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
-          fdn->fd = grpc_fd_create(socks[i], fd_name, false);
-          fdn->ev_driver = ev_driver;
-          fdn->readable_registered = false;
-          fdn->writable_registered = false;
-          fdn->already_shutdown = 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(ev_driver->pollset_set, fdn->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->fd));
-          grpc_fd_notify_on_read(fdn->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->fd));
-          grpc_ares_ev_driver_ref(ev_driver);
-          grpc_fd_notify_on_write(fdn->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 != nullptr) {
-    fd_node* cur = ev_driver->fds;
-    ev_driver->fds = ev_driver->fds->next;
-    gpr_mu_lock(&cur->mu);
-    fd_node_shutdown_locked(cur, "c-ares fd shutdown");
-    if (!cur->readable_registered && !cur->writable_registered) {
-      gpr_mu_unlock(&cur->mu);
-      fd_node_destroy(cur);
-    } else {
-      cur->next = new_list;
-      new_list = cur;
-      gpr_mu_unlock(&cur->mu);
-    }
-  }
-  ev_driver->fds = new_list;
-  // If the ev driver has no working fd, all the tasks are done.
-  if (new_list == nullptr) {
-    ev_driver->working = false;
-    gpr_log(GPR_DEBUG, "ev driver stop working");
-  }
-}
+void ConfigureAresChannelLocked(ares_channel* channel) {}
 
 
-void grpc_ares_ev_driver_start(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(ev_driver);
-  }
-  gpr_mu_unlock(&ev_driver->mu);
-}
+}  // namespace grpc_core
 
 
 #endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */
 #endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */

+ 88 - 67
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc

@@ -65,8 +65,6 @@ struct grpc_ares_request {
   /** number of ongoing queries */
   /** number of ongoing queries */
   gpr_refcount pending_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 */
   /** is there at least one successful query, set in on_done_cb */
   bool success;
   bool success;
   /** the errors explaining the request failure, set in on_done_cb */
   /** the errors explaining the request failure, set in on_done_cb */
@@ -74,7 +72,8 @@ struct grpc_ares_request {
 };
 };
 
 
 typedef struct grpc_ares_hostbyname_request {
 typedef struct grpc_ares_hostbyname_request {
-  /** following members are set in create_hostbyname_request */
+  /** following members are set in create_hostbyname_request_locked
+   */
   /** the top-level request instance */
   /** the top-level request instance */
   grpc_ares_request* parent_request;
   grpc_ares_request* parent_request;
   /** host to resolve, parsed from the name to resolve */
   /** host to resolve, parsed from the name to resolve */
@@ -96,10 +95,6 @@ static uint16_t strhtons(const char* port) {
   return htons(static_cast<unsigned short>(atoi(port)));
   return htons(static_cast<unsigned short>(atoi(port)));
 }
 }
 
 
-static void grpc_ares_request_ref(grpc_ares_request* r) {
-  gpr_ref(&r->pending_queries);
-}
-
 static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
 static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
                                      const char* input_output_str) {
                                      const char* input_output_str) {
   for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
   for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
@@ -149,7 +144,11 @@ void grpc_cares_wrapper_test_only_address_sorting_sort(
   grpc_cares_wrapper_address_sorting_sort(lb_addrs);
   grpc_cares_wrapper_address_sorting_sort(lb_addrs);
 }
 }
 
 
-static void grpc_ares_request_unref(grpc_ares_request* r) {
+static void grpc_ares_request_ref_locked(grpc_ares_request* r) {
+  gpr_ref(&r->pending_queries);
+}
+
+static void grpc_ares_request_unref_locked(grpc_ares_request* r) {
   /* If there are no pending queries, invoke on_done callback and destroy the
   /* If there are no pending queries, invoke on_done callback and destroy the
      request */
      request */
   if (gpr_unref(&r->pending_queries)) {
   if (gpr_unref(&r->pending_queries)) {
@@ -158,13 +157,12 @@ static void grpc_ares_request_unref(grpc_ares_request* r) {
       grpc_cares_wrapper_address_sorting_sort(lb_addrs);
       grpc_cares_wrapper_address_sorting_sort(lb_addrs);
     }
     }
     GRPC_CLOSURE_SCHED(r->on_done, r->error);
     GRPC_CLOSURE_SCHED(r->on_done, r->error);
-    gpr_mu_destroy(&r->mu);
-    grpc_ares_ev_driver_destroy(r->ev_driver);
+    grpc_ares_ev_driver_destroy_locked(r->ev_driver);
     gpr_free(r);
     gpr_free(r);
   }
   }
 }
 }
 
 
-static grpc_ares_hostbyname_request* create_hostbyname_request(
+static grpc_ares_hostbyname_request* create_hostbyname_request_locked(
     grpc_ares_request* parent_request, char* host, uint16_t port,
     grpc_ares_request* parent_request, char* host, uint16_t port,
     bool is_balancer) {
     bool is_balancer) {
   grpc_ares_hostbyname_request* hr = static_cast<grpc_ares_hostbyname_request*>(
   grpc_ares_hostbyname_request* hr = static_cast<grpc_ares_hostbyname_request*>(
@@ -173,22 +171,22 @@ static grpc_ares_hostbyname_request* create_hostbyname_request(
   hr->host = gpr_strdup(host);
   hr->host = gpr_strdup(host);
   hr->port = port;
   hr->port = port;
   hr->is_balancer = is_balancer;
   hr->is_balancer = is_balancer;
-  grpc_ares_request_ref(parent_request);
+  grpc_ares_request_ref_locked(parent_request);
   return hr;
   return hr;
 }
 }
 
 
-static void destroy_hostbyname_request(grpc_ares_hostbyname_request* hr) {
-  grpc_ares_request_unref(hr->parent_request);
+static void destroy_hostbyname_request_locked(
+    grpc_ares_hostbyname_request* hr) {
+  grpc_ares_request_unref_locked(hr->parent_request);
   gpr_free(hr->host);
   gpr_free(hr->host);
   gpr_free(hr);
   gpr_free(hr);
 }
 }
 
 
-static void on_hostbyname_done_cb(void* arg, int status, int timeouts,
-                                  struct hostent* hostent) {
+static void on_hostbyname_done_locked(void* arg, int status, int timeouts,
+                                      struct hostent* hostent) {
   grpc_ares_hostbyname_request* hr =
   grpc_ares_hostbyname_request* hr =
       static_cast<grpc_ares_hostbyname_request*>(arg);
       static_cast<grpc_ares_hostbyname_request*>(arg);
   grpc_ares_request* r = hr->parent_request;
   grpc_ares_request* r = hr->parent_request;
-  gpr_mu_lock(&r->mu);
   if (status == ARES_SUCCESS) {
   if (status == ARES_SUCCESS) {
     GRPC_ERROR_UNREF(r->error);
     GRPC_ERROR_UNREF(r->error);
     r->error = GRPC_ERROR_NONE;
     r->error = GRPC_ERROR_NONE;
@@ -263,33 +261,33 @@ static void on_hostbyname_done_cb(void* arg, int status, int timeouts,
       r->error = grpc_error_add_child(error, r->error);
       r->error = grpc_error_add_child(error, r->error);
     }
     }
   }
   }
-  gpr_mu_unlock(&r->mu);
-  destroy_hostbyname_request(hr);
+  destroy_hostbyname_request_locked(hr);
 }
 }
 
 
-static void on_srv_query_done_cb(void* arg, int status, int timeouts,
-                                 unsigned char* abuf, int alen) {
+static void on_srv_query_done_locked(void* arg, int status, int timeouts,
+                                     unsigned char* abuf, int alen) {
   grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
   grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
-  gpr_log(GPR_DEBUG, "on_query_srv_done_cb");
+  gpr_log(GPR_DEBUG, "on_query_srv_done_locked");
   if (status == ARES_SUCCESS) {
   if (status == ARES_SUCCESS) {
-    gpr_log(GPR_DEBUG, "on_query_srv_done_cb ARES_SUCCESS");
+    gpr_log(GPR_DEBUG, "on_query_srv_done_locked ARES_SUCCESS");
     struct ares_srv_reply* reply;
     struct ares_srv_reply* reply;
     const int parse_status = ares_parse_srv_reply(abuf, alen, &reply);
     const int parse_status = ares_parse_srv_reply(abuf, alen, &reply);
     if (parse_status == ARES_SUCCESS) {
     if (parse_status == ARES_SUCCESS) {
-      ares_channel* channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
+      ares_channel* channel =
+          grpc_ares_ev_driver_get_channel_locked(r->ev_driver);
       for (struct ares_srv_reply* srv_it = reply; srv_it != nullptr;
       for (struct ares_srv_reply* srv_it = reply; srv_it != nullptr;
            srv_it = srv_it->next) {
            srv_it = srv_it->next) {
         if (grpc_ipv6_loopback_available()) {
         if (grpc_ipv6_loopback_available()) {
-          grpc_ares_hostbyname_request* hr = create_hostbyname_request(
+          grpc_ares_hostbyname_request* hr = create_hostbyname_request_locked(
               r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
               r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
           ares_gethostbyname(*channel, hr->host, AF_INET6,
           ares_gethostbyname(*channel, hr->host, AF_INET6,
-                             on_hostbyname_done_cb, hr);
+                             on_hostbyname_done_locked, hr);
         }
         }
-        grpc_ares_hostbyname_request* hr = create_hostbyname_request(
+        grpc_ares_hostbyname_request* hr = create_hostbyname_request_locked(
             r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
             r, srv_it->host, htons(srv_it->port), true /* is_balancer */);
-        ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb,
-                           hr);
-        grpc_ares_ev_driver_start(r->ev_driver);
+        ares_gethostbyname(*channel, hr->host, AF_INET,
+                           on_hostbyname_done_locked, hr);
+        grpc_ares_ev_driver_start_locked(r->ev_driver);
       }
       }
     }
     }
     if (reply != nullptr) {
     if (reply != nullptr) {
@@ -307,21 +305,20 @@ static void on_srv_query_done_cb(void* arg, int status, int timeouts,
       r->error = grpc_error_add_child(error, r->error);
       r->error = grpc_error_add_child(error, r->error);
     }
     }
   }
   }
-  grpc_ares_request_unref(r);
+  grpc_ares_request_unref_locked(r);
 }
 }
 
 
 static const char g_service_config_attribute_prefix[] = "grpc_config=";
 static const char g_service_config_attribute_prefix[] = "grpc_config=";
 
 
-static void on_txt_done_cb(void* arg, int status, int timeouts,
-                           unsigned char* buf, int len) {
-  gpr_log(GPR_DEBUG, "on_txt_done_cb");
+static void on_txt_done_locked(void* arg, int status, int timeouts,
+                               unsigned char* buf, int len) {
+  gpr_log(GPR_DEBUG, "on_txt_done_locked");
   char* error_msg;
   char* error_msg;
   grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
   grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
   const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
   const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
   struct ares_txt_ext* result = nullptr;
   struct ares_txt_ext* result = nullptr;
   struct ares_txt_ext* reply = nullptr;
   struct ares_txt_ext* reply = nullptr;
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_error* error = GRPC_ERROR_NONE;
-  gpr_mu_lock(&r->mu);
   if (status != ARES_SUCCESS) goto fail;
   if (status != ARES_SUCCESS) goto fail;
   status = ares_parse_txt_reply_ext(buf, len, &reply);
   status = ares_parse_txt_reply_ext(buf, len, &reply);
   if (status != ARES_SUCCESS) goto fail;
   if (status != ARES_SUCCESS) goto fail;
@@ -366,14 +363,14 @@ fail:
     r->error = grpc_error_add_child(error, r->error);
     r->error = grpc_error_add_child(error, r->error);
   }
   }
 done:
 done:
-  gpr_mu_unlock(&r->mu);
-  grpc_ares_request_unref(r);
+  grpc_ares_request_unref_locked(r);
 }
 }
 
 
-static grpc_ares_request* grpc_dns_lookup_ares_impl(
+static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
     const char* dns_server, const char* name, const char* default_port,
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json) {
+    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+    grpc_combiner* combiner) {
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_ares_hostbyname_request* hr = nullptr;
   grpc_ares_hostbyname_request* hr = nullptr;
   grpc_ares_request* r = nullptr;
   grpc_ares_request* r = nullptr;
@@ -402,20 +399,19 @@ static grpc_ares_request* grpc_dns_lookup_ares_impl(
     }
     }
     port = gpr_strdup(default_port);
     port = gpr_strdup(default_port);
   }
   }
-
   grpc_ares_ev_driver* ev_driver;
   grpc_ares_ev_driver* ev_driver;
-  error = grpc_ares_ev_driver_create(&ev_driver, interested_parties);
+  error = grpc_ares_ev_driver_create_locked(&ev_driver, interested_parties,
+                                            combiner);
   if (error != GRPC_ERROR_NONE) goto error_cleanup;
   if (error != GRPC_ERROR_NONE) goto error_cleanup;
 
 
   r = static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
   r = static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
-  gpr_mu_init(&r->mu);
   r->ev_driver = ev_driver;
   r->ev_driver = ev_driver;
   r->on_done = on_done;
   r->on_done = on_done;
   r->lb_addrs_out = addrs;
   r->lb_addrs_out = addrs;
   r->service_config_json_out = service_config_json;
   r->service_config_json_out = service_config_json;
   r->success = false;
   r->success = false;
   r->error = GRPC_ERROR_NONE;
   r->error = GRPC_ERROR_NONE;
-  channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
+  channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver);
 
 
   // If dns_server is specified, use it.
   // If dns_server is specified, use it.
   if (dns_server != nullptr) {
   if (dns_server != nullptr) {
@@ -457,32 +453,34 @@ static grpc_ares_request* grpc_dns_lookup_ares_impl(
   }
   }
   gpr_ref_init(&r->pending_queries, 1);
   gpr_ref_init(&r->pending_queries, 1);
   if (grpc_ipv6_loopback_available()) {
   if (grpc_ipv6_loopback_available()) {
-    hr = create_hostbyname_request(r, host, strhtons(port),
-                                   false /* is_balancer */);
-    ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_cb, hr);
+    hr = create_hostbyname_request_locked(r, host, strhtons(port),
+                                          false /* is_balancer */);
+    ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_locked,
+                       hr);
   }
   }
-  hr = create_hostbyname_request(r, host, strhtons(port),
-                                 false /* is_balancer */);
-  ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb, hr);
+  hr = create_hostbyname_request_locked(r, host, strhtons(port),
+                                        false /* is_balancer */);
+  ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_locked,
+                     hr);
   if (check_grpclb) {
   if (check_grpclb) {
     /* Query the SRV record */
     /* Query the SRV record */
-    grpc_ares_request_ref(r);
+    grpc_ares_request_ref_locked(r);
     char* service_name;
     char* service_name;
     gpr_asprintf(&service_name, "_grpclb._tcp.%s", host);
     gpr_asprintf(&service_name, "_grpclb._tcp.%s", host);
-    ares_query(*channel, service_name, ns_c_in, ns_t_srv, on_srv_query_done_cb,
-               r);
+    ares_query(*channel, service_name, ns_c_in, ns_t_srv,
+               on_srv_query_done_locked, r);
     gpr_free(service_name);
     gpr_free(service_name);
   }
   }
   if (service_config_json != nullptr) {
   if (service_config_json != nullptr) {
-    grpc_ares_request_ref(r);
+    grpc_ares_request_ref_locked(r);
     char* config_name;
     char* config_name;
     gpr_asprintf(&config_name, "_grpc_config.%s", host);
     gpr_asprintf(&config_name, "_grpc_config.%s", host);
-    ares_search(*channel, config_name, ns_c_in, ns_t_txt, on_txt_done_cb, r);
+    ares_search(*channel, config_name, ns_c_in, ns_t_txt, on_txt_done_locked,
+                r);
     gpr_free(config_name);
     gpr_free(config_name);
   }
   }
-  /* TODO(zyc): Handle CNAME records here. */
-  grpc_ares_ev_driver_start(r->ev_driver);
-  grpc_ares_request_unref(r);
+  grpc_ares_ev_driver_start_locked(r->ev_driver);
+  grpc_ares_request_unref_locked(r);
   gpr_free(host);
   gpr_free(host);
   gpr_free(port);
   gpr_free(port);
   return r;
   return r;
@@ -494,15 +492,15 @@ error_cleanup:
   return nullptr;
   return nullptr;
 }
 }
 
 
-grpc_ares_request* (*grpc_dns_lookup_ares)(
+grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
     const char* dns_server, const char* name, const char* default_port,
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_lb_addresses** addrs, bool check_grpclb,
-    char** service_config_json) = grpc_dns_lookup_ares_impl;
+    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+    grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
 
 
 void grpc_cancel_ares_request(grpc_ares_request* r) {
 void grpc_cancel_ares_request(grpc_ares_request* r) {
-  if (grpc_dns_lookup_ares == grpc_dns_lookup_ares_impl) {
-    grpc_ares_ev_driver_shutdown(r->ev_driver);
+  if (grpc_dns_lookup_ares_locked == grpc_dns_lookup_ares_locked_impl) {
+    grpc_ares_ev_driver_shutdown_locked(r->ev_driver);
   }
   }
 }
 }
 
 
@@ -534,6 +532,8 @@ void grpc_ares_cleanup(void) {
  */
  */
 
 
 typedef struct grpc_resolve_address_ares_request {
 typedef struct grpc_resolve_address_ares_request {
+  /* combiner that queries and related callbacks run under */
+  grpc_combiner* combiner;
   /** the pointer to receive the resolved addresses */
   /** the pointer to receive the resolved addresses */
   grpc_resolved_addresses** addrs_out;
   grpc_resolved_addresses** addrs_out;
   /** currently resolving lb addresses */
   /** currently resolving lb addresses */
@@ -541,8 +541,14 @@ typedef struct grpc_resolve_address_ares_request {
   /** closure to call when the resolve_address_ares request completes */
   /** closure to call when the resolve_address_ares request completes */
   grpc_closure* on_resolve_address_done;
   grpc_closure* on_resolve_address_done;
   /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the
   /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the
-      grpc_dns_lookup_ares operation is done. */
+      grpc_dns_lookup_ares_locked operation is done. */
   grpc_closure on_dns_lookup_done;
   grpc_closure on_dns_lookup_done;
+  /* target name */
+  const char* name;
+  /* default port to use if none is specified */
+  const char* default_port;
+  /* pollset_set to be driven by */
+  grpc_pollset_set* interested_parties;
 } grpc_resolve_address_ares_request;
 } grpc_resolve_address_ares_request;
 
 
 static void on_dns_lookup_done_cb(void* arg, grpc_error* error) {
 static void on_dns_lookup_done_cb(void* arg, grpc_error* error) {
@@ -566,9 +572,20 @@ static void on_dns_lookup_done_cb(void* arg, grpc_error* error) {
   }
   }
   GRPC_CLOSURE_SCHED(r->on_resolve_address_done, GRPC_ERROR_REF(error));
   GRPC_CLOSURE_SCHED(r->on_resolve_address_done, GRPC_ERROR_REF(error));
   if (r->lb_addrs != nullptr) grpc_lb_addresses_destroy(r->lb_addrs);
   if (r->lb_addrs != nullptr) grpc_lb_addresses_destroy(r->lb_addrs);
+  GRPC_COMBINER_UNREF(r->combiner, "on_dns_lookup_done_cb");
   gpr_free(r);
   gpr_free(r);
 }
 }
 
 
+static void grpc_resolve_address_invoke_dns_lookup_ares_locked(
+    void* arg, grpc_error* unused_error) {
+  grpc_resolve_address_ares_request* r =
+      static_cast<grpc_resolve_address_ares_request*>(arg);
+  grpc_dns_lookup_ares_locked(
+      nullptr /* dns_server */, r->name, r->default_port, r->interested_parties,
+      &r->on_dns_lookup_done, &r->lb_addrs, false /* check_grpclb */,
+      nullptr /* service_config_json */, r->combiner);
+}
+
 static void grpc_resolve_address_ares_impl(const char* name,
 static void grpc_resolve_address_ares_impl(const char* name,
                                            const char* default_port,
                                            const char* default_port,
                                            grpc_pollset_set* interested_parties,
                                            grpc_pollset_set* interested_parties,
@@ -577,14 +594,18 @@ static void grpc_resolve_address_ares_impl(const char* name,
   grpc_resolve_address_ares_request* r =
   grpc_resolve_address_ares_request* r =
       static_cast<grpc_resolve_address_ares_request*>(
       static_cast<grpc_resolve_address_ares_request*>(
           gpr_zalloc(sizeof(grpc_resolve_address_ares_request)));
           gpr_zalloc(sizeof(grpc_resolve_address_ares_request)));
+  r->combiner = grpc_combiner_create();
   r->addrs_out = addrs;
   r->addrs_out = addrs;
   r->on_resolve_address_done = on_done;
   r->on_resolve_address_done = on_done;
   GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
   GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
-  grpc_dns_lookup_ares(nullptr /* dns_server */, name, default_port,
-                       interested_parties, &r->on_dns_lookup_done, &r->lb_addrs,
-                       false /* check_grpclb */,
-                       nullptr /* service_config_json */);
+  r->name = name;
+  r->default_port = default_port;
+  r->interested_parties = interested_parties;
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_CREATE(grpc_resolve_address_invoke_dns_lookup_ares_locked, r,
+                          grpc_combiner_scheduler(r->combiner)),
+      GRPC_ERROR_NONE);
 }
 }
 
 
 void (*grpc_resolve_address_ares)(
 void (*grpc_resolve_address_ares)(

+ 2 - 2
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h

@@ -48,11 +48,11 @@ extern void (*grpc_resolve_address_ares)(const char* name,
   function. \a on_done may be called directly in this function without being
   function. \a on_done may be called directly in this function without being
   scheduled with \a exec_ctx, so it must not try to acquire locks that are
   scheduled with \a exec_ctx, so it must not try to acquire locks that are
   being held by the caller. */
   being held by the caller. */
-extern grpc_ares_request* (*grpc_dns_lookup_ares)(
+extern grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
     const char* dns_server, const char* name, const char* default_port,
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_lb_addresses** addresses, bool check_grpclb,
     grpc_lb_addresses** addresses, bool check_grpclb,
-    char** service_config_json);
+    char** service_config_json, grpc_combiner* combiner);
 
 
 /* Cancel the pending grpc_ares_request \a request */
 /* Cancel the pending grpc_ares_request \a request */
 void grpc_cancel_ares_request(grpc_ares_request* request);
 void grpc_cancel_ares_request(grpc_ares_request* request);

+ 6 - 5
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc

@@ -26,18 +26,19 @@ struct grpc_ares_request {
   char val;
   char val;
 };
 };
 
 
-static grpc_ares_request* grpc_dns_lookup_ares_impl(
+static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
     const char* dns_server, const char* name, const char* default_port,
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json) {
+    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+    grpc_combiner* combiner) {
   return NULL;
   return NULL;
 }
 }
 
 
-grpc_ares_request* (*grpc_dns_lookup_ares)(
+grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
     const char* dns_server, const char* name, const char* default_port,
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_lb_addresses** addrs, bool check_grpclb,
-    char** service_config_json) = grpc_dns_lookup_ares_impl;
+    grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+    grpc_combiner* combiner) = grpc_dns_lookup_ares_locked_impl;
 
 
 void grpc_cancel_ares_request(grpc_ares_request* r) {}
 void grpc_cancel_ares_request(grpc_ares_request* r) {}
 
 

+ 1 - 1
src/core/ext/filters/http/server/http_server_filter.h

@@ -23,7 +23,7 @@
 
 
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/channel_stack.h"
 
 
-/* Processes metadata on the client side for HTTP2 transports */
+/* Processes metadata on the server side for HTTP2 transports */
 extern const grpc_channel_filter grpc_http_server_filter;
 extern const grpc_channel_filter grpc_http_server_filter;
 
 
 #endif /* GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H */
 #endif /* GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H */

+ 21 - 16
src/core/ext/transport/chttp2/transport/writing.cc

@@ -139,22 +139,27 @@ static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
 
 
 static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
 static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
                          const char* staller) {
                          const char* staller) {
-  gpr_log(
-      GPR_DEBUG,
-      "%s:%p stream %d stalled by %s [fc:pending=%" PRIdPTR
-      ":pending-compressed=%" PRIdPTR ":flowed=%" PRId64
-      ":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]",
-      t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length,
-      s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed,
-      t->settings[GRPC_ACKED_SETTINGS]
-                 [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
-      t->flow_control->remote_window(),
-      static_cast<uint32_t> GPR_MAX(
-          0,
-          s->flow_control->remote_window_delta() +
-              (int64_t)t->settings[GRPC_PEER_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]),
-      s->flow_control->remote_window_delta());
+  if (grpc_flowctl_trace.enabled()) {
+    gpr_log(
+        GPR_DEBUG,
+        "%s:%p stream %d moved to stalled list by %s. This is FULLY expected "
+        "to happen in a healthy program that is not seeing flow control stalls."
+        " However, if you know that there are unwanted stalls, here is some "
+        "helpful data: [fc:pending=%" PRIdPTR ":pending-compressed=%" PRIdPTR
+        ":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64
+        ":s_win=%d:s_delta=%" PRId64 "]",
+        t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length,
+        s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed,
+        t->settings[GRPC_ACKED_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
+        t->flow_control->remote_window(),
+        static_cast<uint32_t> GPR_MAX(
+            0,
+            s->flow_control->remote_window_delta() +
+                (int64_t)t->settings[GRPC_PEER_SETTINGS]
+                                    [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]),
+        s->flow_control->remote_window_delta());
+  }
 }
 }
 
 
 static bool stream_ref_if_not_destroyed(gpr_refcount* r) {
 static bool stream_ref_if_not_destroyed(gpr_refcount* r) {

+ 23 - 26
src/core/lib/channel/channel_trace.cc

@@ -28,7 +28,6 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#include "src/core/lib/channel/channelz_registry.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gpr/useful.h"
@@ -40,16 +39,17 @@
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/error_utils.h"
 
 
 namespace grpc_core {
 namespace grpc_core {
+namespace channelz {
 
 
 ChannelTrace::TraceEvent::TraceEvent(
 ChannelTrace::TraceEvent::TraceEvent(
     Severity severity, grpc_slice data,
     Severity severity, grpc_slice data,
-    RefCountedPtr<ChannelTrace> referenced_tracer, ReferencedType type)
+    RefCountedPtr<ChannelNode> referenced_channel, ReferencedType type)
     : severity_(severity),
     : severity_(severity),
       data_(data),
       data_(data),
       timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
       timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
                                          GPR_CLOCK_REALTIME)),
                                          GPR_CLOCK_REALTIME)),
       next_(nullptr),
       next_(nullptr),
-      referenced_tracer_(std::move(referenced_tracer)),
+      referenced_channel_(std::move(referenced_channel)),
       referenced_type_(type) {}
       referenced_type_(type) {}
 
 
 ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
 ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
@@ -62,15 +62,13 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
 ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
 ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
 
 
 ChannelTrace::ChannelTrace(size_t max_events)
 ChannelTrace::ChannelTrace(size_t max_events)
-    : channel_uuid_(-1),
-      num_events_logged_(0),
+    : num_events_logged_(0),
       list_size_(0),
       list_size_(0),
       max_list_size_(max_events),
       max_list_size_(max_events),
       head_trace_(nullptr),
       head_trace_(nullptr),
       tail_trace_(nullptr) {
       tail_trace_(nullptr) {
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   gpr_mu_init(&tracer_mu_);
   gpr_mu_init(&tracer_mu_);
-  channel_uuid_ = ChannelzRegistry::Register(this);
   time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
   time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
                                           GPR_CLOCK_REALTIME);
                                           GPR_CLOCK_REALTIME);
 }
 }
@@ -83,12 +81,9 @@ ChannelTrace::~ChannelTrace() {
     it = it->next();
     it = it->next();
     Delete<TraceEvent>(to_free);
     Delete<TraceEvent>(to_free);
   }
   }
-  ChannelzRegistry::Unregister(channel_uuid_);
   gpr_mu_destroy(&tracer_mu_);
   gpr_mu_destroy(&tracer_mu_);
 }
 }
 
 
-intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; }
-
 void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
 void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
   ++num_events_logged_;
   ++num_events_logged_;
   // first event case
   // first event case
@@ -117,20 +112,21 @@ void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
 
 
 void ChannelTrace::AddTraceEventReferencingChannel(
 void ChannelTrace::AddTraceEventReferencingChannel(
     Severity severity, grpc_slice data,
     Severity severity, grpc_slice data,
-    RefCountedPtr<ChannelTrace> referenced_tracer) {
+    RefCountedPtr<ChannelNode> referenced_channel) {
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   // create and fill up the new event
   // create and fill up the new event
-  AddTraceEventHelper(
-      New<TraceEvent>(severity, data, std::move(referenced_tracer), Channel));
+  AddTraceEventHelper(New<TraceEvent>(
+      severity, data, std::move(referenced_channel), ReferencedType::Channel));
 }
 }
 
 
 void ChannelTrace::AddTraceEventReferencingSubchannel(
 void ChannelTrace::AddTraceEventReferencingSubchannel(
     Severity severity, grpc_slice data,
     Severity severity, grpc_slice data,
-    RefCountedPtr<ChannelTrace> referenced_tracer) {
+    RefCountedPtr<ChannelNode> referenced_subchannel) {
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
   // create and fill up the new event
   // create and fill up the new event
-  AddTraceEventHelper(New<TraceEvent>(
-      severity, data, std::move(referenced_tracer), Subchannel));
+  AddTraceEventHelper(New<TraceEvent>(severity, data,
+                                      std::move(referenced_subchannel),
+                                      ReferencedType::Subchannel));
 }
 }
 
 
 namespace {
 namespace {
@@ -193,22 +189,24 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
   json_iterator =
   json_iterator =
       grpc_json_create_child(json_iterator, json, "timestamp",
       grpc_json_create_child(json_iterator, json, "timestamp",
                              fmt_time(timestamp_), GRPC_JSON_STRING, true);
                              fmt_time(timestamp_), GRPC_JSON_STRING, true);
-  if (referenced_tracer_ != nullptr) {
+  if (referenced_channel_ != nullptr) {
     char* uuid_str;
     char* uuid_str;
-    gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_);
+    gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_channel_->channel_uuid());
     grpc_json* child_ref = grpc_json_create_child(
     grpc_json* child_ref = grpc_json_create_child(
         json_iterator, json,
         json_iterator, json,
-        (referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr,
-        GRPC_JSON_OBJECT, false);
+        (referenced_type_ == ReferencedType::Channel) ? "channelRef"
+                                                      : "subchannelRef",
+        nullptr, GRPC_JSON_OBJECT, false);
     json_iterator = grpc_json_create_child(
     json_iterator = grpc_json_create_child(
         nullptr, child_ref,
         nullptr, child_ref,
-        (referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str,
-        GRPC_JSON_STRING, true);
+        (referenced_type_ == ReferencedType::Channel) ? "channelId"
+                                                      : "subchannelId",
+        uuid_str, GRPC_JSON_STRING, true);
     json_iterator = child_ref;
     json_iterator = child_ref;
   }
   }
 }
 }
 
 
-char* ChannelTrace::RenderTrace() const {
+grpc_json* ChannelTrace::RenderJSON() const {
   if (!max_list_size_)
   if (!max_list_size_)
     return nullptr;  // tracing is disabled if max_events == 0
     return nullptr;  // tracing is disabled if max_events == 0
   grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
   grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
@@ -219,7 +217,7 @@ char* ChannelTrace::RenderTrace() const {
       grpc_json_create_child(json_iterator, json, "numEventsLogged",
       grpc_json_create_child(json_iterator, json, "numEventsLogged",
                              num_events_logged_str, GRPC_JSON_STRING, true);
                              num_events_logged_str, GRPC_JSON_STRING, true);
   json_iterator =
   json_iterator =
-      grpc_json_create_child(json_iterator, json, "creationTime",
+      grpc_json_create_child(json_iterator, json, "creationTimestamp",
                              fmt_time(time_created_), GRPC_JSON_STRING, true);
                              fmt_time(time_created_), GRPC_JSON_STRING, true);
   grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
   grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
                                              nullptr, GRPC_JSON_ARRAY, false);
                                              nullptr, GRPC_JSON_ARRAY, false);
@@ -231,9 +229,8 @@ char* ChannelTrace::RenderTrace() const {
     it->RenderTraceEvent(json_iterator);
     it->RenderTraceEvent(json_iterator);
     it = it->next();
     it = it->next();
   }
   }
-  char* json_str = grpc_json_dump_to_string(json, 0);
-  grpc_json_destroy(json);
-  return json_str;
+  return json;
 }
 }
 
 
+}  // namespace channelz
 }  // namespace grpc_core
 }  // namespace grpc_core

+ 13 - 17
src/core/lib/channel/channel_trace.h

@@ -28,18 +28,18 @@
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/json/json.h"
 
 
 namespace grpc_core {
 namespace grpc_core {
+namespace channelz {
+
+class ChannelNode;
 
 
 // Object used to hold live data for a channel. This data is exposed via the
 // Object used to hold live data for a channel. This data is exposed via the
 // channelz service:
 // channelz service:
 // https://github.com/grpc/proposal/blob/master/A14-channelz.md
 // https://github.com/grpc/proposal/blob/master/A14-channelz.md
-class ChannelTrace : public RefCounted<ChannelTrace> {
+class ChannelTrace {
  public:
  public:
   ChannelTrace(size_t max_events);
   ChannelTrace(size_t max_events);
   ~ChannelTrace();
   ~ChannelTrace();
 
 
-  // returns the tracer's uuid
-  intptr_t GetUuid() const;
-
   enum Severity {
   enum Severity {
     Unset = 0,  // never to be used
     Unset = 0,  // never to be used
     Info,       // we start at 1 to avoid using proto default values
     Info,       // we start at 1 to avoid using proto default values
@@ -59,34 +59,30 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
   // created a new subchannel, then it would record that with a TraceEvent
   // created a new subchannel, then it would record that with a TraceEvent
   // referencing the new subchannel.
   // referencing the new subchannel.
   //
   //
-  // TODO(ncteisen): Once channelz is implemented, the events should reference
-  // the overall channelz object, not just the ChannelTrace object.
   // TODO(ncteisen): as this call is used more and more throughout the gRPC
   // TODO(ncteisen): as this call is used more and more throughout the gRPC
   // stack, determine if it makes more sense to accept a char* instead of a
   // stack, determine if it makes more sense to accept a char* instead of a
   // slice.
   // slice.
   void AddTraceEventReferencingChannel(
   void AddTraceEventReferencingChannel(
       Severity severity, grpc_slice data,
       Severity severity, grpc_slice data,
-      RefCountedPtr<ChannelTrace> referenced_tracer);
+      RefCountedPtr<ChannelNode> referenced_channel);
   void AddTraceEventReferencingSubchannel(
   void AddTraceEventReferencingSubchannel(
       Severity severity, grpc_slice data,
       Severity severity, grpc_slice data,
-      RefCountedPtr<ChannelTrace> referenced_tracer);
+      RefCountedPtr<ChannelNode> referenced_subchannel);
 
 
-  // Returns the tracing data rendered as a grpc json string.
-  // The string is owned by the caller and must be freed.
-  char* RenderTrace() const;
+  // Creates and returns the raw grpc_json object, so a parent channelz
+  // object may incorporate the json before rendering.
+  grpc_json* RenderJSON() const;
 
 
  private:
  private:
   // Types of objects that can be references by trace events.
   // Types of objects that can be references by trace events.
-  enum ReferencedType { Channel, Subchannel };
+  enum class ReferencedType { Channel, Subchannel };
   // Private class to encapsulate all the data and bookkeeping needed for a
   // Private class to encapsulate all the data and bookkeeping needed for a
   // a trace event.
   // a trace event.
   class TraceEvent {
   class TraceEvent {
    public:
    public:
     // Constructor for a TraceEvent that references a different channel.
     // Constructor for a TraceEvent that references a different channel.
-    // TODO(ncteisen): once channelz is implemented, this should reference the
-    // overall channelz object, not just the ChannelTrace object
     TraceEvent(Severity severity, grpc_slice data,
     TraceEvent(Severity severity, grpc_slice data,
-               RefCountedPtr<ChannelTrace> referenced_tracer,
+               RefCountedPtr<ChannelNode> referenced_channel,
                ReferencedType type);
                ReferencedType type);
 
 
     // Constructor for a TraceEvent that does not reverence a different
     // Constructor for a TraceEvent that does not reverence a different
@@ -109,7 +105,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
     gpr_timespec timestamp_;
     gpr_timespec timestamp_;
     TraceEvent* next_;
     TraceEvent* next_;
     // the tracer object for the (sub)channel that this trace event refers to.
     // the tracer object for the (sub)channel that this trace event refers to.
-    RefCountedPtr<ChannelTrace> referenced_tracer_;
+    RefCountedPtr<ChannelNode> referenced_channel_;
     // the type that the referenced tracer points to. Unused if this trace
     // the type that the referenced tracer points to. Unused if this trace
     // does not point to any channel or subchannel
     // does not point to any channel or subchannel
     ReferencedType referenced_type_;
     ReferencedType referenced_type_;
@@ -119,7 +115,6 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
   void AddTraceEventHelper(TraceEvent* new_trace_event);
   void AddTraceEventHelper(TraceEvent* new_trace_event);
 
 
   gpr_mu tracer_mu_;
   gpr_mu tracer_mu_;
-  intptr_t channel_uuid_;
   uint64_t num_events_logged_;
   uint64_t num_events_logged_;
   size_t list_size_;
   size_t list_size_;
   size_t max_list_size_;
   size_t max_list_size_;
@@ -128,6 +123,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
   gpr_timespec time_created_;
   gpr_timespec time_created_;
 };
 };
 
 
+}  // namespace channelz
 }  // namespace grpc_core
 }  // namespace grpc_core
 
 
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */

+ 185 - 0
src/core/lib/channel/channelz.cc

@@ -0,0 +1,185 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include "src/core/lib/channel/channelz.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/lib/channel/channelz_registry.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/error_utils.h"
+
+namespace grpc_core {
+namespace channelz {
+
+namespace {
+
+// TODO(ncteisen): move this function to a common helper location.
+//
+// returns an allocated string that represents tm according to RFC-3339, and,
+// more specifically, follows:
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+//
+// "Uses RFC 3339, where generated output will always be Z-normalized and uses
+// 0, 3, 6 or 9 fractional digits."
+char* fmt_time(gpr_timespec tm) {
+  char time_buffer[35];
+  char ns_buffer[11];  // '.' + 9 digits of precision
+  struct tm* tm_info = localtime((const time_t*)&tm.tv_sec);
+  strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info);
+  snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec);
+  // This loop trims off trailing zeros by inserting a null character that the
+  // right point. We iterate in chunks of three because we want 0, 3, 6, or 9
+  // fractional digits.
+  for (int i = 7; i >= 1; i -= 3) {
+    if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' &&
+        ns_buffer[i + 2] == '0') {
+      ns_buffer[i] = '\0';
+      // Edge case in which all fractional digits were 0.
+      if (i == 1) {
+        ns_buffer[0] = '\0';
+      }
+    } else {
+      break;
+    }
+  }
+  char* full_time_str;
+  gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer);
+  return full_time_str;
+}
+
+// TODO(ncteisen); move this to json library
+grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name,
+                       int64_t num) {
+  char* num_str;
+  gpr_asprintf(&num_str, "%" PRId64, num);
+  return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING,
+                                true);
+}
+
+}  // namespace
+
+ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes)
+    : channel_(channel), target_(nullptr), channel_uuid_(-1) {
+  trace_.Init(channel_tracer_max_nodes);
+  target_ = UniquePtr<char>(grpc_channel_get_target(channel_));
+  channel_uuid_ = ChannelzRegistry::Register(this);
+  gpr_atm_no_barrier_store(&last_call_started_millis_,
+                           (gpr_atm)ExecCtx::Get()->Now());
+}
+
+ChannelNode::~ChannelNode() {
+  trace_.Destroy();
+  ChannelzRegistry::Unregister(channel_uuid_);
+}
+
+void ChannelNode::RecordCallStarted() {
+  gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1);
+  gpr_atm_no_barrier_store(&last_call_started_millis_,
+                           (gpr_atm)ExecCtx::Get()->Now());
+}
+
+grpc_connectivity_state ChannelNode::GetConnectivityState() {
+  if (channel_ == nullptr) {
+    return GRPC_CHANNEL_SHUTDOWN;
+  } else {
+    return grpc_channel_check_connectivity_state(channel_, false);
+  }
+}
+
+char* ChannelNode::RenderJSON() {
+  // We need to track these three json objects to build our object
+  grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+  grpc_json* json = top_level_json;
+  grpc_json* json_iterator = nullptr;
+  // create and fill the ref child
+  json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
+                                         GRPC_JSON_OBJECT, false);
+  json = json_iterator;
+  json_iterator = nullptr;
+  json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_);
+  // reset json iterators to top level object
+  json = top_level_json;
+  json_iterator = nullptr;
+  // create and fill the data child.
+  grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
+                                           GRPC_JSON_OBJECT, false);
+  json = data;
+  json_iterator = nullptr;
+  // create and fill the connectivity state child.
+  grpc_connectivity_state connectivity_state = GetConnectivityState();
+  json_iterator = grpc_json_create_child(json_iterator, json, "state", nullptr,
+                                         GRPC_JSON_OBJECT, false);
+  json = json_iterator;
+  grpc_json_create_child(nullptr, json, "state",
+                         grpc_connectivity_state_name(connectivity_state),
+                         GRPC_JSON_STRING, false);
+  // reset the parent to be the data object.
+  json = data;
+  json_iterator = grpc_json_create_child(
+      json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false);
+  // fill in the channel trace if applicable
+  grpc_json* trace = trace_->RenderJSON();
+  if (trace != nullptr) {
+    // we manuall link up and fill the child since it was created for us in
+    // ChannelTrace::RenderJSON
+    json_iterator = grpc_json_link_child(json, trace, json_iterator);
+    trace->parent = json;
+    trace->value = nullptr;
+    trace->key = "trace";
+    trace->owns_value = false;
+  }
+  // reset the parent to be the data object.
+  json = data;
+  json_iterator = nullptr;
+  // We use -1 as sentinel values since proto default value for integers is
+  // zero, and the confuses the parser into thinking the value weren't present
+  json_iterator =
+      add_num_str(json, json_iterator, "callsStarted", calls_started_);
+  json_iterator =
+      add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_);
+  json_iterator =
+      add_num_str(json, json_iterator, "callsFailed", calls_failed_);
+  gpr_timespec ts =
+      grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME);
+  json_iterator =
+      grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
+                             fmt_time(ts), GRPC_JSON_STRING, true);
+  // render and return the over json object
+  char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+  grpc_json_destroy(top_level_json);
+  return json_str;
+}
+
+}  // namespace channelz
+}  // namespace grpc_core

+ 85 - 0
src/core/lib/channel/channelz.h

@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/json/json.h"
+
+namespace grpc_core {
+namespace channelz {
+
+namespace testing {
+class ChannelNodePeer;
+}
+
+class ChannelNode : public RefCounted<ChannelNode> {
+ public:
+  ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes);
+  ~ChannelNode();
+
+  void RecordCallStarted();
+  void RecordCallFailed() {
+    gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1)));
+  }
+  void RecordCallSucceeded() {
+    gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
+  }
+
+  char* RenderJSON();
+
+  ChannelTrace* trace() { return trace_.get(); }
+
+  void set_channel_destroyed() {
+    GPR_ASSERT(channel_ != nullptr);
+    channel_ = nullptr;
+  }
+
+  intptr_t channel_uuid() { return channel_uuid_; }
+
+ private:
+  // testing peer friend.
+  friend class testing::ChannelNodePeer;
+
+  // helper for getting connectivity state.
+  grpc_connectivity_state GetConnectivityState();
+
+  grpc_channel* channel_ = nullptr;
+  UniquePtr<char> target_;
+  gpr_atm calls_started_ = 0;
+  gpr_atm calls_succeeded_ = 0;
+  gpr_atm calls_failed_ = 0;
+  gpr_atm last_call_started_millis_ = 0;
+  intptr_t channel_uuid_;
+  ManualConstructor<ChannelTrace> trace_;
+};
+
+}  // namespace channelz
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */

+ 17 - 12
src/core/lib/channel/handshaker.cc

@@ -223,18 +223,23 @@ static bool call_next_handshaker_locked(grpc_handshake_manager* mgr,
       mgr->index == mgr->count) {
       mgr->index == mgr->count) {
     if (error == GRPC_ERROR_NONE && mgr->shutdown) {
     if (error == GRPC_ERROR_NONE && mgr->shutdown) {
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("handshaker shutdown");
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("handshaker shutdown");
-      // TODO(roth): It is currently necessary to shutdown endpoints
-      // before destroying then, even when we know that there are no
-      // pending read/write callbacks.  This should be fixed, at which
-      // point this can be removed.
-      grpc_endpoint_shutdown(mgr->args.endpoint, GRPC_ERROR_REF(error));
-      grpc_endpoint_destroy(mgr->args.endpoint);
-      mgr->args.endpoint = nullptr;
-      grpc_channel_args_destroy(mgr->args.args);
-      mgr->args.args = nullptr;
-      grpc_slice_buffer_destroy_internal(mgr->args.read_buffer);
-      gpr_free(mgr->args.read_buffer);
-      mgr->args.read_buffer = nullptr;
+      // It is possible that the endpoint has already been destroyed by
+      // a shutdown call while this callback was sitting on the ExecCtx
+      // with no error.
+      if (mgr->args.endpoint != nullptr) {
+        // TODO(roth): It is currently necessary to shutdown endpoints
+        // before destroying then, even when we know that there are no
+        // pending read/write callbacks.  This should be fixed, at which
+        // point this can be removed.
+        grpc_endpoint_shutdown(mgr->args.endpoint, GRPC_ERROR_REF(error));
+        grpc_endpoint_destroy(mgr->args.endpoint);
+        mgr->args.endpoint = nullptr;
+        grpc_channel_args_destroy(mgr->args.args);
+        mgr->args.args = nullptr;
+        grpc_slice_buffer_destroy_internal(mgr->args.read_buffer);
+        gpr_free(mgr->args.read_buffer);
+        mgr->args.read_buffer = nullptr;
+      }
     }
     }
     if (grpc_handshaker_trace.enabled()) {
     if (grpc_handshaker_trace.enabled()) {
       gpr_log(GPR_INFO,
       gpr_log(GPR_INFO,

+ 53 - 12
src/core/lib/iomgr/ev_epollex_linux.cc

@@ -33,6 +33,7 @@
 #include <poll.h>
 #include <poll.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <string.h>
 #include <string.h>
+#include <sys/epoll.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 #include <unistd.h>
@@ -63,7 +64,7 @@
 // a keepalive ping timeout issue. We may want to revert https://github
 // a keepalive ping timeout issue. We may want to revert https://github
 // .com/grpc/grpc/pull/14943 once we figure out the root cause.
 // .com/grpc/grpc/pull/14943 once we figure out the root cause.
 #define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 16
 #define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 16
-#define MAX_PROBE_EPOLL_FDS 32
+#define MAX_FDS_IN_CACHE 32
 
 
 grpc_core::DebugOnlyTraceFlag grpc_trace_pollable_refcount(false,
 grpc_core::DebugOnlyTraceFlag grpc_trace_pollable_refcount(false,
                                                            "pollable_refcount");
                                                            "pollable_refcount");
@@ -77,8 +78,14 @@ typedef enum { PO_MULTI, PO_FD, PO_EMPTY } pollable_type;
 typedef struct pollable pollable;
 typedef struct pollable pollable;
 
 
 typedef struct cached_fd {
 typedef struct cached_fd {
+  // Set to the grpc_fd's salt value. See 'salt' variable' in grpc_fd for more
+  // details
   intptr_t salt;
   intptr_t salt;
+
+  // The underlying fd
   int fd;
   int fd;
+
+  // A recency time counter that helps to determine the LRU fd in the cache
   uint64_t last_used;
   uint64_t last_used;
 } cached_fd;
 } cached_fd;
 
 
@@ -111,10 +118,32 @@ struct pollable {
   int event_count;
   int event_count;
   struct epoll_event events[MAX_EPOLL_EVENTS];
   struct epoll_event events[MAX_EPOLL_EVENTS];
 
 
-  // Maintain a LRU-eviction cache of fds in this pollable
-  cached_fd fd_cache[MAX_PROBE_EPOLL_FDS];
+  // We may be calling pollable_add_fd() on the same (pollable, fd) multiple
+  // times. To prevent pollable_add_fd() from making multiple sys calls to
+  // epoll_ctl() to add the fd, we maintain a cache of what fds are already
+  // present in the underlying epoll-set.
+  //
+  // Since this is not a correctness issue, we do not need to maintain all the
+  // fds in the cache. Hence we just use an LRU cache of size 'MAX_FDS_IN_CACHE'
+  //
+  // NOTE: An ideal implementation of this should do the following:
+  //  1) Add fds to the cache in pollable_add_fd() function (i.e whenever the fd
+  //     is added to the pollable's epoll set)
+  //  2) Remove the fd from the cache whenever the fd is removed from the
+  //     underlying epoll set (i.e whenever fd_orphan() is called).
+  //
+  // Implementing (2) above (i.e removing fds from cache on fd_orphan) adds a
+  // lot of complexity since an fd can be present in multiple pollalbles. So our
+  // implementation ONLY DOES (1) and NOT (2).
+  //
+  // The cache_fd.salt variable helps here to maintain correctness (it serves as
+  // an epoch that differentiates one grpc_fd from the other even though both of
+  // them may have the same fd number)
+  //
+  // The following implements LRU-eviction cache of fds in this pollable
+  cached_fd fd_cache[MAX_FDS_IN_CACHE];
   int fd_cache_size;
   int fd_cache_size;
-  uint64_t fd_cache_counter;
+  uint64_t fd_cache_counter;  // Recency timer tick counter
 };
 };
 
 
 static const char* pollable_type_string(pollable_type t) {
 static const char* pollable_type_string(pollable_type t) {
@@ -157,15 +186,24 @@ static void pollable_unref(pollable* p, int line, const char* reason);
  * Fd Declarations
  * Fd Declarations
  */
  */
 
 
+// Monotonically increasing Epoch counter that is assinged to each grpc_fd. See
+// the description of 'salt' variable in 'grpc_fd' for more details
+// TODO: (sreek/kpayson) gpr_atm is intptr_t which may not be wide-enough on
+// 32-bit systems. Change this to int_64 - atleast on 32-bit systems
 static gpr_atm g_fd_salt;
 static gpr_atm g_fd_salt;
 
 
 struct grpc_fd {
 struct grpc_fd {
   int fd;
   int fd;
+
+  // Since fd numbers can be reused (after old fds are closed), this serves as
+  // an epoch that uniquely identifies this fd (i.e the pair (salt, fd) is
+  // unique (until the salt counter (i.e g_fd_salt) overflows)
   intptr_t salt;
   intptr_t salt;
-  /* refst format:
-       bit 0    : 1=Active / 0=Orphaned
-       bits 1-n : refcount
-     Ref/Unref by two to avoid altering the orphaned bit */
+
+  // refst format:
+  //     bit 0    : 1=Active / 0=Orphaned
+  //     bits 1-n : refcount
+  //  Ref/Unref by two to avoid altering the orphaned bit
   gpr_atm refst;
   gpr_atm refst;
 
 
   gpr_mu orphan_mu;
   gpr_mu orphan_mu;
@@ -180,13 +218,13 @@ struct grpc_fd {
   struct grpc_fd* freelist_next;
   struct grpc_fd* freelist_next;
   grpc_closure* on_done_closure;
   grpc_closure* on_done_closure;
 
 
-  /* The pollset that last noticed that the fd is readable. The actual type
-   * stored in this is (grpc_pollset *) */
+  // The pollset that last noticed that the fd is readable. The actual type
+  // stored in this is (grpc_pollset *)
   gpr_atm read_notifier_pollset;
   gpr_atm read_notifier_pollset;
 
 
   grpc_iomgr_object iomgr_object;
   grpc_iomgr_object iomgr_object;
 
 
-  /* Do we need to track EPOLLERR events separately? */
+  // Do we need to track EPOLLERR events separately?
   bool track_err;
   bool track_err;
 };
 };
 
 
@@ -562,6 +600,7 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
   const int epfd = p->epfd;
   const int epfd = p->epfd;
   gpr_mu_lock(&p->mu);
   gpr_mu_lock(&p->mu);
   p->fd_cache_counter++;
   p->fd_cache_counter++;
+
   // Handle the case of overflow for our cache counter by
   // Handle the case of overflow for our cache counter by
   // reseting the recency-counter on all cache objects
   // reseting the recency-counter on all cache objects
   if (p->fd_cache_counter == 0) {
   if (p->fd_cache_counter == 0) {
@@ -581,8 +620,9 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
       lru_idx = i;
       lru_idx = i;
     }
     }
   }
   }
+
   // Add to cache
   // Add to cache
-  if (p->fd_cache_size < MAX_PROBE_EPOLL_FDS) {
+  if (p->fd_cache_size < MAX_FDS_IN_CACHE) {
     lru_idx = p->fd_cache_size;
     lru_idx = p->fd_cache_size;
     p->fd_cache_size++;
     p->fd_cache_size++;
   }
   }
@@ -590,6 +630,7 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
   p->fd_cache[lru_idx].salt = fd->salt;
   p->fd_cache[lru_idx].salt = fd->salt;
   p->fd_cache[lru_idx].last_used = p->fd_cache_counter;
   p->fd_cache[lru_idx].last_used = p->fd_cache_counter;
   gpr_mu_unlock(&p->mu);
   gpr_mu_unlock(&p->mu);
+
   if (grpc_polling_trace.enabled()) {
   if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_INFO, "add fd %p (%d) to pollable %p", fd, fd->fd, p);
     gpr_log(GPR_INFO, "add fd %p (%d) to pollable %p", fd, fd->fd, p);
   }
   }

+ 1 - 0
src/core/lib/iomgr/is_epollexclusive_available.cc

@@ -27,6 +27,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/log.h>
 
 
 #include <errno.h>
 #include <errno.h>
+#include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <sys/eventfd.h>
 #include <unistd.h>
 #include <unistd.h>
 
 

+ 9 - 0
src/core/lib/iomgr/socket_utils.h

@@ -23,12 +23,21 @@
 
 
 #include <stddef.h>
 #include <stddef.h>
 
 
+// TODO(juanlishen): The following functions might be simple enough to implement
+// ourselves, so that they don't cause any portability hassle.
+
 /* A wrapper for htons on POSIX and Windows */
 /* A wrapper for htons on POSIX and Windows */
 uint16_t grpc_htons(uint16_t hostshort);
 uint16_t grpc_htons(uint16_t hostshort);
 
 
 /* A wrapper for ntohs on POSIX and WINDOWS */
 /* A wrapper for ntohs on POSIX and WINDOWS */
 uint16_t grpc_ntohs(uint16_t netshort);
 uint16_t grpc_ntohs(uint16_t netshort);
 
 
+/* A wrapper for htonl on POSIX and Windows */
+uint32_t grpc_htonl(uint32_t hostlong);
+
+/* A wrapper for ntohl on POSIX and WINDOWS */
+uint32_t grpc_ntohl(uint32_t netlong);
+
 /* A wrapper for inet_pton on POSIX and WINDOWS */
 /* A wrapper for inet_pton on POSIX and WINDOWS */
 int grpc_inet_pton(int af, const char* src, void* dst);
 int grpc_inet_pton(int af, const char* src, void* dst);
 
 

+ 4 - 0
src/core/lib/iomgr/socket_utils_common_posix.cc

@@ -339,6 +339,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
 
 
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 
 
+uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
+
+uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
+
 int grpc_inet_pton(int af, const char* src, void* dst) {
 int grpc_inet_pton(int af, const char* src, void* dst) {
   return inet_pton(af, src, dst);
   return inet_pton(af, src, dst);
 }
 }

+ 4 - 0
src/core/lib/iomgr/socket_utils_uv.cc

@@ -33,6 +33,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
 
 
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 
 
+uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
+
+uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
+
 int grpc_inet_pton(int af, const char* src, void* dst) {
 int grpc_inet_pton(int af, const char* src, void* dst) {
   return inet_pton(af, src, dst);
   return inet_pton(af, src, dst);
 }
 }

+ 4 - 0
src/core/lib/iomgr/socket_utils_windows.cc

@@ -31,6 +31,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
 
 
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
 
 
+uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
+
+uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
+
 int grpc_inet_pton(int af, const char* src, void* dst) {
 int grpc_inet_pton(int af, const char* src, void* dst) {
   return inet_pton(af, src, dst);
   return inet_pton(af, src, dst);
 }
 }

+ 2 - 1
src/core/lib/security/credentials/google_default/google_default_credentials.cc

@@ -231,7 +231,8 @@ end:
       creds->base.vtable = &google_default_credentials_vtable;
       creds->base.vtable = &google_default_credentials_vtable;
       creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
       creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
       gpr_ref_init(&creds->base.refcount, 1);
       gpr_ref_init(&creds->base.refcount, 1);
-      creds->ssl_creds = grpc_ssl_credentials_create(nullptr, nullptr, nullptr);
+      creds->ssl_creds =
+          grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
       GPR_ASSERT(creds->ssl_creds != nullptr);
       GPR_ASSERT(creds->ssl_creds != nullptr);
       grpc_alts_credentials_options* options =
       grpc_alts_credentials_options* options =
           grpc_alts_credentials_client_options_create();
           grpc_alts_credentials_client_options_create();

+ 17 - 3
src/core/lib/security/credentials/ssl/ssl_credentials.cc

@@ -48,6 +48,10 @@ static void ssl_destruct(grpc_channel_credentials* creds) {
   grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
   grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
   gpr_free(c->config.pem_root_certs);
   gpr_free(c->config.pem_root_certs);
   grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1);
   grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1);
+  if (c->config.verify_options.verify_peer_destruct != nullptr) {
+    c->config.verify_options.verify_peer_destruct(
+        c->config.verify_options.verify_peer_callback_userdata);
+  }
 }
 }
 
 
 static grpc_security_status ssl_create_security_connector(
 static grpc_security_status ssl_create_security_connector(
@@ -87,6 +91,7 @@ static grpc_channel_credentials_vtable ssl_vtable = {
 
 
 static void ssl_build_config(const char* pem_root_certs,
 static void ssl_build_config(const char* pem_root_certs,
                              grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
                              grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
+                             const verify_peer_options* verify_options,
                              grpc_ssl_config* config) {
                              grpc_ssl_config* config) {
   if (pem_root_certs != nullptr) {
   if (pem_root_certs != nullptr) {
     config->pem_root_certs = gpr_strdup(pem_root_certs);
     config->pem_root_certs = gpr_strdup(pem_root_certs);
@@ -101,23 +106,32 @@ static void ssl_build_config(const char* pem_root_certs,
     config->pem_key_cert_pair->private_key =
     config->pem_key_cert_pair->private_key =
         gpr_strdup(pem_key_cert_pair->private_key);
         gpr_strdup(pem_key_cert_pair->private_key);
   }
   }
+  if (verify_options != nullptr) {
+    memcpy(&config->verify_options, verify_options,
+           sizeof(verify_peer_options));
+  } else {
+    // Otherwise set all options to default values
+    memset(&config->verify_options, 0, sizeof(verify_peer_options));
+  }
 }
 }
 
 
 grpc_channel_credentials* grpc_ssl_credentials_create(
 grpc_channel_credentials* grpc_ssl_credentials_create(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
-    void* reserved) {
+    const verify_peer_options* verify_options, void* reserved) {
   grpc_ssl_credentials* c = static_cast<grpc_ssl_credentials*>(
   grpc_ssl_credentials* c = static_cast<grpc_ssl_credentials*>(
       gpr_zalloc(sizeof(grpc_ssl_credentials)));
       gpr_zalloc(sizeof(grpc_ssl_credentials)));
   GRPC_API_TRACE(
   GRPC_API_TRACE(
       "grpc_ssl_credentials_create(pem_root_certs=%s, "
       "grpc_ssl_credentials_create(pem_root_certs=%s, "
       "pem_key_cert_pair=%p, "
       "pem_key_cert_pair=%p, "
+      "verify_options=%p, "
       "reserved=%p)",
       "reserved=%p)",
-      3, (pem_root_certs, pem_key_cert_pair, reserved));
+      4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved));
   GPR_ASSERT(reserved == nullptr);
   GPR_ASSERT(reserved == nullptr);
   c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
   c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
   c->base.vtable = &ssl_vtable;
   c->base.vtable = &ssl_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   gpr_ref_init(&c->base.refcount, 1);
-  ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
+  ssl_build_config(pem_root_certs, pem_key_cert_pair, verify_options,
+                   &c->config);
   return &c->base;
   return &c->base;
 }
 }
 
 

+ 30 - 5
src/core/lib/security/security_connector/security_connector.cc

@@ -620,6 +620,7 @@ typedef struct {
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
   char* target_name;
   char* target_name;
   char* overridden_target_name;
   char* overridden_target_name;
+  const verify_peer_options* verify_options;
 } grpc_ssl_channel_security_connector;
 } grpc_ssl_channel_security_connector;
 
 
 typedef struct {
 typedef struct {
@@ -878,11 +879,34 @@ static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
                                    grpc_closure* on_peer_checked) {
                                    grpc_closure* on_peer_checked) {
   grpc_ssl_channel_security_connector* c =
   grpc_ssl_channel_security_connector* c =
       reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
       reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
-  grpc_error* error = ssl_check_peer(sc,
-                                     c->overridden_target_name != nullptr
-                                         ? c->overridden_target_name
-                                         : c->target_name,
-                                     &peer, auth_context);
+  const char* target_name = c->overridden_target_name != nullptr
+                                ? c->overridden_target_name
+                                : c->target_name;
+  grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context);
+  if (error == GRPC_ERROR_NONE &&
+      c->verify_options->verify_peer_callback != nullptr) {
+    const tsi_peer_property* p =
+        tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
+    if (p == nullptr) {
+      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Cannot check peer: missing pem cert property.");
+    } else {
+      char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
+      memcpy(peer_pem, p->value.data, p->value.length);
+      peer_pem[p->value.length] = '\0';
+      int callback_status = c->verify_options->verify_peer_callback(
+          target_name, peer_pem,
+          c->verify_options->verify_peer_callback_userdata);
+      gpr_free(peer_pem);
+      if (callback_status) {
+        char* msg;
+        gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
+                     callback_status);
+        error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+        gpr_free(msg);
+      }
+    }
+  }
   GRPC_CLOSURE_SCHED(on_peer_checked, error);
   GRPC_CLOSURE_SCHED(on_peer_checked, error);
   tsi_peer_destruct(&peer);
   tsi_peer_destruct(&peer);
 }
 }
@@ -1047,6 +1071,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
   if (overridden_target_name != nullptr) {
   if (overridden_target_name != nullptr) {
     c->overridden_target_name = gpr_strdup(overridden_target_name);
     c->overridden_target_name = gpr_strdup(overridden_target_name);
   }
   }
+  c->verify_options = &config->verify_options;
 
 
   has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
   has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
                       config->pem_key_cert_pair->private_key != nullptr &&
                       config->pem_key_cert_pair->private_key != nullptr &&

+ 1 - 0
src/core/lib/security/security_connector/security_connector.h

@@ -193,6 +193,7 @@ grpc_server_security_connector* grpc_fake_server_security_connector_create(
 typedef struct {
 typedef struct {
   tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
   tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
   char* pem_root_certs;
   char* pem_root_certs;
+  verify_peer_options verify_options;
 } grpc_ssl_config;
 } grpc_ssl_config;
 
 
 /* Creates an SSL channel_security_connector.
 /* Creates an SSL channel_security_connector.

+ 12 - 7
src/core/lib/surface/call.cc

@@ -437,6 +437,12 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
                                                &call->pollent);
                                                &call->pollent);
   }
   }
 
 
+  grpc_core::channelz::ChannelNode* channelz_channel =
+      grpc_channel_get_channelz_node(call->channel);
+  if (channelz_channel != nullptr) {
+    channelz_channel->RecordCallStarted();
+  }
+
   grpc_slice_unref_internal(path);
   grpc_slice_unref_internal(path);
 
 
   return error;
   return error;
@@ -975,13 +981,12 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b,
   } else if (b->idx.named.grpc_status != nullptr) {
   } else if (b->idx.named.grpc_status != nullptr) {
     grpc_status_code status_code =
     grpc_status_code status_code =
         grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
         grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
-    grpc_error* error =
-        status_code == GRPC_STATUS_OK
-            ? GRPC_ERROR_NONE
-            : grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                     "Error received from peer"),
-                                 GRPC_ERROR_INT_GRPC_STATUS,
-                                 static_cast<intptr_t>(status_code));
+    grpc_error* error = GRPC_ERROR_NONE;
+    if (status_code != GRPC_STATUS_OK) {
+      error = grpc_error_set_int(
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"),
+          GRPC_ERROR_INT_GRPC_STATUS, static_cast<intptr_t>(status_code));
+    }
     if (b->idx.named.grpc_message != nullptr) {
     if (b->idx.named.grpc_message != nullptr) {
       error = grpc_error_set_str(
       error = grpc_error_set_str(
           error, GRPC_ERROR_STR_GRPC_MESSAGE,
           error, GRPC_ERROR_STR_GRPC_MESSAGE,

+ 20 - 13
src/core/lib/surface/channel.cc

@@ -32,6 +32,7 @@
 
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
@@ -66,7 +67,7 @@ struct grpc_channel {
   gpr_mu registered_call_mu;
   gpr_mu registered_call_mu;
   registered_call* registered_calls;
   registered_call* registered_calls;
 
 
-  grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer;
+  grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
 
 
   char* target;
   char* target;
 };
 };
@@ -103,6 +104,7 @@ grpc_channel* grpc_channel_create_with_builder(
   channel->target = target;
   channel->target = target;
   channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
   channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
   size_t channel_tracer_max_nodes = 0;  // default to off
   size_t channel_tracer_max_nodes = 0;  // default to off
+  bool channelz_enabled = false;
   gpr_mu_init(&channel->registered_call_mu);
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = nullptr;
   channel->registered_calls = nullptr;
 
 
@@ -141,15 +143,20 @@ grpc_channel* grpc_channel_create_with_builder(
       const grpc_integer_options options = {0, 0, INT_MAX};
       const grpc_integer_options options = {0, 0, INT_MAX};
       channel_tracer_max_nodes =
       channel_tracer_max_nodes =
           (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
           (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
+    } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
+      channelz_enabled = grpc_channel_arg_get_bool(&args->args[i], false);
     }
     }
   }
   }
 
 
   grpc_channel_args_destroy(args);
   grpc_channel_args_destroy(args);
-  channel->tracer = grpc_core::MakeRefCounted<grpc_core::ChannelTrace>(
-      channel_tracer_max_nodes);
-  channel->tracer->AddTraceEvent(
-      grpc_core::ChannelTrace::Severity::Info,
-      grpc_slice_from_static_string("Channel created"));
+  if (channelz_enabled) {
+    channel->channelz_channel =
+        grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
+            channel, channel_tracer_max_nodes);
+    channel->channelz_channel->trace()->AddTraceEvent(
+        grpc_core::channelz::ChannelTrace::Severity::Info,
+        grpc_slice_from_static_string("Channel created"));
+  }
   return channel;
   return channel;
 }
 }
 
 
@@ -184,12 +191,9 @@ static grpc_channel_args* build_channel_args(
   return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
   return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
 }
 }
 
 
-char* grpc_channel_get_trace(grpc_channel* channel) {
-  return channel->tracer->RenderTrace();
-}
-
-intptr_t grpc_channel_get_uuid(grpc_channel* channel) {
-  return channel->tracer->GetUuid();
+grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
+    grpc_channel* channel) {
+  return channel->channelz_channel.get();
 }
 }
 
 
 grpc_channel* grpc_channel_create(const char* target,
 grpc_channel* grpc_channel_create(const char* target,
@@ -395,6 +399,10 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
 
 
 static void destroy_channel(void* arg, grpc_error* error) {
 static void destroy_channel(void* arg, grpc_error* error) {
   grpc_channel* channel = static_cast<grpc_channel*>(arg);
   grpc_channel* channel = static_cast<grpc_channel*>(arg);
+  if (channel->channelz_channel != nullptr) {
+    channel->channelz_channel->set_channel_destroyed();
+    channel->channelz_channel.reset();
+  }
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   while (channel->registered_calls) {
   while (channel->registered_calls) {
     registered_call* rc = channel->registered_calls;
     registered_call* rc = channel->registered_calls;
@@ -403,7 +411,6 @@ static void destroy_channel(void* arg, grpc_error* error) {
     GRPC_MDELEM_UNREF(rc->authority);
     GRPC_MDELEM_UNREF(rc->authority);
     gpr_free(rc);
     gpr_free(rc);
   }
   }
-  channel->tracer.reset();
   gpr_mu_destroy(&channel->registered_call_mu);
   gpr_mu_destroy(&channel->registered_call_mu);
   gpr_free(channel->target);
   gpr_free(channel->target);
   gpr_free(channel);
   gpr_free(channel);

+ 4 - 0
src/core/lib/surface/channel.h

@@ -23,6 +23,7 @@
 
 
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/channel/channelz.h"
 #include "src/core/lib/surface/channel_stack_type.h"
 #include "src/core/lib/surface/channel_stack_type.h"
 
 
 grpc_channel* grpc_channel_create(const char* target,
 grpc_channel* grpc_channel_create(const char* target,
@@ -50,6 +51,9 @@ grpc_call* grpc_channel_create_pollset_set_call(
 /** Get a (borrowed) pointer to this channels underlying channel stack */
 /** Get a (borrowed) pointer to this channels underlying channel stack */
 grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel);
 grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel);
 
 
+grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
+    grpc_channel* channel);
+
 /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
 /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
     status_code.
     status_code.
 
 

+ 1 - 1
src/core/lib/surface/version.cc

@@ -25,4 +25,4 @@
 
 
 const char* grpc_version_string(void) { return "6.0.0-dev"; }
 const char* grpc_version_string(void) { return "6.0.0-dev"; }
 
 
-const char* grpc_g_stands_for(void) { return "gloriosa"; }
+const char* grpc_g_stands_for(void) { return "gladiolus"; }

+ 2 - 2
src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h

@@ -21,8 +21,8 @@
 
 
 #include <grpc/support/port_platform.h>
 #include <grpc/support/port_platform.h>
 
 
-#include "third_party/nanopb/pb_decode.h"
-#include "third_party/nanopb/pb_encode.h"
+#include "pb_decode.h"
+#include "pb_encode.h"
 
 
 #include <grpc/slice.h>
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/slice_buffer.h>

+ 1 - 1
src/core/tsi/alts/handshaker/altscontext.pb.h

@@ -3,7 +3,7 @@
 
 
 #ifndef PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
 #ifndef PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
 #define PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
 #define PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
-#include "third_party/nanopb/pb.h"
+#include "pb.h"
 #include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
 #include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
 
 
 /* @@protoc_insertion_point(includes) */
 /* @@protoc_insertion_point(includes) */

+ 1 - 1
src/core/tsi/alts/handshaker/handshaker.pb.h

@@ -3,7 +3,7 @@
 
 
 #ifndef PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
 #ifndef PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
 #define PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
 #define PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
-#include "third_party/nanopb/pb.h"
+#include "pb.h"
 #include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
 #include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
 
 
 /* @@protoc_insertion_point(includes) */
 /* @@protoc_insertion_point(includes) */

+ 1 - 1
src/core/tsi/alts/handshaker/transport_security_common.pb.h

@@ -3,7 +3,7 @@
 
 
 #ifndef PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
 #ifndef PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
 #define PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
 #define PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
-#include "third_party/nanopb/pb.h"
+#include "pb.h"
 /* @@protoc_insertion_point(includes) */
 /* @@protoc_insertion_point(includes) */
 #if PB_PROTO_HEADER_VERSION != 30
 #if PB_PROTO_HEADER_VERSION != 30
 #error Regenerate this file with the current version of nanopb generator.
 #error Regenerate this file with the current version of nanopb generator.

+ 2 - 2
src/core/tsi/alts/handshaker/transport_security_common_api.h

@@ -21,8 +21,8 @@
 
 
 #include <grpc/support/port_platform.h>
 #include <grpc/support/port_platform.h>
 
 
-#include "third_party/nanopb/pb_decode.h"
-#include "third_party/nanopb/pb_encode.h"
+#include "pb_decode.h"
+#include "pb_encode.h"
 
 
 #include <grpc/slice.h>
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/slice_buffer.h>

+ 2 - 3
src/core/tsi/ssl_transport_security.cc

@@ -260,14 +260,13 @@ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
   X509_NAME* subject_name = X509_get_subject_name(cert);
   X509_NAME* subject_name = X509_get_subject_name(cert);
   int utf8_returned_size = 0;
   int utf8_returned_size = 0;
   if (subject_name == nullptr) {
   if (subject_name == nullptr) {
-    gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
+    gpr_log(GPR_INFO, "Could not get subject name from certificate.");
     return TSI_NOT_FOUND;
     return TSI_NOT_FOUND;
   }
   }
   common_name_index =
   common_name_index =
       X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
       X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
   if (common_name_index == -1) {
   if (common_name_index == -1) {
-    gpr_log(GPR_ERROR,
-            "Could not get common name of subject from certificate.");
+    gpr_log(GPR_INFO, "Could not get common name of subject from certificate.");
     return TSI_NOT_FOUND;
     return TSI_NOT_FOUND;
   }
   }
   common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
   common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);

+ 56 - 8
src/cpp/README.md

@@ -1,13 +1,62 @@
 
 
 # Overview
 # Overview
 
 
-This directory contains source code for C++ implementation of gRPC.
+A C++ implementation of gRPC
 
 
-To install gRPC for C++ on your system, follow the instructions to build from source
-[here](../../INSTALL.md). This also installs the protocol buffer compiler
-`protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
+# To start using gRPC C++
 
 
-# Documentation
+In the C++ world, there's no universally accepted standard for managing project dependencies.
+Therefore, gRPC supports several major build systems, which should satisfy most users.
+
+## bazel
+
+We recommend using Bazel for projects that use gRPC as it will give you the best developer experience
+(easy handling of dependencies that support bazel & fast builds).
+
+To add gRPC as a dependency in bazel:
+1. determine commit SHA for the grpc release you want to use
+2. Use the [http_archive](https://docs.bazel.build/versions/master/be/workspace.html#http_archive) bazel rule to include gRPC source
+  ```
+  http_archive(
+      name = "grpc",
+      urls = [
+          "https://github.com/grpc/grpc/archive/YOUR_GRPC_COMMIT_SHA.tar.gz",
+      ],
+      strip_prefix = "grpc-YOUR_GRPC_COMMIT_SHA",
+  )
+  ```
+
+NOTE: currently bazel is only supported for building gRPC on Linux.
+
+## make
+
+Currently the default choice for building on UNIX based systems is `make`.
+
+To install gRPC for C++ on your system using `make`, follow the [Building gRPC C++](../../BUILDING.md)
+instructions to build from source and then install locally using `make install`.
+This also installs the protocol buffer compiler `protoc` (if you don't have it already),
+and the C++ gRPC plugin for `protoc`.
+
+WARNING: After installing with `make install` there is no easy way to uninstall, which can cause issues
+if you later want to remove the grpc and/or protobuf installation or upgrade to a newer version.
+
+## cmake
+
+`cmake` is the default build option on Windows, but also works on Linux, MacOS. `cmake` has good
+support for crosscompiling and can be used for targeting Android platform.
+
+If your project is using cmake, there are several ways to add gRPC dependency.
+- install gRPC via cmake first and then locate it with `find_package(gRPC CONFIG)`. [Example](../../examples/cpp/helloworld/CMakeLists.txt)
+- via cmake's `ExternalProject_Add` using a technique called "superbuild". [Example](../../examples/cpp/helloworld/cmake_externalproject/CMakeLists.txt)
+- add gRPC source tree to your project (preferrably as a git submodule) and add it to your cmake project with `add_subdirectory`. [Example](../../examples/cpp/helloworld/CMakeLists.txt)
+
+## Packaging systems
+
+There's no standard packaging system for C++. We've looked into supporting some (e.g. Conan and vcpkg) but we are not there yet.
+Contributions and community-maintained packages for popular packaging systems are welcome!
+
+
+## Examples & Additional Documentation
 
 
 You can find out how to build and run our simplest gRPC C++ example in our
 You can find out how to build and run our simplest gRPC C++ example in our
 [C++ quick start](../../examples/cpp).
 [C++ quick start](../../examples/cpp).
@@ -25,7 +74,6 @@ documentation site at [grpc.io](https://grpc.io), specifically:
   APIs.
   APIs.
 
 
 
 
-# Examples
+# To start developing gRPC C++
 
 
-Code examples for gRPC C++ live in this repository's
-[examples/cpp](../../examples/cpp) directory.
+For instructions on how to build gRPC C++ from source, follow the [Building gRPC C++](../../BUILDING.md) instructions.

+ 2 - 1
src/cpp/client/secure_credentials.cc

@@ -83,7 +83,8 @@ std::shared_ptr<ChannelCredentials> SslCredentials(
 
 
   grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
   grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
-      options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr);
+      options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr,
+      nullptr);
   return WrapChannelCredentials(c_creds);
   return WrapChannelCredentials(c_creds);
 }
 }
 
 

+ 1 - 1
src/cpp/common/version_cc.cc

@@ -22,5 +22,5 @@
 #include <grpcpp/grpcpp.h>
 #include <grpcpp/grpcpp.h>
 
 
 namespace grpc {
 namespace grpc {
-grpc::string Version() { return "1.13.0-dev"; }
+grpc::string Version() { return "1.14.0-dev"; }
 }  // namespace grpc
 }  // namespace grpc

+ 9 - 10
test/core/statistics/performance_test.cc → src/cpp/ext/filters/census/channel_filter.cc

@@ -1,6 +1,6 @@
 /*
 /*
  *
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
  *
  *
  */
  */
 
 
-#include "test/core/statistics/census_log_tests.h"
+#include <grpc/support/port_platform.h>
 
 
-#include <stdlib.h>
+#include "src/cpp/ext/filters/census/channel_filter.h"
 
 
-#include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
+namespace grpc {
 
 
-int main(int argc, char** argv) {
-  grpc_test_init(argc, argv);
-  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
-  test_performance();
-  return 0;
+grpc_error* CensusChannelData::Init(grpc_channel_element* elem,
+                                    grpc_channel_element_args* args) {
+  return GRPC_ERROR_NONE;
 }
 }
+
+}  // namespace grpc

+ 16 - 11
test/core/statistics/multiple_writers_test.cc → src/cpp/ext/filters/census/channel_filter.h

@@ -1,6 +1,6 @@
 /*
 /*
  *
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -16,16 +16,21 @@
  *
  *
  */
  */
 
 
-#include "test/core/statistics/census_log_tests.h"
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CHANNEL_FILTER_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CHANNEL_FILTER_H
 
 
-#include <stdlib.h>
+#include <grpc/support/port_platform.h>
 
 
-#include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
+#include "src/cpp/ext/filters/census/context.h"
 
 
-int main(int argc, char** argv) {
-  grpc_test_init(argc, argv);
-  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
-  test_multiple_writers();
-  return 0;
-}
+namespace grpc {
+
+class CensusChannelData : public ChannelData {
+ public:
+  grpc_error* Init(grpc_channel_element* elem,
+                   grpc_channel_element_args* args) override;
+};
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CHANNEL_FILTER_H */

+ 165 - 0
src/cpp/ext/filters/census/client_filter.cc

@@ -0,0 +1,165 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/client_filter.h"
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "opencensus/stats/stats.h"
+#include "src/core/lib/surface/call.h"
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+#include "src/cpp/ext/filters/census/measures.h"
+
+namespace grpc {
+
+constexpr uint32_t CensusClientCallData::kMaxTraceContextLen;
+constexpr uint32_t CensusClientCallData::kMaxTagsLen;
+
+namespace {
+
+void FilterTrailingMetadata(grpc_metadata_batch* b, uint64_t* elapsed_time) {
+  if (b->idx.named.grpc_server_stats_bin != nullptr) {
+    ServerStatsDeserialize(
+        reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(
+            GRPC_MDVALUE(b->idx.named.grpc_server_stats_bin->md))),
+        GRPC_SLICE_LENGTH(GRPC_MDVALUE(b->idx.named.grpc_server_stats_bin->md)),
+        elapsed_time);
+    grpc_metadata_batch_remove(b, b->idx.named.grpc_server_stats_bin);
+  }
+}
+
+}  // namespace
+
+void CensusClientCallData::OnDoneRecvTrailingMetadataCb(void* user_data,
+                                                        grpc_error* error) {
+  grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
+  CensusClientCallData* calld =
+      reinterpret_cast<CensusClientCallData*>(elem->call_data);
+  GPR_ASSERT(calld != nullptr);
+  if (error == GRPC_ERROR_NONE) {
+    GPR_ASSERT(calld->recv_trailing_metadata_ != nullptr);
+    FilterTrailingMetadata(calld->recv_trailing_metadata_,
+                           &calld->elapsed_time_);
+  }
+  GRPC_CLOSURE_RUN(calld->initial_on_done_recv_trailing_metadata_,
+                   GRPC_ERROR_REF(error));
+}
+
+void CensusClientCallData::OnDoneRecvMessageCb(void* user_data,
+                                               grpc_error* error) {
+  grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
+  CensusClientCallData* calld =
+      reinterpret_cast<CensusClientCallData*>(elem->call_data);
+  CensusChannelData* channeld =
+      reinterpret_cast<CensusChannelData*>(elem->channel_data);
+  GPR_ASSERT(calld != nullptr);
+  GPR_ASSERT(channeld != nullptr);
+  // Stream messages are no longer valid after receiving trailing metadata.
+  if ((*calld->recv_message_) != nullptr) {
+    calld->recv_message_count_++;
+  }
+  GRPC_CLOSURE_RUN(calld->initial_on_done_recv_message_, GRPC_ERROR_REF(error));
+}
+
+void CensusClientCallData::StartTransportStreamOpBatch(
+    grpc_call_element* elem, TransportStreamOpBatch* op) {
+  if (op->send_initial_metadata() != nullptr) {
+    census_context* ctxt = op->get_census_context();
+    GenerateClientContext(
+        qualified_method_, &context_,
+        (ctxt == nullptr) ? nullptr : reinterpret_cast<CensusContext*>(ctxt));
+    size_t tracing_len = TraceContextSerialize(context_.Context(), tracing_buf_,
+                                               kMaxTraceContextLen);
+    if (tracing_len > 0) {
+      GRPC_LOG_IF_ERROR(
+          "census grpc_filter",
+          grpc_metadata_batch_add_tail(
+              op->send_initial_metadata()->batch(), &tracing_bin_,
+              grpc_mdelem_from_slices(
+                  GRPC_MDSTR_GRPC_TRACE_BIN,
+                  grpc_slice_from_copied_buffer(tracing_buf_, tracing_len))));
+    }
+    grpc_slice tags = grpc_empty_slice();
+    // TODO: Add in tagging serialization.
+    size_t encoded_tags_len = StatsContextSerialize(kMaxTagsLen, &tags);
+    if (encoded_tags_len > 0) {
+      GRPC_LOG_IF_ERROR(
+          "census grpc_filter",
+          grpc_metadata_batch_add_tail(
+              op->send_initial_metadata()->batch(), &stats_bin_,
+              grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_TAGS_BIN, tags)));
+    }
+  }
+
+  if (op->send_message() != nullptr) {
+    ++sent_message_count_;
+  }
+  if (op->recv_message() != nullptr) {
+    recv_message_ = op->op()->payload->recv_message.recv_message;
+    initial_on_done_recv_message_ =
+        op->op()->payload->recv_message.recv_message_ready;
+    op->op()->payload->recv_message.recv_message_ready = &on_done_recv_message_;
+  }
+  if (op->recv_trailing_metadata() != nullptr) {
+    recv_trailing_metadata_ = op->recv_trailing_metadata()->batch();
+    initial_on_done_recv_trailing_metadata_ =
+        op->op()->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
+    op->op()->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
+        &on_done_recv_trailing_metadata_;
+  }
+  // Call next op.
+  grpc_call_next_op(elem, op->op());
+}
+
+grpc_error* CensusClientCallData::Init(grpc_call_element* elem,
+                                       const grpc_call_element_args* args) {
+  path_ = grpc_slice_ref_internal(args->path);
+  start_time_ = absl::Now();
+  method_ = GetMethod(&path_);
+  qualified_method_ = absl::StrCat("Sent.", method_);
+  GRPC_CLOSURE_INIT(&on_done_recv_message_, OnDoneRecvMessageCb, elem,
+                    grpc_schedule_on_exec_ctx);
+  GRPC_CLOSURE_INIT(&on_done_recv_trailing_metadata_,
+                    OnDoneRecvTrailingMetadataCb, elem,
+                    grpc_schedule_on_exec_ctx);
+  return GRPC_ERROR_NONE;
+}
+
+void CensusClientCallData::Destroy(grpc_call_element* elem,
+                                   const grpc_call_final_info* final_info,
+                                   grpc_closure* then_call_closure) {
+  const uint64_t request_size = GetOutgoingDataSize(final_info);
+  const uint64_t response_size = GetIncomingDataSize(final_info);
+  double latency_ms = absl::ToDoubleMilliseconds(absl::Now() - start_time_);
+  ::opencensus::stats::Record(
+      {{RpcClientSentBytesPerRpc(), static_cast<double>(request_size)},
+       {RpcClientReceivedBytesPerRpc(), static_cast<double>(response_size)},
+       {RpcClientRoundtripLatency(), latency_ms},
+       {RpcClientServerLatency(),
+        ToDoubleMilliseconds(absl::Nanoseconds(elapsed_time_))},
+       {RpcClientSentMessagesPerRpc(), sent_message_count_},
+       {RpcClientReceivedMessagesPerRpc(), recv_message_count_}},
+      {{ClientMethodTagKey(), method_},
+       {ClientStatusTagKey(), StatusCodeToString(final_info->final_status)}});
+  grpc_slice_unref_internal(path_);
+  context_.EndSpan();
+}
+
+}  // namespace grpc

+ 104 - 0
src/cpp/ext/filters/census/client_filter.h

@@ -0,0 +1,104 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CLIENT_FILTER_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CLIENT_FILTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+#include "src/cpp/ext/filters/census/channel_filter.h"
+#include "src/cpp/ext/filters/census/context.h"
+
+namespace grpc {
+
+// A CallData class will be created for every grpc call within a channel. It is
+// used to store data and methods specific to that call. CensusClientCallData is
+// thread-compatible, however typically only 1 thread should be interacting with
+// a call at a time.
+class CensusClientCallData : public CallData {
+ public:
+  // Maximum size of trace context is sent on the wire.
+  static constexpr uint32_t kMaxTraceContextLen = 64;
+  // Maximum size of tags that are sent on the wire.
+  static constexpr uint32_t kMaxTagsLen = 2048;
+
+  CensusClientCallData()
+      : recv_trailing_metadata_(nullptr),
+        initial_on_done_recv_trailing_metadata_(nullptr),
+        initial_on_done_recv_message_(nullptr),
+        elapsed_time_(0),
+        recv_message_(nullptr),
+        recv_message_count_(0),
+        sent_message_count_(0) {
+    memset(&stats_bin_, 0, sizeof(grpc_linked_mdelem));
+    memset(&tracing_bin_, 0, sizeof(grpc_linked_mdelem));
+    memset(&path_, 0, sizeof(grpc_slice));
+    memset(&on_done_recv_trailing_metadata_, 0, sizeof(grpc_closure));
+    memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
+  }
+
+  grpc_error* Init(grpc_call_element* elem,
+                   const grpc_call_element_args* args) override;
+
+  void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
+               grpc_closure* then_call_closure) override;
+
+  void StartTransportStreamOpBatch(grpc_call_element* elem,
+                                   TransportStreamOpBatch* op) override;
+
+  static void OnDoneRecvTrailingMetadataCb(void* user_data, grpc_error* error);
+
+  static void OnDoneSendInitialMetadataCb(void* user_data, grpc_error* error);
+
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+
+ private:
+  CensusContext context_;
+  // Metadata elements for tracing and census stats data.
+  grpc_linked_mdelem stats_bin_;
+  grpc_linked_mdelem tracing_bin_;
+  // Client method.
+  absl::string_view method_;
+  std::string qualified_method_;
+  grpc_slice path_;
+  // The recv trailing metadata callbacks.
+  grpc_metadata_batch* recv_trailing_metadata_;
+  grpc_closure* initial_on_done_recv_trailing_metadata_;
+  grpc_closure on_done_recv_trailing_metadata_;
+  // recv message
+  grpc_closure* initial_on_done_recv_message_;
+  grpc_closure on_done_recv_message_;
+  // Start time (for measuring latency).
+  absl::Time start_time_;
+  // Server elapsed time in nanoseconds.
+  uint64_t elapsed_time_;
+  // The received message--may be null.
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message_;
+  // Number of messages in this RPC.
+  uint64_t recv_message_count_;
+  uint64_t sent_message_count_;
+  // Buffer needed for grpc_slice to reference when adding trace context
+  // metatdata to outgoing message.
+  char tracing_buf_[kMaxTraceContextLen];
+};
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CLIENT_FILTER_H */

+ 132 - 0
src/cpp/ext/filters/census/context.cc

@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/context.h"
+
+namespace grpc {
+
+using ::opencensus::trace::Span;
+using ::opencensus::trace::SpanContext;
+
+void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
+                           absl::string_view primary_role,
+                           absl::string_view method, CensusContext* context) {
+  GrpcTraceContext trace_ctxt;
+  TraceContextEncoding::Decode(tracing, &trace_ctxt);
+  SpanContext parent_ctx = trace_ctxt.ToSpanContext();
+  new (context) CensusContext(method, parent_ctx);
+}
+
+void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
+                           CensusContext* parent_ctxt) {
+  if (parent_ctxt != nullptr) {
+    SpanContext span_ctxt = parent_ctxt->Context();
+    Span span = parent_ctxt->Span();
+    if (span_ctxt.IsValid()) {
+      new (ctxt) CensusContext(method, &span);
+      return;
+    }
+  }
+  new (ctxt) CensusContext(method);
+}
+
+size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
+                             char* tracing_buf, size_t tracing_buf_size) {
+  GrpcTraceContext trace_ctxt(context);
+  return TraceContextEncoding::Encode(trace_ctxt, tracing_buf,
+                                      tracing_buf_size);
+}
+
+size_t StatsContextSerialize(size_t max_tags_len, grpc_slice* tags) {
+  // TODO: Add implementation. Waiting on stats tagging to be added.
+  return 0;
+}
+
+size_t ServerStatsSerialize(uint64_t server_elapsed_time, char* buf,
+                            size_t buf_size) {
+  return RpcServerStatsEncoding::Encode(server_elapsed_time, buf, buf_size);
+}
+
+size_t ServerStatsDeserialize(const char* buf, size_t buf_size,
+                              uint64_t* server_elapsed_time) {
+  return RpcServerStatsEncoding::Decode(absl::string_view(buf, buf_size),
+                                        server_elapsed_time);
+}
+
+uint64_t GetIncomingDataSize(const grpc_call_final_info* final_info) {
+  return final_info->stats.transport_stream_stats.incoming.data_bytes;
+}
+
+uint64_t GetOutgoingDataSize(const grpc_call_final_info* final_info) {
+  return final_info->stats.transport_stream_stats.outgoing.data_bytes;
+}
+
+SpanContext SpanContextFromCensusContext(const census_context* ctxt) {
+  return reinterpret_cast<const CensusContext*>(ctxt)->Context();
+}
+
+Span SpanFromCensusContext(const census_context* ctxt) {
+  return reinterpret_cast<const CensusContext*>(ctxt)->Span();
+}
+
+absl::string_view StatusCodeToString(grpc_status_code code) {
+  switch (code) {
+    case GRPC_STATUS_OK:
+      return "OK";
+    case GRPC_STATUS_CANCELLED:
+      return "CANCELLED";
+    case GRPC_STATUS_UNKNOWN:
+      return "UNKNOWN";
+    case GRPC_STATUS_INVALID_ARGUMENT:
+      return "INVALID_ARGUMENT";
+    case GRPC_STATUS_DEADLINE_EXCEEDED:
+      return "DEADLINE_EXCEEDED";
+    case GRPC_STATUS_NOT_FOUND:
+      return "NOT_FOUND";
+    case GRPC_STATUS_ALREADY_EXISTS:
+      return "ALREADY_EXISTS";
+    case GRPC_STATUS_PERMISSION_DENIED:
+      return "PERMISSION_DENIED";
+    case GRPC_STATUS_UNAUTHENTICATED:
+      return "UNAUTHENTICATED";
+    case GRPC_STATUS_RESOURCE_EXHAUSTED:
+      return "RESOURCE_EXHAUSTED";
+    case GRPC_STATUS_FAILED_PRECONDITION:
+      return "FAILED_PRECONDITION";
+    case GRPC_STATUS_ABORTED:
+      return "ABORTED";
+    case GRPC_STATUS_OUT_OF_RANGE:
+      return "OUT_OF_RANGE";
+    case GRPC_STATUS_UNIMPLEMENTED:
+      return "UNIMPLEMENTED";
+    case GRPC_STATUS_INTERNAL:
+      return "INTERNAL";
+    case GRPC_STATUS_UNAVAILABLE:
+      return "UNAVAILABLE";
+    case GRPC_STATUS_DATA_LOSS:
+      return "DATA_LOSS";
+    default:
+      // gRPC wants users of this enum to include a default branch so that
+      // adding values is not a breaking change.
+      return "UNKNOWN_STATUS";
+  }
+}
+
+}  // namespace grpc

+ 126 - 0
src/cpp/ext/filters/census/context.h

@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CONTEXT_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CONTEXT_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/status.h>
+#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+#include "opencensus/trace/span.h"
+#include "opencensus/trace/span_context.h"
+#include "opencensus/trace/trace_params.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/cpp/common/channel_filter.h"
+#include "src/cpp/ext/filters/census/rpc_encoding.h"
+
+// This is needed because grpc has hardcoded CensusContext with a
+// forward declaration of 'struct census_context;'
+struct census_context;
+
+namespace grpc {
+
+// Thread compatible.
+class CensusContext {
+ public:
+  CensusContext() : span_(::opencensus::trace::Span::BlankSpan()) {}
+
+  explicit CensusContext(absl::string_view name)
+      : span_(::opencensus::trace::Span::StartSpan(name)) {}
+
+  CensusContext(absl::string_view name, const ::opencensus::trace::Span* parent)
+      : span_(::opencensus::trace::Span::StartSpan(name, parent)) {}
+
+  CensusContext(absl::string_view name,
+                const ::opencensus::trace::SpanContext& parent_ctxt)
+      : span_(::opencensus::trace::Span::StartSpanWithRemoteParent(
+            name, parent_ctxt)) {}
+
+  ::opencensus::trace::SpanContext Context() const { return span_.context(); }
+  ::opencensus::trace::Span Span() const { return span_; }
+  void EndSpan() { span_.End(); }
+
+ private:
+  ::opencensus::trace::Span span_;
+};
+
+// Serializes the outgoing trace context. Field IDs are 1 byte followed by
+// field data. A 1 byte version ID is always encoded first.
+size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,
+                             char* tracing_buf, size_t tracing_buf_size);
+
+// Serializes the outgoing stats context.  Field IDs are 1 byte followed by
+// field data. A 1 byte version ID is always encoded first. Tags are directly
+// serialized into the given grpc_slice.
+size_t StatsContextSerialize(size_t max_tags_len, grpc_slice* tags);
+
+// Serialize outgoing server stats. Returns the number of bytes serialized.
+size_t ServerStatsSerialize(uint64_t server_elapsed_time, char* buf,
+                            size_t buf_size);
+
+// Deserialize incoming server stats. Returns the number of bytes deserialized.
+size_t ServerStatsDeserialize(const char* buf, size_t buf_size,
+                              uint64_t* server_elapsed_time);
+
+// Deserialize the incoming SpanContext and generate a new server context based
+// on that. This new span will never be a root span. This should only be called
+// with a blank CensusContext as it overwrites it.
+void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
+                           absl::string_view primary_role,
+                           absl::string_view method, CensusContext* context);
+
+// Creates a new client context that is by default a new root context.
+// If the current context is the default context then the newly created
+// span automatically becomes a root span. This should only be called with a
+// blank CensusContext as it overwrites it.
+void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
+                           CensusContext* parent_ctx);
+
+// Returns the incoming data size from the grpc call final info.
+uint64_t GetIncomingDataSize(const grpc_call_final_info* final_info);
+
+// Returns the outgoing data size from the grpc call final info.
+uint64_t GetOutgoingDataSize(const grpc_call_final_info* final_info);
+
+// These helper functions return the SpanContext and Span, respectively
+// associated with the census_context* stored by grpc. The user will need to
+// call this for manual propagation of tracing data.
+::opencensus::trace::SpanContext SpanContextFromCensusContext(
+    const census_context* ctxt);
+::opencensus::trace::Span SpanFromCensusContext(const census_context* ctxt);
+
+// Returns a string representation of the StatusCode enum.
+absl::string_view StatusCodeToString(grpc_status_code code);
+
+inline absl::string_view GetMethod(const grpc_slice* path) {
+  if (GRPC_SLICE_IS_EMPTY(*path)) {
+    return "";
+  }
+  // Check for leading '/' and trim it if present.
+  return absl::StripPrefix(absl::string_view(reinterpret_cast<const char*>(
+                                                 GRPC_SLICE_START_PTR(*path)),
+                                             GRPC_SLICE_LENGTH(*path)),
+                           "/");
+}
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_CONTEXT_H */

+ 0 - 0
src/core/ext/census/grpc_context.cc → src/cpp/ext/filters/census/grpc_context.cc


+ 130 - 0
src/cpp/ext/filters/census/grpc_plugin.cc

@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+
+#include <grpcpp/server_context.h>
+
+#include "opencensus/trace/span.h"
+#include "src/cpp/ext/filters/census/channel_filter.h"
+#include "src/cpp/ext/filters/census/client_filter.h"
+#include "src/cpp/ext/filters/census/measures.h"
+#include "src/cpp/ext/filters/census/server_filter.h"
+
+namespace grpc {
+
+void RegisterOpenCensusPlugin() {
+  RegisterChannelFilter<CensusChannelData, CensusClientCallData>(
+      "opencensus_client", GRPC_CLIENT_CHANNEL, INT_MAX /* priority */,
+      nullptr /* condition function */);
+  RegisterChannelFilter<CensusChannelData, CensusServerCallData>(
+      "opencensus_server", GRPC_SERVER_CHANNEL, INT_MAX /* priority */,
+      nullptr /* condition function */);
+
+  // Access measures to ensure they are initialized. Otherwise, creating a view
+  // before the first RPC would cause an error.
+  RpcClientSentBytesPerRpc();
+  RpcClientReceivedBytesPerRpc();
+  RpcClientRoundtripLatency();
+  RpcClientServerLatency();
+  RpcClientSentMessagesPerRpc();
+  RpcClientReceivedMessagesPerRpc();
+
+  RpcServerSentBytesPerRpc();
+  RpcServerReceivedBytesPerRpc();
+  RpcServerServerLatency();
+  RpcServerSentMessagesPerRpc();
+  RpcServerReceivedMessagesPerRpc();
+}
+
+::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context) {
+  return reinterpret_cast<const CensusContext*>(context->census_context())
+      ->Span();
+}
+
+// These measure definitions should be kept in sync across opencensus
+// implementations--see
+// https://github.com/census-instrumentation/opencensus-java/blob/master/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcMeasureConstants.java.
+::opencensus::stats::TagKey ClientMethodTagKey() {
+  static const auto method_tag_key =
+      ::opencensus::stats::TagKey::Register("grpc_client_method");
+  return method_tag_key;
+}
+
+::opencensus::stats::TagKey ClientStatusTagKey() {
+  static const auto status_tag_key =
+      ::opencensus::stats::TagKey::Register("grpc_client_status");
+  return status_tag_key;
+}
+
+::opencensus::stats::TagKey ServerMethodTagKey() {
+  static const auto method_tag_key =
+      ::opencensus::stats::TagKey::Register("grpc_server_method");
+  return method_tag_key;
+}
+
+::opencensus::stats::TagKey ServerStatusTagKey() {
+  static const auto status_tag_key =
+      ::opencensus::stats::TagKey::Register("grpc_server_status");
+  return status_tag_key;
+}
+
+// Client
+ABSL_CONST_INIT const absl::string_view
+    kRpcClientSentMessagesPerRpcMeasureName =
+        "grpc.io/client/sent_messages_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view kRpcClientSentBytesPerRpcMeasureName =
+    "grpc.io/client/sent_bytes_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view
+    kRpcClientReceivedMessagesPerRpcMeasureName =
+        "grpc.io/client/received_messages_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view
+    kRpcClientReceivedBytesPerRpcMeasureName =
+        "grpc.io/client/received_bytes_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view kRpcClientRoundtripLatencyMeasureName =
+    "grpc.io/client/roundtrip_latency";
+
+ABSL_CONST_INIT const absl::string_view kRpcClientServerLatencyMeasureName =
+    "grpc.io/client/server_latency";
+
+// Server
+ABSL_CONST_INIT const absl::string_view
+    kRpcServerSentMessagesPerRpcMeasureName =
+        "grpc.io/server/sent_messages_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view kRpcServerSentBytesPerRpcMeasureName =
+    "grpc.io/server/sent_bytes_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view
+    kRpcServerReceivedMessagesPerRpcMeasureName =
+        "grpc.io/server/received_messages_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view
+    kRpcServerReceivedBytesPerRpcMeasureName =
+        "grpc.io/server/received_bytes_per_rpc";
+
+ABSL_CONST_INIT const absl::string_view kRpcServerServerLatencyMeasureName =
+    "grpc.io/server/server_latency";
+
+}  // namespace grpc

+ 111 - 0
src/cpp/ext/filters/census/grpc_plugin.h

@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_GRPC_PLUGIN_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_GRPC_PLUGIN_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/strings/string_view.h"
+#include "include/grpcpp/opencensus.h"
+#include "opencensus/stats/stats.h"
+#include "opencensus/trace/span.h"
+
+namespace grpc {
+
+class ServerContext;
+
+// Returns the tracing Span for the current RPC.
+::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context);
+
+// The tag keys set when recording RPC stats.
+::opencensus::stats::TagKey ClientMethodTagKey();
+::opencensus::stats::TagKey ClientStatusTagKey();
+::opencensus::stats::TagKey ServerMethodTagKey();
+::opencensus::stats::TagKey ServerStatusTagKey();
+
+// Names of measures used by the plugin--users can create views on these
+// measures but should not record data for them.
+extern const absl::string_view kRpcClientSentMessagesPerRpcMeasureName;
+extern const absl::string_view kRpcClientSentBytesPerRpcMeasureName;
+extern const absl::string_view kRpcClientReceivedMessagesPerRpcMeasureName;
+extern const absl::string_view kRpcClientReceivedBytesPerRpcMeasureName;
+extern const absl::string_view kRpcClientRoundtripLatencyMeasureName;
+extern const absl::string_view kRpcClientServerLatencyMeasureName;
+
+extern const absl::string_view kRpcServerSentMessagesPerRpcMeasureName;
+extern const absl::string_view kRpcServerSentBytesPerRpcMeasureName;
+extern const absl::string_view kRpcServerReceivedMessagesPerRpcMeasureName;
+extern const absl::string_view kRpcServerReceivedBytesPerRpcMeasureName;
+extern const absl::string_view kRpcServerServerLatencyMeasureName;
+
+// Canonical gRPC view definitions.
+const ::opencensus::stats::ViewDescriptor& ClientSentMessagesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor& ClientSentBytesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor&
+ClientReceivedMessagesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor&
+ClientReceivedBytesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor& ClientRoundtripLatencyCumulative();
+const ::opencensus::stats::ViewDescriptor& ClientServerLatencyCumulative();
+const ::opencensus::stats::ViewDescriptor& ClientCompletedRpcsCumulative();
+
+const ::opencensus::stats::ViewDescriptor& ServerSentBytesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor&
+ServerReceivedBytesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor& ServerServerLatencyCumulative();
+const ::opencensus::stats::ViewDescriptor& ServerStartedCountCumulative();
+const ::opencensus::stats::ViewDescriptor& ServerCompletedRpcsCumulative();
+const ::opencensus::stats::ViewDescriptor& ServerSentMessagesPerRpcCumulative();
+const ::opencensus::stats::ViewDescriptor&
+ServerReceivedMessagesPerRpcCumulative();
+
+const ::opencensus::stats::ViewDescriptor& ClientSentMessagesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ClientSentBytesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ClientReceivedMessagesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ClientReceivedBytesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ClientRoundtripLatencyMinute();
+const ::opencensus::stats::ViewDescriptor& ClientServerLatencyMinute();
+const ::opencensus::stats::ViewDescriptor& ClientCompletedRpcsMinute();
+
+const ::opencensus::stats::ViewDescriptor& ServerSentMessagesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ServerSentBytesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ServerReceivedMessagesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ServerReceivedBytesPerRpcMinute();
+const ::opencensus::stats::ViewDescriptor& ServerServerLatencyMinute();
+const ::opencensus::stats::ViewDescriptor& ServerCompletedRpcsMinute();
+
+const ::opencensus::stats::ViewDescriptor& ClientSentMessagesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ClientSentBytesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ClientReceivedMessagesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ClientReceivedBytesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ClientRoundtripLatencyHour();
+const ::opencensus::stats::ViewDescriptor& ClientServerLatencyHour();
+const ::opencensus::stats::ViewDescriptor& ClientCompletedRpcsHour();
+
+const ::opencensus::stats::ViewDescriptor& ServerSentMessagesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ServerSentBytesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ServerReceivedMessagesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ServerReceivedBytesPerRpcHour();
+const ::opencensus::stats::ViewDescriptor& ServerServerLatencyHour();
+const ::opencensus::stats::ViewDescriptor& ServerStartedCountHour();
+const ::opencensus::stats::ViewDescriptor& ServerCompletedRpcsHour();
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_GRPC_PLUGIN_H */

+ 129 - 0
src/cpp/ext/filters/census/measures.cc

@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/measures.h"
+
+#include "opencensus/stats/stats.h"
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+
+namespace grpc {
+
+using ::opencensus::stats::MeasureDouble;
+using ::opencensus::stats::MeasureInt64;
+
+// These measure definitions should be kept in sync across opencensus
+// implementations--see
+// https://github.com/census-instrumentation/opencensus-java/blob/master/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcMeasureConstants.java.
+
+namespace {
+
+// Unit constants
+constexpr char kUnitBytes[] = "By";
+constexpr char kUnitMilliseconds[] = "ms";
+constexpr char kCount[] = "1";
+
+}  // namespace
+
+// Client
+MeasureDouble RpcClientSentBytesPerRpc() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcClientSentBytesPerRpcMeasureName,
+      "Total bytes sent across all request messages per RPC", kUnitBytes);
+  return measure;
+}
+
+MeasureDouble RpcClientReceivedBytesPerRpc() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcClientReceivedBytesPerRpcMeasureName,
+      "Total bytes received across all response messages per RPC", kUnitBytes);
+  return measure;
+}
+
+MeasureDouble RpcClientRoundtripLatency() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcClientRoundtripLatencyMeasureName,
+      "Time between first byte of request sent to last byte of response "
+      "received, or terminal error",
+      kUnitMilliseconds);
+  return measure;
+}
+
+MeasureDouble RpcClientServerLatency() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcClientServerLatencyMeasureName,
+      "Time between first byte of request received to last byte of response "
+      "sent, or terminal error (propagated from the server)",
+      kUnitMilliseconds);
+  return measure;
+}
+
+MeasureInt64 RpcClientSentMessagesPerRpc() {
+  static const auto measure =
+      MeasureInt64::Register(kRpcClientSentMessagesPerRpcMeasureName,
+                             "Number of messages sent per RPC", kCount);
+  return measure;
+}
+
+MeasureInt64 RpcClientReceivedMessagesPerRpc() {
+  static const auto measure =
+      MeasureInt64::Register(kRpcClientReceivedMessagesPerRpcMeasureName,
+                             "Number of messages received per RPC", kCount);
+  return measure;
+}
+
+// Server
+MeasureDouble RpcServerSentBytesPerRpc() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcServerSentBytesPerRpcMeasureName,
+      "Total bytes sent across all messages per RPC", kUnitBytes);
+  return measure;
+}
+
+MeasureDouble RpcServerReceivedBytesPerRpc() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcServerReceivedBytesPerRpcMeasureName,
+      "Total bytes received across all messages per RPC", kUnitBytes);
+  return measure;
+}
+
+MeasureDouble RpcServerServerLatency() {
+  static const auto measure = MeasureDouble::Register(
+      kRpcServerServerLatencyMeasureName,
+      "Time between first byte of request received to last byte of response "
+      "sent, or terminal error",
+      kUnitMilliseconds);
+  return measure;
+}
+
+MeasureInt64 RpcServerSentMessagesPerRpc() {
+  static const auto measure =
+      MeasureInt64::Register(kRpcServerSentMessagesPerRpcMeasureName,
+                             "Number of messages sent per RPC", kCount);
+  return measure;
+}
+
+MeasureInt64 RpcServerReceivedMessagesPerRpc() {
+  static const auto measure =
+      MeasureInt64::Register(kRpcServerReceivedMessagesPerRpcMeasureName,
+                             "Number of messages received per RPC", kCount);
+  return measure;
+}
+
+}  // namespace grpc

+ 46 - 0
src/cpp/ext/filters/census/measures.h

@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_MEASURES_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_MEASURES_H
+
+#include <grpc/support/port_platform.h>
+
+#include "opencensus/stats/stats.h"
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+
+namespace grpc {
+
+::opencensus::stats::MeasureInt64 RpcClientSentMessagesPerRpc();
+::opencensus::stats::MeasureDouble RpcClientSentBytesPerRpc();
+::opencensus::stats::MeasureInt64 RpcClientReceivedMessagesPerRpc();
+::opencensus::stats::MeasureDouble RpcClientReceivedBytesPerRpc();
+::opencensus::stats::MeasureDouble RpcClientRoundtripLatency();
+::opencensus::stats::MeasureDouble RpcClientServerLatency();
+::opencensus::stats::MeasureInt64 RpcClientCompletedRpcs();
+
+::opencensus::stats::MeasureInt64 RpcServerSentMessagesPerRpc();
+::opencensus::stats::MeasureDouble RpcServerSentBytesPerRpc();
+::opencensus::stats::MeasureInt64 RpcServerReceivedMessagesPerRpc();
+::opencensus::stats::MeasureDouble RpcServerReceivedBytesPerRpc();
+::opencensus::stats::MeasureDouble RpcServerServerLatency();
+::opencensus::stats::MeasureInt64 RpcServerCompletedRpcs();
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_MEASURES_H */

+ 39 - 0
src/cpp/ext/filters/census/rpc_encoding.cc

@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/rpc_encoding.h"
+
+namespace grpc {
+
+constexpr size_t TraceContextEncoding::kGrpcTraceContextSize;
+constexpr size_t TraceContextEncoding::kEncodeDecodeFailure;
+constexpr size_t TraceContextEncoding::kVersionIdSize;
+constexpr size_t TraceContextEncoding::kFieldIdSize;
+constexpr size_t TraceContextEncoding::kVersionIdOffset;
+constexpr size_t TraceContextEncoding::kVersionId;
+
+constexpr size_t RpcServerStatsEncoding::kRpcServerStatsSize;
+constexpr size_t RpcServerStatsEncoding::kEncodeDecodeFailure;
+constexpr size_t RpcServerStatsEncoding::kVersionIdSize;
+constexpr size_t RpcServerStatsEncoding::kFieldIdSize;
+constexpr size_t RpcServerStatsEncoding::kVersionIdOffset;
+constexpr size_t RpcServerStatsEncoding::kVersionId;
+
+}  // namespace grpc

+ 284 - 0
src/cpp/ext/filters/census/rpc_encoding.h

@@ -0,0 +1,284 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_RPC_ENCODING_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_RPC_ENCODING_H
+
+#include <grpc/support/port_platform.h>
+
+#include <string.h>
+
+#include "absl/base/internal/endian.h"
+#include "absl/strings/string_view.h"
+#include "opencensus/trace/span_context.h"
+#include "opencensus/trace/span_id.h"
+#include "opencensus/trace/trace_id.h"
+
+namespace grpc {
+
+// TODO: Rename to GrpcTraceContextV0.
+struct GrpcTraceContext {
+  GrpcTraceContext() {}
+
+  explicit GrpcTraceContext(const ::opencensus::trace::SpanContext& ctx) {
+    ctx.trace_id().CopyTo(trace_id);
+    ctx.span_id().CopyTo(span_id);
+    ctx.trace_options().CopyTo(trace_options);
+  }
+
+  ::opencensus::trace::SpanContext ToSpanContext() const {
+    return ::opencensus::trace::SpanContext(
+        ::opencensus::trace::TraceId(trace_id),
+        ::opencensus::trace::SpanId(span_id),
+        ::opencensus::trace::TraceOptions(trace_options));
+  }
+
+  // TODO: For performance:
+  // uint8_t version;
+  // uint8_t trace_id_field_id;
+  uint8_t trace_id[::opencensus::trace::TraceId::kSize];
+  // uint8_t span_id_field_id;
+  uint8_t span_id[::opencensus::trace::SpanId::kSize];
+  // uint8_t trace_options_field_id;
+  uint8_t trace_options[::opencensus::trace::TraceOptions::kSize];
+};
+
+// TraceContextEncoding encapsulates the logic for encoding and decoding of
+// trace contexts.
+class TraceContextEncoding {
+ public:
+  // Size of encoded GrpcTraceContext. (16 + 8 + 1 + 4)
+  static constexpr size_t kGrpcTraceContextSize = 29;
+  // Error value.
+  static constexpr size_t kEncodeDecodeFailure = 0;
+
+  // Deserializes a GrpcTraceContext from the incoming buffer. Returns the
+  // number of bytes deserialized from the buffer. If the incoming buffer is
+  // empty or the encoding version is not supported it will return 0 bytes,
+  // currently only version 0 is supported. If an unknown field ID is
+  // encountered it will return immediately without parsing the rest of the
+  // buffer. Inlined for performance reasons.
+  static size_t Decode(absl::string_view buf, GrpcTraceContext* tc) {
+    if (buf.empty()) {
+      return kEncodeDecodeFailure;
+    }
+    uint8_t version = buf[kVersionIdOffset];
+    // TODO: Support other versions later. Only support version 0 for
+    // now.
+    if (version != kVersionId) {
+      return kEncodeDecodeFailure;
+    }
+
+    size_t pos = kVersionIdSize;
+    while (pos < buf.size()) {
+      size_t bytes_read =
+          ParseField(absl::string_view(&buf[pos], buf.size() - pos), tc);
+      if (bytes_read == 0) {
+        break;
+      } else {
+        pos += bytes_read;
+      }
+    }
+    return pos;
+  }
+
+  // Serializes a GrpcTraceContext into the provided buffer. Returns the number
+  // of bytes serialized into the buffer. If the buffer is not of sufficient
+  // size (it must be at least kGrpcTraceContextSize bytes) it will drop
+  // everything and return 0 bytes serialized. Inlined for performance reasons.
+  static size_t Encode(const GrpcTraceContext& tc, char* buf, size_t buf_size) {
+    if (buf_size < kGrpcTraceContextSize) {
+      return kEncodeDecodeFailure;
+    }
+    buf[kVersionIdOffset] = kVersionId;
+    buf[kTraceIdOffset] = kTraceIdField;
+    memcpy(&buf[kTraceIdOffset + 1], tc.trace_id,
+           opencensus::trace::TraceId::kSize);
+    buf[kSpanIdOffset] = kSpanIdField;
+    memcpy(&buf[kSpanIdOffset + 1], tc.span_id,
+           opencensus::trace::SpanId::kSize);
+    buf[kTraceOptionsOffset] = kTraceOptionsField;
+    memcpy(&buf[kTraceOptionsOffset + 1], tc.trace_options,
+           opencensus::trace::TraceOptions::kSize);
+    return kGrpcTraceContextSize;
+  }
+
+ private:
+  // Parses the next field from the incoming buffer and stores the parsed value
+  // in a GrpcTraceContext struct.  If it does not recognize the field ID it
+  // will return 0, otherwise it returns the number of bytes read.
+  static size_t ParseField(absl::string_view buf, GrpcTraceContext* tc) {
+    // TODO: Add support for multi-byte field IDs.
+    if (buf.empty()) {
+      return 0;
+    }
+    // Field ID is always the first byte in a field.
+    uint32_t field_id = buf[0];
+    size_t bytes_read = kFieldIdSize;
+    switch (field_id) {
+      case kTraceIdField:
+        bytes_read += kTraceIdSize;
+        if (bytes_read > buf.size()) {
+          return 0;
+        }
+        memcpy(tc->trace_id, &buf[kFieldIdSize],
+               opencensus::trace::TraceId::kSize);
+        break;
+      case kSpanIdField:
+        bytes_read += kSpanIdSize;
+        if (bytes_read > buf.size()) {
+          return 0;
+        }
+        memcpy(tc->span_id, &buf[kFieldIdSize],
+               opencensus::trace::SpanId::kSize);
+        break;
+      case kTraceOptionsField:
+        bytes_read += kTraceOptionsSize;
+        if (bytes_read > buf.size()) {
+          return 0;
+        }
+        memcpy(tc->trace_options, &buf[kFieldIdSize],
+               opencensus::trace::TraceOptions::kSize);
+        break;
+      default:  // Invalid field ID
+        return 0;
+    }
+
+    return bytes_read;
+  }
+
+  // Size of Version ID.
+  static constexpr size_t kVersionIdSize = 1;
+  // Size of Field ID.
+  static constexpr size_t kFieldIdSize = 1;
+
+  // Offset and value for currently supported version ID.
+  static constexpr size_t kVersionIdOffset = 0;
+  static constexpr size_t kVersionId = 0;
+
+  // Fixed Field ID values:
+  enum FieldIdValue {
+    kTraceIdField = 0,
+    kSpanIdField = 1,
+    kTraceOptionsField = 2,
+  };
+
+  // Field data sizes in bytes
+  enum FieldSize {
+    kTraceIdSize = 16,
+    kSpanIdSize = 8,
+    kTraceOptionsSize = 1,
+  };
+
+  // Fixed size offsets for field ID start positions during encoding.  Field
+  // data immediately follows.
+  enum FieldIdOffset {
+    kTraceIdOffset = kVersionIdSize,
+    kSpanIdOffset = kTraceIdOffset + kFieldIdSize + kTraceIdSize,
+    kTraceOptionsOffset = kSpanIdOffset + kFieldIdSize + kSpanIdSize,
+  };
+
+  TraceContextEncoding() = delete;
+  TraceContextEncoding(const TraceContextEncoding&) = delete;
+  TraceContextEncoding(TraceContextEncoding&&) = delete;
+  TraceContextEncoding operator=(const TraceContextEncoding&) = delete;
+  TraceContextEncoding operator=(TraceContextEncoding&&) = delete;
+};
+
+// TODO: This may not be needed. Check to see if opencensus requires
+// a trailing server response.
+// RpcServerStatsEncoding encapsulates the logic for encoding and decoding of
+// rpc server stats messages. Rpc server stats consists of a uint64_t time
+// value (server latency in nanoseconds).
+class RpcServerStatsEncoding {
+ public:
+  // Size of encoded RPC server stats.
+  static constexpr size_t kRpcServerStatsSize = 10;
+  // Error value.
+  static constexpr size_t kEncodeDecodeFailure = 0;
+
+  // Deserializes rpc server stats from the incoming 'buf' into *time.  Returns
+  // number of bytes decoded. If the buffer is of insufficient size (it must be
+  // at least kRpcServerStatsSize bytes) or the encoding version or field ID are
+  // unrecognized, *time will be set to 0 and it will return
+  // kEncodeDecodeFailure. Inlined for performance reasons.
+  static size_t Decode(absl::string_view buf, uint64_t* time) {
+    if (buf.size() < kRpcServerStatsSize) {
+      *time = 0;
+      return kEncodeDecodeFailure;
+    }
+
+    uint8_t version = buf[kVersionIdOffset];
+    uint32_t fieldID = buf[kServerElapsedTimeOffset];
+    if (version != kVersionId || fieldID != kServerElapsedTimeField) {
+      *time = 0;
+      return kEncodeDecodeFailure;
+    }
+    *time = absl::little_endian::Load64(
+        &buf[kServerElapsedTimeOffset + kFieldIdSize]);
+    return kRpcServerStatsSize;
+  }
+
+  // Serializes rpc server stats into the provided buffer.  It returns the
+  // number of bytes written to the buffer. If the buffer is smaller than
+  // kRpcServerStatsSize bytes it will return kEncodeDecodeFailure. Inlined for
+  // performance reasons.
+  static size_t Encode(uint64_t time, char* buf, size_t buf_size) {
+    if (buf_size < kRpcServerStatsSize) {
+      return kEncodeDecodeFailure;
+    }
+
+    buf[kVersionIdOffset] = kVersionId;
+    buf[kServerElapsedTimeOffset] = kServerElapsedTimeField;
+    absl::little_endian::Store64(&buf[kServerElapsedTimeOffset + kFieldIdSize],
+                                 time);
+    return kRpcServerStatsSize;
+  }
+
+ private:
+  // Size of Version ID.
+  static constexpr size_t kVersionIdSize = 1;
+  // Size of Field ID.
+  static constexpr size_t kFieldIdSize = 1;
+
+  // Offset and value for currently supported version ID.
+  static constexpr size_t kVersionIdOffset = 0;
+  static constexpr size_t kVersionId = 0;
+
+  enum FieldIdValue {
+    kServerElapsedTimeField = 0,
+  };
+
+  enum FieldSize {
+    kServerElapsedTimeSize = 8,
+  };
+
+  enum FieldIdOffset {
+    kServerElapsedTimeOffset = kVersionIdSize,
+  };
+
+  RpcServerStatsEncoding() = delete;
+  RpcServerStatsEncoding(const RpcServerStatsEncoding&) = delete;
+  RpcServerStatsEncoding(RpcServerStatsEncoding&&) = delete;
+  RpcServerStatsEncoding operator=(const RpcServerStatsEncoding&) = delete;
+  RpcServerStatsEncoding operator=(RpcServerStatsEncoding&&) = delete;
+};
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_RPC_ENCODING_H */

+ 198 - 0
src/cpp/ext/filters/census/server_filter.cc

@@ -0,0 +1,198 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/server_filter.h"
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "opencensus/stats/stats.h"
+#include "src/core/lib/surface/call.h"
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+#include "src/cpp/ext/filters/census/measures.h"
+
+namespace grpc {
+
+constexpr uint32_t CensusServerCallData::kMaxServerStatsLen;
+
+namespace {
+
+// server metadata elements
+struct ServerMetadataElements {
+  grpc_slice path;
+  grpc_slice tracing_slice;
+  grpc_slice census_proto;
+};
+
+void FilterInitialMetadata(grpc_metadata_batch* b,
+                           ServerMetadataElements* sml) {
+  if (b->idx.named.path != nullptr) {
+    sml->path = grpc_slice_ref_internal(GRPC_MDVALUE(b->idx.named.path->md));
+  }
+  if (b->idx.named.grpc_trace_bin != nullptr) {
+    sml->tracing_slice =
+        grpc_slice_ref_internal(GRPC_MDVALUE(b->idx.named.grpc_trace_bin->md));
+    grpc_metadata_batch_remove(b, b->idx.named.grpc_trace_bin);
+  }
+  if (b->idx.named.grpc_tags_bin != nullptr) {
+    sml->census_proto =
+        grpc_slice_ref_internal(GRPC_MDVALUE(b->idx.named.grpc_tags_bin->md));
+    grpc_metadata_batch_remove(b, b->idx.named.grpc_tags_bin);
+  }
+}
+
+}  // namespace
+
+void CensusServerCallData::OnDoneRecvMessageCb(void* user_data,
+                                               grpc_error* error) {
+  grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
+  CensusServerCallData* calld =
+      reinterpret_cast<CensusServerCallData*>(elem->call_data);
+  CensusChannelData* channeld =
+      reinterpret_cast<CensusChannelData*>(elem->channel_data);
+  GPR_ASSERT(calld != nullptr);
+  GPR_ASSERT(channeld != nullptr);
+  // Stream messages are no longer valid after receiving trailing metadata.
+  if ((*calld->recv_message_) != nullptr) {
+    ++calld->recv_message_count_;
+  }
+  GRPC_CLOSURE_RUN(calld->initial_on_done_recv_message_, GRPC_ERROR_REF(error));
+}
+
+void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data,
+                                                       grpc_error* error) {
+  grpc_call_element* elem = reinterpret_cast<grpc_call_element*>(user_data);
+  CensusServerCallData* calld =
+      reinterpret_cast<CensusServerCallData*>(elem->call_data);
+  GPR_ASSERT(calld != nullptr);
+  if (error == GRPC_ERROR_NONE) {
+    grpc_metadata_batch* initial_metadata = calld->recv_initial_metadata_;
+    GPR_ASSERT(initial_metadata != nullptr);
+    ServerMetadataElements sml;
+    sml.path = grpc_empty_slice();
+    sml.tracing_slice = grpc_empty_slice();
+    sml.census_proto = grpc_empty_slice();
+    FilterInitialMetadata(initial_metadata, &sml);
+    calld->path_ = grpc_slice_ref_internal(sml.path);
+    calld->method_ = GetMethod(&calld->path_);
+    calld->qualified_method_ = StrCat("Recv.", calld->method_);
+    const char* tracing_str =
+        GRPC_SLICE_IS_EMPTY(sml.tracing_slice)
+            ? ""
+            : reinterpret_cast<const char*>(
+                  GRPC_SLICE_START_PTR(sml.tracing_slice));
+    size_t tracing_str_len = GRPC_SLICE_IS_EMPTY(sml.tracing_slice)
+                                 ? 0
+                                 : GRPC_SLICE_LENGTH(sml.tracing_slice);
+    const char* census_str = GRPC_SLICE_IS_EMPTY(sml.census_proto)
+                                 ? ""
+                                 : reinterpret_cast<const char*>(
+                                       GRPC_SLICE_START_PTR(sml.census_proto));
+    size_t census_str_len = GRPC_SLICE_IS_EMPTY(sml.census_proto)
+                                ? 0
+                                : GRPC_SLICE_LENGTH(sml.census_proto);
+
+    GenerateServerContext(absl::string_view(tracing_str, tracing_str_len),
+                          absl::string_view(census_str, census_str_len),
+                          /*primary_role*/ "", calld->qualified_method_,
+                          &calld->context_);
+
+    grpc_slice_unref_internal(sml.tracing_slice);
+    grpc_slice_unref_internal(sml.census_proto);
+    grpc_slice_unref_internal(sml.path);
+    grpc_census_call_set_context(
+        calld->gc_, reinterpret_cast<census_context*>(&calld->context_));
+  }
+  GRPC_CLOSURE_RUN(calld->initial_on_done_recv_initial_metadata_,
+                   GRPC_ERROR_REF(error));
+}
+
+void CensusServerCallData::StartTransportStreamOpBatch(
+    grpc_call_element* elem, TransportStreamOpBatch* op) {
+  if (op->recv_initial_metadata() != nullptr) {
+    // substitute our callback for the op callback
+    recv_initial_metadata_ = op->recv_initial_metadata()->batch();
+    initial_on_done_recv_initial_metadata_ = op->recv_initial_metadata_ready();
+    op->set_recv_initial_metadata_ready(&on_done_recv_initial_metadata_);
+  }
+  if (op->send_message() != nullptr) {
+    ++sent_message_count_;
+  }
+  if (op->recv_message() != nullptr) {
+    recv_message_ = op->op()->payload->recv_message.recv_message;
+    initial_on_done_recv_message_ =
+        op->op()->payload->recv_message.recv_message_ready;
+    op->op()->payload->recv_message.recv_message_ready = &on_done_recv_message_;
+  }
+  // We need to record the time when the trailing metadata was sent to mark the
+  // completeness of the request.
+  if (op->send_trailing_metadata() != nullptr) {
+    elapsed_time_ = absl::Now() - start_time_;
+    size_t len = ServerStatsSerialize(absl::ToInt64Nanoseconds(elapsed_time_),
+                                      stats_buf_, kMaxServerStatsLen);
+    if (len > 0) {
+      GRPC_LOG_IF_ERROR(
+          "census grpc_filter",
+          grpc_metadata_batch_add_tail(
+              op->send_trailing_metadata()->batch(), &census_bin_,
+              grpc_mdelem_from_slices(
+                  GRPC_MDSTR_GRPC_SERVER_STATS_BIN,
+                  grpc_slice_from_copied_buffer(stats_buf_, len))));
+    }
+  }
+  // Call next op.
+  grpc_call_next_op(elem, op->op());
+}
+
+grpc_error* CensusServerCallData::Init(grpc_call_element* elem,
+                                       const grpc_call_element_args* args) {
+  start_time_ = absl::Now();
+  gc_ =
+      grpc_call_from_top_element(grpc_call_stack_element(args->call_stack, 0));
+  GRPC_CLOSURE_INIT(&on_done_recv_initial_metadata_,
+                    OnDoneRecvInitialMetadataCb, elem,
+                    grpc_schedule_on_exec_ctx);
+  GRPC_CLOSURE_INIT(&on_done_recv_message_, OnDoneRecvMessageCb, elem,
+                    grpc_schedule_on_exec_ctx);
+  auth_context_ = grpc_call_auth_context(gc_);
+  return GRPC_ERROR_NONE;
+}
+
+void CensusServerCallData::Destroy(grpc_call_element* elem,
+                                   const grpc_call_final_info* final_info,
+                                   grpc_closure* then_call_closure) {
+  const uint64_t request_size = GetOutgoingDataSize(final_info);
+  const uint64_t response_size = GetIncomingDataSize(final_info);
+  double elapsed_time_ms = absl::ToDoubleMilliseconds(elapsed_time_);
+  grpc_auth_context_release(auth_context_);
+  ::opencensus::stats::Record(
+      {{RpcServerSentBytesPerRpc(), static_cast<double>(response_size)},
+       {RpcServerReceivedBytesPerRpc(), static_cast<double>(request_size)},
+       {RpcServerServerLatency(), elapsed_time_ms},
+       {RpcServerSentMessagesPerRpc(), sent_message_count_},
+       {RpcServerReceivedMessagesPerRpc(), recv_message_count_}},
+      {{ServerMethodTagKey(), method_},
+       {ServerStatusTagKey(), StatusCodeToString(final_info->final_status)}});
+  grpc_slice_unref_internal(path_);
+  context_.EndSpan();
+}
+
+}  // namespace grpc

+ 101 - 0
src/cpp/ext/filters/census/server_filter.h

@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_SERVER_FILTER_H
+#define GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_SERVER_FILTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "include/grpc/grpc_security.h"
+#include "src/cpp/ext/filters/census/channel_filter.h"
+#include "src/cpp/ext/filters/census/context.h"
+
+namespace grpc {
+
+// A CallData class will be created for every grpc call within a channel. It is
+// used to store data and methods specific to that call. CensusServerCallData is
+// thread-compatible, however typically only 1 thread should be interacting with
+// a call at a time.
+class CensusServerCallData : public CallData {
+ public:
+  // Maximum size of server stats that are sent on the wire.
+  static constexpr uint32_t kMaxServerStatsLen = 16;
+
+  CensusServerCallData()
+      : gc_(nullptr),
+        auth_context_(nullptr),
+        recv_initial_metadata_(nullptr),
+        initial_on_done_recv_initial_metadata_(nullptr),
+        initial_on_done_recv_message_(nullptr),
+        recv_message_(nullptr),
+        recv_message_count_(0),
+        sent_message_count_(0) {
+    memset(&census_bin_, 0, sizeof(grpc_linked_mdelem));
+    memset(&path_, 0, sizeof(grpc_slice));
+    memset(&on_done_recv_initial_metadata_, 0, sizeof(grpc_closure));
+    memset(&on_done_recv_message_, 0, sizeof(grpc_closure));
+  }
+
+  grpc_error* Init(grpc_call_element* elem,
+                   const grpc_call_element_args* args) override;
+
+  void Destroy(grpc_call_element* elem, const grpc_call_final_info* final_info,
+               grpc_closure* then_call_closure) override;
+
+  void StartTransportStreamOpBatch(grpc_call_element* elem,
+                                   TransportStreamOpBatch* op) override;
+
+  static void OnDoneRecvInitialMetadataCb(void* user_data, grpc_error* error);
+
+  static void OnDoneRecvMessageCb(void* user_data, grpc_error* error);
+
+ private:
+  CensusContext context_;
+  // server method
+  absl::string_view method_;
+  std::string qualified_method_;
+  grpc_slice path_;
+  // Pointer to the grpc_call element
+  grpc_call* gc_;
+  // Authorization context for the call.
+  grpc_auth_context* auth_context_;
+  // Metadata element for census stats.
+  grpc_linked_mdelem census_bin_;
+  // recv callback
+  grpc_metadata_batch* recv_initial_metadata_;
+  grpc_closure* initial_on_done_recv_initial_metadata_;
+  grpc_closure on_done_recv_initial_metadata_;
+  // recv message
+  grpc_closure* initial_on_done_recv_message_;
+  grpc_closure on_done_recv_message_;
+  absl::Time start_time_;
+  absl::Duration elapsed_time_;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message_;
+  uint64_t recv_message_count_;
+  uint64_t sent_message_count_;
+  // Buffer needed for grpc_slice to reference it when adding metatdata to
+  // response.
+  char stats_buf_[kMaxServerStatsLen];
+};
+
+}  // namespace grpc
+
+#endif /* GRPC_INTERNAL_CPP_EXT_FILTERS_CENSUS_SERVER_FILTER_H */

+ 491 - 0
src/cpp/ext/filters/census/views.cc

@@ -0,0 +1,491 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/ext/filters/census/grpc_plugin.h"
+
+#include "absl/time/time.h"
+#include "opencensus/stats/internal/aggregation_window.h"
+#include "opencensus/stats/internal/set_aggregation_window.h"
+#include "opencensus/stats/stats.h"
+
+namespace grpc {
+
+using ::opencensus::stats::Aggregation;
+using ::opencensus::stats::AggregationWindow;
+using ::opencensus::stats::BucketBoundaries;
+using ::opencensus::stats::ViewDescriptor;
+
+// These measure definitions should be kept in sync across opencensus
+// implementations.
+
+namespace {
+
+Aggregation BytesDistributionAggregation() {
+  return Aggregation::Distribution(BucketBoundaries::Explicit(
+      {0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216,
+       67108864, 268435456, 1073741824, 4294967296}));
+}
+
+Aggregation MillisDistributionAggregation() {
+  return Aggregation::Distribution(BucketBoundaries::Explicit(
+      {0,   0.01, 0.05, 0.1,  0.3,   0.6,   0.8,   1,     2,   3,   4,
+       5,   6,    8,    10,   13,    16,    20,    25,    30,  40,  50,
+       65,  80,   100,  130,  160,   200,   250,   300,   400, 500, 650,
+       800, 1000, 2000, 5000, 10000, 20000, 50000, 100000}));
+}
+
+Aggregation CountDistributionAggregation() {
+  return Aggregation::Distribution(BucketBoundaries::Exponential(17, 1.0, 2.0));
+}
+
+ViewDescriptor MinuteDescriptor() {
+  auto descriptor = ViewDescriptor();
+  SetAggregationWindow(AggregationWindow::Interval(absl::Minutes(1)),
+                       &descriptor);
+  return descriptor;
+}
+
+ViewDescriptor HourDescriptor() {
+  auto descriptor = ViewDescriptor();
+  SetAggregationWindow(AggregationWindow::Interval(absl::Hours(1)),
+                       &descriptor);
+  return descriptor;
+}
+
+}  // namespace
+
+void RegisterOpenCensusViewsForExport() {
+  ClientSentMessagesPerRpcCumulative().RegisterForExport();
+  ClientSentBytesPerRpcCumulative().RegisterForExport();
+  ClientReceivedMessagesPerRpcCumulative().RegisterForExport();
+  ClientReceivedBytesPerRpcCumulative().RegisterForExport();
+  ClientRoundtripLatencyCumulative().RegisterForExport();
+  ClientServerLatencyCumulative().RegisterForExport();
+
+  ServerSentMessagesPerRpcCumulative().RegisterForExport();
+  ServerSentBytesPerRpcCumulative().RegisterForExport();
+  ServerReceivedMessagesPerRpcCumulative().RegisterForExport();
+  ServerReceivedBytesPerRpcCumulative().RegisterForExport();
+  ServerServerLatencyCumulative().RegisterForExport();
+}
+
+// client cumulative
+const ViewDescriptor& ClientSentBytesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/sent_bytes_per_rpc/cumulative")
+          .set_measure(kRpcClientSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedBytesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/received_bytes_per_rpc/cumulative")
+          .set_measure(kRpcClientReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientRoundtripLatencyCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/roundtrip_latency/cumulative")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientServerLatencyCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/server_latency/cumulative")
+          .set_measure(kRpcClientServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientCompletedRpcsCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/completed_rpcs/cumulative")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ClientMethodTagKey())
+          .add_column(ClientStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientSentMessagesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/received_messages_per_rpc/cumulative")
+          .set_measure(kRpcClientSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedMessagesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/client/sent_messages_per_rpc/cumulative")
+          .set_measure(kRpcClientReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+// server cumulative
+const ViewDescriptor& ServerSentBytesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/received_bytes_per_rpc/cumulative")
+          .set_measure(kRpcServerSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedBytesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/sent_bytes_per_rpc/cumulative")
+          .set_measure(kRpcServerReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerServerLatencyCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/elapsed_time/cumulative")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerCompletedRpcsCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/completed_rpcs/cumulative")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ServerMethodTagKey())
+          .add_column(ServerStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerSentMessagesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/received_messages_per_rpc/cumulative")
+          .set_measure(kRpcServerSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedMessagesPerRpcCumulative() {
+  const static ViewDescriptor descriptor =
+      ViewDescriptor()
+          .set_name("grpc.io/server/sent_messages_per_rpc/cumulative")
+          .set_measure(kRpcServerReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+// client minute
+const ViewDescriptor& ClientSentBytesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/sent_bytes_per_rpc/minute")
+          .set_measure(kRpcClientSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedBytesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/received_bytes_per_rpc/minute")
+          .set_measure(kRpcClientReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientRoundtripLatencyMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/roundtrip_latency/minute")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientServerLatencyMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/server_latency/minute")
+          .set_measure(kRpcClientServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientCompletedRpcsMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/completed_rpcs/minute")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ClientMethodTagKey())
+          .add_column(ClientStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientSentMessagesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/sent_messages_per_rpc/minute")
+          .set_measure(kRpcClientSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedMessagesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/client/received_messages_per_rpc/minute")
+          .set_measure(kRpcClientReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+// server minute
+const ViewDescriptor& ServerSentBytesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/sent_bytes_per_rpc/minute")
+          .set_measure(kRpcServerSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedBytesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/received_bytes_per_rpc/minute")
+          .set_measure(kRpcServerReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerServerLatencyMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/server_latency/minute")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerCompletedRpcsMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/completed_rpcs/minute")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ServerMethodTagKey())
+          .add_column(ServerStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerSentMessagesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/sent_messages_per_rpc/minute")
+          .set_measure(kRpcServerSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedMessagesPerRpcMinute() {
+  const static ViewDescriptor descriptor =
+      MinuteDescriptor()
+          .set_name("grpc.io/server/received_messages_per_rpc/minute")
+          .set_measure(kRpcServerReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+// client hour
+const ViewDescriptor& ClientSentBytesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/sent_bytes_per_rpc/hour")
+          .set_measure(kRpcClientSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedBytesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/received_bytes_per_rpc/hour")
+          .set_measure(kRpcClientReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientRoundtripLatencyHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/roundtrip_latency/hour")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientServerLatencyHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/server_latency/hour")
+          .set_measure(kRpcClientServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientCompletedRpcsHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/completed_rpcs/hour")
+          .set_measure(kRpcClientRoundtripLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ClientMethodTagKey())
+          .add_column(ClientStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientSentMessagesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/sent_messages_per_rpc/hour")
+          .set_measure(kRpcClientSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ClientReceivedMessagesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/client/received_messages_per_rpc/hour")
+          .set_measure(kRpcClientReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ClientMethodTagKey());
+  return descriptor;
+}
+
+// server hour
+const ViewDescriptor& ServerSentBytesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/sent_bytes_per_rpc/hour")
+          .set_measure(kRpcServerSentBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedBytesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/received_bytes_per_rpc/hour")
+          .set_measure(kRpcServerReceivedBytesPerRpcMeasureName)
+          .set_aggregation(BytesDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerServerLatencyHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/server_latency/hour")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(MillisDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerCompletedRpcsHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/completed_rpcs/hour")
+          .set_measure(kRpcServerServerLatencyMeasureName)
+          .set_aggregation(Aggregation::Count())
+          .add_column(ServerMethodTagKey())
+          .add_column(ServerStatusTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerSentMessagesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/sent_messages_per_rpc/hour")
+          .set_measure(kRpcServerSentMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+const ViewDescriptor& ServerReceivedMessagesPerRpcHour() {
+  const static ViewDescriptor descriptor =
+      HourDescriptor()
+          .set_name("grpc.io/server/received_messages_per_rpc/hour")
+          .set_measure(kRpcServerReceivedMessagesPerRpcMeasureName)
+          .set_aggregation(CountDistributionAggregation())
+          .add_column(ServerMethodTagKey());
+  return descriptor;
+}
+
+}  // namespace grpc

+ 2 - 2
src/cpp/server/health/default_health_check_service.cc

@@ -24,10 +24,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/log.h>
 #include <grpcpp/impl/codegen/method_handler_impl.h>
 #include <grpcpp/impl/codegen/method_handler_impl.h>
 
 
+#include "pb_decode.h"
+#include "pb_encode.h"
 #include "src/cpp/server/health/default_health_check_service.h"
 #include "src/cpp/server/health/default_health_check_service.h"
 #include "src/cpp/server/health/health.pb.h"
 #include "src/cpp/server/health/health.pb.h"
-#include "third_party/nanopb/pb_decode.h"
-#include "third_party/nanopb/pb_encode.h"
 
 
 namespace grpc {
 namespace grpc {
 namespace {
 namespace {

Деякі файли не було показано, через те що забагато файлів було змінено