Merge branch 'master' into packet-coalescing-core

pull/9246/head
Muxi Yan 8 years ago
commit b44e089d29
  1. 1
      .gitignore
  2. 5
      BUILD
  3. 10337
      CMakeLists.txt
  4. 74
      INSTALL.md
  5. 743
      Makefile
  6. 4
      Rakefile
  7. 39
      bazel/BUILD
  8. 1
      bazel/cc_grpc_library.bzl
  9. 4
      bazel/generate_cc.bzl
  10. 41
      binding.gyp
  11. 8
      build.yaml
  12. 32
      build_config.rb
  13. 43
      config.m4
  14. 1
      doc/PROTOCOL-HTTP2.md
  15. 4
      doc/environment_variables.md
  16. BIN
      doc/images/load-balancing.png
  17. 4
      doc/images/load-balancing.svg
  18. BIN
      doc/images/load_balancing_design.png
  19. 189
      doc/load-balancing.md
  20. 59
      doc/naming.md
  21. 147
      doc/service_config.md
  22. 42
      examples/cpp/helloworld/BUILD
  23. 4
      examples/cpp/helloworld/greeter_client.cc
  24. 4
      examples/cpp/helloworld/greeter_server.cc
  25. 52
      examples/protos/BUILD
  26. 2
      gRPC-Core.podspec
  27. 60
      grpc.gemspec
  28. 6
      include/grpc++/impl/codegen/config.h
  29. 4
      include/grpc++/support/channel_arguments.h
  30. 84
      include/grpc/impl/codegen/gpr_slice.h
  31. 3
      include/grpc/impl/codegen/grpc_types.h
  32. 19
      include/grpc/impl/codegen/slice.h
  33. 106
      package.xml
  34. 4
      setup.cfg
  35. 1266
      src/boringssl/err_data.c
  36. 15
      src/compiler/cpp_generator.cc
  37. 10
      src/core/ext/census/tracing.c
  38. 3
      src/core/ext/client_channel/connector.h
  39. 4
      src/core/ext/client_channel/resolver_registry.h
  40. 57
      src/core/ext/client_channel/subchannel.c
  41. 13
      src/core/ext/client_channel/subchannel.h
  42. 12
      src/core/ext/client_channel/subchannel_index.c
  43. 12
      src/core/ext/lb_policy/pick_first/pick_first.c
  44. 12
      src/core/ext/lb_policy/round_robin/round_robin.c
  45. 7
      src/core/ext/transport/chttp2/client/chttp2_connector.c
  46. 33
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  47. 6
      src/core/ext/transport/chttp2/transport/internal.h
  48. 2
      src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
  49. 29
      src/core/ext/transport/cronet/transport/cronet_api_dummy.c
  50. 168
      src/core/ext/transport/cronet/transport/cronet_transport.c
  51. 2
      src/core/lib/iomgr/ev_epoll_linux.c
  52. 4
      src/core/lib/iomgr/ev_poll_posix.c
  53. 5
      src/core/lib/iomgr/resource_quota.c
  54. 6
      src/core/lib/iomgr/resource_quota.h
  55. 8
      src/cpp/common/channel_arguments.cc
  56. 12
      src/node/ext/call_credentials.cc
  57. 4
      src/node/ext/call_credentials.h
  58. 14
      src/node/ext/node_grpc.cc
  59. 5
      src/objective-c/CronetFramework.podspec
  60. 6
      src/objective-c/GRPCClient/GRPCCall+Cronet.h
  61. 6
      src/objective-c/GRPCClient/GRPCCall+Cronet.m
  62. 4
      src/objective-c/GRPCClient/private/GRPCChannel.m
  63. 8
      src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
  64. 214
      src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
  65. 24
      src/objective-c/tests/CronetUnitTests/Info.plist
  66. 19
      src/objective-c/tests/Podfile
  67. 204
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  68. 56
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CronetUnitTests.xcscheme
  69. 7
      src/php/README.md
  70. 30
      src/proto/grpc/testing/BUILD
  71. 30
      src/proto/grpc/testing/duplicate/BUILD
  72. 46
      src/python/grpcio/_spawn_patch.py
  73. 352
      src/python/grpcio/commands.py
  74. 767
      src/python/grpcio/grpc/__init__.py
  75. 83
      src/python/grpcio/grpc/_auth.py
  76. 1533
      src/python/grpcio/grpc/_channel.py
  77. 123
      src/python/grpcio/grpc/_common.py
  78. 18
      src/python/grpcio/grpc/_credential_composition.py
  79. 11
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
  80. 19
      src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
  81. 123
      src/python/grpcio/grpc/_plugin_wrapping.py
  82. 1093
      src/python/grpcio/grpc/_server.py
  83. 235
      src/python/grpcio/grpc/_utilities.py
  84. 1028
      src/python/grpcio/grpc/beta/_client_adaptations.py
  85. 213
      src/python/grpcio/grpc/beta/_connectivity_channel.py
  86. 544
      src/python/grpcio/grpc/beta/_server_adaptations.py
  87. 173
      src/python/grpcio/grpc/beta/implementations.py
  88. 78
      src/python/grpcio/grpc/beta/interfaces.py
  89. 202
      src/python/grpcio/grpc/beta/utilities.py
  90. 2
      src/python/grpcio/grpc/framework/__init__.py
  91. 2
      src/python/grpcio/grpc/framework/common/__init__.py
  92. 11
      src/python/grpcio/grpc/framework/common/cardinality.py
  93. 7
      src/python/grpcio/grpc/framework/common/style.py
  94. 2
      src/python/grpcio/grpc/framework/foundation/__init__.py
  95. 3
      src/python/grpcio/grpc/framework/foundation/abandonment.py
  96. 47
      src/python/grpcio/grpc/framework/foundation/callable_util.py
  97. 129
      src/python/grpcio/grpc/framework/foundation/future.py
  98. 55
      src/python/grpcio/grpc/framework/foundation/logging_pool.py
  99. 28
      src/python/grpcio/grpc/framework/foundation/stream.py
  100. 227
      src/python/grpcio/grpc/framework/foundation/stream_util.py
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -8,6 +8,7 @@ objs
# Python items
cython_debug/
python_build/
python_format_venv/
.coverage*
.eggs
htmlcov/

@ -401,6 +401,7 @@ grpc_cc_library(
"include/grpc/impl/codegen/atm_gcc_atomic.h",
"include/grpc/impl/codegen/atm_gcc_sync.h",
"include/grpc/impl/codegen/atm_windows.h",
"include/grpc/impl/codegen/gpr_slice.h",
"include/grpc/impl/codegen/gpr_types.h",
"include/grpc/impl/codegen/port_platform.h",
"include/grpc/impl/codegen/slice.h",
@ -1026,7 +1027,7 @@ grpc_cc_library(
"src/core/ext/transport/cronet/transport/cronet_transport.c",
],
hdrs = [
"third_party/objective_c/Cronet/cronet_c_for_grpc.h",
"third_party/Cronet/bidirectional_stream_c.h",
],
language = "c",
public_hdrs = [
@ -1078,6 +1079,7 @@ grpc_cc_library(
"src/cpp/common/completion_queue_cc.cc",
"src/cpp/common/core_codegen.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/create_default_thread_pool.cc",
"src/cpp/server/dynamic_thread_pool.cc",
@ -1086,6 +1088,7 @@ grpc_cc_library(
"src/cpp/server/server_context.cc",
"src/cpp/server/server_credentials.cc",
"src/cpp/server/server_posix.cc",
"src/cpp/thread_manager/thread_manager.cc",
"src/cpp/util/byte_buffer_cc.cc",
"src/cpp/util/slice_cc.cc",
"src/cpp/util/status.cc",

File diff suppressed because it is too large Load Diff

@ -61,49 +61,45 @@ gRPC C Core library.
There are several ways to build under Windows, of varying complexity depending
on experience with the tools involved.
<!--
###Visual Studio
###Pre-generated Visual Studio solution
Versions 2013 and 2015 are both supported. You can use [their respective
community
editions](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx).
Building the C Core:
- Open [grpc.sln](https://github.com/grpc/grpc/blob/master/vsprojects/grpc.sln).
- Select your build target.
- Build the `grpc` project.
The pre-generated VS projects & solution are checked into the repository under the [vsprojects](/vsprojects) directory.
###Building using CMake (with BoringSSL)
- Install [CMake](https://cmake.org/download/).
- Install [Active State Perl](http://www.activestate.com/activeperl/) (`choco install activeperl`)
- Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
- Install [Go](https://golang.org/dl/) (`choco install golang`)
- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`)
- Run these commands in the repo root directory
```
> md .build
> cd .build
> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake --build .
```
NOTE: Currently you can only use Ninja to build using cmake on Windows (because of the boringssl dependency).
Building the C++ runtime:
- You need [CMake](https://cmake.org/) on your path to build protobuf (see below
for building using solely CMake).
- Run `vsprojects/build_protos.bat` (needs `cmake.exe` in your path).
- Open [buildtests_cxx.sln]()
- Select your build target.
- build the `grpc++` project.
-->
###msys2 (with mingw)
###msys2
The Makefile (and source code) should support msys2's mingw32 and mingw64
compilers. Building with msys2's native compiler is also possible, but
difficult.
This approach requires having [msys2](https://msys2.github.io/) installed.
```
# Install prerequisites
MSYS2$ pacman -S autoconf automake gcc libtool mingw-w64-x86_64-toolchain perl pkg-config zlib
MSYS2$ pacman -S mingw-w64-x86_64-gflags
```
- The Makefile (and source code) should support msys2's mingw32 and mingw64
compilers. Building with msys2's native compiler is also possible, but
difficult.
- The Makefile is expecting the Windows versions of OpenSSL (see
https://slproweb.com/products/Win32OpenSSL.html). It's also possible to build
the Windows version of OpenSSL from scratch. The output should be `libeay32`
and `ssleay32`.
- If you are not installing the above files under msys2's path, you may specify
it, for instance, in the following way:
```CPPFLAGS=”-I/c/OpenSSL-Win32/include” LDFLAGS=”-L/c/OpenSSL-Win32/lib” make static_c```
- [protobuf3](https://github.com/google/protobuf/blob/master/src/README.md#c-installation---windows)
must be installed on the msys2 path.
###Cmake (experimental)
```
# From mingw shell
MINGW64$ export CPPFLAGS="-D_WIN32_WINNT=0x0600"
MINGW64$ make
```
- Install [CMake](https://cmake.org/download/).
- Run it over [grpc's
CMakeLists.txt](https://github.com/grpc/grpc/blob/master/CMakeLists.txt) to
generate "projects" for your compiler.
- Build with your compiler of choice. The generated build files should have the
protobuf3 dependency baked in.
NOTE: While 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).

File diff suppressed because it is too large Load Diff

@ -5,6 +5,8 @@ require 'rubocop/rake_task'
require 'bundler/gem_tasks'
require 'fileutils'
require_relative 'build_config.rb'
load 'tools/distrib/docker_for_windows.rb'
# Add rubocop style checking tasks
@ -83,7 +85,7 @@ task 'dlls' do
env += 'EMBED_ZLIB=true '
env += 'BUILDDIR=/tmp '
env += "V=#{verbose} "
out = '/tmp/libs/opt/grpc-1.dll'
out = GrpcBuildConfig::CORE_WINDOWS_DLL
w64 = { cross: 'x86_64-w64-mingw32', out: 'grpc_c.64.ruby' }
w32 = { cross: 'i686-w64-mingw32', out: 'grpc_c.32.ruby' }

@ -1,9 +1,46 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//:__subpackages__"])
load(":cc_grpc_library.bzl", "cc_grpc_library")
proto_library(
name = "well_known_protos_list",
srcs = ["@submodule_protobuf//:well_known_protos"],
)
cc_grpc_library(
name = "well_known_protos",
srcs = "@submodule_protobuf//:well_known_protos",
srcs = "well_known_protos_list",
deps = [],
proto_only = True,
)

@ -44,7 +44,6 @@ def cc_grpc_library(name, srcs, deps, proto_only, **kwargs):
**kwargs
)
if not proto_only:
native.cc_library(
name = name,
srcs = [":" + codegen_grpc_target, ":" + codegen_target],

@ -24,13 +24,15 @@ def generate_cc_impl(ctx):
if ctx.executable.plugin:
arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
arguments += ["--PLUGIN_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
additional_input = [ctx.executable.plugin]
else:
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
additional_input = []
arguments += ["-I{0}={0}".format(include.path) for include in includes]
arguments += [proto.path for proto in protos]
ctx.action(
inputs = protos + includes,
inputs = protos + includes + additional_input,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,

@ -161,7 +161,6 @@
'third_party/boringssl/crypto/aes/mode_wrappers.c',
'third_party/boringssl/crypto/asn1/a_bitstr.c',
'third_party/boringssl/crypto/asn1/a_bool.c',
'third_party/boringssl/crypto/asn1/a_bytes.c',
'third_party/boringssl/crypto/asn1/a_d2i_fp.c',
'third_party/boringssl/crypto/asn1/a_dup.c',
'third_party/boringssl/crypto/asn1/a_enum.c',
@ -180,18 +179,14 @@
'third_party/boringssl/crypto/asn1/asn1_lib.c',
'third_party/boringssl/crypto/asn1/asn1_par.c',
'third_party/boringssl/crypto/asn1/asn_pack.c',
'third_party/boringssl/crypto/asn1/bio_asn1.c',
'third_party/boringssl/crypto/asn1/bio_ndef.c',
'third_party/boringssl/crypto/asn1/f_enum.c',
'third_party/boringssl/crypto/asn1/f_int.c',
'third_party/boringssl/crypto/asn1/f_string.c',
'third_party/boringssl/crypto/asn1/t_bitst.c',
'third_party/boringssl/crypto/asn1/t_pkey.c',
'third_party/boringssl/crypto/asn1/tasn_dec.c',
'third_party/boringssl/crypto/asn1/tasn_enc.c',
'third_party/boringssl/crypto/asn1/tasn_fre.c',
'third_party/boringssl/crypto/asn1/tasn_new.c',
'third_party/boringssl/crypto/asn1/tasn_prn.c',
'third_party/boringssl/crypto/asn1/tasn_typ.c',
'third_party/boringssl/crypto/asn1/tasn_utl.c',
'third_party/boringssl/crypto/asn1/x_bignum.c',
@ -221,6 +216,7 @@
'third_party/boringssl/crypto/bn/generic.c',
'third_party/boringssl/crypto/bn/kronecker.c',
'third_party/boringssl/crypto/bn/montgomery.c',
'third_party/boringssl/crypto/bn/montgomery_inv.c',
'third_party/boringssl/crypto/bn/mul.c',
'third_party/boringssl/crypto/bn/prime.c',
'third_party/boringssl/crypto/bn/random.c',
@ -232,8 +228,7 @@
'third_party/boringssl/crypto/bytestring/ber.c',
'third_party/boringssl/crypto/bytestring/cbb.c',
'third_party/boringssl/crypto/bytestring/cbs.c',
'third_party/boringssl/crypto/chacha/chacha_generic.c',
'third_party/boringssl/crypto/chacha/chacha_vec.c',
'third_party/boringssl/crypto/chacha/chacha.c',
'third_party/boringssl/crypto/cipher/aead.c',
'third_party/boringssl/crypto/cipher/cipher.c',
'third_party/boringssl/crypto/cipher/derive_key.c',
@ -248,10 +243,14 @@
'third_party/boringssl/crypto/cipher/tls_cbc.c',
'third_party/boringssl/crypto/cmac/cmac.c',
'third_party/boringssl/crypto/conf/conf.c',
'third_party/boringssl/crypto/cpu-aarch64-linux.c',
'third_party/boringssl/crypto/cpu-arm-linux.c',
'third_party/boringssl/crypto/cpu-arm.c',
'third_party/boringssl/crypto/cpu-intel.c',
'third_party/boringssl/crypto/cpu-ppc64le.c',
'third_party/boringssl/crypto/crypto.c',
'third_party/boringssl/crypto/curve25519/curve25519.c',
'third_party/boringssl/crypto/curve25519/spake25519.c',
'third_party/boringssl/crypto/curve25519/x25519-x86_64.c',
'third_party/boringssl/crypto/des/des.c',
'third_party/boringssl/crypto/dh/check.c',
@ -260,8 +259,6 @@
'third_party/boringssl/crypto/dh/params.c',
'third_party/boringssl/crypto/digest/digest.c',
'third_party/boringssl/crypto/digest/digests.c',
'third_party/boringssl/crypto/directory_posix.c',
'third_party/boringssl/crypto/directory_win.c',
'third_party/boringssl/crypto/dsa/dsa.c',
'third_party/boringssl/crypto/dsa/dsa_asn1.c',
'third_party/boringssl/crypto/ec/ec.c',
@ -280,7 +277,6 @@
'third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c',
'third_party/boringssl/crypto/engine/engine.c',
'third_party/boringssl/crypto/err/err.c',
'third_party/boringssl/crypto/evp/algorithm.c',
'third_party/boringssl/crypto/evp/digestsign.c',
'third_party/boringssl/crypto/evp/evp.c',
'third_party/boringssl/crypto/evp/evp_asn1.c',
@ -291,6 +287,7 @@
'third_party/boringssl/crypto/evp/p_rsa.c',
'third_party/boringssl/crypto/evp/p_rsa_asn1.c',
'third_party/boringssl/crypto/evp/pbkdf.c',
'third_party/boringssl/crypto/evp/print.c',
'third_party/boringssl/crypto/evp/sign.c',
'third_party/boringssl/crypto/ex_data.c',
'third_party/boringssl/crypto/hkdf/hkdf.c',
@ -304,6 +301,12 @@
'third_party/boringssl/crypto/modes/ctr.c',
'third_party/boringssl/crypto/modes/gcm.c',
'third_party/boringssl/crypto/modes/ofb.c',
'third_party/boringssl/crypto/newhope/error_correction.c',
'third_party/boringssl/crypto/newhope/newhope.c',
'third_party/boringssl/crypto/newhope/ntt.c',
'third_party/boringssl/crypto/newhope/poly.c',
'third_party/boringssl/crypto/newhope/precomp.c',
'third_party/boringssl/crypto/newhope/reduce.c',
'third_party/boringssl/crypto/obj/obj.c',
'third_party/boringssl/crypto/obj/obj_xref.c',
'third_party/boringssl/crypto/pem/pem_all.c',
@ -321,6 +324,7 @@
'third_party/boringssl/crypto/poly1305/poly1305.c',
'third_party/boringssl/crypto/poly1305/poly1305_arm.c',
'third_party/boringssl/crypto/poly1305/poly1305_vec.c',
'third_party/boringssl/crypto/rand/deterministic.c',
'third_party/boringssl/crypto/rand/rand.c',
'third_party/boringssl/crypto/rand/urandom.c',
'third_party/boringssl/crypto/rand/windows.c',
@ -345,11 +349,13 @@
'third_party/boringssl/crypto/x509/a_sign.c',
'third_party/boringssl/crypto/x509/a_strex.c',
'third_party/boringssl/crypto/x509/a_verify.c',
'third_party/boringssl/crypto/x509/algorithm.c',
'third_party/boringssl/crypto/x509/asn1_gen.c',
'third_party/boringssl/crypto/x509/by_dir.c',
'third_party/boringssl/crypto/x509/by_file.c',
'third_party/boringssl/crypto/x509/i2d_pr.c',
'third_party/boringssl/crypto/x509/pkcs7.c',
'third_party/boringssl/crypto/x509/rsa_pss.c',
'third_party/boringssl/crypto/x509/t_crl.c',
'third_party/boringssl/crypto/x509/t_req.c',
'third_party/boringssl/crypto/x509/t_x509.c',
@ -424,21 +430,17 @@
'third_party/boringssl/crypto/x509v3/v3_utl.c',
'third_party/boringssl/ssl/custom_extensions.c',
'third_party/boringssl/ssl/d1_both.c',
'third_party/boringssl/ssl/d1_clnt.c',
'third_party/boringssl/ssl/d1_lib.c',
'third_party/boringssl/ssl/d1_meth.c',
'third_party/boringssl/ssl/d1_pkt.c',
'third_party/boringssl/ssl/d1_srtp.c',
'third_party/boringssl/ssl/d1_srvr.c',
'third_party/boringssl/ssl/dtls_method.c',
'third_party/boringssl/ssl/dtls_record.c',
'third_party/boringssl/ssl/pqueue/pqueue.c',
'third_party/boringssl/ssl/handshake_client.c',
'third_party/boringssl/ssl/handshake_server.c',
'third_party/boringssl/ssl/s3_both.c',
'third_party/boringssl/ssl/s3_clnt.c',
'third_party/boringssl/ssl/s3_enc.c',
'third_party/boringssl/ssl/s3_lib.c',
'third_party/boringssl/ssl/s3_meth.c',
'third_party/boringssl/ssl/s3_pkt.c',
'third_party/boringssl/ssl/s3_srvr.c',
'third_party/boringssl/ssl/ssl_aead_ctx.c',
'third_party/boringssl/ssl/ssl_asn1.c',
'third_party/boringssl/ssl/ssl_buffer.c',
@ -452,6 +454,11 @@
'third_party/boringssl/ssl/ssl_stat.c',
'third_party/boringssl/ssl/t1_enc.c',
'third_party/boringssl/ssl/t1_lib.c',
'third_party/boringssl/ssl/tls13_both.c',
'third_party/boringssl/ssl/tls13_client.c',
'third_party/boringssl/ssl/tls13_enc.c',
'third_party/boringssl/ssl/tls13_server.c',
'third_party/boringssl/ssl/tls_method.c',
'third_party/boringssl/ssl/tls_record.c',
]
},

@ -144,6 +144,7 @@ filegroups:
- include/grpc/impl/codegen/atm_gcc_atomic.h
- include/grpc/impl/codegen/atm_gcc_sync.h
- include/grpc/impl/codegen/atm_windows.h
- include/grpc/impl/codegen/gpr_slice.h
- include/grpc/impl/codegen/gpr_types.h
- include/grpc/impl/codegen/port_platform.h
- include/grpc/impl/codegen/slice.h
@ -683,7 +684,7 @@ filegroups:
- include/grpc/grpc_security.h
- include/grpc/grpc_security_constants.h
headers:
- third_party/objective_c/Cronet/cronet_c_for_grpc.h
- third_party/Cronet/bidirectional_stream_c.h
src:
- src/core/ext/transport/cronet/client/secure/cronet_channel_create.c
- src/core/ext/transport/cronet/transport/cronet_api_dummy.c
@ -1312,7 +1313,6 @@ libs:
- test/cpp/qps/driver.h
- test/cpp/qps/histogram.h
- test/cpp/qps/interarrival.h
- test/cpp/qps/limit_cores.h
- test/cpp/qps/parse_json.h
- test/cpp/qps/qps_worker.h
- test/cpp/qps/report.h
@ -1329,7 +1329,6 @@ libs:
- test/cpp/qps/client_async.cc
- test/cpp/qps/client_sync.cc
- test/cpp/qps/driver.cc
- test/cpp/qps/limit_cores.cc
- test/cpp/qps/parse_json.cc
- test/cpp/qps/qps_worker.cc
- test/cpp/qps/report.cc
@ -3647,16 +3646,17 @@ targets:
- test/cpp/interop/client_helper.h
- test/cpp/interop/interop_client.h
- test/cpp/interop/stress_interop_client.h
- test/cpp/util/create_test_channel.h
- test/cpp/util/metrics_server.h
src:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/metrics.proto
- src/proto/grpc/testing/test.proto
- test/cpp/interop/client_helper.cc
- test/cpp/interop/interop_client.cc
- test/cpp/interop/stress_interop_client.cc
- test/cpp/interop/stress_test.cc
- test/cpp/util/create_test_channel.cc
- test/cpp/util/metrics_server.cc
deps:
- grpc++_test_util

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

@ -302,7 +302,6 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/aes/mode_wrappers.c \
third_party/boringssl/crypto/asn1/a_bitstr.c \
third_party/boringssl/crypto/asn1/a_bool.c \
third_party/boringssl/crypto/asn1/a_bytes.c \
third_party/boringssl/crypto/asn1/a_d2i_fp.c \
third_party/boringssl/crypto/asn1/a_dup.c \
third_party/boringssl/crypto/asn1/a_enum.c \
@ -321,18 +320,14 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/asn1/asn1_lib.c \
third_party/boringssl/crypto/asn1/asn1_par.c \
third_party/boringssl/crypto/asn1/asn_pack.c \
third_party/boringssl/crypto/asn1/bio_asn1.c \
third_party/boringssl/crypto/asn1/bio_ndef.c \
third_party/boringssl/crypto/asn1/f_enum.c \
third_party/boringssl/crypto/asn1/f_int.c \
third_party/boringssl/crypto/asn1/f_string.c \
third_party/boringssl/crypto/asn1/t_bitst.c \
third_party/boringssl/crypto/asn1/t_pkey.c \
third_party/boringssl/crypto/asn1/tasn_dec.c \
third_party/boringssl/crypto/asn1/tasn_enc.c \
third_party/boringssl/crypto/asn1/tasn_fre.c \
third_party/boringssl/crypto/asn1/tasn_new.c \
third_party/boringssl/crypto/asn1/tasn_prn.c \
third_party/boringssl/crypto/asn1/tasn_typ.c \
third_party/boringssl/crypto/asn1/tasn_utl.c \
third_party/boringssl/crypto/asn1/x_bignum.c \
@ -362,6 +357,7 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/bn/generic.c \
third_party/boringssl/crypto/bn/kronecker.c \
third_party/boringssl/crypto/bn/montgomery.c \
third_party/boringssl/crypto/bn/montgomery_inv.c \
third_party/boringssl/crypto/bn/mul.c \
third_party/boringssl/crypto/bn/prime.c \
third_party/boringssl/crypto/bn/random.c \
@ -373,8 +369,7 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/bytestring/ber.c \
third_party/boringssl/crypto/bytestring/cbb.c \
third_party/boringssl/crypto/bytestring/cbs.c \
third_party/boringssl/crypto/chacha/chacha_generic.c \
third_party/boringssl/crypto/chacha/chacha_vec.c \
third_party/boringssl/crypto/chacha/chacha.c \
third_party/boringssl/crypto/cipher/aead.c \
third_party/boringssl/crypto/cipher/cipher.c \
third_party/boringssl/crypto/cipher/derive_key.c \
@ -389,10 +384,14 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/cipher/tls_cbc.c \
third_party/boringssl/crypto/cmac/cmac.c \
third_party/boringssl/crypto/conf/conf.c \
third_party/boringssl/crypto/cpu-aarch64-linux.c \
third_party/boringssl/crypto/cpu-arm-linux.c \
third_party/boringssl/crypto/cpu-arm.c \
third_party/boringssl/crypto/cpu-intel.c \
third_party/boringssl/crypto/cpu-ppc64le.c \
third_party/boringssl/crypto/crypto.c \
third_party/boringssl/crypto/curve25519/curve25519.c \
third_party/boringssl/crypto/curve25519/spake25519.c \
third_party/boringssl/crypto/curve25519/x25519-x86_64.c \
third_party/boringssl/crypto/des/des.c \
third_party/boringssl/crypto/dh/check.c \
@ -401,8 +400,6 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/dh/params.c \
third_party/boringssl/crypto/digest/digest.c \
third_party/boringssl/crypto/digest/digests.c \
third_party/boringssl/crypto/directory_posix.c \
third_party/boringssl/crypto/directory_win.c \
third_party/boringssl/crypto/dsa/dsa.c \
third_party/boringssl/crypto/dsa/dsa_asn1.c \
third_party/boringssl/crypto/ec/ec.c \
@ -421,7 +418,6 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c \
third_party/boringssl/crypto/engine/engine.c \
third_party/boringssl/crypto/err/err.c \
third_party/boringssl/crypto/evp/algorithm.c \
third_party/boringssl/crypto/evp/digestsign.c \
third_party/boringssl/crypto/evp/evp.c \
third_party/boringssl/crypto/evp/evp_asn1.c \
@ -432,6 +428,7 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/evp/p_rsa.c \
third_party/boringssl/crypto/evp/p_rsa_asn1.c \
third_party/boringssl/crypto/evp/pbkdf.c \
third_party/boringssl/crypto/evp/print.c \
third_party/boringssl/crypto/evp/sign.c \
third_party/boringssl/crypto/ex_data.c \
third_party/boringssl/crypto/hkdf/hkdf.c \
@ -445,6 +442,12 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/modes/ctr.c \
third_party/boringssl/crypto/modes/gcm.c \
third_party/boringssl/crypto/modes/ofb.c \
third_party/boringssl/crypto/newhope/error_correction.c \
third_party/boringssl/crypto/newhope/newhope.c \
third_party/boringssl/crypto/newhope/ntt.c \
third_party/boringssl/crypto/newhope/poly.c \
third_party/boringssl/crypto/newhope/precomp.c \
third_party/boringssl/crypto/newhope/reduce.c \
third_party/boringssl/crypto/obj/obj.c \
third_party/boringssl/crypto/obj/obj_xref.c \
third_party/boringssl/crypto/pem/pem_all.c \
@ -462,6 +465,7 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/poly1305/poly1305.c \
third_party/boringssl/crypto/poly1305/poly1305_arm.c \
third_party/boringssl/crypto/poly1305/poly1305_vec.c \
third_party/boringssl/crypto/rand/deterministic.c \
third_party/boringssl/crypto/rand/rand.c \
third_party/boringssl/crypto/rand/urandom.c \
third_party/boringssl/crypto/rand/windows.c \
@ -486,11 +490,13 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/x509/a_sign.c \
third_party/boringssl/crypto/x509/a_strex.c \
third_party/boringssl/crypto/x509/a_verify.c \
third_party/boringssl/crypto/x509/algorithm.c \
third_party/boringssl/crypto/x509/asn1_gen.c \
third_party/boringssl/crypto/x509/by_dir.c \
third_party/boringssl/crypto/x509/by_file.c \
third_party/boringssl/crypto/x509/i2d_pr.c \
third_party/boringssl/crypto/x509/pkcs7.c \
third_party/boringssl/crypto/x509/rsa_pss.c \
third_party/boringssl/crypto/x509/t_crl.c \
third_party/boringssl/crypto/x509/t_req.c \
third_party/boringssl/crypto/x509/t_x509.c \
@ -565,21 +571,17 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/crypto/x509v3/v3_utl.c \
third_party/boringssl/ssl/custom_extensions.c \
third_party/boringssl/ssl/d1_both.c \
third_party/boringssl/ssl/d1_clnt.c \
third_party/boringssl/ssl/d1_lib.c \
third_party/boringssl/ssl/d1_meth.c \
third_party/boringssl/ssl/d1_pkt.c \
third_party/boringssl/ssl/d1_srtp.c \
third_party/boringssl/ssl/d1_srvr.c \
third_party/boringssl/ssl/dtls_method.c \
third_party/boringssl/ssl/dtls_record.c \
third_party/boringssl/ssl/pqueue/pqueue.c \
third_party/boringssl/ssl/handshake_client.c \
third_party/boringssl/ssl/handshake_server.c \
third_party/boringssl/ssl/s3_both.c \
third_party/boringssl/ssl/s3_clnt.c \
third_party/boringssl/ssl/s3_enc.c \
third_party/boringssl/ssl/s3_lib.c \
third_party/boringssl/ssl/s3_meth.c \
third_party/boringssl/ssl/s3_pkt.c \
third_party/boringssl/ssl/s3_srvr.c \
third_party/boringssl/ssl/ssl_aead_ctx.c \
third_party/boringssl/ssl/ssl_asn1.c \
third_party/boringssl/ssl/ssl_buffer.c \
@ -593,6 +595,11 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/ssl/ssl_stat.c \
third_party/boringssl/ssl/t1_enc.c \
third_party/boringssl/ssl/t1_lib.c \
third_party/boringssl/ssl/tls13_both.c \
third_party/boringssl/ssl/tls13_client.c \
third_party/boringssl/ssl/tls13_enc.c \
third_party/boringssl/ssl/tls13_server.c \
third_party/boringssl/ssl/tls_method.c \
third_party/boringssl/ssl/tls_record.c \
, $ext_shared, , -Wall -Werror \
-Wno-parentheses-equality -Wno-unused-value -std=c11 \
@ -675,6 +682,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/md4)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/md5)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/modes)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/newhope)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/obj)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/pem)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/pkcs8)
@ -687,6 +695,5 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509v3)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/ssl)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/ssl/pqueue)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/nanopb)
fi

@ -153,6 +153,7 @@ DATA (flags = END_STREAM)
HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip
content-type = application/grpc+proto
DATA
<Length-Prefixed Message>

@ -55,10 +55,12 @@ some configuration as environment variables that can be set.
- secure_endpoint - traces bytes flowing through encrypted channels
- transport_security - traces metadata about secure channel establishment
- tcp - traces bytes in and out of a channel
'all' can additionally be used to turn all traces on.
Individual traces can be disabled by prefixing them with '-'.
Example:
export GRPC_TRACE=all,-pending_tags
export GRPC_TRACE=all,-pending_tags
* GRPC_VERBOSITY
Default gRPC logging verbosity - one of:

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

@ -1,13 +1,21 @@
Load Balancing in gRPC
=======================
======================
# Objective
# Scope
To design a load balancing API between a gRPC client and a Load Balancer to
instruct the client how to send load to multiple backend servers.
This document explains the design for load balancing within gRPC.
# Background
## Per-Call Load Balancing
It is worth noting that load-balancing within gRPC happens on a per-call
basis, not a per-connection basis. In other words, even if all requests
come from a single client, we still want them to be load-balanced across
all servers.
## Approaches to Load Balancing
Prior to any gRPC specifics, we explore some usual ways to approach load
balancing.
@ -44,30 +52,31 @@ list of servers to the client.
### External Load Balancing Service
The client load balancing code is kept simple and portable, implementing
well-known algorithms (ie, Round Robin) for server selection.
Complex load balancing algorithms are instead provided by the load balancer. The
client relies on the load balancer to provide _load balancing configuration_ and
_the list of servers_ to which the client should send requests. The balancer
updates the server list as needed to balance the load as well as handle server
well-known algorithms (e.g., Round Robin) for server selection.
Complex load balancing algorithms are instead provided by the load
balancer. The client relies on the load balancer to provide _load
balancing configuration_ and _the list of servers_ to which the client
should send requests. The balancer updates the server list as needed
to balance the load as well as handle server unavailability or health
issues. The load balancer will make any necessary complex decisions and
inform the client. The load balancer may communicate with the backend
servers to collect load and health information.
# Requirements
## Simple API and client
The gRPC client load balancing code must be simple and portable. The
client should only contain simple algorithms (e.g., Round Robin) for
server selection. For complex algorithms, the client should rely on
a load balancer to provide load balancing configuration and the list of
servers to which the client should send requests. The balancer will update
the server list as needed to balance the load as well as handle server
unavailability or health issues. The load balancer will make any necessary
complex decisions and inform the client. The load balancer may communicate with
the backend servers to collect load and health information.
## Requirements
#### Simple API and client
The gRPC client load balancing code must be simple and portable. The client
should only contain simple algorithms (ie Round Robin) for server selection. For
complex algorithms, the client should rely on a load balancer to provide load
balancing configuration and the list of servers to which the client should send
requests. The balancer will update the server list as needed to balance the load
as well as handle server unavailability or health issues. The load balancer will
make any necessary complex decisions and inform the client. The load balancer
may communicate with the backend servers to collect load and health information.
complex decisions and inform the client. The load balancer may communicate
with the backend servers to collect load and health information.
#### Security
## Security
The load balancer may be separate from the actual server backends and a
compromise of the load balancer should only lead to a compromise of the
@ -75,70 +84,64 @@ loadbalancing functionality. In other words, a compromised load balancer should
not be able to cause a client to trust a (potentially malicious) backend server
any more than in a comparable situation without loadbalancing.
# Proposed Architecture
The gRPC load balancing implements the external load balancing server approach:
an external load balancer provides simple clients with an up-to-date list of
servers.
![image](images/load_balancing_design.png)
1. On startup, the gRPC client issues a name resolution request for the service.
The name will resolve to one or more IP addresses to gRPC servers, a hint on
whether the IP address(es) point to a load balancer or not, and also return a
client config.
2. The gRPC client connects to a gRPC Server.
1. If the name resolution has hinted that the endpoint is a load balancer,
the client's gRPC LB policy will attempt to open a stream to the load
balancer service. The server may respond in only one of the following
ways.
1. `status::UNIMPLEMENTED`. There is no loadbalancing in use. The client
call will fail.
2. "I am a Load Balancer and here is the server list." (Goto Step 4.)
3. "Please contact Load Balancer X" (See Step 3.) The client will close
this connection and cancel the stream.
4. If the server fails to respond, the client will wait for some timeout
and then re-resolve the name (process to Step 1 above).
2. If the name resolution has not hinted that the endpoint is a load
balancer, the client connects directly to the service it wants to talk to.
3. The gRPC client's gRPC LB policy opens a separate connection to the Load
Balancer. If this fails, it will go back to step 1 and try another address.
1. During channel initialization to the Load Balancer, the client will
attempt to open a stream to the Load Balancer service.
2. The Load Balancer will return a server list to the gRPC client. If the
server list is empty, the call will wait until a non-empty one is
received. Optional: The Load Balancer will also open channels to the gRPC
servers if load reporting is needed.
4. The gRPC client will send RPCs to the gRPC servers contained in the server
list from the Load Balancer.
5. Optional: The gRPC servers may periodically report load to the Load Balancer.
## Client
When establishing a gRPC _stream_ to the balancer, the client will send an initial
request to the load balancer (via a regular gRPC message). The load balancer
will respond with client config (including, for example, settings for flow
control, RPC deadlines, etc.) or a redirect to another load balancer. If the
balancer did not redirect the client, it will then send a list of servers to the
client. The client will contain simple load balancing logic for choosing the
next server when it needs to send a request.
## Load Balancer
The Load Balancer is responsible for providing the client with a list of servers
and client RPC parameters. The balancer chooses when to update the list of
servers and can decide whether to provide a complete list, a subset, or a
specific list of “picked” servers in a particular order. The balancer can
optionally provide an expiration interval after which the server list should no
longer be trusted and should be updated by the balancer.
The load balancer may open reporting streams to each server contained in the
server list. These streams are primarily used for load reporting. For example,
Weighted Round Robin requires that the servers report utilization to the load
balancer in order to compute the next list of servers.
## Server
The gRPC Server is responsible for answering RPC requests and providing
responses to the client. The server will also report load to the load balancer
if a reporting stream was opened for this purpose.
# Architecture
## Overview
The primary mechanism for load-balancing in gRPC is external
load-balancing, where an external load balancer provides simple clients
with an up-to-date list of servers.
The gRPC client does support an API for built-in load balancing policies.
However, there are only a small number of these (one of which is the
`grpclb` policy, which implements external load balancing), and users
are discouraged from trying to extend gRPC by adding more. Instead, new
load balancing policies should be implemented in external load balancers.
## Workflow
Load-balancing policies fit into the gRPC client workflow in between
name resolution and the connection to the server. Here's how it all
works:
![image](images/load-balancing.png)
1. On startup, the gRPC client issues a [name resolution](naming.md) request
for the server name. The name will resolve to one or more IP addresses,
each of which will indicate whether it is a server address or
a load balancer address, and a [service config](service_config.md)
that indicates which client-side load-balancing policy to use (e.g.,
`round_robin` or `grpclb`).
2. The client instantiates the load balancing policy.
- Note: If all addresses returned by the resolver are balancer
addresses, then the client will use the `grpclb` policy, regardless
of what load-balancing policy was requested by the service config.
Otherwise, the client will use the load-balancing policy requested
by the service config. If no load-balancing policy is requested
by the service config, then the client will default to a policy
that picks the first available server address.
3. The load balancing policy creates a subchannel to each server address.
- For all policies *except* `grpclb`, this means one subchannel for each
address returned by the resolver. Note that these policies
ignore any balancer addresses returned by the resolver.
- In the case of the `grpclb` policy, the workflow is as follows:
1. The policy opens a stream to one of the balancer addresses returned
by the resolver. It asks the balancer for the server addresses to
use for the server name originally requested by the client (i.e.,
the same one originally passed to the name resolver).
- Note: The `grpclb` policy currently ignores any non-balancer
addresses returned by the resolver. However, in the future, it
may be changed to use these addresses as a fallback in case no
balancers can be contacted.
2. The gRPC servers to which the load balancer is directing the client
may report load to the load balancers, if that information is needed
by the load balancer's configuration.
3. The load balancer returns a server list to the gRPC client's `grpclb`
policy. The `grpclb` policy will then create a subchannel to each of
server in the list.
4. For each RPC sent, the load balancing policy decides which
subchannel (i.e., which server) the RPC should be sent to.
- In the case of the `grpclb` policy, the client will send requests
to the servers in the order in which they were returned by the load
balancer. If the server list is empty, the call will block until a
non-empty one is received.

@ -1,30 +1,65 @@
#gRPC Naming and Discovery Support
# gRPC Name Resolution
## Overview
gRPC supports DNS as the default name-system. A number of alternative name-systems are used in various deployments. We propose an API that is general enough to support a range of name-systems and the corresponding syntax for names. The gRPC client library in various languages will provide a plugin mechanism so resolvers for different name-systems can be plugged in.
gRPC supports DNS as the default name-system. A number of alternative
name-systems are used in various deployments. We support an API that is
general enough to support a range of name-systems and the corresponding
syntax for names. The gRPC client library in various languages will
provide a plugin mechanism so resolvers for different name-systems can
be plugged in.
## Detailed Proposal
## Detailed Design
A fully qualified, self contained name used for gRPC channel construction uses the syntax:
### Name Syntax
A fully qualified, self contained name used for gRPC channel construction
uses the syntax:
```
scheme://authority/endpoint_name
```
Here, scheme indicates the name-system to be used. Example schemes to be supported include:
Here, `scheme` indicates the name-system to be used. Currently, we
support the following schemes:
- `dns`
- `ipv4` (IPv4 address)
- `ipv6` (IPv6 address)
- `unix` (path to unix domain socket -- unix systems only)
* `dns`
In the future, additional schemes such as `etcd` could be added.
* `etcd`
The `authority` indicates some scheme-specific bootstrap information, e.g.,
for DNS, the authority may include the IP[:port] of the DNS server to
use. Often, a DNS name may be used as the authority, since the ability to
resolve DNS names is already built into all gRPC client libraries.
Authority indicates some scheme-specific bootstrap information, e.g., for DNS, the authority may include the IP[:port] of the DNS server to use. Often, a DNS name may used as the authority, since the ability to resolve DNS names is already built into all gRPC client libraries.
Finally, the `endpoint_name` indicates a concrete name to be looked up
in a given name-system identified by the scheme and the authority. The
syntax of the endpoint name is dictated by the scheme in use.
Finally, the endpoint_name indicates a concrete name to be looked up in a given name-system identified by the scheme and the authority. The syntax of endpoint name is dictated by the scheme in use.
### Resolver Plugins
### Plugins
The gRPC client library will use the specified scheme to pick the right
resolver plugin and pass it the fully qualified name string.
The gRPC client library will switch on the scheme to pick the right resolver plugin and pass it the fully qualified name string.
Resolvers should be able to contact the authority and get a resolution
that they return back to the gRPC client library. The returned contents
include:
Resolvers should be able to contact the authority and get a resolution that they return back to the gRPC client library. The returned contents include a list of IP:port, an optional config and optional auth config data to be used for channel authentication. The plugin API allows the resolvers to continuously watch an endpoint_name and return updated resolutions as needed.
- A list of resolved addresses, each of which has three attributes:
- The address itself, including both IP address and port.
- A boolean indicating whether the address is a backend address (i.e.,
the address to use to contact the server directly) or a balancer
address (for cases where [external load balancing](load-balancing.md)
is in use).
- The name of the balancer, if the address is a balancer address.
This will be used to perform peer authorization.
- A [service config](service_config.md).
The plugin API allows the resolvers to continuously watch an endpoint
and return updated resolutions as needed.

@ -0,0 +1,147 @@
Service Config in gRPC
======================
# Objective
The service config is a mechanism that allows service owners to publish
parameters to be automatically used by all clients of their service.
# Format
The service config is a JSON string of the following form:
```
{
# Load balancing policy name.
# Supported values are 'round_robin' and 'grpclb'.
# Optional; if unset, the default behavior is pick the first available
# backend.
# Note that if the resolver returns only balancer addresses and no
# backend addresses, gRPC will always use the 'grpclb' policy,
# regardless of what this field is set to.
'loadBalancingPolicy': string,
# Per-method configuration. Optional.
'methodConfig': [
{
# The names of the methods to which this method config applies. There
# must be at least one name. Each name entry must be unique across the
# entire service config. If the 'method' field is empty, then this
# method config specifies the defaults for all methods for the specified
# service.
#
# For example, let's say that the service config contains the following
# method config entries:
#
# 'methodConfig': [
# { 'name': [ { 'service': 'MyService' } ] ... },
# { 'name': [ { 'service': 'MyService', 'method': 'Foo' } ] ... }
# ]
#
# For a request for MyService/Foo, we will use the second entry, because
# it exactly matches the service and method name.
# For a request for MyService/Bar, we will use the first entry, because
# it provides the default for all methods of MyService.
'name': [
{
# RPC service name. Required.
# If using gRPC with protobuf as the IDL, then this will be of
# the form "pkg.service_name", where "pkg" is the package name
# defined in the proto file.
'service': string,
# RPC method name. Optional (see above).
'method': string,
}
],
# Whether RPCs sent to this method should wait until the connection is
# ready by default. If false, the RPC will abort immediately if there
# is a transient failure connecting to the server. Otherwise, gRPC will
# attempt to connect until the deadline is exceeded.
#
# The value specified via the gRPC client API will override the value
# set here. However, note that setting the value in the client API will
# also affect transient errors encountered during name resolution,
# which cannot be caught by the value here, since the service config
# is obtained by the gRPC client via name resolution.
'waitForReady': bool,
# The default timeout in seconds for RPCs sent to this method. This can
# be overridden in code. If no reply is received in the specified amount
# of time, the request is aborted and a deadline-exceeded error status
# is returned to the caller.
#
# The actual deadline used will be the minimum of the value specified
# here and the value set by the application via the gRPC client API.
# If either one is not set, then the other will be used.
# If neither is set, then the request has no deadline.
#
# The format of the value is that of the 'Duration' type defined here:
# https://developers.google.com/protocol-buffers/docs/proto3#json
'timeout': string,
# The maximum allowed payload size for an individual request or object
# in a stream (client->server) in bytes. The size which is measured is
# the serialized, uncompressed payload in bytes. This applies both
# to streaming and non-streaming requests.
#
# The actual value used is the minimum of the value specified here and
# the value set by the application via the gRPC client API.
# If either one is not set, then the other will be used.
# If neither is set, then the built-in default is used.
#
# If a client attempts to send an object larger than this value, it
# will not be sent and the client will see an error.
# Note that 0 is a valid value, meaning that the request message must
# be empty.
#
# The format of the value is that of the 'uint64' type defined here:
# https://developers.google.com/protocol-buffers/docs/proto3#json
'maxRequestMessageBytes': string,
# The maximum allowed payload size for an individual response or object
# in a stream (server->client) in bytes. The size which is measured is
# the serialized, uncompressed payload in bytes. This applies both
# to streaming and non-streaming requests.
#
# The actual value used is the minimum of the value specified here and
# the value set by the application via the gRPC client API.
# If either one is not set, then the other will be used.
# If neither is set, then the built-in default is used.
#
# If a server attempts to send an object larger than this value, it
# will not be sent, and the client will see an error.
# Note that 0 is a valid value, meaning that the response message must
# be empty.
#
# The format of the value is that of the 'uint64' type defined here:
# https://developers.google.com/protocol-buffers/docs/proto3#json
'maxResponseMessageBytes': string
}
]
}
```
Note that new per-method parameters may be added in the future as new
functionality is introduced.
# Architecture
A service config is associated with a server name. The [name
resolver](naming.md) plugin, when asked to resolve a particular server
name, will return both the resolved addresses and the service config.
TODO(roth): Design how the service config will be encoded in DNS.
# APIs
The service config is used in the following APIs:
- In the resolver API, used by resolver plugins to return the service
config to the gRPC client.
- In the gRPC client API, where users can query the channel to obtain
the service config associated with the channel (for debugging
purposes).
- In the gRPC client API, where users can set the service config
explicitly. This is intended for use in unit tests.

@ -0,0 +1,42 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cc_binary(
name = "greeter_client",
srcs = ["greeter_client.cc"],
deps = ["//examples/protos:helloworld"],
defines = ["BAZEL_BUILD"],
)
cc_binary(
name = "greeter_server",
srcs = ["greeter_server.cc"],
deps = ["//examples/protos:helloworld"],
defines = ["BAZEL_BUILD"],
)

@ -37,7 +37,11 @@
#include <grpc++/grpc++.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientContext;

@ -37,7 +37,11 @@
#include <grpc++/grpc++.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Server;
using grpc::ServerBuilder;

@ -0,0 +1,52 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library(
name = "auth_sample",
srcs = ["auth_sample.proto"],
)
grpc_proto_library(
name = "hellostreamingworld",
srcs = ["hellostreamingworld.proto"],
)
grpc_proto_library(
name = "helloworld",
srcs = ["helloworld.proto"],
)
grpc_proto_library(
name = "route_guide",
srcs = ["route_guide.proto"],
)

@ -148,6 +148,7 @@ Pod::Spec.new do |s|
'include/grpc/impl/codegen/atm_gcc_atomic.h',
'include/grpc/impl/codegen/atm_gcc_sync.h',
'include/grpc/impl/codegen/atm_windows.h',
'include/grpc/impl/codegen/gpr_slice.h',
'include/grpc/impl/codegen/gpr_types.h',
'include/grpc/impl/codegen/port_platform.h',
'include/grpc/impl/codegen/slice.h',
@ -175,6 +176,7 @@ Pod::Spec.new do |s|
'include/grpc/impl/codegen/atm_gcc_atomic.h',
'include/grpc/impl/codegen/atm_gcc_sync.h',
'include/grpc/impl/codegen/atm_windows.h',
'include/grpc/impl/codegen/gpr_slice.h',
'include/grpc/impl/codegen/gpr_types.h',
'include/grpc/impl/codegen/port_platform.h',
'include/grpc/impl/codegen/slice.h',

@ -73,6 +73,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
s.files += %w( include/grpc/impl/codegen/atm_windows.h )
s.files += %w( include/grpc/impl/codegen/gpr_slice.h )
s.files += %w( include/grpc/impl/codegen/gpr_types.h )
s.files += %w( include/grpc/impl/codegen/port_platform.h )
s.files += %w( include/grpc/impl/codegen/slice.h )
@ -156,6 +157,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
s.files += %w( include/grpc/impl/codegen/atm_windows.h )
s.files += %w( include/grpc/impl/codegen/gpr_slice.h )
s.files += %w( include/grpc/impl/codegen/gpr_types.h )
s.files += %w( include/grpc/impl/codegen/port_platform.h )
s.files += %w( include/grpc/impl/codegen/slice.h )
@ -575,23 +577,22 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/conf/internal.h )
s.files += %w( third_party/boringssl/crypto/curve25519/internal.h )
s.files += %w( third_party/boringssl/crypto/des/internal.h )
s.files += %w( third_party/boringssl/crypto/dh/internal.h )
s.files += %w( third_party/boringssl/crypto/digest/internal.h )
s.files += %w( third_party/boringssl/crypto/digest/md32_common.h )
s.files += %w( third_party/boringssl/crypto/directory.h )
s.files += %w( third_party/boringssl/crypto/ec/internal.h )
s.files += %w( third_party/boringssl/crypto/ec/p256-x86_64-table.h )
s.files += %w( third_party/boringssl/crypto/evp/internal.h )
s.files += %w( third_party/boringssl/crypto/internal.h )
s.files += %w( third_party/boringssl/crypto/modes/internal.h )
s.files += %w( third_party/boringssl/crypto/newhope/internal.h )
s.files += %w( third_party/boringssl/crypto/obj/obj_dat.h )
s.files += %w( third_party/boringssl/crypto/obj/obj_xref.h )
s.files += %w( third_party/boringssl/crypto/pkcs8/internal.h )
s.files += %w( third_party/boringssl/crypto/poly1305/internal.h )
s.files += %w( third_party/boringssl/crypto/rand/internal.h )
s.files += %w( third_party/boringssl/crypto/rsa/internal.h )
s.files += %w( third_party/boringssl/crypto/test/scoped_types.h )
s.files += %w( third_party/boringssl/crypto/test/test_util.h )
s.files += %w( third_party/boringssl/crypto/x509/charmap.h )
s.files += %w( third_party/boringssl/crypto/x509/internal.h )
s.files += %w( third_party/boringssl/crypto/x509/vpm_int.h )
s.files += %w( third_party/boringssl/crypto/x509v3/ext_dat.h )
s.files += %w( third_party/boringssl/crypto/x509v3/pcy_int.h )
@ -637,10 +638,12 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/include/openssl/md4.h )
s.files += %w( third_party/boringssl/include/openssl/md5.h )
s.files += %w( third_party/boringssl/include/openssl/mem.h )
s.files += %w( third_party/boringssl/include/openssl/newhope.h )
s.files += %w( third_party/boringssl/include/openssl/nid.h )
s.files += %w( third_party/boringssl/include/openssl/obj.h )
s.files += %w( third_party/boringssl/include/openssl/obj_mac.h )
s.files += %w( third_party/boringssl/include/openssl/objects.h )
s.files += %w( third_party/boringssl/include/openssl/opensslfeatures.h )
s.files += %w( third_party/boringssl/include/openssl/opensslconf.h )
s.files += %w( third_party/boringssl/include/openssl/opensslv.h )
s.files += %w( third_party/boringssl/include/openssl/ossl_typ.h )
s.files += %w( third_party/boringssl/include/openssl/pem.h )
@ -648,9 +651,9 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/include/openssl/pkcs7.h )
s.files += %w( third_party/boringssl/include/openssl/pkcs8.h )
s.files += %w( third_party/boringssl/include/openssl/poly1305.h )
s.files += %w( third_party/boringssl/include/openssl/pqueue.h )
s.files += %w( third_party/boringssl/include/openssl/rand.h )
s.files += %w( third_party/boringssl/include/openssl/rc4.h )
s.files += %w( third_party/boringssl/include/openssl/ripemd.h )
s.files += %w( third_party/boringssl/include/openssl/rsa.h )
s.files += %w( third_party/boringssl/include/openssl/safestack.h )
s.files += %w( third_party/boringssl/include/openssl/sha.h )
@ -667,16 +670,11 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/include/openssl/x509_vfy.h )
s.files += %w( third_party/boringssl/include/openssl/x509v3.h )
s.files += %w( third_party/boringssl/ssl/internal.h )
s.files += %w( third_party/boringssl/ssl/test/async_bio.h )
s.files += %w( third_party/boringssl/ssl/test/packeted_bio.h )
s.files += %w( third_party/boringssl/ssl/test/scoped_types.h )
s.files += %w( third_party/boringssl/ssl/test/test_config.h )
s.files += %w( src/boringssl/err_data.c )
s.files += %w( third_party/boringssl/crypto/aes/aes.c )
s.files += %w( third_party/boringssl/crypto/aes/mode_wrappers.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_bitstr.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_bool.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_bytes.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_d2i_fp.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_dup.c )
s.files += %w( third_party/boringssl/crypto/asn1/a_enum.c )
@ -695,18 +693,14 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/asn1/asn1_lib.c )
s.files += %w( third_party/boringssl/crypto/asn1/asn1_par.c )
s.files += %w( third_party/boringssl/crypto/asn1/asn_pack.c )
s.files += %w( third_party/boringssl/crypto/asn1/bio_asn1.c )
s.files += %w( third_party/boringssl/crypto/asn1/bio_ndef.c )
s.files += %w( third_party/boringssl/crypto/asn1/f_enum.c )
s.files += %w( third_party/boringssl/crypto/asn1/f_int.c )
s.files += %w( third_party/boringssl/crypto/asn1/f_string.c )
s.files += %w( third_party/boringssl/crypto/asn1/t_bitst.c )
s.files += %w( third_party/boringssl/crypto/asn1/t_pkey.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_dec.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_enc.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_fre.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_new.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_prn.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_typ.c )
s.files += %w( third_party/boringssl/crypto/asn1/tasn_utl.c )
s.files += %w( third_party/boringssl/crypto/asn1/x_bignum.c )
@ -736,6 +730,7 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/bn/generic.c )
s.files += %w( third_party/boringssl/crypto/bn/kronecker.c )
s.files += %w( third_party/boringssl/crypto/bn/montgomery.c )
s.files += %w( third_party/boringssl/crypto/bn/montgomery_inv.c )
s.files += %w( third_party/boringssl/crypto/bn/mul.c )
s.files += %w( third_party/boringssl/crypto/bn/prime.c )
s.files += %w( third_party/boringssl/crypto/bn/random.c )
@ -747,8 +742,7 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/bytestring/ber.c )
s.files += %w( third_party/boringssl/crypto/bytestring/cbb.c )
s.files += %w( third_party/boringssl/crypto/bytestring/cbs.c )
s.files += %w( third_party/boringssl/crypto/chacha/chacha_generic.c )
s.files += %w( third_party/boringssl/crypto/chacha/chacha_vec.c )
s.files += %w( third_party/boringssl/crypto/chacha/chacha.c )
s.files += %w( third_party/boringssl/crypto/cipher/aead.c )
s.files += %w( third_party/boringssl/crypto/cipher/cipher.c )
s.files += %w( third_party/boringssl/crypto/cipher/derive_key.c )
@ -763,10 +757,14 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/cipher/tls_cbc.c )
s.files += %w( third_party/boringssl/crypto/cmac/cmac.c )
s.files += %w( third_party/boringssl/crypto/conf/conf.c )
s.files += %w( third_party/boringssl/crypto/cpu-aarch64-linux.c )
s.files += %w( third_party/boringssl/crypto/cpu-arm-linux.c )
s.files += %w( third_party/boringssl/crypto/cpu-arm.c )
s.files += %w( third_party/boringssl/crypto/cpu-intel.c )
s.files += %w( third_party/boringssl/crypto/cpu-ppc64le.c )
s.files += %w( third_party/boringssl/crypto/crypto.c )
s.files += %w( third_party/boringssl/crypto/curve25519/curve25519.c )
s.files += %w( third_party/boringssl/crypto/curve25519/spake25519.c )
s.files += %w( third_party/boringssl/crypto/curve25519/x25519-x86_64.c )
s.files += %w( third_party/boringssl/crypto/des/des.c )
s.files += %w( third_party/boringssl/crypto/dh/check.c )
@ -775,8 +773,6 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/dh/params.c )
s.files += %w( third_party/boringssl/crypto/digest/digest.c )
s.files += %w( third_party/boringssl/crypto/digest/digests.c )
s.files += %w( third_party/boringssl/crypto/directory_posix.c )
s.files += %w( third_party/boringssl/crypto/directory_win.c )
s.files += %w( third_party/boringssl/crypto/dsa/dsa.c )
s.files += %w( third_party/boringssl/crypto/dsa/dsa_asn1.c )
s.files += %w( third_party/boringssl/crypto/ec/ec.c )
@ -795,7 +791,6 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c )
s.files += %w( third_party/boringssl/crypto/engine/engine.c )
s.files += %w( third_party/boringssl/crypto/err/err.c )
s.files += %w( third_party/boringssl/crypto/evp/algorithm.c )
s.files += %w( third_party/boringssl/crypto/evp/digestsign.c )
s.files += %w( third_party/boringssl/crypto/evp/evp.c )
s.files += %w( third_party/boringssl/crypto/evp/evp_asn1.c )
@ -806,6 +801,7 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/evp/p_rsa.c )
s.files += %w( third_party/boringssl/crypto/evp/p_rsa_asn1.c )
s.files += %w( third_party/boringssl/crypto/evp/pbkdf.c )
s.files += %w( third_party/boringssl/crypto/evp/print.c )
s.files += %w( third_party/boringssl/crypto/evp/sign.c )
s.files += %w( third_party/boringssl/crypto/ex_data.c )
s.files += %w( third_party/boringssl/crypto/hkdf/hkdf.c )
@ -819,6 +815,12 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/modes/ctr.c )
s.files += %w( third_party/boringssl/crypto/modes/gcm.c )
s.files += %w( third_party/boringssl/crypto/modes/ofb.c )
s.files += %w( third_party/boringssl/crypto/newhope/error_correction.c )
s.files += %w( third_party/boringssl/crypto/newhope/newhope.c )
s.files += %w( third_party/boringssl/crypto/newhope/ntt.c )
s.files += %w( third_party/boringssl/crypto/newhope/poly.c )
s.files += %w( third_party/boringssl/crypto/newhope/precomp.c )
s.files += %w( third_party/boringssl/crypto/newhope/reduce.c )
s.files += %w( third_party/boringssl/crypto/obj/obj.c )
s.files += %w( third_party/boringssl/crypto/obj/obj_xref.c )
s.files += %w( third_party/boringssl/crypto/pem/pem_all.c )
@ -836,6 +838,7 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/poly1305/poly1305.c )
s.files += %w( third_party/boringssl/crypto/poly1305/poly1305_arm.c )
s.files += %w( third_party/boringssl/crypto/poly1305/poly1305_vec.c )
s.files += %w( third_party/boringssl/crypto/rand/deterministic.c )
s.files += %w( third_party/boringssl/crypto/rand/rand.c )
s.files += %w( third_party/boringssl/crypto/rand/urandom.c )
s.files += %w( third_party/boringssl/crypto/rand/windows.c )
@ -860,11 +863,13 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/x509/a_sign.c )
s.files += %w( third_party/boringssl/crypto/x509/a_strex.c )
s.files += %w( third_party/boringssl/crypto/x509/a_verify.c )
s.files += %w( third_party/boringssl/crypto/x509/algorithm.c )
s.files += %w( third_party/boringssl/crypto/x509/asn1_gen.c )
s.files += %w( third_party/boringssl/crypto/x509/by_dir.c )
s.files += %w( third_party/boringssl/crypto/x509/by_file.c )
s.files += %w( third_party/boringssl/crypto/x509/i2d_pr.c )
s.files += %w( third_party/boringssl/crypto/x509/pkcs7.c )
s.files += %w( third_party/boringssl/crypto/x509/rsa_pss.c )
s.files += %w( third_party/boringssl/crypto/x509/t_crl.c )
s.files += %w( third_party/boringssl/crypto/x509/t_req.c )
s.files += %w( third_party/boringssl/crypto/x509/t_x509.c )
@ -939,21 +944,17 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/crypto/x509v3/v3_utl.c )
s.files += %w( third_party/boringssl/ssl/custom_extensions.c )
s.files += %w( third_party/boringssl/ssl/d1_both.c )
s.files += %w( third_party/boringssl/ssl/d1_clnt.c )
s.files += %w( third_party/boringssl/ssl/d1_lib.c )
s.files += %w( third_party/boringssl/ssl/d1_meth.c )
s.files += %w( third_party/boringssl/ssl/d1_pkt.c )
s.files += %w( third_party/boringssl/ssl/d1_srtp.c )
s.files += %w( third_party/boringssl/ssl/d1_srvr.c )
s.files += %w( third_party/boringssl/ssl/dtls_method.c )
s.files += %w( third_party/boringssl/ssl/dtls_record.c )
s.files += %w( third_party/boringssl/ssl/pqueue/pqueue.c )
s.files += %w( third_party/boringssl/ssl/handshake_client.c )
s.files += %w( third_party/boringssl/ssl/handshake_server.c )
s.files += %w( third_party/boringssl/ssl/s3_both.c )
s.files += %w( third_party/boringssl/ssl/s3_clnt.c )
s.files += %w( third_party/boringssl/ssl/s3_enc.c )
s.files += %w( third_party/boringssl/ssl/s3_lib.c )
s.files += %w( third_party/boringssl/ssl/s3_meth.c )
s.files += %w( third_party/boringssl/ssl/s3_pkt.c )
s.files += %w( third_party/boringssl/ssl/s3_srvr.c )
s.files += %w( third_party/boringssl/ssl/ssl_aead_ctx.c )
s.files += %w( third_party/boringssl/ssl/ssl_asn1.c )
s.files += %w( third_party/boringssl/ssl/ssl_buffer.c )
@ -967,6 +968,11 @@ Gem::Specification.new do |s|
s.files += %w( third_party/boringssl/ssl/ssl_stat.c )
s.files += %w( third_party/boringssl/ssl/t1_enc.c )
s.files += %w( third_party/boringssl/ssl/t1_lib.c )
s.files += %w( third_party/boringssl/ssl/tls13_both.c )
s.files += %w( third_party/boringssl/ssl/tls13_client.c )
s.files += %w( third_party/boringssl/ssl/tls13_enc.c )
s.files += %w( third_party/boringssl/ssl/tls13_server.c )
s.files += %w( third_party/boringssl/ssl/tls_method.c )
s.files += %w( third_party/boringssl/ssl/tls_record.c )
s.files += %w( third_party/zlib/crc32.h )
s.files += %w( third_party/zlib/deflate.h )

@ -39,6 +39,12 @@
#define GRPC_CUSTOM_STRING std::string
#endif
// The following macros are deprecated and appear only for users
// with PB files generated using gRPC 1.0.x plugins. They should
// not be used in new code
#define GRPC_OVERRIDE override // deprecated
#define GRPC_FINAL final // deprecated
namespace grpc {
typedef GRPC_CUSTOM_STRING string;

@ -88,6 +88,10 @@ class ChannelArguments {
/// The given buffer pool will be attached to the constructed channel
void SetResourceQuota(const ResourceQuota& resource_quota);
/// Sets the max receive and send message sizes.
void SetMaxReceiveMessageSize(int size);
void SetMaxSendMessageSize(int size);
/// Set LB policy name.
/// Note that if the name resolver returns only balancer addresses, the
/// grpclb LB policy will be used, regardless of what is specified here.

@ -0,0 +1,84 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_IMPL_CODEGEN_GPR_SLICE_H
#define GRPC_IMPL_CODEGEN_GPR_SLICE_H
/* WARNING: Please do not use this header. This was added as a temporary measure
* to not break some of the external projects that depend on gpr_slice_*
* functions. We are actively working on moving all the gpr_slice_* references
* to grpc_slice_* and this file will be removed
* */
/* TODO (sreek) - Allowed by default but will be very soon turned off */
#define GRPC_ALLOW_GPR_SLICE_FUNCTIONS 1
#ifdef GRPC_ALLOW_GPR_SLICE_FUNCTIONS
#define gpr_slice_refcount grpc_slice_refcount
#define gpr_slice grpc_slice
#define gpr_slice_buffer grpc_slice_buffer
#define gpr_slice_ref grpc_slice_ref
#define gpr_slice_unref grpc_slice_unref
#define gpr_slice_new grpc_slice_new
#define gpr_slice_new_with_user_data grpc_slice_new_with_user_data
#define gpr_slice_new_with_len grpc_slice_new_with_len
#define gpr_slice_malloc grpc_slice_malloc
#define gpr_slice_from_copied_string grpc_slice_from_copied_string
#define gpr_slice_from_copied_buffer grpc_slice_from_copied_buffer
#define gpr_slice_from_static_string grpc_slice_from_static_string
#define gpr_slice_sub grpc_slice_sub
#define gpr_slice_sub_no_ref grpc_slice_sub_no_ref
#define gpr_slice_split_tail grpc_slice_split_tail
#define gpr_slice_split_head grpc_slice_split_head
#define gpr_slice_cmp grpc_slice_cmp
#define gpr_slice_str_cmp grpc_slice_str_cmp
#define gpr_slice_buffer grpc_slice_buffer
#define gpr_slice_buffer_init grpc_slice_buffer_init
#define gpr_slice_buffer_destroy grpc_slice_buffer_destroy
#define gpr_slice_buffer_add grpc_slice_buffer_add
#define gpr_slice_buffer_add_indexed grpc_slice_buffer_add_indexed
#define gpr_slice_buffer_addn grpc_slice_buffer_addn
#define gpr_slice_buffer_tiny_add grpc_slice_buffer_tiny_add
#define gpr_slice_buffer_pop grpc_slice_buffer_pop
#define gpr_slice_buffer_reset_and_unref grpc_slice_buffer_reset_and_unref
#define gpr_slice_buffer_swap grpc_slice_buffer_swap
#define gpr_slice_buffer_move_into grpc_slice_buffer_move_into
#define gpr_slice_buffer_trim_end grpc_slice_buffer_trim_end
#define gpr_slice_buffer_move_first grpc_slice_buffer_move_first
#define gpr_slice_buffer_take_first grpc_slice_buffer_take_first
#endif /* GRPC_ALLOW_GPR_SLICE_FUNCTIONS */
#endif /* GRPC_IMPL_CODEGEN_GPR_SLICE_H */

@ -179,6 +179,9 @@ typedef struct {
Larger values give lower CPU usage for large messages, but more head of line
blocking for small messages. */
#define GRPC_ARG_HTTP2_MAX_FRAME_SIZE "grpc.http2.max_frame_size"
/** How much data are we willing to queue up per stream if
GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */
#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
/** Default authority to pass if none specified on call construction. A string.
* */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"

@ -38,6 +38,7 @@
#include <stdint.h>
#include <grpc/impl/codegen/exec_ctx_fwd.h>
#include <grpc/impl/codegen/gpr_slice.h>
/* Slice API
@ -117,4 +118,22 @@ typedef struct {
GRPC_SLICE_START_PTR(slice) + GRPC_SLICE_LENGTH(slice)
#define GRPC_SLICE_IS_EMPTY(slice) (GRPC_SLICE_LENGTH(slice) == 0)
#ifdef GRPC_ALLOW_GPR_SLICE_FUNCTIONS
/* Duplicate GPR_* definitions */
#define GPR_SLICE_START_PTR(slice) \
((slice).refcount ? (slice).data.refcounted.bytes \
: (slice).data.inlined.bytes)
#define GPR_SLICE_LENGTH(slice) \
((slice).refcount ? (slice).data.refcounted.length \
: (slice).data.inlined.length)
#define GPR_SLICE_SET_LENGTH(slice, newlen) \
((slice).refcount ? ((slice).data.refcounted.length = (size_t)(newlen)) \
: ((slice).data.inlined.length = (uint8_t)(newlen)))
#define GPR_SLICE_END_PTR(slice) \
GRPC_SLICE_START_PTR(slice) + GRPC_SLICE_LENGTH(slice)
#define GPR_SLICE_IS_EMPTY(slice) (GRPC_SLICE_LENGTH(slice) == 0)
#endif /* GRPC_ALLOW_GPR_SLICE_FUNCTIONS */
#endif /* GRPC_IMPL_CODEGEN_SLICE_H */

@ -10,19 +10,20 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
<date>2016-08-22</date>
<date>2017-01-13</date>
<time>16:06:07</time>
<version>
<release>1.1.0dev</release>
<api>1.1.0dev</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
<release>beta</release>
<api>beta</api>
</stability>
<license>BSD</license>
<notes>
- Reject metadata keys which are not legal #7881
- PHP Proto3 adoption #8179
- Various bug fixes
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@ -81,6 +82,7 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_windows.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_slice.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_types.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/slice.h" role="src" />
@ -164,6 +166,7 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/atm_windows.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_slice.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_types.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/slice.h" role="src" />
@ -583,23 +586,22 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/conf/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/des/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/dh/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/digest/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/digest/md32_common.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/directory.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/ec/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/ec/p256-x86_64-table.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/modes/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/obj/obj_dat.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/obj/obj_xref.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/pkcs8/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/poly1305/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rand/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rsa/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/test/scoped_types.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/test/test_util.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/charmap.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/vpm_int.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509v3/ext_dat.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509v3/pcy_int.h" role="src" />
@ -645,10 +647,12 @@
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/md4.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/md5.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/mem.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/newhope.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/nid.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/obj.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/obj_mac.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/objects.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/opensslfeatures.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/opensslconf.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/opensslv.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/ossl_typ.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/pem.h" role="src" />
@ -656,9 +660,9 @@
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/pkcs7.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/pkcs8.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/poly1305.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/pqueue.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/rand.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/rc4.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/ripemd.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/rsa.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/safestack.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/sha.h" role="src" />
@ -675,16 +679,11 @@
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/x509_vfy.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/include/openssl/x509v3.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/internal.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/test/async_bio.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/test/packeted_bio.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/test/scoped_types.h" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/test/test_config.h" role="src" />
<file baseinstalldir="/" name="src/boringssl/err_data.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/aes/aes.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/aes/mode_wrappers.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_bitstr.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_bool.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_bytes.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_d2i_fp.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_dup.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_enum.c" role="src" />
@ -703,18 +702,14 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn1_lib.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn1_par.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn_pack.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/bio_asn1.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/bio_ndef.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/f_enum.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/f_int.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/f_string.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/t_bitst.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/t_pkey.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_dec.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_enc.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_fre.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_new.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_prn.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_typ.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/tasn_utl.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/x_bignum.c" role="src" />
@ -744,6 +739,7 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/generic.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/kronecker.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/montgomery.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/montgomery_inv.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/mul.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/prime.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bn/random.c" role="src" />
@ -755,8 +751,7 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/bytestring/ber.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bytestring/cbb.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/bytestring/cbs.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/chacha/chacha_generic.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/chacha/chacha_vec.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/chacha/chacha.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cipher/aead.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cipher/cipher.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cipher/derive_key.c" role="src" />
@ -771,10 +766,14 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/cipher/tls_cbc.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cmac/cmac.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/conf/conf.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-aarch64-linux.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-arm-linux.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-arm.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-intel.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-ppc64le.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/crypto.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/curve25519.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/spake25519.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/x25519-x86_64.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/des/des.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/dh/check.c" role="src" />
@ -783,8 +782,6 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/dh/params.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/digest/digest.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/digest/digests.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/directory_posix.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/directory_win.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/dsa/dsa.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/dsa/dsa_asn1.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/ec/ec.c" role="src" />
@ -803,7 +800,6 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/engine/engine.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/err/err.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/algorithm.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/digestsign.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/evp.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/evp_asn1.c" role="src" />
@ -814,6 +810,7 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/p_rsa.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/p_rsa_asn1.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/pbkdf.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/print.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/evp/sign.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/ex_data.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/hkdf/hkdf.c" role="src" />
@ -827,6 +824,12 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/modes/ctr.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/modes/gcm.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/modes/ofb.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/error_correction.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/newhope.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/ntt.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/poly.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/precomp.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/newhope/reduce.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/obj/obj.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/obj/obj_xref.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/pem/pem_all.c" role="src" />
@ -844,6 +847,7 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/poly1305/poly1305.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/poly1305/poly1305_arm.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/poly1305/poly1305_vec.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rand/deterministic.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rand/rand.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rand/urandom.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/rand/windows.c" role="src" />
@ -868,11 +872,13 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/a_sign.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/a_strex.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/a_verify.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/algorithm.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/asn1_gen.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/by_dir.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/by_file.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/i2d_pr.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/pkcs7.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/rsa_pss.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/t_crl.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/t_req.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509/t_x509.c" role="src" />
@ -947,21 +953,17 @@
<file baseinstalldir="/" name="third_party/boringssl/crypto/x509v3/v3_utl.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/custom_extensions.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_both.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_clnt.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_lib.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_meth.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_pkt.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_srtp.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/d1_srvr.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/dtls_method.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/dtls_record.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/pqueue/pqueue.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/handshake_client.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/handshake_server.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_both.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_clnt.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_enc.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_lib.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_meth.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_pkt.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/s3_srvr.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/ssl_aead_ctx.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/ssl_asn1.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/ssl_buffer.c" role="src" />
@ -975,6 +977,11 @@
<file baseinstalldir="/" name="third_party/boringssl/ssl/ssl_stat.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/t1_enc.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/t1_lib.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_both.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_client.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_enc.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_server.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls_method.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls_record.c" role="src" />
</dir>
</contents>
@ -1215,18 +1222,49 @@ Update to wrap gRPC C Core version 0.10.0
</release>
<release>
<version>
<release>1.1.0dev</release>
<api>1.1.0dev</api>
<release>1.0.1RC1</release>
<api>1.0.1RC1</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2016-10-06</date>
<license>BSD</license>
<notes>
- Reject metadata keys which are not legal #7881
</notes>
</release>
<release>
<version>
<release>1.0.1</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2016-08-22</date>
<date>2016-10-27</date>
<license>BSD</license>
<notes>
- Reject metadata keys which are not legal #7881
</notes>
</release>
<release>
<version>
<release>1.1.0dev</release>
<api>1.1.0dev</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2017-01-13</date>
<license>BSD</license>
<notes>
- PHP Proto3 adoption #8179
- Various bug fixes
</notes>
</release>
</changelog>
</package>

@ -11,3 +11,7 @@ inplace=1
[build_package_protos]
exclude=.*protoc_plugin/protoc_plugin_test\.proto$
# Style settings
[yapf]
based_on_style = google

File diff suppressed because it is too large Load Diff

@ -1218,13 +1218,15 @@ void PrintSourceService(Printer *printer, const Service *service,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
"static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Method"] = service->method(i).get()->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
if (service->method_count() > 0) {
printer->Print(*vars,
"static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Method"] = service->method(i).get()->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
}
printer->Print(*vars, "};\n\n");
}
printer->Print(*vars, "};\n\n");
printer->Print(*vars,
"std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
@ -1272,7 +1274,6 @@ void PrintSourceService(Printer *printer, const Service *service,
printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
printer->Indent();
printer->Print(*vars, "(void)$prefix$$Service$_method_names;\n");
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
(*vars)["Idx"] = as_string(i);

@ -31,15 +31,21 @@
*
*/
//#include "src/core/ext/census/tracing.h"
#include <grpc/census.h>
#include <stdlib.h>
/* TODO(aveitch): These are all placeholder implementations. */
int census_trace_mask(const census_context *context) {
abort();
return CENSUS_TRACE_MASK_NONE;
}
void census_set_trace_mask(int trace_mask) {}
void census_set_trace_mask(int trace_mask) { abort(); }
void census_trace_print(census_context *context, uint32_t type,
const char *buffer, size_t n) {}
const char *buffer, size_t n) {
abort();
}

@ -48,9 +48,6 @@ struct grpc_connector {
typedef struct {
/** set of pollsets interested in this connection */
grpc_pollset_set *interested_parties;
/** address to connect to */
const grpc_resolved_address *addr;
size_t addr_len;
/** initial connect string to send */
grpc_slice initial_connect_string;
/** deadline for connection */

@ -60,7 +60,9 @@ void grpc_register_resolver_type(grpc_resolver_factory *factory);
return it.
If a resolver factory was not found, return NULL.
\a args is a set of channel arguments to be included in the result
(typically the set of arguments passed in from the client API). */
(typically the set of arguments passed in from the client API).
\a pollset_set is used to drive IO in the name resolution process, it
should not be NULL. */
grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_args *args,
grpc_pollset_set *pollset_set);

@ -38,12 +38,16 @@
#include <grpc/support/alloc.h>
#include <grpc/support/avl.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/initial_connect_string.h"
#include "src/core/ext/client_channel/parse_address.h"
#include "src/core/ext/client_channel/subchannel_index.h"
#include "src/core/ext/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
@ -95,8 +99,6 @@ struct grpc_subchannel {
size_t num_filters;
/** channel arguments */
grpc_channel_args *args;
/** address to connect to */
grpc_resolved_address *addr;
grpc_subchannel_key *key;
@ -211,7 +213,6 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel *c = arg;
gpr_free((void *)c->filters);
grpc_channel_args_destroy(exec_ctx, c->args);
gpr_free(c->addr);
grpc_slice_unref_internal(exec_ctx, c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
@ -327,12 +328,17 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
} else {
c->filters = NULL;
}
c->addr = gpr_malloc(sizeof(grpc_resolved_address));
if (args->addr->len)
memcpy(c->addr, args->addr, sizeof(grpc_resolved_address));
c->pollset_set = grpc_pollset_set_create();
grpc_set_initial_connect_string(&c->addr, &c->initial_connect_string);
c->args = grpc_channel_args_copy(args->args);
grpc_resolved_address *addr = gpr_malloc(sizeof(*addr));
grpc_get_subchannel_address_arg(args->args, addr);
grpc_set_initial_connect_string(&addr, &c->initial_connect_string);
static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS};
grpc_arg new_arg = grpc_create_subchannel_address_arg(addr);
gpr_free(addr);
c->args = grpc_channel_args_copy_and_add_and_remove(
args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &new_arg, 1);
gpr_free(new_arg.value.string);
c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
&c->root_external_state_watcher;
grpc_closure_init(&c->connected, subchannel_connected, c,
@ -385,7 +391,6 @@ static void continue_connect_locked(grpc_exec_ctx *exec_ctx,
grpc_connect_in_args args;
args.interested_parties = c->pollset_set;
args.addr = c->addr;
args.deadline = c->next_attempt;
args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string;
@ -771,3 +776,37 @@ grpc_call_stack *grpc_subchannel_call_get_call_stack(
grpc_subchannel_call *subchannel_call) {
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
}
static void grpc_uri_to_sockaddr(char *uri_str, grpc_resolved_address *addr) {
grpc_uri *uri = grpc_uri_parse(uri_str, 0 /* suppress_errors */);
GPR_ASSERT(uri != NULL);
if (strcmp(uri->scheme, "ipv4") == 0) {
GPR_ASSERT(parse_ipv4(uri, addr));
} else if (strcmp(uri->scheme, "ipv6") == 0) {
GPR_ASSERT(parse_ipv6(uri, addr));
} else {
GPR_ASSERT(parse_unix(uri, addr));
}
grpc_uri_destroy(uri);
}
void grpc_get_subchannel_address_arg(const grpc_channel_args *args,
grpc_resolved_address *addr) {
const grpc_arg *addr_arg =
grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS);
GPR_ASSERT(addr_arg != NULL); // Should have been set by LB policy.
GPR_ASSERT(addr_arg->type == GRPC_ARG_STRING);
memset(addr, 0, sizeof(*addr));
if (*addr_arg->value.string != '\0') {
grpc_uri_to_sockaddr(addr_arg->value.string, addr);
}
}
grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr) {
grpc_arg new_arg;
new_arg.key = GRPC_ARG_SUBCHANNEL_ADDRESS;
new_arg.type = GRPC_ARG_STRING;
new_arg.value.string =
addr->len > 0 ? grpc_sockaddr_to_uri(addr) : gpr_strdup("");
return new_arg;
}

@ -40,6 +40,9 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
// Channel arg containing a grpc_resolved_address to connect to.
#define GRPC_ARG_SUBCHANNEL_ADDRESS "grpc.subchannel_address"
/** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */
typedef struct grpc_subchannel grpc_subchannel;
@ -164,8 +167,6 @@ struct grpc_subchannel_args {
size_t filter_count;
/** Channel arguments to be supplied to the newly created channel */
const grpc_channel_args *args;
/** Address to connect to */
grpc_resolved_address *addr;
};
/** create a subchannel given a connector */
@ -173,4 +174,12 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
grpc_connector *connector,
const grpc_subchannel_args *args);
/// Sets \a addr from \a args.
void grpc_get_subchannel_address_arg(const grpc_channel_args *args,
grpc_resolved_address *addr);
/// Returns a new channel arg encoding the subchannel address as a string.
/// Caller is responsible for freeing the string.
grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr);
#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H */

@ -86,11 +86,6 @@ static grpc_subchannel_key *create_key(
} else {
k->args.filters = NULL;
}
k->args.addr = gpr_malloc(sizeof(grpc_resolved_address));
k->args.addr->len = args->addr->len;
if (k->args.addr->len > 0) {
memcpy(k->args.addr, args->addr, sizeof(grpc_resolved_address));
}
k->args.args = copy_channel_args(args->args);
return k;
}
@ -108,14 +103,8 @@ static int subchannel_key_compare(grpc_subchannel_key *a,
grpc_subchannel_key *b) {
int c = GPR_ICMP(a->connector, b->connector);
if (c != 0) return c;
c = GPR_ICMP(a->args.addr->len, b->args.addr->len);
if (c != 0) return c;
c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
if (c != 0) return c;
if (a->args.addr->len) {
c = memcmp(a->args.addr->addr, b->args.addr->addr, a->args.addr->len);
if (c != 0) return c;
}
if (a->args.filter_count > 0) {
c = memcmp(a->args.filters, b->args.filters,
a->args.filter_count * sizeof(*a->args.filters));
@ -129,7 +118,6 @@ void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
grpc_connector_unref(exec_ctx, k->connector);
gpr_free((grpc_channel_args *)k->args.filters);
grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)k->args.args);
gpr_free(k->args.addr);
gpr_free(k);
}

@ -36,7 +36,9 @@
#include <grpc/support/alloc.h>
#include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/transport/connectivity_state.h"
typedef struct pending_pick {
@ -466,11 +468,15 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
}
memset(&sc_args, 0, sizeof(grpc_subchannel_args));
sc_args.addr = &addresses->addresses[i].address;
sc_args.args = args->args;
grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args =
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
gpr_free(addr_arg.value.string);
sc_args.args = new_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
grpc_channel_args_destroy(exec_ctx, new_args);
if (subchannel != NULL) {
p->subchannels[subchannel_idx++] = subchannel;

@ -64,8 +64,10 @@
#include <grpc/support/alloc.h>
#include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/static_metadata.h"
@ -729,11 +731,15 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
if (addresses->addresses[i].is_balancer) continue;
memset(&sc_args, 0, sizeof(grpc_subchannel_args));
sc_args.addr = &addresses->addresses[i].address;
sc_args.args = args->args;
grpc_arg addr_arg =
grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
grpc_channel_args *new_args =
grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
gpr_free(addr_arg.value.string);
sc_args.args = new_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
grpc_channel_args_destroy(exec_ctx, new_args);
if (subchannel != NULL) {
subchannel_data *sd = gpr_malloc(sizeof(*sd));

@ -43,6 +43,7 @@
#include "src/core/ext/client_channel/connector.h"
#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/subchannel.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
@ -220,6 +221,8 @@ static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx,
grpc_connect_out_args *result,
grpc_closure *notify) {
chttp2_connector *c = (chttp2_connector *)con;
grpc_resolved_address addr;
grpc_get_subchannel_address_arg(args->channel_args, &addr);
gpr_mu_lock(&c->mu);
GPR_ASSERT(c->notify == NULL);
c->notify = notify;
@ -231,8 +234,8 @@ static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(!c->connecting);
c->connecting = true;
grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint,
args->interested_parties, args->channel_args,
args->addr, args->deadline);
args->interested_parties, args->channel_args, &addr,
args->deadline);
gpr_mu_unlock(&c->mu);
}

@ -62,7 +62,7 @@
#define DEFAULT_WINDOW 65535
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define MAX_CLIENT_STREAM_ID 0x7fffffffu
@ -271,6 +271,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
window -- this should by rights be 0 */
t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
t->sent_local_settings = 0;
t->write_buffer_size = DEFAULT_WINDOW;
if (is_client) {
grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
@ -321,6 +322,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_hpack_compressor_set_max_usable_size(&t->hpack_compressor,
(uint32_t)value);
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
&channel_args->args[i],
(grpc_integer_options){0, 0, MAX_WRITE_BUFFER_SIZE});
} else {
static const struct {
const char *channel_arg_name;
@ -899,15 +905,22 @@ static bool contains_non_ok_status(grpc_metadata_batch *batch) {
return false;
}
static void maybe_become_writable_due_to_send_msg(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
if (s->id != 0 && (!s->write_buffering ||
s->flow_controlled_buffer.length > t->write_buffer_size)) {
grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
}
}
static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
s->fetched_send_message_length +=
(uint32_t)GRPC_SLICE_LENGTH(s->fetching_slice);
grpc_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
if (s->id != 0) {
grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
}
maybe_become_writable_due_to_send_msg(exec_ctx, t, s);
}
static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx,
@ -1100,14 +1113,13 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
(int64_t)len;
s->complete_fetch_covered_by_poller = op->covered_by_poller;
if (flags & GRPC_WRITE_BUFFER_HINT) {
/* allow up to 64kb to be buffered */
/* TODO(ctiller): make this configurable */
s->next_message_end_offset -= 65536;
s->next_message_end_offset -= t->write_buffer_size;
s->write_buffering = true;
} else {
s->write_buffering = false;
}
continue_fetching_send_locked(exec_ctx, t, s);
if (s->id != 0) {
grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
}
maybe_become_writable_due_to_send_msg(exec_ctx, t, s);
}
}
@ -1116,6 +1128,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->send_trailing_metadata_finished = add_closure_barrier(on_complete);
s->send_trailing_metadata = op->send_trailing_metadata;
s->write_buffering = false;
const size_t metadata_size =
grpc_metadata_batch_size(op->send_trailing_metadata);
const size_t metadata_peer_limit =

@ -249,6 +249,9 @@ struct grpc_chttp2_transport {
int64_t announce_incoming_window;
/** how much window would we like to have for incoming_window */
uint32_t connection_window_target;
/** how much data are we willing to buffer when the WRITE_BUFFER_HINT is set?
*/
uint32_t write_buffer_size;
/** have we seen a goaway */
uint8_t seen_goaway;
@ -403,6 +406,9 @@ struct grpc_chttp2_stream {
/** Has this stream seen an error.
If true, then pending incoming frames can be thrown away. */
bool seen_error;
/** Are we buffering writes on this stream? If yes, we won't become writable
until there's enough queued up in the flow_controlled_buffer */
bool write_buffering;
/** the error that resulted in this stream being read-closed */
grpc_error *read_closed_error;

@ -60,7 +60,7 @@ GRPCAPI grpc_channel *grpc_cronet_secure_channel_create(
ct->host = gpr_malloc(strlen(target) + 1);
strcpy(ct->host, target);
gpr_log(GPR_DEBUG,
"grpc_create_cronet_transport: cronet_engine = %p, target=%s", engine,
"grpc_create_cronet_transport: stream_engine = %p, target=%s", engine,
ct->host);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;

@ -38,46 +38,45 @@ library, so we can build it in all environments */
#include <grpc/support/log.h>
#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
#include "third_party/Cronet/bidirectional_stream_c.h"
#ifdef GRPC_COMPILE_WITH_CRONET
/* link with the real CRONET library in the build system */
#else
/* Dummy implementation of cronet API just to test for build-ability */
cronet_bidirectional_stream* cronet_bidirectional_stream_create(
cronet_engine* engine, void* annotation,
cronet_bidirectional_stream_callback* callback) {
bidirectional_stream* bidirectional_stream_create(
stream_engine* engine, void* annotation,
bidirectional_stream_callback* callback) {
GPR_ASSERT(0);
return NULL;
}
int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream) {
int bidirectional_stream_destroy(bidirectional_stream* stream) {
GPR_ASSERT(0);
return 0;
}
int cronet_bidirectional_stream_start(
cronet_bidirectional_stream* stream, const char* url, int priority,
const char* method, const cronet_bidirectional_stream_header_array* headers,
bool end_of_stream) {
int bidirectional_stream_start(bidirectional_stream* stream, const char* url,
int priority, const char* method,
const bidirectional_stream_header_array* headers,
bool end_of_stream) {
GPR_ASSERT(0);
return 0;
}
int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream,
char* buffer, int capacity) {
int bidirectional_stream_read(bidirectional_stream* stream, char* buffer,
int capacity) {
GPR_ASSERT(0);
return 0;
}
int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream,
const char* buffer, int count,
bool end_of_stream) {
int bidirectional_stream_write(bidirectional_stream* stream, const char* buffer,
int count, bool end_of_stream) {
GPR_ASSERT(0);
return 0;
}
void cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream) {
void bidirectional_stream_cancel(bidirectional_stream* stream) {
GPR_ASSERT(0);
}

@ -49,7 +49,7 @@
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
#include "third_party/Cronet/bidirectional_stream_c.h"
#define GRPC_HEADER_SIZE_IN_BYTES 5
@ -86,19 +86,18 @@ enum e_op_id {
/* Cronet callbacks. See cronet_c_for_grpc.h for documentation for each. */
static void on_stream_ready(cronet_bidirectional_stream *);
static void on_stream_ready(bidirectional_stream *);
static void on_response_headers_received(
cronet_bidirectional_stream *,
const cronet_bidirectional_stream_header_array *, const char *);
static void on_write_completed(cronet_bidirectional_stream *, const char *);
static void on_read_completed(cronet_bidirectional_stream *, char *, int);
bidirectional_stream *, const bidirectional_stream_header_array *,
const char *);
static void on_write_completed(bidirectional_stream *, const char *);
static void on_read_completed(bidirectional_stream *, char *, int);
static void on_response_trailers_received(
cronet_bidirectional_stream *,
const cronet_bidirectional_stream_header_array *);
static void on_succeeded(cronet_bidirectional_stream *);
static void on_failed(cronet_bidirectional_stream *, int);
static void on_canceled(cronet_bidirectional_stream *);
static cronet_bidirectional_stream_callback cronet_callbacks = {
bidirectional_stream *, const bidirectional_stream_header_array *);
static void on_succeeded(bidirectional_stream *);
static void on_failed(bidirectional_stream *, int);
static void on_canceled(bidirectional_stream *);
static bidirectional_stream_callback cronet_callbacks = {
on_stream_ready,
on_response_headers_received,
on_read_completed,
@ -111,7 +110,7 @@ static cronet_bidirectional_stream_callback cronet_callbacks = {
/* Cronet transport object */
struct grpc_cronet_transport {
grpc_transport base; /* must be first element in this structure */
cronet_engine *engine;
stream_engine *engine;
char *host;
};
typedef struct grpc_cronet_transport grpc_cronet_transport;
@ -181,8 +180,8 @@ struct stream_obj {
grpc_transport_stream_op *curr_op;
grpc_cronet_transport curr_ct;
grpc_stream *curr_gs;
cronet_bidirectional_stream *cbs;
cronet_bidirectional_stream_header_array header_array;
bidirectional_stream *cbs;
bidirectional_stream_header_array header_array;
/* Stream level state. Some state will be tracked both at stream and stream_op
* level */
@ -352,11 +351,11 @@ static void execute_from_storage(stream_obj *s) {
/*
Cronet callback
*/
static void on_failed(cronet_bidirectional_stream *stream, int net_error) {
static void on_failed(bidirectional_stream *stream, int net_error) {
CRONET_LOG(GPR_DEBUG, "on_failed(%p, %d)", stream, net_error);
stream_obj *s = (stream_obj *)stream->annotation;
gpr_mu_lock(&s->mu);
cronet_bidirectional_stream_destroy(s->cbs);
bidirectional_stream_destroy(s->cbs);
s->state.state_callback_received[OP_FAILED] = true;
s->cbs = NULL;
if (s->header_array.headers) {
@ -375,11 +374,11 @@ static void on_failed(cronet_bidirectional_stream *stream, int net_error) {
/*
Cronet callback
*/
static void on_canceled(cronet_bidirectional_stream *stream) {
static void on_canceled(bidirectional_stream *stream) {
CRONET_LOG(GPR_DEBUG, "on_canceled(%p)", stream);
stream_obj *s = (stream_obj *)stream->annotation;
gpr_mu_lock(&s->mu);
cronet_bidirectional_stream_destroy(s->cbs);
bidirectional_stream_destroy(s->cbs);
s->state.state_callback_received[OP_CANCELED] = true;
s->cbs = NULL;
if (s->header_array.headers) {
@ -398,11 +397,11 @@ static void on_canceled(cronet_bidirectional_stream *stream) {
/*
Cronet callback
*/
static void on_succeeded(cronet_bidirectional_stream *stream) {
static void on_succeeded(bidirectional_stream *stream) {
CRONET_LOG(GPR_DEBUG, "on_succeeded(%p)", stream);
stream_obj *s = (stream_obj *)stream->annotation;
gpr_mu_lock(&s->mu);
cronet_bidirectional_stream_destroy(s->cbs);
bidirectional_stream_destroy(s->cbs);
s->state.state_callback_received[OP_SUCCEEDED] = true;
s->cbs = NULL;
free_read_buffer(s);
@ -413,7 +412,7 @@ static void on_succeeded(cronet_bidirectional_stream *stream) {
/*
Cronet callback
*/
static void on_stream_ready(cronet_bidirectional_stream *stream) {
static void on_stream_ready(bidirectional_stream *stream) {
CRONET_LOG(GPR_DEBUG, "W: on_stream_ready(%p)", stream);
stream_obj *s = (stream_obj *)stream->annotation;
gpr_mu_lock(&s->mu);
@ -429,7 +428,7 @@ static void on_stream_ready(cronet_bidirectional_stream *stream) {
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
if (s->state.flush_cronet_when_ready) {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_flush (%p)", s->cbs);
cronet_bidirectional_stream_flush(stream);
bidirectional_stream_flush(stream);
}
#endif
gpr_mu_unlock(&s->mu);
@ -440,8 +439,8 @@ static void on_stream_ready(cronet_bidirectional_stream *stream) {
Cronet callback
*/
static void on_response_headers_received(
cronet_bidirectional_stream *stream,
const cronet_bidirectional_stream_header_array *headers,
bidirectional_stream *stream,
const bidirectional_stream_header_array *headers,
const char *negotiated_protocol) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
@ -467,9 +466,9 @@ static void on_response_headers_received(
s->state.rs.read_buffer = s->state.rs.grpc_header_bytes;
s->state.rs.received_bytes = 0;
s->state.rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
cronet_bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
s->state.rs.remaining_bytes);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
s->state.rs.remaining_bytes);
}
gpr_mu_unlock(&s->mu);
grpc_exec_ctx_finish(&exec_ctx);
@ -479,8 +478,7 @@ static void on_response_headers_received(
/*
Cronet callback
*/
static void on_write_completed(cronet_bidirectional_stream *stream,
const char *data) {
static void on_write_completed(bidirectional_stream *stream, const char *data) {
stream_obj *s = (stream_obj *)stream->annotation;
CRONET_LOG(GPR_DEBUG, "W: on_write_completed(%p, %s)", stream, data);
gpr_mu_lock(&s->mu);
@ -496,7 +494,7 @@ static void on_write_completed(cronet_bidirectional_stream *stream,
/*
Cronet callback
*/
static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
static void on_read_completed(bidirectional_stream *stream, char *data,
int count) {
stream_obj *s = (stream_obj *)stream->annotation;
CRONET_LOG(GPR_DEBUG, "R: on_read_completed(%p, %p, %d)", stream, data,
@ -504,16 +502,16 @@ static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
gpr_mu_lock(&s->mu);
s->state.state_callback_received[OP_RECV_MESSAGE] = true;
if (count > 0 && s->state.flush_read) {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
cronet_bidirectional_stream_read(s->cbs, s->state.rs.read_buffer, 4096);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, s->state.rs.read_buffer, 4096);
gpr_mu_unlock(&s->mu);
} else if (count > 0) {
s->state.rs.received_bytes += count;
s->state.rs.remaining_bytes -= count;
if (s->state.rs.remaining_bytes > 0) {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
s->state.state_op_done[OP_READ_REQ_MADE] = true;
cronet_bidirectional_stream_read(
bidirectional_stream_read(
s->cbs, s->state.rs.read_buffer + s->state.rs.received_bytes,
s->state.rs.remaining_bytes);
gpr_mu_unlock(&s->mu);
@ -536,8 +534,8 @@ static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
Cronet callback
*/
static void on_response_trailers_received(
cronet_bidirectional_stream *stream,
const cronet_bidirectional_stream_header_array *trailers) {
bidirectional_stream *stream,
const bidirectional_stream_header_array *trailers) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
CRONET_LOG(GPR_DEBUG, "R: on_response_trailers_received(%p,%p)", stream,
trailers);
@ -567,12 +565,12 @@ static void on_response_trailers_received(
if (!s->state.state_op_done[OP_SEND_TRAILING_METADATA] &&
!(s->state.state_op_done[OP_CANCEL_ERROR] ||
s->state.state_callback_received[OP_FAILED])) {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, 0)", s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, 0)", s->cbs);
s->state.state_callback_received[OP_SEND_MESSAGE] = false;
cronet_bidirectional_stream_write(s->cbs, "", 0, true);
bidirectional_stream_write(s->cbs, "", 0, true);
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_flush (%p)", s->cbs);
cronet_bidirectional_stream_flush(s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_flush (%p)", s->cbs);
bidirectional_stream_flush(s->cbs);
#endif
s->state.state_op_done[OP_SEND_TRAILING_METADATA] = true;
@ -614,7 +612,7 @@ static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer,
*/
static void convert_metadata_to_cronet_headers(
grpc_linked_mdelem *head, const char *host, char **pp_url,
cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers,
bidirectional_stream_header **pp_headers, size_t *p_num_headers,
const char **method) {
grpc_linked_mdelem *curr = head;
/* Walk the linked list and get number of header fields */
@ -625,9 +623,9 @@ static void convert_metadata_to_cronet_headers(
}
/* Allocate enough memory. It is freed in the on_stream_ready callback
*/
cronet_bidirectional_stream_header *headers =
(cronet_bidirectional_stream_header *)gpr_malloc(
sizeof(cronet_bidirectional_stream_header) * num_headers_available);
bidirectional_stream_header *headers =
(bidirectional_stream_header *)gpr_malloc(
sizeof(bidirectional_stream_header) * num_headers_available);
*pp_headers = headers;
/* Walk the linked list again, this time copying the header fields.
@ -857,12 +855,12 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
* on_failed */
GPR_ASSERT(s->cbs == NULL);
GPR_ASSERT(!stream_state->state_op_done[OP_SEND_INITIAL_METADATA]);
s->cbs = cronet_bidirectional_stream_create(s->curr_ct.engine, s->curr_gs,
&cronet_callbacks);
CRONET_LOG(GPR_DEBUG, "%p = cronet_bidirectional_stream_create()", s->cbs);
s->cbs = bidirectional_stream_create(s->curr_ct.engine, s->curr_gs,
&cronet_callbacks);
CRONET_LOG(GPR_DEBUG, "%p = bidirectional_stream_create()", s->cbs);
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
cronet_bidirectional_stream_disable_auto_flush(s->cbs, true);
cronet_bidirectional_stream_delay_request_headers_until_flush(s->cbs, true);
bidirectional_stream_disable_auto_flush(s->cbs, true);
bidirectional_stream_delay_request_headers_until_flush(s->cbs, true);
#endif
char *url = NULL;
const char *method = "POST";
@ -871,10 +869,8 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_op->send_initial_metadata->list.head, s->curr_ct.host, &url,
&s->header_array.headers, &s->header_array.count, &method);
s->header_array.capacity = s->header_array.count;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_start(%p, %s)", s->cbs,
url);
cronet_bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array,
false);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_start(%p, %s)", s->cbs, url);
bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array, false);
stream_state->state_op_done[OP_SEND_INITIAL_METADATA] = true;
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
if (!stream_op->send_message && !stream_op->send_trailing_metadata) {
@ -912,16 +908,16 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
size_t write_buffer_size;
create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
&write_buffer_size);
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, %p)",
s->cbs, stream_state->ws.write_buffer);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs,
stream_state->ws.write_buffer);
stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
cronet_bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
(int)write_buffer_size, false);
bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
(int)write_buffer_size, false);
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
if (!stream_op->send_trailing_metadata) {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_flush (%p)",
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_flush (%p)",
s->cbs);
cronet_bidirectional_stream_flush(s->cbs);
bidirectional_stream_flush(s->cbs);
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
stream_state->pending_write_for_trailer = true;
@ -944,13 +940,13 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
result = NO_ACTION_POSSIBLE;
CRONET_LOG(GPR_DEBUG, "Stream is either cancelled or failed.");
} else {
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, 0)",
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, 0)",
s->cbs);
stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
cronet_bidirectional_stream_write(s->cbs, "", 0, true);
bidirectional_stream_write(s->cbs, "", 0, true);
#ifdef GRPC_CRONET_WITH_PACKET_COALESCING
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_flush (%p)", s->cbs);
cronet_bidirectional_stream_flush(s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_flush (%p)", s->cbs);
bidirectional_stream_flush(s->cbs);
#endif
result = ACTION_TAKEN_WITH_CALLBACK;
}
@ -981,14 +977,13 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
CRONET_LOG(GPR_DEBUG, "Stream is cancelled.");
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
GRPC_ERROR_CANCELLED);
GRPC_ERROR_NONE);
stream_state->state_op_done[OP_RECV_MESSAGE] = true;
result = ACTION_TAKEN_NO_CALLBACK;
} else if (stream_state->state_callback_received[OP_FAILED]) {
CRONET_LOG(GPR_DEBUG, "Stream failed.");
grpc_closure_sched(
exec_ctx, stream_op->recv_message_ready,
make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."));
grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
GRPC_ERROR_NONE);
stream_state->state_op_done[OP_RECV_MESSAGE] = true;
result = ACTION_TAKEN_NO_CALLBACK;
} else if (stream_state->rs.read_stream_closed == true) {
@ -1014,11 +1009,11 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(stream_state->rs.read_buffer);
stream_state->rs.remaining_bytes = stream_state->rs.length_field;
stream_state->rs.received_bytes = 0;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */
cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
stream_state->rs.remaining_bytes = 0;
@ -1037,10 +1032,10 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */
cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
result = ACTION_TAKEN_NO_CALLBACK;
}
@ -1049,11 +1044,11 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.received_bytes = 0;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
stream_state->state_op_done[OP_READ_REQ_MADE] =
true; /* Indicates that at least one read request has been made */
cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
result = NO_ACTION_POSSIBLE;
@ -1083,9 +1078,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
stream_state->rs.received_bytes = 0;
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
stream_state->rs.length_field_received = false;
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
stream_state->rs.remaining_bytes);
result = ACTION_TAKEN_NO_CALLBACK;
}
} else if (stream_op->recv_trailing_metadata &&
@ -1104,9 +1099,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
op_can_be_run(stream_op, stream_state, &oas->state,
OP_CANCEL_ERROR)) {
CRONET_LOG(GPR_DEBUG, "running: %p OP_CANCEL_ERROR", oas);
CRONET_LOG(GPR_DEBUG, "W: cronet_bidirectional_stream_cancel(%p)", s->cbs);
CRONET_LOG(GPR_DEBUG, "W: bidirectional_stream_cancel(%p)", s->cbs);
if (s->cbs) {
cronet_bidirectional_stream_cancel(s->cbs);
bidirectional_stream_cancel(s->cbs);
result = ACTION_TAKEN_WITH_CALLBACK;
} else {
result = ACTION_TAKEN_NO_CALLBACK;
@ -1207,18 +1202,17 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
header_has_authority(op->send_initial_metadata->list.head)) {
/* Cronet does not support :authority header field. We cancel the call when
this field is present in metadata */
cronet_bidirectional_stream_header_array header_array;
cronet_bidirectional_stream_header *header;
cronet_bidirectional_stream cbs;
bidirectional_stream_header_array header_array;
bidirectional_stream_header *header;
bidirectional_stream cbs;
CRONET_LOG(GPR_DEBUG,
":authority header is provided but not supported;"
" cancel operations");
/* Notify application that operation is cancelled by forging trailers */
header_array.count = 1;
header_array.capacity = 1;
header_array.headers =
gpr_malloc(sizeof(cronet_bidirectional_stream_header));
header = (cronet_bidirectional_stream_header *)header_array.headers;
header_array.headers = gpr_malloc(sizeof(bidirectional_stream_header));
header = (bidirectional_stream_header *)header_array.headers;
header->key = "grpc-status";
header->value = "1"; /* Return status GRPC_STATUS_CANCELLED */
cbs.annotation = (void *)s;

@ -796,7 +796,7 @@ static polling_island *polling_island_merge(polling_island *p,
gpr_atm_rel_store(&p->merged_to, (gpr_atm)q);
PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */
workqueue_move_items_to_parent(q);
workqueue_move_items_to_parent(p);
}
/* else if p == q, nothing needs to be done */

@ -413,9 +413,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
const char *reason) {
fd->on_done_closure = on_done;
fd->released = release_fd != NULL;
if (!fd->released) {
shutdown(fd->fd, SHUT_RDWR);
} else {
if (fd->released) {
*release_fd = fd->fd;
}
gpr_mu_lock(&fd->mu);

@ -691,6 +691,11 @@ grpc_resource_user *grpc_resource_user_create(
return resource_user;
}
grpc_resource_quota *grpc_resource_user_quota(
grpc_resource_user *resource_user) {
return resource_user->resource_quota;
}
static void ru_ref_by(grpc_resource_user *resource_user, gpr_atm amount) {
GPR_ASSERT(amount > 0);
GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&resource_user->refs, amount) != 0);

@ -88,6 +88,12 @@ typedef struct grpc_resource_user grpc_resource_user;
grpc_resource_user *grpc_resource_user_create(
grpc_resource_quota *resource_quota, const char *name);
/* Returns a borrowed reference to the underlying resource quota for this
resource user. */
grpc_resource_quota *grpc_resource_user_quota(
grpc_resource_user *resource_user);
void grpc_resource_user_ref(grpc_resource_user *resource_user);
void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user);

@ -143,6 +143,14 @@ void ChannelArguments::SetResourceQuota(
grpc_resource_quota_arg_vtable());
}
void ChannelArguments::SetMaxReceiveMessageSize(int size) {
SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, size);
}
void ChannelArguments::SetMaxSendMessageSize(int size) {
SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, size);
}
void ChannelArguments::SetLoadBalancingPolicyName(
const grpc::string& lb_policy_name) {
SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name);

@ -35,7 +35,7 @@
#include <nan.h>
#include <uv.h>
#include <list>
#include <queue>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
@ -170,7 +170,7 @@ NAN_METHOD(CallCredentials::CreateFromPlugin) {
grpc_metadata_credentials_plugin plugin;
plugin_state *state = new plugin_state;
state->callback = new Nan::Callback(info[0].As<Function>());
state->pending_callbacks = new std::list<plugin_callback_data*>();
state->pending_callbacks = new std::queue<plugin_callback_data*>();
uv_mutex_init(&state->plugin_mutex);
uv_async_init(uv_default_loop(),
&state->plugin_async,
@ -232,13 +232,13 @@ NAN_METHOD(PluginCallback) {
NAUV_WORK_CB(SendPluginCallback) {
Nan::HandleScope scope;
plugin_state *state = reinterpret_cast<plugin_state*>(async->data);
std::list<plugin_callback_data*> callbacks;
std::queue<plugin_callback_data*> callbacks;
uv_mutex_lock(&state->plugin_mutex);
callbacks.splice(callbacks.begin(), *state->pending_callbacks);
state->pending_callbacks->swap(callbacks);
uv_mutex_unlock(&state->plugin_mutex);
while (!callbacks.empty()) {
plugin_callback_data *data = callbacks.front();
callbacks.pop_front();
callbacks.pop();
Local<Object> callback_data = Nan::New<Object>();
Nan::Set(callback_data, Nan::New("cb").ToLocalChecked(),
Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
@ -267,7 +267,7 @@ void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
data->user_data = user_data;
uv_mutex_lock(&p_state->plugin_mutex);
p_state->pending_callbacks->push_back(data);
p_state->pending_callbacks->push(data);
uv_mutex_unlock(&p_state->plugin_mutex);
uv_async_send(&p_state->plugin_async);

@ -34,7 +34,7 @@
#ifndef GRPC_NODE_CALL_CREDENTIALS_H_
#define GRPC_NODE_CALL_CREDENTIALS_H_
#include <list>
#include <queue>
#include <node.h>
#include <nan.h>
@ -84,7 +84,7 @@ typedef struct plugin_callback_data {
typedef struct plugin_state {
Nan::Callback *callback;
std::list<plugin_callback_data*> *pending_callbacks;
std::queue<plugin_callback_data*> *pending_callbacks;
uv_mutex_t plugin_mutex;
// async.data == this
uv_async_t plugin_async;

@ -31,7 +31,7 @@
*
*/
#include <list>
#include <queue>
#include <node.h>
#include <nan.h>
@ -74,7 +74,7 @@ typedef struct log_args {
typedef struct logger_state {
Nan::Callback *callback;
std::list<log_args *> *pending_args;
std::queue<log_args *> *pending_args;
uv_mutex_t mutex;
uv_async_t async;
// Indicates that a logger has been set
@ -342,14 +342,14 @@ NAN_METHOD(SetDefaultRootsPem) {
NAUV_WORK_CB(LogMessagesCallback) {
Nan::HandleScope scope;
std::list<log_args *> args;
std::queue<log_args *> args;
uv_mutex_lock(&grpc_logger_state.mutex);
args.splice(args.begin(), *grpc_logger_state.pending_args);
grpc_logger_state.pending_args->swap(args);
uv_mutex_unlock(&grpc_logger_state.mutex);
/* Call the callback with each log message */
while (!args.empty()) {
log_args *arg = args.front();
args.pop_front();
args.pop();
Local<Value> file = Nan::New(arg->core_args.file).ToLocalChecked();
Local<Value> line = Nan::New<Uint32, uint32_t>(arg->core_args.line);
Local<Value> severity = Nan::New(
@ -376,7 +376,7 @@ void node_log_func(gpr_log_func_args *args) {
args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME);
uv_mutex_lock(&grpc_logger_state.mutex);
grpc_logger_state.pending_args->push_back(args_copy);
grpc_logger_state.pending_args->push(args_copy);
uv_mutex_unlock(&grpc_logger_state.mutex);
uv_async_send(&grpc_logger_state.async);
@ -384,7 +384,7 @@ void node_log_func(gpr_log_func_args *args) {
void init_logger() {
memset(&grpc_logger_state, 0, sizeof(logger_state));
grpc_logger_state.pending_args = new std::list<log_args *>();
grpc_logger_state.pending_args = new std::queue<log_args *>();
uv_mutex_init(&grpc_logger_state.mutex);
uv_async_init(uv_default_loop(),
&grpc_logger_state.async,

@ -30,7 +30,8 @@
Pod::Spec.new do |s|
s.name = "CronetFramework"
s.version = "0.0.3"
v = '0.0.4'
s.version = v
s.summary = "Cronet, precompiled and used as a framework."
s.homepage = "http://chromium.org"
s.license = {
@ -69,7 +70,7 @@ Pod::Spec.new do |s|
s.vendored_framework = "Cronet.framework"
s.author = "The Chromium Authors"
s.ios.deployment_target = "8.0"
s.source = { :http => 'https://storage.googleapis.com/grpc-precompiled-binaries/cronet/Cronet.framework.zip' }
s.source = { :http => "https://storage.googleapis.com/grpc-precompiled-binaries/cronet/Cronet.framework-v#{v}.zip"}
s.preserve_paths = "Cronet.framework"
s.public_header_files = "Cronet.framework/Headers/**/*{.h}"
s.source_files = "Cronet.framework/Headers/**/*{.h}"

@ -43,13 +43,13 @@
/**
* This method should be called before issuing the first RPC. It should be
* called only once. Create an instance of Cronet engine in your app elsewhere
* and pass the instance pointer in the cronet_engine parameter. Once set,
* and pass the instance pointer in the stream_engine parameter. Once set,
* all subsequent RPCs will use Cronet transport. The method is not thread
* safe.
*/
+(void)useCronetWithEngine:(cronet_engine *)engine;
+(void)useCronetWithEngine:(stream_engine *)engine;
+(cronet_engine *)cronetEngine;
+(stream_engine *)cronetEngine;
+(BOOL)isUsingCronet;

@ -35,16 +35,16 @@
#ifdef GRPC_COMPILE_WITH_CRONET
static BOOL useCronet = NO;
static cronet_engine *globalCronetEngine;
static stream_engine *globalCronetEngine;
@implementation GRPCCall (Cronet)
+ (void)useCronetWithEngine:(cronet_engine *)engine {
+ (void)useCronetWithEngine:(stream_engine *)engine {
useCronet = YES;
globalCronetEngine = engine;
}
+ (cronet_engine *)cronetEngine {
+ (stream_engine *)cronetEngine {
return globalCronetEngine;
}

@ -108,7 +108,7 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
#ifdef GRPC_COMPILE_WITH_CRONET
- (instancetype)initWithHost:(NSString *)host
cronetEngine:(cronet_engine *)cronetEngine
cronetEngine:(stream_engine *)cronetEngine
channelArgs:(NSDictionary *)channelArgs {
if (!host) {
[NSException raise:NSInvalidArgumentException format:@"host argument missing"];
@ -163,7 +163,7 @@ static grpc_channel_args *BuildChannelArgs(NSDictionary *dictionary) {
#ifdef GRPC_COMPILE_WITH_CRONET
+ (GRPCChannel *)secureCronetChannelWithHost:(NSString *)host
channelArgs:(NSDictionary *)channelArgs {
cronet_engine *engine = [GRPCCall cronetEngine];
stream_engine *engine = [GRPCCall cronetEngine];
if (!engine) {
[NSException raise:NSInvalidArgumentException
format:@"cronet_engine is NULL. Set it first."];

@ -94,7 +94,7 @@ static void process_auth_failure(void *state, grpc_auth_context *ctx,
static void cronet_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args,
cronet_engine *cronetEngine) {
stream_engine *cronetEngine) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr,
client_args, NULL);
@ -124,11 +124,13 @@ static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
static void cronet_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
cronet_engine *cronetEngine = [Cronet getGlobalEngine];
grpc_exec_ctx ctx = GRPC_EXEC_CTX_INIT;
stream_engine *cronetEngine = [Cronet getGlobalEngine];
grpc_channel_args *new_client_args = grpc_channel_args_copy(client_args);
cronet_init_client_secure_fullstack(f, new_client_args, cronetEngine);
grpc_channel_args_destroy(new_client_args);
grpc_channel_args_destroy(&ctx, new_client_args);
grpc_exec_ctx_finish(&ctx);
}
static int fail_server_auth_check(grpc_channel_args *server_args) {

@ -0,0 +1,214 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import <XCTest/XCTest.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <Cronet/Cronet.h>
#import <grpc/support/host_port.h>
#import <grpc/grpc_cronet.h>
#import <grpc/grpc.h>
#import "test/core/end2end/cq_verifier.h"
#import "test/core/util/port.h"
#import <grpc/support/alloc.h>
#import <grpc/support/log.h>
#import "src/core/lib/channel/channel_args.h"
#import "src/core/lib/support/env.h"
#import "src/core/lib/support/string.h"
#import "src/core/lib/support/tmpfile.h"
#import "test/core/util/test_config.h"
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
@interface CronetUnitTests : XCTestCase
@end
@implementation CronetUnitTests
+ (void)setUp {
[super setUp];
/*** FILE *roots_file;
size_t roots_size = strlen(test_root_cert);*/
char *argv[] = {"CoreCronetEnd2EndTests"};
grpc_test_init(1, argv);
grpc_init();
[Cronet setHttp2Enabled:YES];
NSURL *url = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES];
}
+ (void)tearDown {
grpc_shutdown();
[super tearDown];
}
- (void)testInternalError {
grpc_call *c;
grpc_slice request_payload_slice =
grpc_slice_from_copied_string("hello world");
grpc_byte_buffer *request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5);
grpc_metadata meta_c[2] = {
{"key1", "val1", 4, 0, {{NULL, NULL, NULL, NULL}}},
{"key2", "val2", 4, 0, {{NULL, NULL, NULL, NULL}}}};
int port = grpc_pick_unused_port_or_die();
char *addr;
gpr_join_host_port(&addr, "127.0.0.1", port);
grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
cronet_engine *cronetEngine = [Cronet getGlobalEngine];
grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr,
NULL, NULL);
cq_verifier *cqv = cq_verifier_create(cq);
grpc_op ops[6];
grpc_op *op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_byte_buffer *response_payload_recv = NULL;
grpc_call_details call_details;
grpc_status_code status;
grpc_call_error error;
char *details = NULL;
size_t details_capacity = 0;
c = grpc_channel_create_call(
client, NULL, GRPC_PROPAGATE_DEFAULTS, cq, "/foo",
NULL, deadline, NULL);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 2;
op->data.send_initial_metadata.metadata = meta_c;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message = request_payload;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message = &response_payload_recv;
op->flags = 0;
op->reserved = NULL;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->data.recv_status_on_client.status_details_capacity = &details_capacity;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), (void*)1, NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int sl = socket(AF_INET, SOCK_STREAM, 0);
GPR_ASSERT(sl >= 0);
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_port = htons(port);
bind(sl, (struct sockaddr*)&s_addr, sizeof(s_addr));
listen(sl, 5);
int s = accept(sl, NULL, NULL);
sleep(1);
close(s);
close(sl);
});
CQ_EXPECT_COMPLETION(cqv, (void*)1, 1);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
gpr_free(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_destroy(c);
cq_verifier_destroy(cqv);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_channel_destroy(client);
grpc_completion_queue_shutdown(cq);
drain_cq(cq);
grpc_completion_queue_destroy(cq);
}
@end

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -37,13 +37,18 @@ GRPC_LOCAL_SRC = '../../..'
end
end
target 'CoreCronetEnd2EndTests' do
pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
%w(
CoreCronetEnd2EndTests
CronetUnitTests
).each do |target_name|
target target_name do
pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
end
end
# gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
06467F3A8D01EC493D12ADA2 /* libPods-CronetUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */; };
09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */; };
0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */; };
16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; };
@ -15,6 +16,8 @@
3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */; };
5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */; };
5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; };
5EAD6D291E27047400002378 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
5EE84BF41D4717E40050C6CC /* InteropTestsRemoteWithCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */; };
5EE84BF61D4717E40050C6CC /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
5EE84BFE1D471D400050C6CC /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
@ -52,6 +55,13 @@
remoteGlobalIDString = 635697C61B14FC11007A7283;
remoteInfo = Tests;
};
5EAD6D2A1E27047400002378 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 635697C61B14FC11007A7283;
remoteInfo = Tests;
};
5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
@ -109,6 +119,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
02192CF1FF9534E3D18C65FC /* Pods-CronetUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.release.xcconfig"; sourceTree = "<group>"; };
060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = "<group>"; };
07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
@ -117,6 +128,7 @@
17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = "<group>"; };
20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
386712AEACF7C2190C4B8B3F /* Pods-CronetUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.cronet.xcconfig"; sourceTree = "<group>"; };
3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.release.xcconfig"; sourceTree = "<group>"; };
3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; sourceTree = "<group>"; };
4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.release.xcconfig"; sourceTree = "<group>"; };
@ -127,6 +139,9 @@
5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreCronetEnd2EndTests.m; sourceTree = "<group>"; };
5EAD6D241E27047400002378 /* CronetUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = "<group>"; };
5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteWithCronet.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemoteWithCronet.m; sourceTree = "<group>"; };
5EE84BF51D4717E40050C6CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -146,6 +161,7 @@
63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = "<group>"; };
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = "<group>"; };
64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.cronet.xcconfig"; sourceTree = "<group>"; };
7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = "<group>"; };
9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteWithCronet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -153,6 +169,7 @@
AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.cronet.xcconfig"; sourceTree = "<group>"; };
AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.release.xcconfig"; sourceTree = "<group>"; };
B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.debug.xcconfig"; sourceTree = "<group>"; };
C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CronetUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AllTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemote.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSL.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -177,6 +194,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
5EAD6D211E27047400002378 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5EAD6D291E27047400002378 /* libTests.a in Frameworks */,
06467F3A8D01EC493D12ADA2 /* libPods-CronetUnitTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5EE84BEE1D4717E40050C6CC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -254,6 +280,7 @@
20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */,
FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */,
9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */,
C6134277D2EB8B380862A03F /* libPods-CronetUnitTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -287,6 +314,9 @@
3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */,
79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */,
F671D4CAD2864FB203B920B4 /* Pods-Tests.cronet.xcconfig */,
64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */,
386712AEACF7C2190C4B8B3F /* Pods-CronetUnitTests.cronet.xcconfig */,
02192CF1FF9534E3D18C65FC /* Pods-CronetUnitTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@ -299,6 +329,15 @@
path = CoreCronetEnd2EndTests;
sourceTree = "<group>";
};
5EAD6D251E27047400002378 /* CronetUnitTests */ = {
isa = PBXGroup;
children = (
5EAD6D261E27047400002378 /* CronetUnitTests.m */,
5EAD6D281E27047400002378 /* Info.plist */,
);
path = CronetUnitTests;
sourceTree = "<group>";
};
5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
isa = PBXGroup;
children = (
@ -315,6 +354,7 @@
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */,
5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
5EAD6D251E27047400002378 /* CronetUnitTests */,
635697C81B14FC11007A7283 /* Products */,
51E4650F34F854F41FF053B3 /* Pods */,
136D535E19727099B941D7B1 /* Frameworks */,
@ -332,6 +372,7 @@
63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */,
5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */,
5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */,
5EAD6D241E27047400002378 /* CronetUnitTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -384,6 +425,27 @@
productReference = 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
5EAD6D231E27047400002378 /* CronetUnitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5EAD6D2F1E27047400002378 /* Build configuration list for PBXNativeTarget "CronetUnitTests" */;
buildPhases = (
80E2DDD2EC04A4009F45E933 /* [CP] Check Pods Manifest.lock */,
5EAD6D201E27047400002378 /* Sources */,
5EAD6D211E27047400002378 /* Frameworks */,
5EAD6D221E27047400002378 /* Resources */,
A686B9967BB4CB81B1CBF8F8 /* [CP] Embed Pods Frameworks */,
051806D6A59B19C8A0B76BED /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
5EAD6D2B1E27047400002378 /* PBXTargetDependency */,
);
name = CronetUnitTests;
productName = CronetUnitTests;
productReference = 5EAD6D241E27047400002378 /* CronetUnitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */;
@ -541,6 +603,9 @@
5E8A5DA31D3840B4000F8BC4 = {
CreatedOnToolsVersion = 7.3.1;
};
5EAD6D231E27047400002378 = {
CreatedOnToolsVersion = 7.3.1;
};
5EE84BF01D4717E40050C6CC = {
CreatedOnToolsVersion = 7.3.1;
};
@ -584,6 +649,7 @@
63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */,
5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
5EAD6D231E27047400002378 /* CronetUnitTests */,
);
};
/* End PBXProject section */
@ -596,6 +662,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
5EAD6D221E27047400002378 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5EE84BEF1D4717E40050C6CC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -643,6 +716,21 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
051806D6A59B19C8A0B76BED /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -670,7 +758,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
4F5690DC0E6AD6663FE78B8B /* [CP] Embed Pods Frameworks */ = {
@ -700,7 +788,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
5F14F59509E10C2852014F9E /* [CP] Embed Pods Frameworks */ = {
@ -760,7 +848,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
796680C7599CB4ED736DD62A /* [CP] Check Pods Manifest.lock */ = {
@ -775,7 +863,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
80E2DDD2EC04A4009F45E933 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
8AD3130D3C58A0FB32FF2A36 /* [CP] Copy Pods Resources */ = {
@ -820,7 +923,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
A441F71824DCB9D0CA297748 /* [CP] Copy Pods Resources */ = {
@ -838,6 +941,21 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
A686B9967BB4CB81B1CBF8F8 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A8E3AC66DF770B774114A30E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -880,7 +998,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */ = {
@ -895,7 +1013,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = {
@ -985,7 +1103,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -999,6 +1117,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
5EAD6D201E27047400002378 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5EE84BED1D4717E40050C6CC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -1073,6 +1199,11 @@
target = 635697C61B14FC11007A7283 /* Tests */;
targetProxy = 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */;
};
5EAD6D2B1E27047400002378 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 635697C61B14FC11007A7283 /* Tests */;
targetProxy = 5EAD6D2A1E27047400002378 /* PBXContainerItemProxy */;
};
5EE84BF81D4717E40050C6CC /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 635697C61B14FC11007A7283 /* Tests */;
@ -1138,6 +1269,53 @@
};
name = Release;
};
5EAD6D2C1E27047400002378 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 64F68A9A6A63CC930DD30A6E /* Pods-CronetUnitTests.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
INFOPLIST_FILE = CronetUnitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
};
name = Debug;
};
5EAD6D2D1E27047400002378 /* Cronet */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 386712AEACF7C2190C4B8B3F /* Pods-CronetUnitTests.cronet.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = CronetUnitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
};
name = Cronet;
};
5EAD6D2E1E27047400002378 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 02192CF1FF9534E3D18C65FC /* Pods-CronetUnitTests.release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = CronetUnitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "\"${PODS_ROOT}/../../../..\" $(inherited)";
};
name = Release;
};
5EC3C7A01D4FC18C000330E2 /* Cronet */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1598,6 +1776,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5EAD6D2F1E27047400002378 /* Build configuration list for PBXNativeTarget "CronetUnitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5EAD6D2C1E27047400002378 /* Debug */,
5EAD6D2D1E27047400002378 /* Cronet */,
5EAD6D2E1E27047400002378 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */ = {
isa = XCConfigurationList;
buildConfigurations = (

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EAD6D231E27047400002378"
BuildableName = "CronetUnitTests.xctest"
BlueprintName = "CronetUnitTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -163,6 +163,13 @@ of this repo. The plugin can be found in the `bins/opt` directory. We are
planning to provide a better way to download and install the plugin
in the future.
You can also just build the gRPC PHP protoc plugin by running:
```sh
$ cd grpc
$ make grpc_php_plugin
```
### Client Stub

@ -1,3 +1,33 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])

@ -1,3 +1,33 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Patches the spawn() command for windows compilers.
Windows has an 8191 character command line limit, but some compilers
@ -45,29 +44,32 @@ MAX_COMMAND_LENGTH = 8191
_classic_spawn = ccompiler.CCompiler.spawn
def _commandfile_spawn(self, command):
command_length = sum([len(arg) for arg in command])
if os.name == 'nt' and command_length > MAX_COMMAND_LENGTH:
# Even if this command doesn't support the @command_file, it will
# fail as is so we try blindly
print('Command line length exceeded, using command file')
print(' '.join(command))
temporary_directory = tempfile.mkdtemp()
command_filename = os.path.abspath(
os.path.join(temporary_directory, 'command'))
with open(command_filename, 'w') as command_file:
escaped_args = ['"' + arg.replace('\\', '\\\\') + '"' for arg in command[1:]]
command_file.write(' '.join(escaped_args))
modified_command = command[:1] + ['@{}'.format(command_filename)]
try:
_classic_spawn(self, modified_command)
finally:
shutil.rmtree(temporary_directory)
else:
_classic_spawn(self, command)
command_length = sum([len(arg) for arg in command])
if os.name == 'nt' and command_length > MAX_COMMAND_LENGTH:
# Even if this command doesn't support the @command_file, it will
# fail as is so we try blindly
print('Command line length exceeded, using command file')
print(' '.join(command))
temporary_directory = tempfile.mkdtemp()
command_filename = os.path.abspath(
os.path.join(temporary_directory, 'command'))
with open(command_filename, 'w') as command_file:
escaped_args = [
'"' + arg.replace('\\', '\\\\') + '"' for arg in command[1:]
]
command_file.write(' '.join(escaped_args))
modified_command = command[:1] + ['@{}'.format(command_filename)]
try:
_classic_spawn(self, modified_command)
finally:
shutil.rmtree(temporary_directory)
else:
_classic_spawn(self, command)
def monkeypatch_spawn():
"""Monkeypatching is dumb, but it's either that or we become maintainers of
"""Monkeypatching is dumb, but it's either that or we become maintainers of
something much, much bigger."""
ccompiler.CCompiler.spawn = _commandfile_spawn
ccompiler.CCompiler.spawn = _commandfile_spawn

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Provides distutils command classes for the GRPC Python setup process."""
import distutils
@ -87,138 +86,144 @@ Glossary
class CommandError(Exception):
"""Simple exception class for GRPC custom commands."""
"""Simple exception class for GRPC custom commands."""
# TODO(atash): Remove this once PyPI has better Linux bdist support. See
# https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
def _get_grpc_custom_bdist(decorated_basename, target_bdist_basename):
"""Returns a string path to a bdist file for Linux to install.
"""Returns a string path to a bdist file for Linux to install.
If we can retrieve a pre-compiled bdist from online, uses it. Else, emits a
warning and builds from source.
"""
# TODO(atash): somehow the name that's returned from `wheel` is different
# between different versions of 'wheel' (but from a compatibility standpoint,
# the names are compatible); we should have some way of determining name
# compatibility in the same way `wheel` does to avoid having to rename all of
# the custom wheels that we build/upload to GCS.
# Break import style to ensure that setup.py has had a chance to install the
# relevant package.
from six.moves.urllib import request
decorated_path = decorated_basename + GRPC_CUSTOM_BDIST_EXT
try:
url = BINARIES_REPOSITORY + '/{target}'.format(target=decorated_path)
bdist_data = request.urlopen(url).read()
except IOError as error:
raise CommandError(
'{}\n\nCould not find the bdist {}: {}'
.format(traceback.format_exc(), decorated_path, error.message))
# Our chosen local bdist path.
bdist_path = target_bdist_basename + GRPC_CUSTOM_BDIST_EXT
try:
with open(bdist_path, 'w') as bdist_file:
bdist_file.write(bdist_data)
except IOError as error:
raise CommandError(
'{}\n\nCould not write grpcio bdist: {}'
.format(traceback.format_exc(), error.message))
return bdist_path
# TODO(atash): somehow the name that's returned from `wheel` is different
# between different versions of 'wheel' (but from a compatibility standpoint,
# the names are compatible); we should have some way of determining name
# compatibility in the same way `wheel` does to avoid having to rename all of
# the custom wheels that we build/upload to GCS.
# Break import style to ensure that setup.py has had a chance to install the
# relevant package.
from six.moves.urllib import request
decorated_path = decorated_basename + GRPC_CUSTOM_BDIST_EXT
try:
url = BINARIES_REPOSITORY + '/{target}'.format(target=decorated_path)
bdist_data = request.urlopen(url).read()
except IOError as error:
raise CommandError('{}\n\nCould not find the bdist {}: {}'.format(
traceback.format_exc(), decorated_path, error.message))
# Our chosen local bdist path.
bdist_path = target_bdist_basename + GRPC_CUSTOM_BDIST_EXT
try:
with open(bdist_path, 'w') as bdist_file:
bdist_file.write(bdist_data)
except IOError as error:
raise CommandError('{}\n\nCould not write grpcio bdist: {}'
.format(traceback.format_exc(), error.message))
return bdist_path
class SphinxDocumentation(setuptools.Command):
"""Command to generate documentation via sphinx."""
description = 'generate sphinx documentation'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# We import here to ensure that setup.py has had a chance to install the
# relevant package eggs first.
import sphinx
import sphinx.apidoc
metadata = self.distribution.metadata
src_dir = os.path.join(PYTHON_STEM, 'grpc')
sys.path.append(src_dir)
sphinx.apidoc.main([
'', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
'-V', metadata.version, '-R', metadata.version,
'-o', os.path.join('doc', 'src'), src_dir])
conf_filepath = os.path.join('doc', 'src', 'conf.py')
with open(conf_filepath, 'a') as conf_file:
conf_file.write(CONF_PY_ADDENDUM)
glossary_filepath = os.path.join('doc', 'src', 'grpc.rst')
with open(glossary_filepath, 'a') as glossary_filepath:
glossary_filepath.write(API_GLOSSARY)
sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])
"""Command to generate documentation via sphinx."""
description = 'generate sphinx documentation'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# We import here to ensure that setup.py has had a chance to install the
# relevant package eggs first.
import sphinx
import sphinx.apidoc
metadata = self.distribution.metadata
src_dir = os.path.join(PYTHON_STEM, 'grpc')
sys.path.append(src_dir)
sphinx.apidoc.main([
'', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
'-V', metadata.version, '-R', metadata.version, '-o',
os.path.join('doc', 'src'), src_dir
])
conf_filepath = os.path.join('doc', 'src', 'conf.py')
with open(conf_filepath, 'a') as conf_file:
conf_file.write(CONF_PY_ADDENDUM)
glossary_filepath = os.path.join('doc', 'src', 'grpc.rst')
with open(glossary_filepath, 'a') as glossary_filepath:
glossary_filepath.write(API_GLOSSARY)
sphinx.main(
['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])
class BuildProjectMetadata(setuptools.Command):
"""Command to generate project metadata in a module."""
"""Command to generate project metadata in a module."""
description = 'build grpcio project metadata files'
user_options = []
description = 'build grpcio project metadata files'
user_options = []
def initialize_options(self):
pass
def initialize_options(self):
pass
def finalize_options(self):
pass
def finalize_options(self):
pass
def run(self):
with open(os.path.join(PYTHON_STEM, 'grpc/_grpcio_metadata.py'), 'w') as module_file:
module_file.write('__version__ = """{}"""'.format(
self.distribution.get_version()))
def run(self):
with open(os.path.join(PYTHON_STEM, 'grpc/_grpcio_metadata.py'),
'w') as module_file:
module_file.write('__version__ = """{}"""'.format(
self.distribution.get_version()))
class BuildPy(build_py.build_py):
"""Custom project build command."""
"""Custom project build command."""
def run(self):
self.run_command('build_project_metadata')
build_py.build_py.run(self)
def run(self):
self.run_command('build_project_metadata')
build_py.build_py.run(self)
def _poison_extensions(extensions, message):
"""Includes a file that will always fail to compile in all extensions."""
poison_filename = os.path.join(PYTHON_STEM, 'poison.c')
with open(poison_filename, 'w') as poison:
poison.write('#error {}'.format(message))
for extension in extensions:
extension.sources = [poison_filename]
"""Includes a file that will always fail to compile in all extensions."""
poison_filename = os.path.join(PYTHON_STEM, 'poison.c')
with open(poison_filename, 'w') as poison:
poison.write('#error {}'.format(message))
for extension in extensions:
extension.sources = [poison_filename]
def check_and_update_cythonization(extensions):
"""Replace .pyx files with their generated counterparts and return whether or
"""Replace .pyx files with their generated counterparts and return whether or
not cythonization still needs to occur."""
for extension in extensions:
generated_pyx_sources = []
other_sources = []
for source in extension.sources:
base, file_ext = os.path.splitext(source)
if file_ext == '.pyx':
generated_pyx_source = next(
(base + gen_ext for gen_ext in ('.c', '.cpp',)
if os.path.isfile(base + gen_ext)), None)
if generated_pyx_source:
generated_pyx_sources.append(generated_pyx_source)
else:
sys.stderr.write('Cython-generated files are missing...\n')
return False
else:
other_sources.append(source)
extension.sources = generated_pyx_sources + other_sources
sys.stderr.write('Found cython-generated files...\n')
return True
for extension in extensions:
generated_pyx_sources = []
other_sources = []
for source in extension.sources:
base, file_ext = os.path.splitext(source)
if file_ext == '.pyx':
generated_pyx_source = next((base + gen_ext
for gen_ext in (
'.c',
'.cpp',)
if os.path.isfile(base + gen_ext)),
None)
if generated_pyx_source:
generated_pyx_sources.append(generated_pyx_source)
else:
sys.stderr.write('Cython-generated files are missing...\n')
return False
else:
other_sources.append(source)
extension.sources = generated_pyx_sources + other_sources
sys.stderr.write('Found cython-generated files...\n')
return True
def try_cythonize(extensions, linetracing=False, mandatory=True):
"""Attempt to cythonize the extensions.
"""Attempt to cythonize the extensions.
Args:
extensions: A list of `distutils.extension.Extension`.
@ -226,78 +231,83 @@ def try_cythonize(extensions, linetracing=False, mandatory=True):
mandatory: Whether or not having Cython-generated files is mandatory. If it
is, extensions will be poisoned when they can't be fully generated.
"""
try:
# Break import style to ensure we have access to Cython post-setup_requires
import Cython.Build
except ImportError:
if mandatory:
sys.stderr.write(
"This package needs to generate C files with Cython but it cannot. "
"Poisoning extension sources to disallow extension commands...")
_poison_extensions(
extensions,
"Extensions have been poisoned due to missing Cython-generated code.")
return extensions
cython_compiler_directives = {}
if linetracing:
additional_define_macros = [('CYTHON_TRACE_NOGIL', '1')]
cython_compiler_directives['linetrace'] = True
return Cython.Build.cythonize(
extensions,
include_path=[
include_dir for extension in extensions for include_dir in extension.include_dirs
] + [CYTHON_STEM],
compiler_directives=cython_compiler_directives
)
try:
# Break import style to ensure we have access to Cython post-setup_requires
import Cython.Build
except ImportError:
if mandatory:
sys.stderr.write(
"This package needs to generate C files with Cython but it cannot. "
"Poisoning extension sources to disallow extension commands...")
_poison_extensions(
extensions,
"Extensions have been poisoned due to missing Cython-generated code."
)
return extensions
cython_compiler_directives = {}
if linetracing:
additional_define_macros = [('CYTHON_TRACE_NOGIL', '1')]
cython_compiler_directives['linetrace'] = True
return Cython.Build.cythonize(
extensions,
include_path=[
include_dir
for extension in extensions
for include_dir in extension.include_dirs
] + [CYTHON_STEM],
compiler_directives=cython_compiler_directives)
class BuildExt(build_ext.build_ext):
"""Custom build_ext command to enable compiler-specific flags."""
C_OPTIONS = {
'unix': ('-pthread', '-std=gnu99'),
'msvc': (),
}
LINK_OPTIONS = {}
def build_extensions(self):
compiler = self.compiler.compiler_type
if compiler in BuildExt.C_OPTIONS:
for extension in self.extensions:
extension.extra_compile_args += list(BuildExt.C_OPTIONS[compiler])
if compiler in BuildExt.LINK_OPTIONS:
for extension in self.extensions:
extension.extra_link_args += list(BuildExt.LINK_OPTIONS[compiler])
if not check_and_update_cythonization(self.extensions):
self.extensions = try_cythonize(self.extensions)
try:
build_ext.build_ext.build_extensions(self)
except Exception as error:
formatted_exception = traceback.format_exc()
support.diagnose_build_ext_error(self, error, formatted_exception)
raise CommandError(
"Failed `build_ext` step:\n{}".format(formatted_exception))
"""Custom build_ext command to enable compiler-specific flags."""
C_OPTIONS = {
'unix': ('-pthread', '-std=gnu99'),
'msvc': (),
}
LINK_OPTIONS = {}
def build_extensions(self):
compiler = self.compiler.compiler_type
if compiler in BuildExt.C_OPTIONS:
for extension in self.extensions:
extension.extra_compile_args += list(
BuildExt.C_OPTIONS[compiler])
if compiler in BuildExt.LINK_OPTIONS:
for extension in self.extensions:
extension.extra_link_args += list(
BuildExt.LINK_OPTIONS[compiler])
if not check_and_update_cythonization(self.extensions):
self.extensions = try_cythonize(self.extensions)
try:
build_ext.build_ext.build_extensions(self)
except Exception as error:
formatted_exception = traceback.format_exc()
support.diagnose_build_ext_error(self, error, formatted_exception)
raise CommandError(
"Failed `build_ext` step:\n{}".format(formatted_exception))
class Gather(setuptools.Command):
"""Command to gather project dependencies."""
description = 'gather dependencies for grpcio'
user_options = [
('test', 't', 'flag indicating to gather test dependencies'),
('install', 'i', 'flag indicating to gather install dependencies')
]
def initialize_options(self):
self.test = False
self.install = False
def finalize_options(self):
# distutils requires this override.
pass
def run(self):
if self.install and self.distribution.install_requires:
self.distribution.fetch_build_eggs(self.distribution.install_requires)
if self.test and self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)
"""Command to gather project dependencies."""
description = 'gather dependencies for grpcio'
user_options = [
('test', 't', 'flag indicating to gather test dependencies'),
('install', 'i', 'flag indicating to gather install dependencies')
]
def initialize_options(self):
self.test = False
self.install = False
def finalize_options(self):
# distutils requires this override.
pass
def run(self):
if self.install and self.distribution.install_requires:
self.distribution.fetch_build_eggs(
self.distribution.install_requires)
if self.test and self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)

File diff suppressed because it is too large Load Diff

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""GRPCAuthMetadataPlugins for standard authentication."""
import inspect
@ -36,51 +35,53 @@ import grpc
def _sign_request(callback, token, error):
metadata = (('authorization', 'Bearer {}'.format(token)),)
callback(metadata, error)
metadata = (('authorization', 'Bearer {}'.format(token)),)
callback(metadata, error)
class GoogleCallCredentials(grpc.AuthMetadataPlugin):
"""Metadata wrapper for GoogleCredentials from the oauth2client library."""
def __init__(self, credentials):
self._credentials = credentials
self._pool = futures.ThreadPoolExecutor(max_workers=1)
# Hack to determine if these are JWT creds and we need to pass
# additional_claims when getting a token
if 'additional_claims' in inspect.getargspec(
credentials.get_access_token).args:
self._is_jwt = True
else:
self._is_jwt = False
def __call__(self, context, callback):
# MetadataPlugins cannot block (see grpc.beta.interfaces.py)
if self._is_jwt:
future = self._pool.submit(self._credentials.get_access_token,
additional_claims={'aud': context.service_url})
else:
future = self._pool.submit(self._credentials.get_access_token)
future.add_done_callback(lambda x: self._get_token_callback(callback, x))
def _get_token_callback(self, callback, future):
try:
access_token = future.result().access_token
except Exception as e:
_sign_request(callback, None, e)
else:
_sign_request(callback, access_token, None)
def __del__(self):
self._pool.shutdown(wait=False)
"""Metadata wrapper for GoogleCredentials from the oauth2client library."""
def __init__(self, credentials):
self._credentials = credentials
self._pool = futures.ThreadPoolExecutor(max_workers=1)
# Hack to determine if these are JWT creds and we need to pass
# additional_claims when getting a token
if 'additional_claims' in inspect.getargspec(
credentials.get_access_token).args:
self._is_jwt = True
else:
self._is_jwt = False
def __call__(self, context, callback):
# MetadataPlugins cannot block (see grpc.beta.interfaces.py)
if self._is_jwt:
future = self._pool.submit(
self._credentials.get_access_token,
additional_claims={'aud': context.service_url})
else:
future = self._pool.submit(self._credentials.get_access_token)
future.add_done_callback(
lambda x: self._get_token_callback(callback, x))
def _get_token_callback(self, callback, future):
try:
access_token = future.result().access_token
except Exception as e:
_sign_request(callback, None, e)
else:
_sign_request(callback, access_token, None)
def __del__(self):
self._pool.shutdown(wait=False)
class AccessTokenCallCredentials(grpc.AuthMetadataPlugin):
"""Metadata wrapper for raw access token credentials."""
"""Metadata wrapper for raw access token credentials."""
def __init__(self, access_token):
self._access_token = access_token
def __init__(self, access_token):
self._access_token = access_token
def __call__(self, context, callback):
_sign_request(callback, self._access_token, None)
def __call__(self, context, callback):
_sign_request(callback, self._access_token, None)

File diff suppressed because it is too large Load Diff

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Shared implementation."""
import logging
@ -45,9 +44,8 @@ CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
cygrpc.ConnectivityState.connecting: grpc.ChannelConnectivity.CONNECTING,
cygrpc.ConnectivityState.ready: grpc.ChannelConnectivity.READY,
cygrpc.ConnectivityState.transient_failure:
grpc.ChannelConnectivity.TRANSIENT_FAILURE,
cygrpc.ConnectivityState.shutdown:
grpc.ChannelConnectivity.SHUTDOWN,
grpc.ChannelConnectivity.TRANSIENT_FAILURE,
cygrpc.ConnectivityState.shutdown: grpc.ChannelConnectivity.SHUTDOWN,
}
CYGRPC_STATUS_CODE_TO_STATUS_CODE = {
@ -77,83 +75,88 @@ STATUS_CODE_TO_CYGRPC_STATUS_CODE = {
def encode(s):
if isinstance(s, bytes):
return s
else:
return s.encode('ascii')
if isinstance(s, bytes):
return s
else:
return s.encode('ascii')
def decode(b):
if isinstance(b, str):
return b
else:
try:
return b.decode('utf8')
except UnicodeDecodeError:
logging.exception('Invalid encoding on {}'.format(b))
return b.decode('latin1')
if isinstance(b, str):
return b
else:
try:
return b.decode('utf8')
except UnicodeDecodeError:
logging.exception('Invalid encoding on {}'.format(b))
return b.decode('latin1')
def channel_args(options):
channel_args = []
for key, value in options:
if isinstance(value, six.string_types):
channel_args.append(cygrpc.ChannelArg(encode(key), encode(value)))
else:
channel_args.append(cygrpc.ChannelArg(encode(key), value))
return cygrpc.ChannelArgs(channel_args)
channel_args = []
for key, value in options:
if isinstance(value, six.string_types):
channel_args.append(cygrpc.ChannelArg(encode(key), encode(value)))
else:
channel_args.append(cygrpc.ChannelArg(encode(key), value))
return cygrpc.ChannelArgs(channel_args)
def cygrpc_metadata(application_metadata):
return _EMPTY_METADATA if application_metadata is None else cygrpc.Metadata(
cygrpc.Metadatum(encode(key), encode(value))
for key, value in application_metadata)
return _EMPTY_METADATA if application_metadata is None else cygrpc.Metadata(
cygrpc.Metadatum(encode(key), encode(value))
for key, value in application_metadata)
def application_metadata(cygrpc_metadata):
if cygrpc_metadata is None:
return ()
else:
return tuple(
(decode(key), value if key[-4:] == b'-bin' else decode(value))
for key, value in cygrpc_metadata)
if cygrpc_metadata is None:
return ()
else:
return tuple((decode(key), value
if key[-4:] == b'-bin' else decode(value))
for key, value in cygrpc_metadata)
def _transform(message, transformer, exception_message):
if transformer is None:
return message
else:
try:
return transformer(message)
except Exception: # pylint: disable=broad-except
logging.exception(exception_message)
return None
if transformer is None:
return message
else:
try:
return transformer(message)
except Exception: # pylint: disable=broad-except
logging.exception(exception_message)
return None
def serialize(message, serializer):
return _transform(message, serializer, 'Exception serializing message!')
return _transform(message, serializer, 'Exception serializing message!')
def deserialize(serialized_message, deserializer):
return _transform(serialized_message, deserializer,
'Exception deserializing message!')
return _transform(serialized_message, deserializer,
'Exception deserializing message!')
def fully_qualified_method(group, method):
return '/{}/{}'.format(group, method)
return '/{}/{}'.format(group, method)
class CleanupThread(threading.Thread):
"""A threading.Thread subclass supporting custom behavior on join().
"""A threading.Thread subclass supporting custom behavior on join().
On Python Interpreter exit, Python will attempt to join outstanding threads
prior to garbage collection. We may need to do additional cleanup, and
we accomplish this by overriding the join() method.
"""
def __init__(self, behavior, group=None, target=None, name=None,
args=(), kwargs={}):
"""Constructor.
def __init__(self,
behavior,
group=None,
target=None,
name=None,
args=(),
kwargs={}):
"""Constructor.
Args:
behavior (function): Function called on join() with a single
@ -169,15 +172,15 @@ class CleanupThread(threading.Thread):
kwargs (dict[str,object]): A dictionary of keyword arguments to
pass to `target`.
"""
super(CleanupThread, self).__init__(group=group, target=target,
name=name, args=args, kwargs=kwargs)
self._behavior = behavior
def join(self, timeout=None):
start_time = time.time()
self._behavior(timeout)
end_time = time.time()
if timeout is not None:
timeout -= end_time - start_time
timeout = max(timeout, 0)
super(CleanupThread, self).join(timeout)
super(CleanupThread, self).__init__(
group=group, target=target, name=name, args=args, kwargs=kwargs)
self._behavior = behavior
def join(self, timeout=None):
start_time = time.time()
self._behavior(timeout)
end_time = time.time()
if timeout is not None:
timeout -= end_time - start_time
timeout = max(timeout, 0)
super(CleanupThread, self).join(timeout)

@ -31,18 +31,18 @@ from grpc._cython import cygrpc
def _call(call_credentialses):
call_credentials_iterator = iter(call_credentialses)
composition = next(call_credentials_iterator)
for additional_call_credentials in call_credentials_iterator:
composition = cygrpc.call_credentials_composite(
composition, additional_call_credentials)
return composition
call_credentials_iterator = iter(call_credentialses)
composition = next(call_credentials_iterator)
for additional_call_credentials in call_credentials_iterator:
composition = cygrpc.call_credentials_composite(
composition, additional_call_credentials)
return composition
def call(call_credentialses):
return _call(call_credentialses)
return _call(call_credentialses)
def channel(channel_credentials, call_credentialses):
return cygrpc.channel_credentials_composite(
channel_credentials, _call(call_credentialses))
return cygrpc.channel_credentials_composite(channel_credentials,
_call(call_credentialses))

@ -29,6 +29,8 @@
cimport cpython
import traceback
cdef class ChannelCredentials:
@ -138,15 +140,22 @@ cdef class AuthMetadataContext:
cdef void plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
called_flag = [False]
def python_callback(
Metadata metadata, grpc_status_code status,
bytes error_details):
cb(user_data, metadata.c_metadata_array.metadata,
metadata.c_metadata_array.count, status, error_details)
called_flag[0] = True
cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
cdef AuthMetadataContext cy_context = AuthMetadataContext()
cy_context.context = context
self.plugin_callback(cy_context, python_callback)
try:
self.plugin_callback(cy_context, python_callback)
except Exception as error:
if not called_flag[0]:
cb(user_data, Metadata([]).c_metadata_array.metadata,
0, StatusCode.unknown, traceback.format_exc().encode())
cdef void plugin_destroy_c_plugin_state(void *state) with gil:
cpython.Py_DECREF(<CredentialsMetadataPlugin>state)

@ -174,6 +174,25 @@ cdef class Timespec:
def infinite_past():
return Timespec(float("-inf"))
def __richcmp__(Timespec self not None, Timespec other not None, int op):
cdef gpr_timespec self_c_time = self.c_time
cdef gpr_timespec other_c_time = other.c_time
cdef int result = gpr_time_cmp(self_c_time, other_c_time)
if op == 0: # <
return result < 0
elif op == 2: # ==
return result == 0
elif op == 4: # >
return result > 0
elif op == 1: # <=
return result <= 0
elif op == 3: # !=
return result != 0
elif op == 5: # >=
return result >= 0
else:
raise ValueError('__richcmp__ `op` contract violated')
cdef class CallDetails:

@ -36,82 +36,82 @@ from grpc._cython import cygrpc
class AuthMetadataContext(
collections.namedtuple(
'AuthMetadataContext', ('service_url', 'method_name',)),
grpc.AuthMetadataContext):
pass
collections.namedtuple('AuthMetadataContext', (
'service_url',
'method_name',)), grpc.AuthMetadataContext):
pass
class AuthMetadataPluginCallback(grpc.AuthMetadataContext):
def __init__(self, callback):
self._callback = callback
def __init__(self, callback):
self._callback = callback
def __call__(self, metadata, error):
self._callback(metadata, error)
def __call__(self, metadata, error):
self._callback(metadata, error)
class _WrappedCygrpcCallback(object):
def __init__(self, cygrpc_callback):
self.is_called = False
self.error = None
self.is_called_lock = threading.Lock()
self.cygrpc_callback = cygrpc_callback
def _invoke_failure(self, error):
# TODO(atash) translate different Exception superclasses into different
# status codes.
self.cygrpc_callback(
_common.EMPTY_METADATA, cygrpc.StatusCode.internal,
_common.encode(str(error)))
def _invoke_success(self, metadata):
try:
cygrpc_metadata = _common.cygrpc_metadata(metadata)
except Exception as error:
self._invoke_failure(error)
return
self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, b'')
def __call__(self, metadata, error):
with self.is_called_lock:
if self.is_called:
raise RuntimeError('callback should only ever be invoked once')
if self.error:
self._invoke_failure(self.error)
return
self.is_called = True
if error is None:
self._invoke_success(metadata)
else:
self._invoke_failure(error)
def notify_failure(self, error):
with self.is_called_lock:
if not self.is_called:
self.error = error
def __init__(self, cygrpc_callback):
self.is_called = False
self.error = None
self.is_called_lock = threading.Lock()
self.cygrpc_callback = cygrpc_callback
def _invoke_failure(self, error):
# TODO(atash) translate different Exception superclasses into different
# status codes.
self.cygrpc_callback(_common.EMPTY_METADATA, cygrpc.StatusCode.internal,
_common.encode(str(error)))
def _invoke_success(self, metadata):
try:
cygrpc_metadata = _common.cygrpc_metadata(metadata)
except Exception as error:
self._invoke_failure(error)
return
self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, b'')
def __call__(self, metadata, error):
with self.is_called_lock:
if self.is_called:
raise RuntimeError('callback should only ever be invoked once')
if self.error:
self._invoke_failure(self.error)
return
self.is_called = True
if error is None:
self._invoke_success(metadata)
else:
self._invoke_failure(error)
def notify_failure(self, error):
with self.is_called_lock:
if not self.is_called:
self.error = error
class _WrappedPlugin(object):
def __init__(self, plugin):
self.plugin = plugin
def __init__(self, plugin):
self.plugin = plugin
def __call__(self, context, cygrpc_callback):
wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback)
wrapped_context = AuthMetadataContext(
_common.decode(context.service_url), _common.decode(context.method_name))
try:
self.plugin(
wrapped_context, AuthMetadataPluginCallback(wrapped_cygrpc_callback))
except Exception as error:
wrapped_cygrpc_callback.notify_failure(error)
raise
def __call__(self, context, cygrpc_callback):
wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback)
wrapped_context = AuthMetadataContext(
_common.decode(context.service_url),
_common.decode(context.method_name))
try:
self.plugin(wrapped_context,
AuthMetadataPluginCallback(wrapped_cygrpc_callback))
except Exception as error:
wrapped_cygrpc_callback.notify_failure(error)
raise
def call_credentials_metadata_plugin(plugin, name):
"""
"""
Args:
plugin: A callable accepting a grpc.AuthMetadataContext
object and a callback (itself accepting a list of metadata key/value
@ -119,5 +119,6 @@ def call_credentials_metadata_plugin(plugin, name):
called, but need not be called in plugin's invocation.
plugin's invocation must be non-blocking.
"""
return cygrpc.call_credentials_metadata_plugin(
cygrpc.CredentialsMetadataPlugin(_WrappedPlugin(plugin), _common.encode(name)))
return cygrpc.call_credentials_metadata_plugin(
cygrpc.CredentialsMetadataPlugin(
_WrappedPlugin(plugin), _common.encode(name)))

File diff suppressed because it is too large Load Diff

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Internal utilities for gRPC Python."""
import collections
@ -44,132 +43,136 @@ _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
class RpcMethodHandler(
collections.namedtuple(
'_RpcMethodHandler',
('request_streaming', 'response_streaming', 'request_deserializer',
'response_serializer', 'unary_unary', 'unary_stream', 'stream_unary',
'stream_stream',)),
grpc.RpcMethodHandler):
pass
collections.namedtuple('_RpcMethodHandler', (
'request_streaming',
'response_streaming',
'request_deserializer',
'response_serializer',
'unary_unary',
'unary_stream',
'stream_unary',
'stream_stream',)), grpc.RpcMethodHandler):
pass
class DictionaryGenericHandler(grpc.ServiceRpcHandler):
def __init__(self, service, method_handlers):
self._name = service
self._method_handlers = {
_common.fully_qualified_method(service, method): method_handler
for method, method_handler in six.iteritems(method_handlers)}
def __init__(self, service, method_handlers):
self._name = service
self._method_handlers = {
_common.fully_qualified_method(service, method): method_handler
for method, method_handler in six.iteritems(method_handlers)
}
def service_name(self):
return self._name
def service_name(self):
return self._name
def service(self, handler_call_details):
return self._method_handlers.get(handler_call_details.method)
def service(self, handler_call_details):
return self._method_handlers.get(handler_call_details.method)
class _ChannelReadyFuture(grpc.Future):
def __init__(self, channel):
self._condition = threading.Condition()
self._channel = channel
self._matured = False
self._cancelled = False
self._done_callbacks = []
def _block(self, timeout):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._cancelled:
raise grpc.FutureCancelledError()
elif self._matured:
return
else:
if until is None:
self._condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise grpc.FutureTimeoutError()
def __init__(self, channel):
self._condition = threading.Condition()
self._channel = channel
self._matured = False
self._cancelled = False
self._done_callbacks = []
def _block(self, timeout):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._cancelled:
raise grpc.FutureCancelledError()
elif self._matured:
return
else:
if until is None:
self._condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise grpc.FutureTimeoutError()
else:
self._condition.wait(timeout=remaining)
def _update(self, connectivity):
with self._condition:
if (not self._cancelled and
connectivity is grpc.ChannelConnectivity.READY):
self._matured = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancel(self):
with self._condition:
if not self._matured:
self._cancelled = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
self._condition.wait(timeout=remaining)
def _update(self, connectivity):
with self._condition:
if (not self._cancelled and
connectivity is grpc.ChannelConnectivity.READY):
self._matured = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancel(self):
with self._condition:
if not self._matured:
self._cancelled = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return False
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._cancelled and not self._matured
def done(self):
with self._condition:
return self._cancelled or self._matured
def result(self, timeout=None):
self._block(timeout)
return None
def exception(self, timeout=None):
self._block(timeout)
return None
def traceback(self, timeout=None):
self._block(timeout)
return None
def add_done_callback(self, fn):
with self._condition:
if not self._cancelled and not self._matured:
self._done_callbacks.append(fn)
return
fn(self)
def start(self):
with self._condition:
self._channel.subscribe(self._update, try_to_connect=True)
def __del__(self):
with self._condition:
if not self._cancelled and not self._matured:
self._channel.unsubscribe(self._update)
return False
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._cancelled and not self._matured
def done(self):
with self._condition:
return self._cancelled or self._matured
def result(self, timeout=None):
self._block(timeout)
return None
def exception(self, timeout=None):
self._block(timeout)
return None
def traceback(self, timeout=None):
self._block(timeout)
return None
def add_done_callback(self, fn):
with self._condition:
if not self._cancelled and not self._matured:
self._done_callbacks.append(fn)
return
fn(self)
def start(self):
with self._condition:
self._channel.subscribe(self._update, try_to_connect=True)
def __del__(self):
with self._condition:
if not self._cancelled and not self._matured:
self._channel.unsubscribe(self._update)
def channel_ready_future(channel):
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future

File diff suppressed because it is too large Load Diff

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Affords a connectivity-state-listenable channel."""
import threading
@ -41,116 +40,122 @@ _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
'Exception calling channel subscription callback!')
_LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
state: connectivity for state, connectivity in zip(
_types.ConnectivityState, interfaces.ChannelConnectivity)
state: connectivity
for state, connectivity in zip(_types.ConnectivityState,
interfaces.ChannelConnectivity)
}
class ConnectivityChannel(object):
def __init__(self, low_channel):
self._lock = threading.Lock()
self._low_channel = low_channel
self._polling = False
self._connectivity = None
self._try_to_connect = False
self._callbacks_and_connectivities = []
self._delivering = False
def _deliveries(self, connectivity):
callbacks_needing_update = []
for callback_and_connectivity in self._callbacks_and_connectivities:
callback, callback_connectivity = callback_and_connectivity
if callback_connectivity is not connectivity:
callbacks_needing_update.append(callback)
callback_and_connectivity[1] = connectivity
return callbacks_needing_update
def _deliver(self, initial_connectivity, initial_callbacks):
connectivity = initial_connectivity
callbacks = initial_callbacks
while True:
for callback in callbacks:
callable_util.call_logging_exceptions(
callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE,
connectivity)
with self._lock:
callbacks = self._deliveries(self._connectivity)
if callbacks:
connectivity = self._connectivity
else:
self._delivering = False
return
def _spawn_delivery(self, connectivity, callbacks):
delivering_thread = threading.Thread(
target=self._deliver, args=(connectivity, callbacks,))
delivering_thread.start()
self._delivering = True
def __init__(self, low_channel):
self._lock = threading.Lock()
self._low_channel = low_channel
# TODO(issue 3064): Don't poll.
def _poll_connectivity(self, low_channel, initial_try_to_connect):
try_to_connect = initial_try_to_connect
low_connectivity = low_channel.check_connectivity_state(try_to_connect)
with self._lock:
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
low_connectivity]
callbacks = tuple(
callback for callback, unused_but_known_to_be_none_connectivity
in self._callbacks_and_connectivities)
for callback_and_connectivity in self._callbacks_and_connectivities:
callback_and_connectivity[1] = self._connectivity
if callbacks:
self._spawn_delivery(self._connectivity, callbacks)
completion_queue = _low.CompletionQueue()
while True:
low_channel.watch_connectivity_state(
low_connectivity, time.time() + 0.2, completion_queue, None)
event = completion_queue.next()
with self._lock:
if not self._callbacks_and_connectivities and not self._try_to_connect:
self._polling = False
self._connectivity = None
completion_queue.shutdown()
break
try_to_connect = self._try_to_connect
self._polling = False
self._connectivity = None
self._try_to_connect = False
if event.success or try_to_connect:
self._callbacks_and_connectivities = []
self._delivering = False
def _deliveries(self, connectivity):
callbacks_needing_update = []
for callback_and_connectivity in self._callbacks_and_connectivities:
callback, callback_connectivity = callback_and_connectivity
if callback_connectivity is not connectivity:
callbacks_needing_update.append(callback)
callback_and_connectivity[1] = connectivity
return callbacks_needing_update
def _deliver(self, initial_connectivity, initial_callbacks):
connectivity = initial_connectivity
callbacks = initial_callbacks
while True:
for callback in callbacks:
callable_util.call_logging_exceptions(
callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE,
connectivity)
with self._lock:
callbacks = self._deliveries(self._connectivity)
if callbacks:
connectivity = self._connectivity
else:
self._delivering = False
return
def _spawn_delivery(self, connectivity, callbacks):
delivering_thread = threading.Thread(
target=self._deliver, args=(
connectivity,
callbacks,))
delivering_thread.start()
self._delivering = True
# TODO(issue 3064): Don't poll.
def _poll_connectivity(self, low_channel, initial_try_to_connect):
try_to_connect = initial_try_to_connect
low_connectivity = low_channel.check_connectivity_state(try_to_connect)
with self._lock:
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
low_connectivity]
if not self._delivering:
callbacks = self._deliveries(self._connectivity)
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
low_connectivity]
callbacks = tuple(
callback
for callback, unused_but_known_to_be_none_connectivity in
self._callbacks_and_connectivities)
for callback_and_connectivity in self._callbacks_and_connectivities:
callback_and_connectivity[1] = self._connectivity
if callbacks:
self._spawn_delivery(self._connectivity, callbacks)
def subscribe(self, callback, try_to_connect):
with self._lock:
if not self._callbacks_and_connectivities and not self._polling:
polling_thread = threading.Thread(
target=self._poll_connectivity,
args=(self._low_channel, bool(try_to_connect)))
polling_thread.start()
self._polling = True
self._callbacks_and_connectivities.append([callback, None])
elif not self._delivering and self._connectivity is not None:
self._spawn_delivery(self._connectivity, (callback,))
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append(
[callback, self._connectivity])
else:
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append([callback, None])
def unsubscribe(self, callback):
with self._lock:
for index, (subscribed_callback, unused_connectivity) in enumerate(
self._callbacks_and_connectivities):
if callback == subscribed_callback:
self._callbacks_and_connectivities.pop(index)
break
def low_channel(self):
return self._low_channel
self._spawn_delivery(self._connectivity, callbacks)
completion_queue = _low.CompletionQueue()
while True:
low_channel.watch_connectivity_state(low_connectivity,
time.time() + 0.2,
completion_queue, None)
event = completion_queue.next()
with self._lock:
if not self._callbacks_and_connectivities and not self._try_to_connect:
self._polling = False
self._connectivity = None
completion_queue.shutdown()
break
try_to_connect = self._try_to_connect
self._try_to_connect = False
if event.success or try_to_connect:
low_connectivity = low_channel.check_connectivity_state(
try_to_connect)
with self._lock:
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
low_connectivity]
if not self._delivering:
callbacks = self._deliveries(self._connectivity)
if callbacks:
self._spawn_delivery(self._connectivity, callbacks)
def subscribe(self, callback, try_to_connect):
with self._lock:
if not self._callbacks_and_connectivities and not self._polling:
polling_thread = threading.Thread(
target=self._poll_connectivity,
args=(self._low_channel, bool(try_to_connect)))
polling_thread.start()
self._polling = True
self._callbacks_and_connectivities.append([callback, None])
elif not self._delivering and self._connectivity is not None:
self._spawn_delivery(self._connectivity, (callback,))
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append(
[callback, self._connectivity])
else:
self._try_to_connect |= bool(try_to_connect)
self._callbacks_and_connectivities.append([callback, None])
def unsubscribe(self, callback):
with self._lock:
for index, (subscribed_callback, unused_connectivity
) in enumerate(self._callbacks_and_connectivities):
if callback == subscribed_callback:
self._callbacks_and_connectivities.pop(index)
break
def low_channel(self):
return self._low_channel

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Translates gRPC's server-side API into gRPC's server-side Beta API."""
import collections
@ -47,329 +46,352 @@ _DEFAULT_POOL_SIZE = 8
class _ServerProtocolContext(interfaces.GRPCServicerContext):
def __init__(self, servicer_context):
self._servicer_context = servicer_context
def __init__(self, servicer_context):
self._servicer_context = servicer_context
def peer(self):
return self._servicer_context.peer()
def peer(self):
return self._servicer_context.peer()
def disable_next_response_compression(self):
pass # TODO(https://github.com/grpc/grpc/issues/4078): design, implement.
def disable_next_response_compression(self):
pass # TODO(https://github.com/grpc/grpc/issues/4078): design, implement.
class _FaceServicerContext(face.ServicerContext):
def __init__(self, servicer_context):
self._servicer_context = servicer_context
def __init__(self, servicer_context):
self._servicer_context = servicer_context
def is_active(self):
return self._servicer_context.is_active()
def is_active(self):
return self._servicer_context.is_active()
def time_remaining(self):
return self._servicer_context.time_remaining()
def time_remaining(self):
return self._servicer_context.time_remaining()
def add_abortion_callback(self, abortion_callback):
raise NotImplementedError(
'add_abortion_callback no longer supported server-side!')
def add_abortion_callback(self, abortion_callback):
raise NotImplementedError(
'add_abortion_callback no longer supported server-side!')
def cancel(self):
self._servicer_context.cancel()
def cancel(self):
self._servicer_context.cancel()
def protocol_context(self):
return _ServerProtocolContext(self._servicer_context)
def protocol_context(self):
return _ServerProtocolContext(self._servicer_context)
def invocation_metadata(self):
return _common.cygrpc_metadata(
self._servicer_context.invocation_metadata())
def invocation_metadata(self):
return _common.cygrpc_metadata(
self._servicer_context.invocation_metadata())
def initial_metadata(self, initial_metadata):
self._servicer_context.send_initial_metadata(initial_metadata)
def initial_metadata(self, initial_metadata):
self._servicer_context.send_initial_metadata(initial_metadata)
def terminal_metadata(self, terminal_metadata):
self._servicer_context.set_terminal_metadata(terminal_metadata)
def terminal_metadata(self, terminal_metadata):
self._servicer_context.set_terminal_metadata(terminal_metadata)
def code(self, code):
self._servicer_context.set_code(code)
def code(self, code):
self._servicer_context.set_code(code)
def details(self, details):
self._servicer_context.set_details(details)
def details(self, details):
self._servicer_context.set_details(details)
def _adapt_unary_request_inline(unary_request_inline):
def adaptation(request, servicer_context):
return unary_request_inline(request, _FaceServicerContext(servicer_context))
return adaptation
def adaptation(request, servicer_context):
return unary_request_inline(request,
_FaceServicerContext(servicer_context))
return adaptation
def _adapt_stream_request_inline(stream_request_inline):
def adaptation(request_iterator, servicer_context):
return stream_request_inline(
request_iterator, _FaceServicerContext(servicer_context))
return adaptation
def adaptation(request_iterator, servicer_context):
return stream_request_inline(request_iterator,
_FaceServicerContext(servicer_context))
return adaptation
class _Callback(stream.Consumer):
def __init__(self):
self._condition = threading.Condition()
self._values = []
self._terminated = False
self._cancelled = False
def consume(self, value):
with self._condition:
self._values.append(value)
self._condition.notify_all()
def terminate(self):
with self._condition:
self._terminated = True
self._condition.notify_all()
def consume_and_terminate(self, value):
with self._condition:
self._values.append(value)
self._terminated = True
self._condition.notify_all()
def cancel(self):
with self._condition:
self._cancelled = True
self._condition.notify_all()
def draw_one_value(self):
with self._condition:
while True:
if self._cancelled:
raise abandonment.Abandoned()
elif self._values:
return self._values.pop(0)
elif self._terminated:
return None
else:
self._condition.wait()
def draw_all_values(self):
with self._condition:
while True:
if self._cancelled:
raise abandonment.Abandoned()
elif self._terminated:
all_values = tuple(self._values)
self._values = None
return all_values
else:
self._condition.wait()
def __init__(self):
self._condition = threading.Condition()
self._values = []
self._terminated = False
self._cancelled = False
def consume(self, value):
with self._condition:
self._values.append(value)
self._condition.notify_all()
def terminate(self):
with self._condition:
self._terminated = True
self._condition.notify_all()
def consume_and_terminate(self, value):
with self._condition:
self._values.append(value)
self._terminated = True
self._condition.notify_all()
def cancel(self):
with self._condition:
self._cancelled = True
self._condition.notify_all()
def draw_one_value(self):
with self._condition:
while True:
if self._cancelled:
raise abandonment.Abandoned()
elif self._values:
return self._values.pop(0)
elif self._terminated:
return None
else:
self._condition.wait()
def draw_all_values(self):
with self._condition:
while True:
if self._cancelled:
raise abandonment.Abandoned()
elif self._terminated:
all_values = tuple(self._values)
self._values = None
return all_values
else:
self._condition.wait()
def _run_request_pipe_thread(request_iterator, request_consumer,
servicer_context):
thread_joined = threading.Event()
def pipe_requests():
for request in request_iterator:
if not servicer_context.is_active() or thread_joined.is_set():
return
request_consumer.consume(request)
if not servicer_context.is_active() or thread_joined.is_set():
return
request_consumer.terminate()
thread_joined = threading.Event()
def pipe_requests():
for request in request_iterator:
if not servicer_context.is_active() or thread_joined.is_set():
return
request_consumer.consume(request)
if not servicer_context.is_active() or thread_joined.is_set():
return
request_consumer.terminate()
def stop_request_pipe(timeout):
thread_joined.set()
def stop_request_pipe(timeout):
thread_joined.set()
request_pipe_thread = _common.CleanupThread(
stop_request_pipe, target=pipe_requests)
request_pipe_thread.start()
request_pipe_thread = _common.CleanupThread(
stop_request_pipe, target=pipe_requests)
request_pipe_thread.start()
def _adapt_unary_unary_event(unary_unary_event):
def adaptation(request, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
unary_unary_event(
request, callback.consume_and_terminate,
_FaceServicerContext(servicer_context))
return callback.draw_all_values()[0]
return adaptation
def adaptation(request, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
unary_unary_event(request, callback.consume_and_terminate,
_FaceServicerContext(servicer_context))
return callback.draw_all_values()[0]
return adaptation
def _adapt_unary_stream_event(unary_stream_event):
def adaptation(request, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
unary_stream_event(
request, callback, _FaceServicerContext(servicer_context))
while True:
response = callback.draw_one_value()
if response is None:
return
else:
yield response
return adaptation
def adaptation(request, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
unary_stream_event(request, callback,
_FaceServicerContext(servicer_context))
while True:
response = callback.draw_one_value()
if response is None:
return
else:
yield response
return adaptation
def _adapt_stream_unary_event(stream_unary_event):
def adaptation(request_iterator, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
request_consumer = stream_unary_event(
callback.consume_and_terminate, _FaceServicerContext(servicer_context))
_run_request_pipe_thread(
request_iterator, request_consumer, servicer_context)
return callback.draw_all_values()[0]
return adaptation
def adaptation(request_iterator, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
request_consumer = stream_unary_event(
callback.consume_and_terminate,
_FaceServicerContext(servicer_context))
_run_request_pipe_thread(request_iterator, request_consumer,
servicer_context)
return callback.draw_all_values()[0]
return adaptation
def _adapt_stream_stream_event(stream_stream_event):
def adaptation(request_iterator, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
request_consumer = stream_stream_event(
callback, _FaceServicerContext(servicer_context))
_run_request_pipe_thread(
request_iterator, request_consumer, servicer_context)
while True:
response = callback.draw_one_value()
if response is None:
return
else:
yield response
return adaptation
def adaptation(request_iterator, servicer_context):
callback = _Callback()
if not servicer_context.add_callback(callback.cancel):
raise abandonment.Abandoned()
request_consumer = stream_stream_event(
callback, _FaceServicerContext(servicer_context))
_run_request_pipe_thread(request_iterator, request_consumer,
servicer_context)
while True:
response = callback.draw_one_value()
if response is None:
return
else:
yield response
return adaptation
class _SimpleMethodHandler(
collections.namedtuple(
'_MethodHandler',
('request_streaming', 'response_streaming', 'request_deserializer',
'response_serializer', 'unary_unary', 'unary_stream', 'stream_unary',
'stream_stream',)),
grpc.RpcMethodHandler):
pass
def _simple_method_handler(
implementation, request_deserializer, response_serializer):
if implementation.style is style.Service.INLINE:
if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
return _SimpleMethodHandler(
False, False, request_deserializer, response_serializer,
_adapt_unary_request_inline(implementation.unary_unary_inline), None,
None, None)
elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
return _SimpleMethodHandler(
False, True, request_deserializer, response_serializer, None,
_adapt_unary_request_inline(implementation.unary_stream_inline), None,
None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
return _SimpleMethodHandler(
True, False, request_deserializer, response_serializer, None, None,
_adapt_stream_request_inline(implementation.stream_unary_inline),
None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
return _SimpleMethodHandler(
True, True, request_deserializer, response_serializer, None, None,
None,
_adapt_stream_request_inline(implementation.stream_stream_inline))
elif implementation.style is style.Service.EVENT:
if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
return _SimpleMethodHandler(
False, False, request_deserializer, response_serializer,
_adapt_unary_unary_event(implementation.unary_unary_event), None,
None, None)
elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
return _SimpleMethodHandler(
False, True, request_deserializer, response_serializer, None,
_adapt_unary_stream_event(implementation.unary_stream_event), None,
None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
return _SimpleMethodHandler(
True, False, request_deserializer, response_serializer, None, None,
_adapt_stream_unary_event(implementation.stream_unary_event), None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
return _SimpleMethodHandler(
True, True, request_deserializer, response_serializer, None, None,
None, _adapt_stream_stream_event(implementation.stream_stream_event))
collections.namedtuple('_MethodHandler', (
'request_streaming',
'response_streaming',
'request_deserializer',
'response_serializer',
'unary_unary',
'unary_stream',
'stream_unary',
'stream_stream',)), grpc.RpcMethodHandler):
pass
def _simple_method_handler(implementation, request_deserializer,
response_serializer):
if implementation.style is style.Service.INLINE:
if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
return _SimpleMethodHandler(
False, False, request_deserializer, response_serializer,
_adapt_unary_request_inline(implementation.unary_unary_inline),
None, None, None)
elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
return _SimpleMethodHandler(
False, True, request_deserializer, response_serializer, None,
_adapt_unary_request_inline(implementation.unary_stream_inline),
None, None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
return _SimpleMethodHandler(True, False, request_deserializer,
response_serializer, None, None,
_adapt_stream_request_inline(
implementation.stream_unary_inline),
None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
return _SimpleMethodHandler(
True, True, request_deserializer, response_serializer, None,
None, None,
_adapt_stream_request_inline(
implementation.stream_stream_inline))
elif implementation.style is style.Service.EVENT:
if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
return _SimpleMethodHandler(
False, False, request_deserializer, response_serializer,
_adapt_unary_unary_event(implementation.unary_unary_event),
None, None, None)
elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
return _SimpleMethodHandler(
False, True, request_deserializer, response_serializer, None,
_adapt_unary_stream_event(implementation.unary_stream_event),
None, None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
return _SimpleMethodHandler(
True, False, request_deserializer, response_serializer, None,
None,
_adapt_stream_unary_event(implementation.stream_unary_event),
None)
elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
return _SimpleMethodHandler(
True, True, request_deserializer, response_serializer, None,
None, None,
_adapt_stream_stream_event(implementation.stream_stream_event))
def _flatten_method_pair_map(method_pair_map):
method_pair_map = method_pair_map or {}
flat_map = {}
for method_pair in method_pair_map:
method = _common.fully_qualified_method(method_pair[0], method_pair[1])
flat_map[method] = method_pair_map[method_pair]
return flat_map
method_pair_map = method_pair_map or {}
flat_map = {}
for method_pair in method_pair_map:
method = _common.fully_qualified_method(method_pair[0], method_pair[1])
flat_map[method] = method_pair_map[method_pair]
return flat_map
class _GenericRpcHandler(grpc.GenericRpcHandler):
def __init__(
self, method_implementations, multi_method_implementation,
request_deserializers, response_serializers):
self._method_implementations = _flatten_method_pair_map(
method_implementations)
self._request_deserializers = _flatten_method_pair_map(
request_deserializers)
self._response_serializers = _flatten_method_pair_map(
response_serializers)
self._multi_method_implementation = multi_method_implementation
def service(self, handler_call_details):
method_implementation = self._method_implementations.get(
handler_call_details.method)
if method_implementation is not None:
return _simple_method_handler(
method_implementation,
self._request_deserializers.get(handler_call_details.method),
self._response_serializers.get(handler_call_details.method))
elif self._multi_method_implementation is None:
return None
else:
try:
return None #TODO(nathaniel): call the multimethod.
except face.NoSuchMethodError:
return None
def __init__(self, method_implementations, multi_method_implementation,
request_deserializers, response_serializers):
self._method_implementations = _flatten_method_pair_map(
method_implementations)
self._request_deserializers = _flatten_method_pair_map(
request_deserializers)
self._response_serializers = _flatten_method_pair_map(
response_serializers)
self._multi_method_implementation = multi_method_implementation
def service(self, handler_call_details):
method_implementation = self._method_implementations.get(
handler_call_details.method)
if method_implementation is not None:
return _simple_method_handler(
method_implementation,
self._request_deserializers.get(handler_call_details.method),
self._response_serializers.get(handler_call_details.method))
elif self._multi_method_implementation is None:
return None
else:
try:
return None #TODO(nathaniel): call the multimethod.
except face.NoSuchMethodError:
return None
class _Server(interfaces.Server):
def __init__(self, server):
self._server = server
def __init__(self, server):
self._server = server
def add_insecure_port(self, address):
return self._server.add_insecure_port(address)
def add_insecure_port(self, address):
return self._server.add_insecure_port(address)
def add_secure_port(self, address, server_credentials):
return self._server.add_secure_port(address, server_credentials)
def add_secure_port(self, address, server_credentials):
return self._server.add_secure_port(address, server_credentials)
def start(self):
self._server.start()
def start(self):
self._server.start()
def stop(self, grace):
return self._server.stop(grace)
def stop(self, grace):
return self._server.stop(grace)
def __enter__(self):
self._server.start()
return self
def __enter__(self):
self._server.start()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._server.stop(None)
return False
def __exit__(self, exc_type, exc_val, exc_tb):
self._server.stop(None)
return False
def server(
service_implementations, multi_method_implementation, request_deserializers,
response_serializers, thread_pool, thread_pool_size):
generic_rpc_handler = _GenericRpcHandler(
service_implementations, multi_method_implementation,
request_deserializers, response_serializers)
if thread_pool is None:
effective_thread_pool = logging_pool.pool(
_DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
else:
effective_thread_pool = thread_pool
return _Server(
grpc.server(effective_thread_pool, handlers=(generic_rpc_handler,)))
def server(service_implementations, multi_method_implementation,
request_deserializers, response_serializers, thread_pool,
thread_pool_size):
generic_rpc_handler = _GenericRpcHandler(
service_implementations, multi_method_implementation,
request_deserializers, response_serializers)
if thread_pool is None:
effective_thread_pool = logging_pool.pool(_DEFAULT_POOL_SIZE
if thread_pool_size is None
else thread_pool_size)
else:
effective_thread_pool = thread_pool
return _Server(
grpc.server(
effective_thread_pool, handlers=(generic_rpc_handler,)))

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Entry points into the Beta API of gRPC Python."""
# threading is referenced from specification in this module.
@ -43,7 +42,6 @@ from grpc.beta import interfaces
from grpc.framework.common import cardinality # pylint: disable=unused-import
from grpc.framework.interfaces.face import face # pylint: disable=unused-import
ChannelCredentials = grpc.ChannelCredentials
ssl_channel_credentials = grpc.ssl_channel_credentials
CallCredentials = grpc.CallCredentials
@ -51,7 +49,7 @@ metadata_call_credentials = grpc.metadata_call_credentials
def google_call_credentials(credentials):
"""Construct CallCredentials from GoogleCredentials.
"""Construct CallCredentials from GoogleCredentials.
Args:
credentials: A GoogleCredentials object from the oauth2client library.
@ -59,7 +57,8 @@ def google_call_credentials(credentials):
Returns:
A CallCredentials object for use in a GRPCCallOptions object.
"""
return metadata_call_credentials(_auth.GoogleCallCredentials(credentials))
return metadata_call_credentials(_auth.GoogleCallCredentials(credentials))
access_token_call_credentials = grpc.access_token_call_credentials
composite_call_credentials = grpc.composite_call_credentials
@ -67,18 +66,18 @@ composite_channel_credentials = grpc.composite_channel_credentials
class Channel(object):
"""A channel to a remote host through which RPCs may be conducted.
"""A channel to a remote host through which RPCs may be conducted.
Only the "subscribe" and "unsubscribe" methods are supported for application
use. This class' instance constructor and all other attributes are
unsupported.
"""
def __init__(self, channel):
self._channel = channel
def __init__(self, channel):
self._channel = channel
def subscribe(self, callback, try_to_connect=None):
"""Subscribes to this Channel's connectivity.
def subscribe(self, callback, try_to_connect=None):
"""Subscribes to this Channel's connectivity.
Args:
callback: A callable to be invoked and passed an
@ -90,20 +89,20 @@ class Channel(object):
attempt to connect if it is not already connected and ready to conduct
RPCs.
"""
self._channel.subscribe(callback, try_to_connect=try_to_connect)
self._channel.subscribe(callback, try_to_connect=try_to_connect)
def unsubscribe(self, callback):
"""Unsubscribes a callback from this Channel's connectivity.
def unsubscribe(self, callback):
"""Unsubscribes a callback from this Channel's connectivity.
Args:
callback: A callable previously registered with this Channel from having
been passed to its "subscribe" method.
"""
self._channel.unsubscribe(callback)
self._channel.unsubscribe(callback)
def insecure_channel(host, port):
"""Creates an insecure Channel to a remote host.
"""Creates an insecure Channel to a remote host.
Args:
host: The name of the remote host to which to connect.
@ -113,13 +112,13 @@ def insecure_channel(host, port):
Returns:
A Channel to the remote host through which RPCs may be conducted.
"""
channel = grpc.insecure_channel(
host if port is None else '%s:%d' % (host, port))
return Channel(channel)
channel = grpc.insecure_channel(host
if port is None else '%s:%d' % (host, port))
return Channel(channel)
def secure_channel(host, port, channel_credentials):
"""Creates a secure Channel to a remote host.
"""Creates a secure Channel to a remote host.
Args:
host: The name of the remote host to which to connect.
@ -130,37 +129,39 @@ def secure_channel(host, port, channel_credentials):
Returns:
A secure Channel to the remote host through which RPCs may be conducted.
"""
channel = grpc.secure_channel(
host if port is None else '%s:%d' % (host, port), channel_credentials)
return Channel(channel)
channel = grpc.secure_channel(host if port is None else
'%s:%d' % (host, port), channel_credentials)
return Channel(channel)
class StubOptions(object):
"""A value encapsulating the various options for creation of a Stub.
"""A value encapsulating the various options for creation of a Stub.
This class and its instances have no supported interface - it exists to define
the type of its instances and its instances exist to be passed to other
functions.
"""
def __init__(
self, host, request_serializers, response_deserializers,
metadata_transformer, thread_pool, thread_pool_size):
self.host = host
self.request_serializers = request_serializers
self.response_deserializers = response_deserializers
self.metadata_transformer = metadata_transformer
self.thread_pool = thread_pool
self.thread_pool_size = thread_pool_size
def __init__(self, host, request_serializers, response_deserializers,
metadata_transformer, thread_pool, thread_pool_size):
self.host = host
self.request_serializers = request_serializers
self.response_deserializers = response_deserializers
self.metadata_transformer = metadata_transformer
self.thread_pool = thread_pool
self.thread_pool_size = thread_pool_size
_EMPTY_STUB_OPTIONS = StubOptions(
None, None, None, None, None, None)
_EMPTY_STUB_OPTIONS = StubOptions(None, None, None, None, None, None)
def stub_options(
host=None, request_serializers=None, response_deserializers=None,
metadata_transformer=None, thread_pool=None, thread_pool_size=None):
"""Creates a StubOptions value to be passed at stub creation.
def stub_options(host=None,
request_serializers=None,
response_deserializers=None,
metadata_transformer=None,
thread_pool=None,
thread_pool_size=None):
"""Creates a StubOptions value to be passed at stub creation.
All parameters are optional and should always be passed by keyword.
@ -180,13 +181,12 @@ def stub_options(
Returns:
A StubOptions value created from the passed parameters.
"""
return StubOptions(
host, request_serializers, response_deserializers,
metadata_transformer, thread_pool, thread_pool_size)
return StubOptions(host, request_serializers, response_deserializers,
metadata_transformer, thread_pool, thread_pool_size)
def generic_stub(channel, options=None):
"""Creates a face.GenericStub on which RPCs can be made.
"""Creates a face.GenericStub on which RPCs can be made.
Args:
channel: A Channel for use by the created stub.
@ -195,16 +195,17 @@ def generic_stub(channel, options=None):
Returns:
A face.GenericStub on which RPCs can be made.
"""
effective_options = _EMPTY_STUB_OPTIONS if options is None else options
return _client_adaptations.generic_stub(
channel._channel, # pylint: disable=protected-access
effective_options.host, effective_options.metadata_transformer,
effective_options.request_serializers,
effective_options.response_deserializers)
effective_options = _EMPTY_STUB_OPTIONS if options is None else options
return _client_adaptations.generic_stub(
channel._channel, # pylint: disable=protected-access
effective_options.host,
effective_options.metadata_transformer,
effective_options.request_serializers,
effective_options.response_deserializers)
def dynamic_stub(channel, service, cardinalities, options=None):
"""Creates a face.DynamicStub with which RPCs can be invoked.
"""Creates a face.DynamicStub with which RPCs can be invoked.
Args:
channel: A Channel for the returned face.DynamicStub to use.
@ -217,13 +218,15 @@ def dynamic_stub(channel, service, cardinalities, options=None):
Returns:
A face.DynamicStub with which RPCs can be invoked.
"""
effective_options = StubOptions() if options is None else options
return _client_adaptations.dynamic_stub(
channel._channel, # pylint: disable=protected-access
service, cardinalities, effective_options.host,
effective_options.metadata_transformer,
effective_options.request_serializers,
effective_options.response_deserializers)
effective_options = StubOptions() if options is None else options
return _client_adaptations.dynamic_stub(
channel._channel, # pylint: disable=protected-access
service,
cardinalities,
effective_options.host,
effective_options.metadata_transformer,
effective_options.request_serializers,
effective_options.response_deserializers)
ServerCredentials = grpc.ServerCredentials
@ -231,34 +234,36 @@ ssl_server_credentials = grpc.ssl_server_credentials
class ServerOptions(object):
"""A value encapsulating the various options for creation of a Server.
"""A value encapsulating the various options for creation of a Server.
This class and its instances have no supported interface - it exists to define
the type of its instances and its instances exist to be passed to other
functions.
"""
def __init__(
self, multi_method_implementation, request_deserializers,
response_serializers, thread_pool, thread_pool_size, default_timeout,
maximum_timeout):
self.multi_method_implementation = multi_method_implementation
self.request_deserializers = request_deserializers
self.response_serializers = response_serializers
self.thread_pool = thread_pool
self.thread_pool_size = thread_pool_size
self.default_timeout = default_timeout
self.maximum_timeout = maximum_timeout
def __init__(self, multi_method_implementation, request_deserializers,
response_serializers, thread_pool, thread_pool_size,
default_timeout, maximum_timeout):
self.multi_method_implementation = multi_method_implementation
self.request_deserializers = request_deserializers
self.response_serializers = response_serializers
self.thread_pool = thread_pool
self.thread_pool_size = thread_pool_size
self.default_timeout = default_timeout
self.maximum_timeout = maximum_timeout
_EMPTY_SERVER_OPTIONS = ServerOptions(
None, None, None, None, None, None, None)
_EMPTY_SERVER_OPTIONS = ServerOptions(None, None, None, None, None, None, None)
def server_options(
multi_method_implementation=None, request_deserializers=None,
response_serializers=None, thread_pool=None, thread_pool_size=None,
default_timeout=None, maximum_timeout=None):
"""Creates a ServerOptions value to be passed at server creation.
def server_options(multi_method_implementation=None,
request_deserializers=None,
response_serializers=None,
thread_pool=None,
thread_pool_size=None,
default_timeout=None,
maximum_timeout=None):
"""Creates a ServerOptions value to be passed at server creation.
All parameters are optional and should always be passed by keyword.
@ -282,13 +287,13 @@ def server_options(
Returns:
A StubOptions value created from the passed parameters.
"""
return ServerOptions(
multi_method_implementation, request_deserializers, response_serializers,
thread_pool, thread_pool_size, default_timeout, maximum_timeout)
return ServerOptions(multi_method_implementation, request_deserializers,
response_serializers, thread_pool, thread_pool_size,
default_timeout, maximum_timeout)
def server(service_implementations, options=None):
"""Creates an interfaces.Server with which RPCs can be serviced.
"""Creates an interfaces.Server with which RPCs can be serviced.
Args:
service_implementations: A dictionary from service name-method name pair to
@ -299,9 +304,9 @@ def server(service_implementations, options=None):
Returns:
An interfaces.Server with which RPCs can be serviced.
"""
effective_options = _EMPTY_SERVER_OPTIONS if options is None else options
return _server_adaptations.server(
service_implementations, effective_options.multi_method_implementation,
effective_options.request_deserializers,
effective_options.response_serializers, effective_options.thread_pool,
effective_options.thread_pool_size)
effective_options = _EMPTY_SERVER_OPTIONS if options is None else options
return _server_adaptations.server(
service_implementations, effective_options.multi_method_implementation,
effective_options.request_deserializers,
effective_options.response_serializers, effective_options.thread_pool,
effective_options.thread_pool_size)

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Constants and interfaces of the Beta API of gRPC Python."""
import abc
@ -43,21 +42,21 @@ StatusCode = grpc.StatusCode
class GRPCCallOptions(object):
"""A value encapsulating gRPC-specific options passed on RPC invocation.
"""A value encapsulating gRPC-specific options passed on RPC invocation.
This class and its instances have no supported interface - it exists to
define the type of its instances and its instances exist to be passed to
other functions.
"""
def __init__(self, disable_compression, subcall_of, credentials):
self.disable_compression = disable_compression
self.subcall_of = subcall_of
self.credentials = credentials
def __init__(self, disable_compression, subcall_of, credentials):
self.disable_compression = disable_compression
self.subcall_of = subcall_of
self.credentials = credentials
def grpc_call_options(disable_compression=False, credentials=None):
"""Creates a GRPCCallOptions value to be passed at RPC invocation.
"""Creates a GRPCCallOptions value to be passed at RPC invocation.
All parameters are optional and should always be passed by keyword.
@ -67,7 +66,8 @@ def grpc_call_options(disable_compression=False, credentials=None):
request-unary RPCs.
credentials: A CallCredentials object to use for the invoked RPC.
"""
return GRPCCallOptions(disable_compression, None, credentials)
return GRPCCallOptions(disable_compression, None, credentials)
GRPCAuthMetadataContext = grpc.AuthMetadataContext
GRPCAuthMetadataPluginCallback = grpc.AuthMetadataPluginCallback
@ -75,38 +75,38 @@ GRPCAuthMetadataPlugin = grpc.AuthMetadataPlugin
class GRPCServicerContext(six.with_metaclass(abc.ABCMeta)):
"""Exposes gRPC-specific options and behaviors to code servicing RPCs."""
"""Exposes gRPC-specific options and behaviors to code servicing RPCs."""
@abc.abstractmethod
def peer(self):
"""Identifies the peer that invoked the RPC being serviced.
@abc.abstractmethod
def peer(self):
"""Identifies the peer that invoked the RPC being serviced.
Returns:
A string identifying the peer that invoked the RPC being serviced.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def disable_next_response_compression(self):
"""Disables compression of the next response passed by the application."""
raise NotImplementedError()
@abc.abstractmethod
def disable_next_response_compression(self):
"""Disables compression of the next response passed by the application."""
raise NotImplementedError()
class GRPCInvocationContext(six.with_metaclass(abc.ABCMeta)):
"""Exposes gRPC-specific options and behaviors to code invoking RPCs."""
"""Exposes gRPC-specific options and behaviors to code invoking RPCs."""
@abc.abstractmethod
def disable_next_request_compression(self):
"""Disables compression of the next request passed by the application."""
raise NotImplementedError()
@abc.abstractmethod
def disable_next_request_compression(self):
"""Disables compression of the next request passed by the application."""
raise NotImplementedError()
class Server(six.with_metaclass(abc.ABCMeta)):
"""Services RPCs."""
"""Services RPCs."""
@abc.abstractmethod
def add_insecure_port(self, address):
"""Reserves a port for insecure RPC service once this Server becomes active.
@abc.abstractmethod
def add_insecure_port(self, address):
"""Reserves a port for insecure RPC service once this Server becomes active.
This method may only be called before calling this Server's start method is
called.
@ -120,11 +120,11 @@ class Server(six.with_metaclass(abc.ABCMeta)):
in the passed address, but will likely be different if the port number
contained in the passed address was zero.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def add_secure_port(self, address, server_credentials):
"""Reserves a port for secure RPC service after this Server becomes active.
@abc.abstractmethod
def add_secure_port(self, address, server_credentials):
"""Reserves a port for secure RPC service after this Server becomes active.
This method may only be called before calling this Server's start method is
called.
@ -139,20 +139,20 @@ class Server(six.with_metaclass(abc.ABCMeta)):
in the passed address, but will likely be different if the port number
contained in the passed address was zero.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def start(self):
"""Starts this Server's service of RPCs.
@abc.abstractmethod
def start(self):
"""Starts this Server's service of RPCs.
This method may only be called while the server is not serving RPCs (i.e. it
is not idempotent).
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def stop(self, grace):
"""Stops this Server's service of RPCs.
@abc.abstractmethod
def stop(self, grace):
"""Stops this Server's service of RPCs.
All calls to this method immediately stop service of new RPCs. When existing
RPCs are aborted is controlled by the grace period parameter passed to this
@ -177,4 +177,4 @@ class Server(six.with_metaclass(abc.ABCMeta)):
at the time it was stopped or if all RPCs that it had underway completed
very early in the grace period).
"""
raise NotImplementedError()
raise NotImplementedError()

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Utilities for the gRPC Python Beta API."""
import threading
@ -44,107 +43,107 @@ _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
class _ChannelReadyFuture(future.Future):
def __init__(self, channel):
self._condition = threading.Condition()
self._channel = channel
self._matured = False
self._cancelled = False
self._done_callbacks = []
def _block(self, timeout):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._cancelled:
raise future.CancelledError()
elif self._matured:
return
else:
if until is None:
self._condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise future.TimeoutError()
def __init__(self, channel):
self._condition = threading.Condition()
self._channel = channel
self._matured = False
self._cancelled = False
self._done_callbacks = []
def _block(self, timeout):
until = None if timeout is None else time.time() + timeout
with self._condition:
while True:
if self._cancelled:
raise future.CancelledError()
elif self._matured:
return
else:
if until is None:
self._condition.wait()
else:
remaining = until - time.time()
if remaining < 0:
raise future.TimeoutError()
else:
self._condition.wait(timeout=remaining)
def _update(self, connectivity):
with self._condition:
if (not self._cancelled and
connectivity is interfaces.ChannelConnectivity.READY):
self._matured = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancel(self):
with self._condition:
if not self._matured:
self._cancelled = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
self._condition.wait(timeout=remaining)
def _update(self, connectivity):
with self._condition:
if (not self._cancelled and
connectivity is interfaces.ChannelConnectivity.READY):
self._matured = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancel(self):
with self._condition:
if not self._matured:
self._cancelled = True
self._channel.unsubscribe(self._update)
self._condition.notify_all()
done_callbacks = tuple(self._done_callbacks)
self._done_callbacks = None
else:
return False
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._cancelled and not self._matured
def done(self):
with self._condition:
return self._cancelled or self._matured
def result(self, timeout=None):
self._block(timeout)
return None
def exception(self, timeout=None):
self._block(timeout)
return None
def traceback(self, timeout=None):
self._block(timeout)
return None
def add_done_callback(self, fn):
with self._condition:
if not self._cancelled and not self._matured:
self._done_callbacks.append(fn)
return
fn(self)
def start(self):
with self._condition:
self._channel.subscribe(self._update, try_to_connect=True)
def __del__(self):
with self._condition:
if not self._cancelled and not self._matured:
self._channel.unsubscribe(self._update)
return False
for done_callback in done_callbacks:
callable_util.call_logging_exceptions(
done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
def cancelled(self):
with self._condition:
return self._cancelled
def running(self):
with self._condition:
return not self._cancelled and not self._matured
def done(self):
with self._condition:
return self._cancelled or self._matured
def result(self, timeout=None):
self._block(timeout)
return None
def exception(self, timeout=None):
self._block(timeout)
return None
def traceback(self, timeout=None):
self._block(timeout)
return None
def add_done_callback(self, fn):
with self._condition:
if not self._cancelled and not self._matured:
self._done_callbacks.append(fn)
return
fn(self)
def start(self):
with self._condition:
self._channel.subscribe(self._update, try_to_connect=True)
def __del__(self):
with self._condition:
if not self._cancelled and not self._matured:
self._channel.unsubscribe(self._update)
def channel_ready_future(channel):
"""Creates a future.Future tracking when an implementations.Channel is ready.
"""Creates a future.Future tracking when an implementations.Channel is ready.
Cancelling the returned future.Future does not tell the given
implementations.Channel to abandon attempts it may have been making to
@ -158,7 +157,6 @@ def channel_ready_future(channel):
A future.Future that matures when the given Channel has connectivity
interfaces.ChannelConnectivity.READY.
"""
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future

@ -26,5 +26,3 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -26,5 +26,3 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Defines an enum for classifying RPC methods by streaming semantics."""
import enum
@ -34,9 +33,9 @@ import enum
@enum.unique
class Cardinality(enum.Enum):
"""Describes the streaming semantics of an RPC method."""
"""Describes the streaming semantics of an RPC method."""
UNARY_UNARY = 'request-unary/response-unary'
UNARY_STREAM = 'request-unary/response-streaming'
STREAM_UNARY = 'request-streaming/response-unary'
STREAM_STREAM = 'request-streaming/response-streaming'
UNARY_UNARY = 'request-unary/response-unary'
UNARY_STREAM = 'request-unary/response-streaming'
STREAM_UNARY = 'request-streaming/response-unary'
STREAM_STREAM = 'request-streaming/response-streaming'

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Defines an enum for classifying RPC methods by control flow semantics."""
import enum
@ -34,7 +33,7 @@ import enum
@enum.unique
class Service(enum.Enum):
"""Describes the control flow style of RPC method implementation."""
"""Describes the control flow style of RPC method implementation."""
INLINE = 'inline'
EVENT = 'event'
INLINE = 'inline'
EVENT = 'event'

@ -26,5 +26,3 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -26,12 +26,11 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Utilities for indicating abandonment of computation."""
class Abandoned(Exception):
"""Indicates that some computation is being abandoned.
"""Indicates that some computation is being abandoned.
Abandoning a computation is different than returning a value or raising
an exception indicating some operational or programming defect.

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Utilities for working with callables."""
import abc
@ -39,7 +38,7 @@ import six
class Outcome(six.with_metaclass(abc.ABCMeta)):
"""A sum type describing the outcome of some call.
"""A sum type describing the outcome of some call.
Attributes:
kind: One of Kind.RETURNED or Kind.RAISED respectively indicating that the
@ -50,31 +49,31 @@ class Outcome(six.with_metaclass(abc.ABCMeta)):
Kind.RAISED.
"""
@enum.unique
class Kind(enum.Enum):
"""Identifies the general kind of the outcome of some call."""
@enum.unique
class Kind(enum.Enum):
"""Identifies the general kind of the outcome of some call."""
RETURNED = object()
RAISED = object()
RETURNED = object()
RAISED = object()
class _EasyOutcome(
collections.namedtuple(
'_EasyOutcome', ['kind', 'return_value', 'exception']),
Outcome):
"""A trivial implementation of Outcome."""
collections.namedtuple('_EasyOutcome',
['kind', 'return_value', 'exception']), Outcome):
"""A trivial implementation of Outcome."""
def _call_logging_exceptions(behavior, message, *args, **kwargs):
try:
return _EasyOutcome(Outcome.Kind.RETURNED, behavior(*args, **kwargs), None)
except Exception as e: # pylint: disable=broad-except
logging.exception(message)
return _EasyOutcome(Outcome.Kind.RAISED, None, e)
try:
return _EasyOutcome(Outcome.Kind.RETURNED,
behavior(*args, **kwargs), None)
except Exception as e: # pylint: disable=broad-except
logging.exception(message)
return _EasyOutcome(Outcome.Kind.RAISED, None, e)
def with_exceptions_logged(behavior, message):
"""Wraps a callable in a try-except that logs any exceptions it raises.
"""Wraps a callable in a try-except that logs any exceptions it raises.
Args:
behavior: Any callable.
@ -86,14 +85,16 @@ def with_exceptions_logged(behavior, message):
future.Outcome describing whether the given behavior returned a value or
raised an exception.
"""
@functools.wraps(behavior)
def wrapped_behavior(*args, **kwargs):
return _call_logging_exceptions(behavior, message, *args, **kwargs)
return wrapped_behavior
@functools.wraps(behavior)
def wrapped_behavior(*args, **kwargs):
return _call_logging_exceptions(behavior, message, *args, **kwargs)
return wrapped_behavior
def call_logging_exceptions(behavior, message, *args, **kwargs):
"""Calls a behavior in a try-except that logs any exceptions it raises.
"""Calls a behavior in a try-except that logs any exceptions it raises.
Args:
behavior: Any callable.
@ -105,4 +106,4 @@ def call_logging_exceptions(behavior, message, *args, **kwargs):
An Outcome describing whether the given behavior returned a value or raised
an exception.
"""
return _call_logging_exceptions(behavior, message, *args, **kwargs)
return _call_logging_exceptions(behavior, message, *args, **kwargs)

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A Future interface.
Python doesn't have a Future interface in its standard library. In the absence
@ -53,33 +52,33 @@ import six
class TimeoutError(Exception):
"""Indicates that a particular call timed out."""
"""Indicates that a particular call timed out."""
class CancelledError(Exception):
"""Indicates that the computation underlying a Future was cancelled."""
"""Indicates that the computation underlying a Future was cancelled."""
class Future(six.with_metaclass(abc.ABCMeta)):
"""A representation of a computation in another control flow.
"""A representation of a computation in another control flow.
Computations represented by a Future may be yet to be begun, may be ongoing,
or may have already completed.
"""
# NOTE(nathaniel): This isn't the return type that I would want to have if it
# were up to me. Were this interface being written from scratch, the return
# type of this method would probably be a sum type like:
#
# NOT_COMMENCED
# COMMENCED_AND_NOT_COMPLETED
# PARTIAL_RESULT<Partial_Result_Type>
# COMPLETED<Result_Type>
# UNCANCELLABLE
# NOT_IMMEDIATELY_DETERMINABLE
@abc.abstractmethod
def cancel(self):
"""Attempts to cancel the computation.
# NOTE(nathaniel): This isn't the return type that I would want to have if it
# were up to me. Were this interface being written from scratch, the return
# type of this method would probably be a sum type like:
#
# NOT_COMMENCED
# COMMENCED_AND_NOT_COMPLETED
# PARTIAL_RESULT<Partial_Result_Type>
# COMPLETED<Result_Type>
# UNCANCELLABLE
# NOT_IMMEDIATELY_DETERMINABLE
@abc.abstractmethod
def cancel(self):
"""Attempts to cancel the computation.
This method does not block.
@ -92,25 +91,25 @@ class Future(six.with_metaclass(abc.ABCMeta)):
remote system for which a determination of whether or not it commenced
before being cancelled cannot be made without blocking.
"""
raise NotImplementedError()
# NOTE(nathaniel): Here too this isn't the return type that I'd want this
# method to have if it were up to me. I think I'd go with another sum type
# like:
#
# NOT_CANCELLED (this object's cancel method hasn't been called)
# NOT_COMMENCED
# COMMENCED_AND_NOT_COMPLETED
# PARTIAL_RESULT<Partial_Result_Type>
# COMPLETED<Result_Type>
# UNCANCELLABLE
# NOT_IMMEDIATELY_DETERMINABLE
#
# Notice how giving the cancel method the right semantics obviates most
# reasons for this method to exist.
@abc.abstractmethod
def cancelled(self):
"""Describes whether the computation was cancelled.
raise NotImplementedError()
# NOTE(nathaniel): Here too this isn't the return type that I'd want this
# method to have if it were up to me. I think I'd go with another sum type
# like:
#
# NOT_CANCELLED (this object's cancel method hasn't been called)
# NOT_COMMENCED
# COMMENCED_AND_NOT_COMPLETED
# PARTIAL_RESULT<Partial_Result_Type>
# COMPLETED<Result_Type>
# UNCANCELLABLE
# NOT_IMMEDIATELY_DETERMINABLE
#
# Notice how giving the cancel method the right semantics obviates most
# reasons for this method to exist.
@abc.abstractmethod
def cancelled(self):
"""Describes whether the computation was cancelled.
This method does not block.
@ -120,11 +119,11 @@ class Future(six.with_metaclass(abc.ABCMeta)):
not limited to this object's cancel method not having been called and
the computation's result having become immediately available.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def running(self):
"""Describes whether the computation is taking place.
@abc.abstractmethod
def running(self):
"""Describes whether the computation is taking place.
This method does not block.
@ -133,15 +132,15 @@ class Future(six.with_metaclass(abc.ABCMeta)):
taking place now, or False if the computation took place in the past or
was cancelled.
"""
raise NotImplementedError()
raise NotImplementedError()
# NOTE(nathaniel): These aren't quite the semantics I'd like here either. I
# would rather this only returned True in cases in which the underlying
# computation completed successfully. A computation's having been cancelled
# conflicts with considering that computation "done".
@abc.abstractmethod
def done(self):
"""Describes whether the computation has taken place.
# NOTE(nathaniel): These aren't quite the semantics I'd like here either. I
# would rather this only returned True in cases in which the underlying
# computation completed successfully. A computation's having been cancelled
# conflicts with considering that computation "done".
@abc.abstractmethod
def done(self):
"""Describes whether the computation has taken place.
This method does not block.
@ -150,11 +149,11 @@ class Future(six.with_metaclass(abc.ABCMeta)):
unscheduled or interrupted. False if the computation may possibly be
executing or scheduled to execute later.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def result(self, timeout=None):
"""Accesses the outcome of the computation or raises its exception.
@abc.abstractmethod
def result(self, timeout=None):
"""Accesses the outcome of the computation or raises its exception.
This method may return immediately or may block.
@ -173,11 +172,11 @@ class Future(six.with_metaclass(abc.ABCMeta)):
Exception: If the computation raised an exception, this call will raise
the same exception.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def exception(self, timeout=None):
"""Return the exception raised by the computation.
@abc.abstractmethod
def exception(self, timeout=None):
"""Return the exception raised by the computation.
This method may return immediately or may block.
@ -196,11 +195,11 @@ class Future(six.with_metaclass(abc.ABCMeta)):
terminate within the allotted time.
CancelledError: If the computation was cancelled.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def traceback(self, timeout=None):
"""Access the traceback of the exception raised by the computation.
@abc.abstractmethod
def traceback(self, timeout=None):
"""Access the traceback of the exception raised by the computation.
This method may return immediately or may block.
@ -219,11 +218,11 @@ class Future(six.with_metaclass(abc.ABCMeta)):
terminate within the allotted time.
CancelledError: If the computation was cancelled.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def add_done_callback(self, fn):
"""Adds a function to be called at completion of the computation.
@abc.abstractmethod
def add_done_callback(self, fn):
"""Adds a function to be called at completion of the computation.
The callback will be passed this Future object describing the outcome of
the computation.
@ -234,4 +233,4 @@ class Future(six.with_metaclass(abc.ABCMeta)):
Args:
fn: A callable taking this Future object as its single parameter.
"""
raise NotImplementedError()
raise NotImplementedError()

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A thread pool that logs exceptions raised by tasks executed within it."""
import logging
@ -35,42 +34,46 @@ from concurrent import futures
def _wrap(behavior):
"""Wraps an arbitrary callable behavior in exception-logging."""
def _wrapping(*args, **kwargs):
try:
return behavior(*args, **kwargs)
except Exception as e:
logging.exception(
'Unexpected exception from %s executed in logging pool!', behavior)
raise
return _wrapping
"""Wraps an arbitrary callable behavior in exception-logging."""
def _wrapping(*args, **kwargs):
try:
return behavior(*args, **kwargs)
except Exception as e:
logging.exception(
'Unexpected exception from %s executed in logging pool!',
behavior)
raise
return _wrapping
class _LoggingPool(object):
"""An exception-logging futures.ThreadPoolExecutor-compatible thread pool."""
"""An exception-logging futures.ThreadPoolExecutor-compatible thread pool."""
def __init__(self, backing_pool):
self._backing_pool = backing_pool
def __init__(self, backing_pool):
self._backing_pool = backing_pool
def __enter__(self):
return self
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._backing_pool.shutdown(wait=True)
def __exit__(self, exc_type, exc_val, exc_tb):
self._backing_pool.shutdown(wait=True)
def submit(self, fn, *args, **kwargs):
return self._backing_pool.submit(_wrap(fn), *args, **kwargs)
def submit(self, fn, *args, **kwargs):
return self._backing_pool.submit(_wrap(fn), *args, **kwargs)
def map(self, func, *iterables, **kwargs):
return self._backing_pool.map(
_wrap(func), *iterables, timeout=kwargs.get('timeout', None))
def map(self, func, *iterables, **kwargs):
return self._backing_pool.map(_wrap(func),
*iterables,
timeout=kwargs.get('timeout', None))
def shutdown(self, wait=True):
self._backing_pool.shutdown(wait=wait)
def shutdown(self, wait=True):
self._backing_pool.shutdown(wait=wait)
def pool(max_workers):
"""Creates a thread pool that logs exceptions raised by the tasks within it.
"""Creates a thread pool that logs exceptions raised by the tasks within it.
Args:
max_workers: The maximum number of worker threads to allow the pool.
@ -79,4 +82,4 @@ def pool(max_workers):
A futures.ThreadPoolExecutor-compatible thread pool that logs exceptions
raised by the tasks executed within it.
"""
return _LoggingPool(futures.ThreadPoolExecutor(max_workers))
return _LoggingPool(futures.ThreadPoolExecutor(max_workers))

@ -26,35 +26,35 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces related to streams of values or objects."""
import abc
import six
class Consumer(six.with_metaclass(abc.ABCMeta)):
"""Interface for consumers of finite streams of values or objects."""
"""Interface for consumers of finite streams of values or objects."""
@abc.abstractmethod
def consume(self, value):
"""Accepts a value.
@abc.abstractmethod
def consume(self, value):
"""Accepts a value.
Args:
value: Any value accepted by this Consumer.
"""
raise NotImplementedError()
raise NotImplementedError()
@abc.abstractmethod
def terminate(self):
"""Indicates to this Consumer that no more values will be supplied."""
raise NotImplementedError()
@abc.abstractmethod
def terminate(self):
"""Indicates to this Consumer that no more values will be supplied."""
raise NotImplementedError()
@abc.abstractmethod
def consume_and_terminate(self, value):
"""Supplies a value and signals that no more values will be supplied.
@abc.abstractmethod
def consume_and_terminate(self, value):
"""Supplies a value and signals that no more values will be supplied.
Args:
value: Any value accepted by this Consumer.
"""
raise NotImplementedError()
raise NotImplementedError()

@ -26,7 +26,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Helpful utilities related to the stream module."""
import logging
@ -38,126 +37,126 @@ _NO_VALUE = object()
class TransformingConsumer(stream.Consumer):
"""A stream.Consumer that passes a transformation of its input to another."""
"""A stream.Consumer that passes a transformation of its input to another."""
def __init__(self, transformation, downstream):
self._transformation = transformation
self._downstream = downstream
def __init__(self, transformation, downstream):
self._transformation = transformation
self._downstream = downstream
def consume(self, value):
self._downstream.consume(self._transformation(value))
def consume(self, value):
self._downstream.consume(self._transformation(value))
def terminate(self):
self._downstream.terminate()
def terminate(self):
self._downstream.terminate()
def consume_and_terminate(self, value):
self._downstream.consume_and_terminate(self._transformation(value))
def consume_and_terminate(self, value):
self._downstream.consume_and_terminate(self._transformation(value))
class IterableConsumer(stream.Consumer):
"""A Consumer that when iterated over emits the values it has consumed."""
def __init__(self):
self._condition = threading.Condition()
self._values = []
self._active = True
def consume(self, stock_reply):
with self._condition:
if self._active:
self._values.append(stock_reply)
self._condition.notify()
def terminate(self):
with self._condition:
self._active = False
self._condition.notify()
def consume_and_terminate(self, stock_reply):
with self._condition:
if self._active:
self._values.append(stock_reply)
self._active = False
self._condition.notify()
def __iter__(self):
return self
def __next__(self):
return self.next()
def next(self):
with self._condition:
while self._active and not self._values:
self._condition.wait()
if self._values:
return self._values.pop(0)
else:
raise StopIteration()
"""A Consumer that when iterated over emits the values it has consumed."""
def __init__(self):
self._condition = threading.Condition()
self._values = []
self._active = True
def consume(self, stock_reply):
with self._condition:
if self._active:
self._values.append(stock_reply)
self._condition.notify()
def terminate(self):
with self._condition:
self._active = False
self._condition.notify()
def consume_and_terminate(self, stock_reply):
with self._condition:
if self._active:
self._values.append(stock_reply)
self._active = False
self._condition.notify()
def __iter__(self):
return self
def __next__(self):
return self.next()
def next(self):
with self._condition:
while self._active and not self._values:
self._condition.wait()
if self._values:
return self._values.pop(0)
else:
raise StopIteration()
class ThreadSwitchingConsumer(stream.Consumer):
"""A Consumer decorator that affords serialization and asynchrony."""
def __init__(self, sink, pool):
self._lock = threading.Lock()
self._sink = sink
self._pool = pool
# True if self._spin has been submitted to the pool to be called once and
# that call has not yet returned, False otherwise.
self._spinning = False
self._values = []
self._active = True
def _spin(self, sink, value, terminate):
while True:
try:
if value is _NO_VALUE:
sink.terminate()
elif terminate:
sink.consume_and_terminate(value)
else:
sink.consume(value)
except Exception as e: # pylint:disable=broad-except
logging.exception(e)
with self._lock:
if terminate:
self._spinning = False
return
elif self._values:
value = self._values.pop(0)
terminate = not self._values and not self._active
elif not self._active:
value = _NO_VALUE
terminate = True
else:
self._spinning = False
return
def consume(self, value):
with self._lock:
if self._active:
if self._spinning:
self._values.append(value)
else:
self._pool.submit(self._spin, self._sink, value, False)
self._spinning = True
def terminate(self):
with self._lock:
if self._active:
self._active = False
if not self._spinning:
self._pool.submit(self._spin, self._sink, _NO_VALUE, True)
self._spinning = True
def consume_and_terminate(self, value):
with self._lock:
if self._active:
self._active = False
if self._spinning:
self._values.append(value)
else:
self._pool.submit(self._spin, self._sink, value, True)
self._spinning = True
"""A Consumer decorator that affords serialization and asynchrony."""
def __init__(self, sink, pool):
self._lock = threading.Lock()
self._sink = sink
self._pool = pool
# True if self._spin has been submitted to the pool to be called once and
# that call has not yet returned, False otherwise.
self._spinning = False
self._values = []
self._active = True
def _spin(self, sink, value, terminate):
while True:
try:
if value is _NO_VALUE:
sink.terminate()
elif terminate:
sink.consume_and_terminate(value)
else:
sink.consume(value)
except Exception as e: # pylint:disable=broad-except
logging.exception(e)
with self._lock:
if terminate:
self._spinning = False
return
elif self._values:
value = self._values.pop(0)
terminate = not self._values and not self._active
elif not self._active:
value = _NO_VALUE
terminate = True
else:
self._spinning = False
return
def consume(self, value):
with self._lock:
if self._active:
if self._spinning:
self._values.append(value)
else:
self._pool.submit(self._spin, self._sink, value, False)
self._spinning = True
def terminate(self):
with self._lock:
if self._active:
self._active = False
if not self._spinning:
self._pool.submit(self._spin, self._sink, _NO_VALUE, True)
self._spinning = True
def consume_and_terminate(self, value):
with self._lock:
if self._active:
self._active = False
if self._spinning:
self._values.append(value)
else:
self._pool.submit(self._spin, self._sink, value, True)
self._spinning = True

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

Loading…
Cancel
Save