Merge github.com:grpc/grpc into xoxo

pull/5527/head
Craig Tiller 9 years ago
commit 239d6d5341
  1. 19
      CONTRIBUTING.md
  2. 217
      INSTALL
  3. 57
      INSTALL.md
  4. 72
      Makefile
  5. 2
      README.md
  6. 21
      build.yaml
  7. 11
      composer.json
  8. 5
      doc/interop-test-descriptions.md
  9. 447
      examples/README.md
  10. 17
      examples/cpp/README.md
  11. 2
      examples/cpp/cpptutorial.md
  12. 2
      examples/cpp/helloworld/README.md
  13. 2
      examples/node/README.md
  14. 10
      examples/php/README.md
  15. 11
      examples/php/composer.json
  16. 6
      examples/php/greeter_client.php
  17. 6
      examples/php/route_guide/route_guide_client.php
  18. 4
      examples/python/route_guide/route_guide_server.py
  19. 1
      grpc.def
  20. 1
      include/grpc++/impl/codegen/completion_queue.h
  21. 3
      include/grpc++/impl/codegen/server_context.h
  22. 4
      include/grpc/impl/codegen/sync.h
  23. 2
      package.xml
  24. 9
      setup.py
  25. 31
      src/core/channel/client_channel.c
  26. 2
      src/core/channel/client_uchannel.c
  27. 6
      src/core/channel/subchannel_call_holder.c
  28. 6
      src/core/client_config/client_config.c
  29. 2
      src/core/client_config/lb_policies/pick_first.c
  30. 57
      src/core/client_config/resolvers/dns_resolver.c
  31. 24
      src/core/client_config/subchannel.c
  32. 14
      src/core/iomgr/iocp_windows.c
  33. 11
      src/core/iomgr/iocp_windows.h
  34. 16
      src/core/iomgr/iomgr.c
  35. 6
      src/core/iomgr/iomgr_internal.h
  36. 7
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  37. 6
      src/core/iomgr/resolve_address.h
  38. 19
      src/core/iomgr/resolve_address_posix.c
  39. 19
      src/core/iomgr/resolve_address_windows.c
  40. 3
      src/core/iomgr/tcp_server_windows.c
  41. 16
      src/core/iomgr/timer.c
  42. 1
      src/core/iomgr/timer.h
  43. 22
      src/core/iomgr/timer_heap.c
  44. 4
      src/core/support/alloc.c
  45. 7
      src/core/support/sync.c
  46. 2
      src/core/surface/completion_queue.c
  47. 14
      src/core/surface/server.c
  48. 21
      src/core/transport/chttp2/internal.h
  49. 6
      src/core/transport/chttp2/parsing.c
  50. 38
      src/core/transport/chttp2/stream_lists.c
  51. 37
      src/core/transport/chttp2/writing.c
  52. 99
      src/core/transport/chttp2_transport.c
  53. 8
      src/core/transport/metadata.c
  54. 2
      src/core/transport/transport.c
  55. 12
      src/core/transport/transport.h
  56. 76
      src/core/tsi/ssl_transport_security.c
  57. 5
      src/core/tsi/ssl_transport_security.h
  58. 74
      src/cpp/README.md
  59. 26
      src/cpp/server/server_context.cc
  60. 10
      src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
  61. 2
      src/csharp/Grpc.Core/Metadata.cs
  62. 4
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  63. 2
      src/node/README.md
  64. 3
      src/node/interop/interop_client.js
  65. 119
      src/node/src/client.js
  66. 8
      src/node/test/surface_test.js
  67. 37
      src/objective-c/GRPCClient/GRPCCall.m
  68. 3
      src/objective-c/GRPCClient/private/GRPCChannel.h
  69. 14
      src/objective-c/GRPCClient/private/GRPCChannel.m
  70. 9
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
  71. 33
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  72. 77
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  73. 192
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  74. 26
      src/objective-c/GRPCClient/private/GRPCHost.h
  75. 97
      src/objective-c/GRPCClient/private/GRPCHost.m
  76. 65
      src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
  77. 2
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  78. 43
      src/objective-c/RxLibrary/GRXWriteable.m
  79. 2
      src/objective-c/tests/GRPCClientTests.m
  80. 51
      src/objective-c/tests/RxLibraryUnitTests.m
  81. 117
      src/php/README.md
  82. 6
      src/php/composer.json
  83. 67
      src/php/ext/grpc/README.md
  84. 6
      src/php/tests/generated_code/math_client.php
  85. 1
      src/proto/grpc/testing/echo_messages.proto
  86. 26
      src/python/grpcio/README.rst
  87. 39
      src/python/grpcio/commands.py
  88. 1
      src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
  89. 7
      src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
  90. 45
      src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
  91. 2
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  92. 1
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
  93. 2
      src/python/grpcio/grpc/_cython/imports.generated.c
  94. 3
      src/python/grpcio/grpc/_cython/imports.generated.h
  95. 13
      src/python/grpcio/precompiled.py
  96. 24
      src/python/grpcio/tests/_runner.py
  97. 53
      src/python/grpcio/tests/tests.json
  98. 30
      src/python/grpcio/tests/unit/_sanity/__init__.py
  99. 53
      src/python/grpcio/tests/unit/_sanity/_sanity_test.py
  100. 381
      src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -13,7 +13,7 @@ In order to protect both you and ourselves, you will need to sign the
### Technical requirements
You will need several tools to work with this repository. In addition to all of
the packages described in the [INSTALL](INSTALL) file, you will also need
the packages described in the [INSTALL](INSTALL.md) file, you will also need
python, and the mako template renderer. To install the latter, using pip, one
should simply be able to do `pip install mako`.
@ -21,6 +21,15 @@ In order to run all of the tests we provide, you will need valgrind and clang.
More specifically, under debian, you will need the package libc++-dev to
properly run all the tests.
Compiling and running grpc C++ tests depend on protobuf 3.0.0, gtest and gflags.
Although gflags is provided in third_party, you will need to manually install
that dependency on your system to run these tests. Under a Debian or Ubuntu
system, you can install the gtests and gflags packages using apt-get:
```sh
$ [sudo] apt-get install libgflags-dev libgtest-dev
```
If you are planning to work on any of the languages other than C and C++, you
will also need their appropriate development environments.
@ -36,9 +45,13 @@ In order to run most of the available tests, one would need to run:
`./tools/run_tests/run_tests.py`
If you want to run all the possible tests for any of the languages {c, c++, node, php, python}, do this:
If you want to run tests for any of the languages {c, c++, csharp, node, objc, php, python, ruby}, do this:
`./tools/run_tests/run_tests.py -l <lang>`
To know about the list of available commands, do this:
`./tools/run_tests/run_tests.py -l <lang> -c all`
`./tools/run_tests/run_tests.py -h`
## Adding or removing source code

@ -1,217 +0,0 @@
These instructions only cover building grpc C and C++ libraries under
typical unix systems. If you need more information, please try grpc's
wiki pages:
https://github.com/google/grpc/wiki
*************************
* If you are in a hurry *
*************************
On Linux (Debian):
Note: you will need to add the Debian 'jessie-backports' distribution to your sources
file first.
Add the following line to your `/etc/apt/sources.list` file:
deb http://http.debian.net/debian jessie-backports main
Install the gRPC library:
$ [sudo] apt-get install libgrpc-dev
OR
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git submodule update --init
$ make
$ [sudo] make install
You don't need anything else than GNU Make, gcc and autotools. Under a Debian
or Ubuntu system, this should boil down to the following packages:
$ [sudo] apt-get install build-essential autoconf libtool
Building the python wrapper requires the following:
$ [sudo] apt-get install python-all-dev python-virtualenv
If you want to install in a different directory than the default /usr/lib, you can
override it on the command line:
$ [sudo] make install prefix=/opt
*******************************
* More detailled instructions *
*******************************
Setting up dependencies
=======================
Dependencies to compile the libraries
-------------------------------------
grpc libraries have few external dependencies. If you need to compile and
install them, they are present in the third_party directory if you have
cloned the github repository recursively. If you didn't clone recursively,
you can still get them later by running the following command:
$ git submodule update --init
Note that the Makefile makes it much easier for you to compile from sources
if you were to clone recursively our git repository: it will automatically
compile zlib and OpenSSL, which are core requirements for grpc. Note this
creates grpc libraries that will have zlib and OpenSSL built-in inside of them,
which significantly increases the libraries' size.
In order to decrease that size, you can manually install zlib and OpenSSL on
your system, so that the Makefile can use them instead.
Under a Debian or Ubuntu system, one can acquire the development package
for zlib this way:
# apt-get install zlib1g-dev
To the best of our knowledge, no distribution has an OpenSSL package that
supports ALPN yet, so you would still have to depend on installing from source
for that particular dependency if you want to reduce the libraries' size.
The recommended version of OpenSSL that provides ALPN support is available
at this URL:
https://www.openssl.org/source/openssl-1.0.2.tar.gz
Dependencies to compile and run the tests
-----------------------------------------
Compiling and running grpc plain-C tests dont't require any more dependency.
Compiling and running grpc C++ tests depend on protobuf 3.0.0, gtest and
gflags. Although gflags is provided in third_party, you will need to manually
install that dependency on your system to run these tests.
Under a Debian or Ubuntu system, you can install the gtests and gflags packages
using apt-get:
# apt-get install libgflags-dev libgtest-dev
However, protobuf 3.0.0 isn't in a debian package yet, but the Makefile will
automatically try and compile the one present in third_party if you cloned the
repository recursively, and that it detects your system is lacking it.
Compiling and installing protobuf 3.0.0 requires a few more dependencies in
itself, notably the autoconf suite. If you have apt-get, you can install
these dependencies this way:
# apt-get install autoconf libtool
If you want to run the tests using one of the sanitized configurations, you
will need clang and its instrumented libc++:
# apt-get install clang libc++-dev
Mac-specific notes:
-------------------
For a Mac system, git is not available by default. You will first need to
install Xcode from the Mac AppStore and then run the following command from a
terminal:
$ sudo xcode-select --install
You should also install "port" following the instructions at
https://www.macports.org . This will reside in /opt/local/bin/port for
most Mac installations. Do the "git submodule" command listed above.
Then execute the following for all the needed build dependencies
$ sudo /opt/local/bin/port install autoconf automake libtool gflags cmake
$ mkdir ~/gtest-svn
$ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
$ mkdir mybuild
$ cd mybuild
$ cmake ../gtest-svn
$ make
$ make gtest.a gtest_main.a
$ sudo cp libgtest.a libgtest_main.a /opt/local/lib
$ sudo mkdir /opt/local/include/gtest
$ sudo cp -pr ../gtest-svn/include/gtest /opt/local/include/gtest
If you are going to make changes and need to regenerate the projects file,
you will need to install certain modules for python.
$ sudo easy_install simplejson mako
Mingw-specific notes:
---------------------
While gRPC compiles properly under mingw, some more preparation work is needed.
The recommendation is to use msys2. The installation instructions are available
at that address: http://msys2.github.io/
Once this is installed, make sure you are using the following: MinGW-w64 Win64.
You'll be required to install a few more packages:
$ pacman -S make mingw-w64-x86_64-gcc mingw-w64-x86_64-zlib autoconf automake libtool
Please also install OpenSSL from that website:
http://slproweb.com/products/Win32OpenSSL.html
The package Win64 OpenSSL v1.0.2a should do. At that point you should be able
to compile gRPC with the following:
$ export LDFLAGS="-L/mingw64/lib -L/c/OpenSSL-Win64"
$ export CPPFLAGS="-I/mingw64/include -I/c/OpenSSL-Win64/include"
$ make
A word on OpenSSL
-----------------
Secure HTTP2 requires the TLS extension ALPN (see rfc 7301 and
http://http2.github.io/http2-spec/ section 3.3). Our HTTP2 implementation
relies on OpenSSL's implementation. OpenSSL 1.0.2 is the first released version
of OpenSSL that has ALPN support, and this explains our dependency on it.
Note that the Makefile supports compiling only the unsecure elements of grpc,
and if you do not have OpenSSL and do not want it, you can still proceed
with installing only the elements you require. However, we strongly recommend
the use of encryption for all network traffic, and discourage the use of grpc
without TLS.
Compiling
=========
If you have all the dependencies mentioned above, you should simply be able
to go ahead and run "make" to compile grpc's C and C++ libraries:
$ make
Testing
=======
To build and run the tests, you can run the command:
$ make test
If you want to be able to run them in parallel, and get better output, you can
also use the python tool we have written:
$ ./tools/run_tests/run_tests.py
Installing
==========
Once everything is compiled, you should be able to install grpc C and C++
libraries and headers:
# make install

@ -0,0 +1,57 @@
#If you are in a hurry
For language-specific installation instructions for gRPC runtime, please
refer to these documents
* [C++](examples/cpp): Currently to install gRPC for C++, you need to build from source as described below.
* [C#](src/csharp): NuGet package `Grpc`
* [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc`
* [Java](https://github.com/grpc/grpc-java)
* [Node](src/node): `npm install grpc`
* [Objective-C](src/objective-c)
* [PHP](src/php): `pecl install grpc-beta`
* [Python](src/python/grpcio): `pip install grpcio`
* [Ruby](src/ruby): `gem install grpc`
#Pre-requisites
##Linux
```sh
$ [sudo] apt-get install build-essential autoconf libtool
```
##Mac OSX
For a Mac system, git is not available by default. You will first need to
install Xcode from the Mac AppStore and then run the following command from a
terminal:
```sh
$ [sudo] xcode-select --install
```
##Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
you will need the `protoc` compiler to generate stub server and client code.
If you compile gRPC from source, as described below, the Makefile will
automatically try and compile the `protoc` in third_party if you cloned the
repository recursively and it detects that you don't already have it
installed.
#Build from Source
For developers who are interested to contribute, here is how to compile the
gRPC C Core library.
```sh
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git submodule update --init
$ make
$ [sudo] make install
```

@ -849,6 +849,8 @@ chttp2_status_conversion_test: $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test
chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
compression_test: $(BINDIR)/$(CONFIG)/compression_test
concurrent_connectivity_test: $(BINDIR)/$(CONFIG)/concurrent_connectivity_test
dns_resolver_connectivity_test: $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
dns_resolver_test: $(BINDIR)/$(CONFIG)/dns_resolver_test
dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
@ -1159,6 +1161,8 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
$(BINDIR)/$(CONFIG)/chttp2_varint_test \
$(BINDIR)/$(CONFIG)/compression_test \
$(BINDIR)/$(CONFIG)/concurrent_connectivity_test \
$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test \
$(BINDIR)/$(CONFIG)/dns_resolver_test \
$(BINDIR)/$(CONFIG)/dualstack_socket_test \
$(BINDIR)/$(CONFIG)/endpoint_pair_test \
@ -1402,6 +1406,10 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
$(E) "[RUN] Testing compression_test"
$(Q) $(BINDIR)/$(CONFIG)/compression_test || ( echo test compression_test failed ; exit 1 )
$(E) "[RUN] Testing concurrent_connectivity_test"
$(Q) $(BINDIR)/$(CONFIG)/concurrent_connectivity_test || ( echo test concurrent_connectivity_test failed ; exit 1 )
$(E) "[RUN] Testing dns_resolver_connectivity_test"
$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test || ( echo test dns_resolver_connectivity_test failed ; exit 1 )
$(E) "[RUN] Testing dns_resolver_test"
$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_test || ( echo test dns_resolver_test failed ; exit 1 )
$(E) "[RUN] Testing dualstack_socket_test"
@ -6075,6 +6083,70 @@ endif
endif
CONCURRENT_CONNECTIVITY_TEST_SRC = \
test/core/surface/concurrent_connectivity_test.c \
CONCURRENT_CONNECTIVITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CONCURRENT_CONNECTIVITY_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/concurrent_connectivity_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/concurrent_connectivity_test: $(CONCURRENT_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(CONCURRENT_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/concurrent_connectivity_test
endif
$(OBJDIR)/$(CONFIG)/test/core/surface/concurrent_connectivity_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_concurrent_connectivity_test: $(CONCURRENT_CONNECTIVITY_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(CONCURRENT_CONNECTIVITY_TEST_OBJS:.o=.dep)
endif
endif
DNS_RESOLVER_CONNECTIVITY_TEST_SRC = \
test/core/client_config/resolvers/dns_resolver_connectivity_test.c \
DNS_RESOLVER_CONNECTIVITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DNS_RESOLVER_CONNECTIVITY_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
endif
$(OBJDIR)/$(CONFIG)/test/core/client_config/resolvers/dns_resolver_connectivity_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
endif
endif
DNS_RESOLVER_TEST_SRC = \
test/core/client_config/resolvers/dns_resolver_test.c \

@ -13,7 +13,7 @@ You can find more detailed documentation and examples in the [doc](doc) and [exa
#Installation
See [grpc/INSTALL](INSTALL) for installation instructions for various platforms.
See [INSTALL](INSTALL.md) for installation instructions for various platforms.
#Repository Structure & Status

@ -1057,6 +1057,27 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: concurrent_connectivity_test
build: test
language: c
src:
- test/core/surface/concurrent_connectivity_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: dns_resolver_connectivity_test
cpu_cost: 0.1
build: test
language: c
src:
- test/core/client_config/resolvers/dns_resolver_connectivity_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: dns_resolver_test
build: test
language: c

@ -2,13 +2,20 @@
"name": "grpc/grpc",
"type": "library",
"description": "gRPC library for PHP",
"version": "0.6.0",
"version": "0.14.0",
"keywords": ["rpc"],
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/stanley-cheung/Protobuf-PHP"
}
],
"require": {
"php": ">=5.5.0",
"google/auth": "dev-master"
"datto/protobuf-php": "dev-master",
"google/auth": "v0.7"
},
"autoload": {
"psr-4": {

@ -2,9 +2,8 @@ Interoperability Test Case Descriptions
=======================================
Client and server use
[test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto)
and the [gRPC over HTTP/2 v2
protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).
[test.proto](../src/proto/grpc/testing/test.proto)
and the [gRPC over HTTP/2 v2 protocol](./PROTOCOL-HTTP2.md).
Client
------

@ -1,450 +1,27 @@
# Examples
# Getting started
This directory contains code examples for all the C-based gRPC implementations: C++, Node.js, Python, Ruby, Objective-C, PHP, and C#. You can find examples and instructions specific to your
favourite language in the relevant subdirectory.
Examples for Go and Java gRPC live in their own repositories:
Welcome to the developer documentation for gRPC, a language-neutral,
platform-neutral remote procedure call (RPC) system developed at Google.
* [Java](https://github.com/grpc/grpc-java/tree/master/examples)
* [Android Java](https://github.com/grpc/grpc-java/tree/master/examples/android)
* [Go](https://github.com/grpc/grpc-go/tree/master/examples)
This document introduces you to gRPC with a quick overview and a simple
Hello World example. You'll find more tutorials and reference docs in this repository - more documentation is coming soon!
For more comprehensive documentation, including an [overview](http://www.grpc.io/docs/) and tutorials that use this example code, visit [grpc.io](http://www.grpc.io/docs/).
<a name="quickstart"></a>
## Quick start
You can find quick start guides for each language, including installation instructions, examples, and tutorials here:
Each example directory has quick start instructions for the appropriate language, including installation instructions and how to run our simplest Hello World example:
* [C++](cpp)
* [Java](https://github.com/grpc/grpc-java/tree/master/examples)
* [Go](https://github.com/grpc/grpc-go/tree/master/examples)
* [Ruby](ruby)
* [Node.js](node)
* [Android Java](https://github.com/grpc/grpc-java/tree/master/examples/android)
* [Python](python/helloworld)
* [C#](csharp)
* [Objective-C](objective-c/helloworld)
* [PHP](php)
## What's in this repository?
The `examples` directory contains documentation, resources, and examples
for all gRPC users. You can find examples and instructions specific to your
favourite language in the relevant subdirectory.
You can find out about the gRPC source code repositories in
[`grpc`](https://github.com/grpc/grpc). Each repository provides instructions
for building the appropriate libraries for your language.
## What is gRPC?
In gRPC a *client* application can directly call
methods on a *server* application on a different machine as if it was a
local object, making it easier for you to create distributed applications and
services. As in many RPC systems, gRPC is based around the idea of defining
a *service*, specifying the methods that can be called remotely with their
parameters and return types. On the server side, the server implements this
interface and runs a gRPC server to handle client calls. On the client side,
the client has a *stub* that provides exactly the same methods as the server.
<!--TODO: diagram-->
gRPC clients and servers can run and talk to each other in a variety of
environments - from servers inside Google to your own desktop - and can
be written in any of gRPC's [supported languages](#quickstart). So, for
example, you can easily create a gRPC server in Java with clients in Go,
Python, or Ruby. In addition, the latest Google APIs will have gRPC versions
of their interfaces, letting you easily build Google functionality into
your applications.
<a name="protocolbuffers"></a>
### Working with protocol buffers
By default gRPC uses *protocol buffers*, Google’s
mature open source mechanism for serializing structured data (although it
can be used with other data formats such as JSON). As you'll
see in our example below, you define gRPC services using *proto files*,
with method parameters and return types specified as protocol buffer message
types. You
can find out lots more about protocol buffers in the [Protocol Buffers
documentation](https://developers.google.com/protocol-buffers/docs/overview).
#### Protocol buffer versions
While protocol buffers have been available for open source users for some
time, our examples use a new flavour of protocol buffers called proto3,
which has a slightly simplified syntax, some useful new features, and supports
lots more languages. This is currently available as an alpha release in
Java, C++, Java_nano (Android Java), Python, and Ruby from [the protocol buffers Github
repo](https://github.com/google/protobuf/releases), as well as a Go language
generator from [the golang/protobuf Github repo](https://github.com/golang/protobuf), with more languages in development. You can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3), and see
the major differences from the current default version in the [release notes](https://github.com/google/protobuf/releases). More proto3 documentation is coming soon.
In general, while you *can* use proto2 (the current default protocol buffers version), we recommend that you use proto3 with gRPC as it lets you use the full range of gRPC-supported languages, as well as avoiding compatibility
issues with proto2 clients talking to proto3 servers and vice versa.
<a name="hello"></a>
## Hello gRPC!
Now that you know a bit more about gRPC, the easiest way to see how it
works is to look at a simple example. Our Hello World walks you through the
construction of a simple gRPC client-server application, showing you how to:
- Create a protocol buffers schema that defines a simple RPC service with
a single
Hello World method.
- Create a Java server that implements this interface.
- Create a Java client that accesses the Java server.
- Create a Go client that accesses
the same Java server.
The complete code for the example is available in the `examples`
directory. We use the Git versioning system for source code management:
however, you don't need to know anything about Git to follow along other
than how to install and run a few git commands.
This is an introductory example rather than a comprehensive tutorial, so
don't worry if you're not a Go or
Java developer - the concepts are similar for all languages, and you can
find more implementations of our Hello World example in other languages (and full tutorials where available) in
the [language-specific folders](#quickstart) in this repository. Complete tutorials and
reference documentation for all gRPC languages are coming soon.
<a name="setup"></a>
### Setup
This section explains how to set up your local machine to work with
the example code. If you just want to read the example, you can go straight
to the [next step](#servicedef).
#### Install Git
You can download and install Git from http://git-scm.com/download. Once
installed you should have access to the git command line tool. The main
commands that you will need to use are:
- git clone ... : clone a remote repository onto your local machine
- git checkout ... : check out a particular branch or a tagged version of
the code to hack on
#### Install gRPC
To build and install gRPC plugins and related tools:
- For Java, see the [Java quick start](https://github.com/grpc/grpc-java).
- For Go, see the [Go quick start](https://github.com/grpc/grpc-go).
#### Get the source code
The example code for our Java example lives in the `grpc-java`
GitHub repository. Clone this repository to your local machine by running the
following command:
```
git clone https://github.com/grpc/grpc-java.git
```
Change your current directory to grpc-java/examples
```
cd grpc-java/examples
```
<a name="servicedef"></a>
### Defining a service
The first step in creating our example is to define a *service*: an RPC
service specifies the methods that can be called remotely with their parameters
and return types. As you saw in the
[overview](#protocolbuffers) above, gRPC does this using [protocol
buffers](https://developers.google.com/protocol-buffers/docs/overview). We
use the protocol buffers interface definition language (IDL) to define our
service methods, and define the parameters and return
types as protocol buffer message types. Both the client and the
server use interface code generated from the service definition.
Here's our example service definition, defined using protocol buffers IDL in
[helloworld.proto](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto). The `Greeter`
service has one method, `SayHello`, that lets the server receive a single
`HelloRequest`
message from the remote client containing the user's name, then send back
a greeting in a single `HelloReply`. This is the simplest type of RPC you
can specify in gRPC - you can find out about other types in the tutorial for your chosen language.
```proto
syntax = "proto3";
option java_package = "io.grpc.examples";
package helloworld;
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
```
<a name="generating"></a>
### Generating gRPC code
Once we've defined our service, we use the protocol buffer compiler
`protoc` to generate the special client and server code we need to create
our application - right now we're going to generate Java code, though you
can generate gRPC code in any gRPC-supported language (as you'll see later
in this example). The generated code contains both stub code for clients to
use and an abstract interface for servers to implement, both with the method
defined in our `Greeter` service.
(If you didn't install the gRPC plugins and protoc on your system and are just reading along with
the example, you can skip this step and move
onto the next one where we examine the generated code.)
For simplicity, we've provided a [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) with our Java examples that runs `protoc` for you with the appropriate plugin, input, and output:
```shell
../gradlew build
```
This generates the following classes from our .proto, which contain all the generated code
we need to create our example:
- `Helloworld.java`, which
has all the protocol buffer code to populate, serialize, and retrieve our
`HelloRequest` and `HelloReply` message types
- `GreeterGrpc.java`, which contains (along with some other useful code):
- an interface for `Greeter` servers to implement
```java
public static interface Greeter {
public void sayHello(io.grpc.examples.Helloworld.HelloRequest request,
io.grpc.stub.StreamObserver<io.grpc.examples.Helloworld.HelloReply> responseObserver);
}
```
- _stub_ classes that clients can use to talk to a `Greeter` server. As you can see, they also implement the `Greeter` interface.
```java
public static class GreeterStub extends
io.grpc.stub.AbstractStub<GreeterStub, GreeterServiceDescriptor>
implements Greeter {
...
}
```
<a name="server"></a>
### Writing a server
Now let's write some code! First we'll create a server application to implement
our service. Note that we're not going to go into a lot of detail about how
to create a server in this section. More detailed information will be in the
tutorial for your chosen language: check if there's one available yet in the relevant [quick start](#quickstart).
Our server application has two classes:
- a main server class that hosts the service implementation and allows access over the
network: [HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java).
- a simple service implementation class [GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51).
#### Service implementation
[GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51)
actually implements our `Greeter` service's required behaviour.
As you can see, the class `GreeterImpl` implements the interface
`GreeterGrpc.Greeter` that we [generated](#generating) from our proto
[IDL](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto) by implementing the method `sayHello`:
```java
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onValue(reply);
responseObserver.onCompleted();
}
```
- `sayHello` takes two parameters:
- `HelloRequest`: the request
- `StreamObserver<HelloReply>`: a response observer, which is
a special interface for the server to call with its response
To return our response to the client and complete the call:
1. We construct and populate a `HelloReply` response object with our exciting
message, as specified in our interface definition.
2. We return the `HelloReply` to the client and then specify that we've finished dealing with the RPC.
#### Server implementation
[HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java)
shows the other main feature required to provide a gRPC service; making the service
implementation available from the network.
```java
/* The port on which the server should run */
private int port = 50051;
private ServerImpl server;
private void start() throws Exception {
server = NettyServerBuilder.forPort(port)
.addService(GreeterGrpc.bindService(new GreeterImpl()))
.build().start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// Use stderr here since the logger may have been reset by its JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
HelloWorldServer.this.stop();
System.err.println("*** server shut down");
}
});
}
```
Here we create an appropriate gRPC server, binding the `Greeter` service
implementation that we created to a port. Then we start the server running: the server is now ready to receive
requests from `Greeter` service clients on our specified port. We'll cover
how all this works in a bit more detail in our language-specific documentation.
<a name="client"></a>
### Writing a client
Client-side gRPC is pretty simple. In this step, we'll use the generated code
to write a simple client that can access the `Greeter` server we created
in the [previous section](#server). You can see the complete client code in
[HelloWorldClient.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java).
Again, we're not going to go into much detail about how to implement a client;
we'll leave that for the tutorial.
#### Connecting to the service
First let's look at how we connect to the `Greeter` server. First we need
to create a gRPC channel, specifying the hostname and port of the server we
want to connect to. Then we use the channel to construct the stub instance.
```java
private final ChannelImpl channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
public HelloWorldClient(String host, int port) {
channel =
NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT)
.build();
blockingStub = GreeterGrpc.newBlockingStub(channel);
}
```
In this case, we create a blocking stub. This means that the RPC call waits
for the server to respond, and will either return a response or raise an
exception. gRPC Java has other kinds of stubs that make non-blocking calls
to the server, where the response is returned asynchronously.
#### Calling an RPC
Now we can contact the service and obtain a greeting:
1. We construct and fill in a `HelloRequest` to send to the service.
2. We call the stub's `hello()` RPC with our request and get a `HelloReply`
back, from which we can get our greeting.
```java
HelloRequest req = HelloRequest.newBuilder().setName(name).build();
HelloReply reply = blockingStub.sayHello(req);
```
<a name="run"></a>
### Try it out!
Our [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) simplifies building and running the examples.
You can build and run the server from the `grpc-java` root folder with:
```sh
$ ./gradlew :grpc-examples:helloWorldServer
```
and in another terminal window confirm that it receives a message.
```sh
$ ./gradlew :grpc-examples:helloWorldClient
```
### Adding another client
Finally, let's look at one of gRPC's most useful features - interoperability
between code in different languages. So far, we've just looked at Java code
generated from and implementing our `Greeter` service definition. However,
as you'll see if you look at the language-specific subdirectories
in this repository, we've also generated and implemented `Greeter`
in some of gRPC's other supported languages. Each service
and client uses interface code generated from the same proto
that we used for the Java example.
So, for example, if we visit the [`go` example
directory](https://github.com/grpc/grpc-go/tree/master/examples) and look at the
[`greeter_client`](https://github.com/grpc/grpc-go/blob/master/examples/greeter_client/main.go),
we can see that like the Java client, it connects to a `Greeter` service
at `localhost:50051` and uses a stub to call the `SayHello` method with a
`HelloRequest`:
```go
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address)
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name:
name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
```
If we run the Java server from earlier in another terminal window, we can
run the Go client and connect to it just like the Java client, even though
it's written in a different language.
```
$ greeter_client
```
## Read more!
- You can find links to language-specific tutorials, examples, and other docs in each language's [quick start](#quickstart).
- [gRPC Authentication Support](doc/grpc-auth-support.md) introduces authentication support in gRPC with supported mechanisms and examples.

@ -2,7 +2,7 @@
## Installation
To install gRPC on your system, follow the instructions [here](../../INSTALL).
To install gRPC on your system, follow the instructions to build from source [here](../../INSTALL.md). This also installs the protocol buffer compiler `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
## Hello C++ gRPC!
@ -23,21 +23,6 @@ Change your current directory to examples/cpp/helloworld
$ cd examples/cpp/helloworld/
```
### Generating gRPC code
To generate the client and server side interfaces:
```sh
$ make helloworld.grpc.pb.cc helloworld.pb.cc
```
Which internally invokes the proto-compiler as:
```sh
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
```
### Client and server implementations
The client implementation is at [greeter_client.cc](helloworld/greeter_client.cc).

@ -91,7 +91,7 @@ message Point {
Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC C++ plugin.
For simplicity, we've provided a [makefile](route_guide/Makefile) that runs `protoc` for you with the appropriate plugin, input, and output (if you want to run this yourself, make sure you've installed protoc and followed the gRPC code [installation instructions](../../INSTALL) first):
For simplicity, we've provided a [makefile](route_guide/Makefile) that runs `protoc` for you with the appropriate plugin, input, and output (if you want to run this yourself, make sure you've installed protoc and followed the gRPC code [installation instructions](../../INSTALL.md) first):
```shell
$ make route_guide.grpc.pb.cc route_guide.pb.cc

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

@ -20,7 +20,7 @@ TRY IT!
- Run the server
```sh
$ # from this directory (grpc_common/node).
$ # from this directory
$ node ./greeter_server.js &
```

@ -4,16 +4,15 @@ gRPC in 3 minutes (PHP)
PREREQUISITES
-------------
This requires PHP 5.5 or greater.
This requires `php` >=5.5, `phpize`, `pecl`, `phpunit`
INSTALL
-------
- On Mac OS X, install [homebrew][]. Run the following command to install gRPC.
- Install the gRPC PHP extension
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s php
$ [sudo] pecl install grpc-beta
```
This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
- Clone this repository
@ -37,6 +36,7 @@ TRY IT!
Please follow the instruction in [Node][] to run the server
```
$ cd examples/node
$ npm install
$ nodejs greeter_server.js
```
@ -58,7 +58,5 @@ TUTORIAL
You can find a more detailed tutorial in [gRPC Basics: PHP][]
[homebrew]:http://brew.sh
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/examples/node
[gRPC Basics: PHP]:http://www.grpc.io/docs/tutorials/basic/php.html

@ -1,17 +1,14 @@
{
"name": "grpc/grpc-demo",
"description": "gRPC example for PHP",
"minimum-stability": "dev",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/stanley-cheung/Protobuf-PHP"
}
],
"name": "grpc/grpc-demo",
"description": "gRPC example for PHP",
"minimum-stability": "dev",
"require": {
"php": ">=5.5.0",
"datto/protobuf-php": "dev-master",
"google/auth": "dev-master",
"grpc/grpc": "dev-release-0_11"
"grpc/grpc": "dev-release-0_13"
}
}

@ -1,7 +1,7 @@
<?php
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,7 +36,9 @@ require dirname(__FILE__) . '/vendor/autoload.php';
require dirname(__FILE__) . '/helloworld.php';
function greet($name) {
$client = new helloworld\GreeterClient('localhost:50051', []);
$client = new helloworld\GreeterClient('localhost:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure()
]);
$request = new helloworld\HelloRequest();
$request->setName($name);
list($reply, $status) = $client->SayHello($request)->wait();

@ -1,7 +1,7 @@
<?php
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -37,7 +37,9 @@ require dirname(__FILE__) . '/route_guide.php';
define('COORD_FACTOR', 1e7);
$client = new routeguide\RouteGuideClient('localhost:50051', []);
$client = new routeguide\RouteGuideClient('localhost:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure()
]);
function printFeature($feature) {
$name = $feature->getName();

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc.
# Copyright 2015-2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -128,7 +128,7 @@ def serve():
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop()
server.stop(0)
if __name__ == '__main__':
serve()

@ -182,6 +182,7 @@ EXPORTS
gpr_event_wait
gpr_ref_init
gpr_ref
gpr_ref_non_zero
gpr_refn
gpr_unref
gpr_stats_init

@ -184,6 +184,7 @@ class CompletionQueue : private GrpcLibrary {
bool Pluck(CompletionQueueTag* tag);
/// Performs a single polling pluck on \a tag.
/// \warning Must not be mixed with calls to \a Next.
void TryPluck(CompletionQueueTag* tag);
grpc_completion_queue* cq_; // owned

@ -103,6 +103,9 @@ class ServerContext {
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
// IsCancelled is always safe to call when using sync API
// When using async API, it is only safe to call IsCancelled after
// the AsyncNotifyWhenDone tag has been delivered
bool IsCancelled() const;
// Cancel the Call from the server. This is a best-effort API and depending on

@ -182,6 +182,10 @@ GPRAPI void gpr_ref_init(gpr_refcount *r, int n);
/* Increment the reference count *r. Requires *r initialized. */
GPRAPI void gpr_ref(gpr_refcount *r);
/* Increment the reference count *r. Requires *r initialized.
Crashes if refcount is zero */
GPRAPI void gpr_ref_non_zero(gpr_refcount *r);
/* Increment the reference count *r by n. Requires *r initialized, n > 0. */
GPRAPI void gpr_refn(gpr_refcount *r, int n);

@ -27,9 +27,9 @@
<contents>
<dir baseinstalldir="/" name="/">
<file baseinstalldir="/" name="config.m4" role="src" />
<file baseinstalldir="/" name="src/php/README.md" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/CREDITS" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/LICENSE" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/README.md" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/byte_buffer.c" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/call.c" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/call_credentials.c" role="src" />

@ -108,8 +108,13 @@ if "linux" in sys.platform or "darwin" in sys.platform:
def cython_extensions(package_names, module_names, extra_sources, include_dirs,
libraries, define_macros, build_with_cython=False):
# Set compiler directives linetrace argument only if we care about tracing;
# this is due to Cython having different behavior between linetrace being
# False and linetrace being unset. See issue #5689.
cython_compiler_directives = {}
if ENABLE_CYTHON_TRACING:
define_macros = define_macros + [('CYTHON_TRACE_NOGIL', 1)]
cython_compiler_directives['linetrace'] = True
file_extension = 'pyx' if build_with_cython else 'c'
module_files = [os.path.join(PYTHON_STEM,
name.replace('.', '/') + '.' + file_extension)
@ -129,7 +134,7 @@ def cython_extensions(package_names, module_names, extra_sources, include_dirs,
return Cython.Build.cythonize(
extensions,
include_path=include_dirs,
compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)})
compiler_directives=cython_compiler_directives)
else:
return extensions
@ -154,6 +159,7 @@ INSTALL_REQUIRES = (
SETUP_REQUIRES = (
'sphinx>=1.3',
'sphinx_rtd_theme>=0.1.8'
) + INSTALL_REQUIRES
COMMAND_CLASS = {
@ -165,6 +171,7 @@ COMMAND_CLASS = {
'build_tagged_ext': precompiled.BuildTaggedExt,
'gather': commands.Gather,
'run_interop': commands.RunInterop,
'test_lite': commands.TestLite
}
# Ensure that package data is copied over before any commands have been run:

@ -165,7 +165,6 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_resolver *old_resolver;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
int exit_idle = 0;
@ -201,28 +200,25 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
if (iomgr_success && chand->resolver) {
grpc_resolver *resolver = chand->resolver;
GRPC_RESOLVER_REF(resolver, "channel-next");
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state,
"new_lb+resolver");
if (lb_policy != NULL) {
watch_lb_policy(exec_ctx, chand, lb_policy, state);
}
gpr_mu_unlock(&chand->mu_config);
GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
grpc_resolver_next(exec_ctx, chand->resolver,
&chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel-next");
gpr_mu_unlock(&chand->mu_config);
} else {
old_resolver = chand->resolver;
chand->resolver = NULL;
if (chand->resolver != NULL) {
grpc_resolver_shutdown(exec_ctx, chand->resolver);
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
chand->resolver = NULL;
}
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
gpr_mu_unlock(&chand->mu_config);
if (old_resolver != NULL) {
grpc_resolver_shutdown(exec_ctx, old_resolver);
GRPC_RESOLVER_UNREF(exec_ctx, old_resolver, "channel");
}
}
if (exit_idle) {
@ -247,11 +243,10 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_transport_op *op) {
channel_data *chand = elem->channel_data;
grpc_resolver *destroy_resolver = NULL;
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
GPR_ASSERT(op->set_accept_stream == NULL);
GPR_ASSERT(op->set_accept_stream == false);
if (op->bind_pollset != NULL) {
grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
op->bind_pollset);
@ -279,7 +274,8 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
if (op->disconnect && chand->resolver != NULL) {
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
destroy_resolver = chand->resolver;
grpc_resolver_shutdown(exec_ctx, chand->resolver);
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
chand->resolver = NULL;
if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx,
@ -290,11 +286,6 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
}
}
gpr_mu_unlock(&chand->mu_config);
if (destroy_resolver) {
grpc_resolver_shutdown(exec_ctx, destroy_resolver);
GRPC_RESOLVER_UNREF(exec_ctx, destroy_resolver, "channel");
}
}
typedef struct {

@ -107,7 +107,7 @@ static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
GPR_ASSERT(op->set_accept_stream == NULL);
GPR_ASSERT(op->set_accept_stream == false);
GPR_ASSERT(op->bind_pollset == NULL);
if (op->on_connectivity_state_change != NULL) {

@ -168,15 +168,15 @@ retry:
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_subchannel_call_holder *holder = arg;
grpc_subchannel_call *call;
gpr_mu_lock(&holder->mu);
GPR_ASSERT(holder->creation_phase ==
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
call = GET_CALL(holder);
GPR_ASSERT(call == NULL || call == CANCELLED_CALL);
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (holder->connected_subchannel == NULL) {
fail_locked(exec_ctx, holder);
} else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
/* already cancelled before subchannel became ready */
fail_locked(exec_ctx, holder);
} else {
gpr_atm_rel_store(
&holder->subchannel_call,

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -53,7 +53,9 @@ void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); }
void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, grpc_client_config *c) {
if (gpr_unref(&c->refs)) {
GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
if (c->lb_policy != NULL) {
GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
}
gpr_free(c);
}
}

@ -387,8 +387,8 @@ static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
if (args->num_subchannels == 0) return NULL;
pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
GPR_ASSERT(args->num_subchannels > 0);
memset(p, 0, sizeof(*p));
grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
p->subchannels =

@ -41,6 +41,7 @@
#include "src/core/client_config/lb_policy_registry.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/timer.h"
#include "src/core/support/string.h"
typedef struct {
@ -71,6 +72,9 @@ typedef struct {
grpc_client_config **target_config;
/** current (fully resolved) config */
grpc_client_config *resolved_config;
/** retry timer */
bool have_retry_timer;
grpc_timer retry_timer;
} dns_resolver;
static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@ -91,6 +95,9 @@ static const grpc_resolver_vtable dns_resolver_vtable = {
static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->have_retry_timer) {
grpc_timer_cancel(exec_ctx, &r->retry_timer);
}
if (r->next_completion != NULL) {
*r->target_config = NULL;
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
@ -125,6 +132,22 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
gpr_mu_unlock(&r->mu);
}
static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
bool success) {
dns_resolver *r = arg;
gpr_mu_lock(&r->mu);
r->have_retry_timer = false;
if (success) {
if (!r->resolving) {
dns_start_resolving_locked(r);
}
}
gpr_mu_unlock(&r->mu);
GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer");
}
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_resolved_addresses *addresses) {
dns_resolver *r = arg;
@ -133,29 +156,47 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel_args args;
grpc_lb_policy *lb_policy;
size_t i;
if (addresses) {
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving);
r->resolving = 0;
if (addresses != NULL) {
grpc_lb_policy_args lb_policy_args;
config = grpc_client_config_create();
subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
size_t naddrs = 0;
for (i = 0; i < addresses->naddrs; i++) {
memset(&args, 0, sizeof(args));
args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
args.addr_len = (size_t)addresses->addrs[i].len;
subchannels[i] = grpc_subchannel_factory_create_subchannel(
grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
exec_ctx, r->subchannel_factory, &args);
if (subchannel != NULL) {
subchannels[naddrs++] = subchannel;
}
}
memset(&lb_policy_args, 0, sizeof(lb_policy_args));
lb_policy_args.subchannels = subchannels;
lb_policy_args.num_subchannels = addresses->naddrs;
lb_policy_args.num_subchannels = naddrs;
lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
grpc_client_config_set_lb_policy(config, lb_policy);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
if (lb_policy != NULL) {
grpc_client_config_set_lb_policy(config, lb_policy);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
}
grpc_resolved_addresses_destroy(addresses);
gpr_free(subchannels);
} else {
int retry_seconds = 15;
gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d seconds",
retry_seconds);
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
GRPC_RESOLVER_REF(&r->base, "retry-timer");
grpc_timer_init(
exec_ctx, &r->retry_timer,
gpr_time_add(now, gpr_time_from_seconds(retry_seconds, GPR_TIMESPAN)),
dns_on_retry_timer, r, now);
}
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving);
r->resolving = 0;
if (r->resolved_config) {
grpc_client_config_unref(exec_ctx, r->resolved_config);
}

@ -395,7 +395,6 @@ void grpc_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *notify) {
int do_connect = 0;
external_state_watcher *w;
if (state == NULL) {
@ -425,17 +424,13 @@ void grpc_subchannel_notify_on_state_change(
w->next->prev = w->prev->next = w;
if (grpc_connectivity_state_notify_on_state_change(
exec_ctx, &c->state_tracker, state, &w->closure)) {
do_connect = 1;
c->connecting = 1;
/* released by connection */
GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
start_connect(exec_ctx, c);
}
gpr_mu_unlock(&c->mu);
}
if (do_connect) {
start_connect(exec_ctx, c);
}
}
void grpc_connected_subchannel_process_transport_op(
@ -510,7 +505,8 @@ void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
elem->filter->start_transport_op(exec_ctx, elem, &op);
}
static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c) {
size_t channel_stack_size;
grpc_connected_subchannel *con;
grpc_channel_stack *stk;
@ -546,8 +542,6 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
sw_subchannel);
gpr_mu_lock(&c->mu);
if (c->disconnected) {
gpr_mu_unlock(&c->mu);
gpr_free(sw_subchannel);
@ -580,7 +574,6 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
"connected");
gpr_mu_unlock(&c->mu);
gpr_free((void *)filters);
}
@ -635,11 +628,12 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
if (c->disconnected) {
iomgr_success = 0;
}
gpr_mu_unlock(&c->mu);
if (iomgr_success) {
update_reconnect_parameters(c);
continue_connect(exec_ctx, c);
gpr_mu_unlock(&c->mu);
} else {
gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
}
}
@ -648,21 +642,23 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) {
grpc_subchannel *c = arg;
GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
gpr_mu_lock(&c->mu);
if (c->connecting_result.transport != NULL) {
publish_transport(exec_ctx, c);
publish_transport_locked(exec_ctx, c);
} else if (c->disconnected) {
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connect_failed");
grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
gpr_mu_unlock(&c->mu);
}
gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
}
static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {

@ -71,7 +71,8 @@ static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
}
void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
gpr_timespec deadline) {
BOOL success;
DWORD bytes = 0;
DWORD flags = 0;
@ -84,14 +85,14 @@ void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
g_iocp, &bytes, &completion_key, &overlapped,
deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
if (success == 0 && overlapped == NULL) {
return;
return GRPC_IOCP_WORK_TIMEOUT;
}
GPR_ASSERT(completion_key && overlapped);
if (overlapped == &g_iocp_custom_overlap) {
gpr_atm_full_fetch_add(&g_custom_events, -1);
if (completion_key == (ULONG_PTR)&g_iocp_kick_token) {
/* We were awoken from a kick. */
return;
return GRPC_IOCP_WORK_KICK;
}
gpr_log(GPR_ERROR, "Unknown custom completion key.");
abort();
@ -121,6 +122,7 @@ void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
}
gpr_mu_unlock(&socket->state_mu);
grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
return GRPC_IOCP_WORK_WORK;
}
void grpc_iocp_init(void) {
@ -140,10 +142,12 @@ void grpc_iocp_kick(void) {
void grpc_iocp_flush(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_iocp_work_status work_status;
do {
grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
} while (grpc_exec_ctx_flush(&exec_ctx));
work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
} while (work_status == GRPC_IOCP_WORK_KICK ||
grpc_exec_ctx_flush(&exec_ctx));
}
void grpc_iocp_shutdown(void) {

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -38,7 +38,14 @@
#include "src/core/iomgr/socket_windows.h"
void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline);
typedef enum {
GRPC_IOCP_WORK_WORK,
GRPC_IOCP_WORK_TIMEOUT,
GRPC_IOCP_WORK_KICK
} grpc_iocp_work_status;
grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
gpr_timespec deadline);
void grpc_iocp_init(void);
void grpc_iocp_kick(void);
void grpc_iocp_flush(void);

@ -41,9 +41,11 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/timer.h"
#include "src/core/support/env.h"
#include "src/core/support/string.h"
static gpr_mu g_mu;
@ -116,6 +118,9 @@ void grpc_iomgr_shutdown(void) {
"memory leaks are likely",
count_objects());
dump_objects("LEAKED");
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
}
break;
}
@ -154,3 +159,14 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
gpr_mu_unlock(&g_mu);
gpr_free(obj->name);
}
bool grpc_iomgr_abort_on_leaks(void) {
char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS");
if (env == NULL) return false;
static const char *truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) return true;
}
return false;
}

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,6 +34,8 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
#include <stdbool.h>
#include "src/core/iomgr/iomgr.h"
#include <grpc/support/sync.h>
@ -55,4 +57,6 @@ void grpc_iomgr_platform_flush(void);
/** tear down all platform specific global iomgr structures */
void grpc_iomgr_platform_shutdown(void);
bool grpc_iomgr_abort_on_leaks(void);
#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */

@ -122,6 +122,7 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
} else {
h->fds[fd_count++] = h->fds[i];
watchers[pfd_count].fd = h->fds[i];
GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start");
pfds[pfd_count].fd = h->fds[i]->fd;
pfds[pfd_count].revents = 0;
pfd_count++;
@ -135,8 +136,10 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
gpr_mu_unlock(&pollset->mu);
for (i = 2; i < pfd_count; i++) {
pfds[i].events = (short)grpc_fd_begin_poll(watchers[i].fd, pollset, worker,
POLLIN, POLLOUT, &watchers[i]);
grpc_fd *fd = watchers[i].fd;
pfds[i].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
POLLOUT, &watchers[i]);
GRPC_FD_UNREF(fd, "multipoller_start");
}
/* TODO(vpai): Consider first doing a 0 timeout poll here to avoid

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -66,7 +66,7 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
result must be freed with grpc_resolved_addresses_destroy. */
grpc_resolved_addresses *grpc_blocking_resolve_address(
const char *addr, const char *default_port);
extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
const char *name, const char *default_port);
#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */

@ -34,18 +34,13 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/sockaddr.h"
#include <string.h>
#include <sys/types.h>
#include <sys/un.h>
#include <string.h>
#include "src/core/iomgr/executor.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/block_annotate.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
@ -53,6 +48,11 @@
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/iomgr/executor.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/block_annotate.h"
#include "src/core/support/string.h"
typedef struct {
char *name;
@ -62,7 +62,7 @@ typedef struct {
void *arg;
} request;
grpc_resolved_addresses *grpc_blocking_resolve_address(
static grpc_resolved_addresses *blocking_resolve_address_impl(
const char *name, const char *default_port) {
struct addrinfo hints;
struct addrinfo *result = NULL, *resp;
@ -150,6 +150,9 @@ done:
return addrs;
}
grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
const char *name, const char *default_port) = blocking_resolve_address_impl;
/* Callback to be passed to grpc_executor to asynch-ify
* grpc_blocking_resolve_address */
static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {

@ -34,17 +34,12 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_WINSOCK_SOCKET
#include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/sockaddr.h"
#include <sys/types.h>
#include <string.h>
#include <sys/types.h>
#include "src/core/iomgr/executor.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/block_annotate.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
@ -52,6 +47,11 @@
#include <grpc/support/string_util.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include "src/core/iomgr/executor.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/block_annotate.h"
#include "src/core/support/string.h"
typedef struct {
char *name;
@ -61,7 +61,7 @@ typedef struct {
void *arg;
} request;
grpc_resolved_addresses *grpc_blocking_resolve_address(
static grpc_resolved_addresses *blocking_resolve_address_impl(
const char *name, const char *default_port) {
struct addrinfo hints;
struct addrinfo *result = NULL, *resp;
@ -133,6 +133,9 @@ done:
return addrs;
}
grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
const char *name, const char *default_port) = blocking_resolve_address_impl;
/* Callback to be passed to grpc_executor to asynch-ify
* grpc_blocking_resolve_address */
static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {

@ -240,8 +240,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
sp->shutting_down = 0;
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
if (0 == --sp->server->active_ports &&
sp->server->shutdown_complete != NULL) {
if (0 == --sp->server->active_ports) {
notify = 1;
}
gpr_mu_unlock(&sp->server->mu);

@ -33,11 +33,11 @@
#include "src/core/iomgr/timer.h"
#include "src/core/iomgr/timer_heap.h"
#include "src/core/iomgr/time_averaged_stats.h"
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/iomgr/time_averaged_stats.h"
#include "src/core/iomgr/timer_heap.h"
#define INVALID_HEAP_INDEX 0xffffffffu
@ -330,6 +330,18 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
gpr_mu_unlock(&g_mu);
gpr_mu_unlock(&g_checker_mu);
} else if (next != NULL) {
/* TODO(ctiller): this forces calling code to do an short poll, and
then retry the timer check (because this time through the timer list was
contended).
We could reduce the cost here dramatically by keeping a count of how many
currently active pollers got through the uncontended case above
successfully, and waking up other pollers IFF that count drops to zero.
Once that count is in place, this entire else branch could disappear. */
*next = gpr_time_min(
*next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN)));
}
return (int)n;

@ -96,7 +96,6 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer);
*next is never guaranteed to be updated on any given execution; however,
with high probability at least one thread in the system will see an update
at any time slice. */
bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
gpr_timespec *next);
void grpc_timer_list_init(gpr_timespec now);

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -46,7 +46,7 @@
static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
while (i > 0) {
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
if (gpr_time_cmp(first[parent]->deadline, t->deadline) >= 0) break;
if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
first[i] = first[parent];
first[i]->heap_index = i;
i = parent;
@ -62,16 +62,14 @@ static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
grpc_timer *t) {
for (;;) {
uint32_t left_child = 1u + 2u * i;
uint32_t right_child;
uint32_t next_i;
if (left_child >= length) break;
right_child = left_child + 1;
next_i = right_child < length &&
gpr_time_cmp(first[left_child]->deadline,
first[right_child]->deadline) < 0
? right_child
: left_child;
if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break;
uint32_t right_child = left_child + 1;
uint32_t next_i = right_child < length &&
gpr_time_cmp(first[left_child]->deadline,
first[right_child]->deadline) > 0
? right_child
: left_child;
if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
first[i] = first[next_i];
first[i]->heap_index = i;
i = next_i;
@ -95,7 +93,7 @@ static void maybe_shrink(grpc_timer_heap *heap) {
static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
uint32_t i = timer->heap_index;
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) < 0) {
if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
adjust_upwards(heap->timers, i, timer);
} else {
adjust_downwards(heap->timers, i, heap->timer_count, timer);

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -87,4 +87,4 @@ void *gpr_malloc_aligned(size_t size, size_t alignment_log) {
return (void *)ret;
}
void gpr_free_aligned(void *ptr) { free(((void **)ptr)[-1]); }
void gpr_free_aligned(void *ptr) { gpr_free(((void **)ptr)[-1]); }

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -98,6 +98,11 @@ void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
void gpr_ref_non_zero(gpr_refcount *r) {
gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1);
GPR_ASSERT(prior > 0);
}
void gpr_refn(gpr_refcount *r, int n) {
gpr_atm_no_barrier_fetch_add(&r->count, n);
}

@ -86,7 +86,7 @@ struct grpc_completion_queue {
#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1))
static gpr_mu g_freelist_mu;
grpc_completion_queue *g_freelist;
static grpc_completion_queue *g_freelist;
static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
bool success);

@ -407,8 +407,15 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) {
maybe_finish_shutdown(exec_ctx, chand->server);
chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
chand->finish_destroy_channel_closure.cb_arg = chand;
grpc_exec_ctx_enqueue(exec_ctx, &chand->finish_destroy_channel_closure, true,
NULL);
grpc_transport_op op;
memset(&op, 0, sizeof(op));
op.set_accept_stream = true;
op.on_consumed = &chand->finish_destroy_channel_closure;
grpc_channel_next_op(exec_ctx,
grpc_channel_stack_element(
grpc_channel_get_channel_stack(chand->channel), 0),
&op);
}
static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server,
@ -971,7 +978,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
memset(&op, 0, sizeof(op));
op.set_accept_stream = accept_stream;
op.set_accept_stream = true;
op.set_accept_stream_fn = accept_stream;
op.set_accept_stream_user_data = chand;
op.on_connectivity_state_change = &chand->channel_connectivity_changed;
op.connectivity_state = &chand->connectivity_state;

@ -358,6 +358,9 @@ struct grpc_chttp2_transport {
/** connectivity tracking */
grpc_connectivity_state_tracker state_tracker;
} channel_callback;
/** Transport op to be applied post-parsing */
grpc_transport_op *post_parsing_op;
};
typedef struct {
@ -417,7 +420,7 @@ typedef struct {
/** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id;
uint8_t fetching;
uint8_t sent_initial_metadata;
bool sent_initial_metadata;
uint8_t sent_message;
uint8_t sent_trailing_metadata;
uint8_t read_closed;
@ -509,7 +512,7 @@ void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing);
void grpc_chttp2_list_add_writable_stream(
bool grpc_chttp2_list_add_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
/** Get a writable stream
@ -519,14 +522,13 @@ int grpc_chttp2_list_pop_writable_stream(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_global **stream_global,
grpc_chttp2_stream_writing **stream_writing);
void grpc_chttp2_list_remove_writable_stream(
bool grpc_chttp2_list_remove_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT;
/* returns 1 if stream added, 0 if it was already present */
int grpc_chttp2_list_add_writing_stream(
void grpc_chttp2_list_add_writing_stream(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) GRPC_MUST_USE_RESULT;
grpc_chttp2_stream_writing *stream_writing);
int grpc_chttp2_list_have_writing_streams(
grpc_chttp2_transport_writing *transport_writing);
int grpc_chttp2_list_pop_writing_stream(
@ -770,4 +772,9 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *parsing,
const uint8_t *opaque_8bytes);
/** add a ref to the stream and add it to the writable list;
ref will be dropped in writing.c */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
#endif

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -149,7 +149,7 @@ void grpc_chttp2_publish_reads(
if (was_zero && !is_zero) {
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
&stream_global)) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
}
@ -178,7 +178,7 @@ void grpc_chttp2_publish_reads(
outgoing_window);
is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(

@ -100,11 +100,14 @@ static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
}
}
static void stream_list_maybe_remove(grpc_chttp2_transport *t,
static bool stream_list_maybe_remove(grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) {
if (s->included[id]) {
stream_list_remove(t, s, id);
return true;
} else {
return false;
}
}
@ -125,23 +128,24 @@ static void stream_list_add_tail(grpc_chttp2_transport *t,
s->included[id] = 1;
}
static int stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) {
static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) {
if (s->included[id]) {
return 0;
return false;
}
stream_list_add_tail(t, s, id);
return 1;
return true;
}
/* wrappers for specializations */
void grpc_chttp2_list_add_writable_stream(
bool grpc_chttp2_list_add_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
GPR_ASSERT(stream_global->id != 0);
stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE);
return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE);
}
int grpc_chttp2_list_pop_writable_stream(
@ -159,20 +163,20 @@ int grpc_chttp2_list_pop_writable_stream(
return r;
}
void grpc_chttp2_list_remove_writable_stream(
bool grpc_chttp2_list_remove_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE);
return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE);
}
int grpc_chttp2_list_add_writing_stream(
void grpc_chttp2_list_add_writing_stream(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) {
return stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
STREAM_FROM_WRITING(stream_writing),
GRPC_CHTTP2_LIST_WRITING);
GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
STREAM_FROM_WRITING(stream_writing),
GRPC_CHTTP2_LIST_WRITING));
}
int grpc_chttp2_list_have_writing_streams(
@ -332,7 +336,7 @@ void grpc_chttp2_list_flush_writing_stalled_by_transport(
while (stream_list_pop(transport, &stream,
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
if (is_window_available) {
grpc_chttp2_list_add_writable_stream(&transport->global, &stream->global);
grpc_chttp2_become_writable(&transport->global, &stream->global);
} else {
grpc_chttp2_list_add_stalled_by_transport(transport_writing,
&stream->writing);

@ -83,7 +83,8 @@ int grpc_chttp2_unlocking_check_writes(
(according to available window sizes) and add to the output buffer */
while (grpc_chttp2_list_pop_writable_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) {
uint8_t sent_initial_metadata;
bool sent_initial_metadata = stream_writing->sent_initial_metadata;
bool become_writable = false;
stream_writing->id = stream_global->id;
stream_writing->read_closed = stream_global->read_closed;
@ -92,16 +93,12 @@ int grpc_chttp2_unlocking_check_writes(
outgoing_window, stream_global,
outgoing_window);
sent_initial_metadata = stream_writing->sent_initial_metadata;
if (!sent_initial_metadata && stream_global->send_initial_metadata) {
stream_writing->send_initial_metadata =
stream_global->send_initial_metadata;
stream_global->send_initial_metadata = NULL;
if (grpc_chttp2_list_add_writing_stream(transport_writing,
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
sent_initial_metadata = 1;
become_writable = true;
sent_initial_metadata = true;
}
if (sent_initial_metadata) {
if (stream_global->send_message != NULL) {
@ -128,10 +125,7 @@ int grpc_chttp2_unlocking_check_writes(
stream_writing->flow_controlled_buffer.length > 0) &&
stream_writing->outgoing_window > 0) {
if (transport_writing->outgoing_window > 0) {
if (grpc_chttp2_list_add_writing_stream(transport_writing,
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
become_writable = true;
} else {
grpc_chttp2_list_add_stalled_by_transport(transport_writing,
stream_writing);
@ -141,10 +135,7 @@ int grpc_chttp2_unlocking_check_writes(
stream_writing->send_trailing_metadata =
stream_global->send_trailing_metadata;
stream_global->send_trailing_metadata = NULL;
if (grpc_chttp2_list_add_writing_stream(transport_writing,
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
become_writable = true;
}
}
@ -153,10 +144,13 @@ int grpc_chttp2_unlocking_check_writes(
GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
announce_window, stream_global,
unannounced_incoming_window_for_writing);
if (grpc_chttp2_list_add_writing_stream(transport_writing,
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
become_writable = true;
}
if (become_writable) {
grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
} else {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
}
@ -310,10 +304,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
(stream_writing->send_message && !stream_writing->fetching)) &&
stream_writing->outgoing_window > 0) {
if (transport_writing->outgoing_window > 0) {
if (grpc_chttp2_list_add_writing_stream(transport_writing,
stream_writing)) {
/* do nothing - already reffed */
}
grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
} else {
grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
stream_writing);

@ -142,7 +142,7 @@ static void incoming_byte_stream_update_flow_control(
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global);
/*
/*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
@ -432,6 +432,14 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
if (t->ep) {
allow_endpoint_shutdown_locked(exec_ctx, t);
}
/* flush writable stream list to avoid dangling references */
grpc_chttp2_stream_global *stream_global;
grpc_chttp2_stream_writing *stream_writing;
while (grpc_chttp2_list_pop_writable_stream(
&t->global, &t->writing, &stream_global, &stream_writing)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
}
}
@ -521,7 +529,6 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
s->global.id) == NULL);
}
grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
&s->global);
grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
@ -583,7 +590,7 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
return &accepting->parsing;
}
/*
/*******************************************************************************
* LOCK MANAGEMENT
*/
@ -611,10 +618,18 @@ static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_TIMER_END("unlock", 0);
}
/*
/*******************************************************************************
* OUTPUT PROCESSING
*/
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
}
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value) {
const grpc_chttp2_setting_parameters *sp =
@ -732,7 +747,7 @@ static void maybe_start_some_streams(
stream_global->id, STREAM_FROM_GLOBAL(stream_global));
stream_global->in_stream_map = 1;
transport_global->concurrent_stream_count++;
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
/* cancel out streams that will never be started */
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@ -821,7 +836,7 @@ static void perform_stream_op_locked(
maybe_start_some_streams(exec_ctx, transport_global);
} else {
GPR_ASSERT(stream_global->id != 0);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
} else {
grpc_chttp2_complete_closure_step(
@ -836,9 +851,11 @@ static void perform_stream_op_locked(
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_message_finished, 0);
} else if (stream_global->id != 0) {
} else {
stream_global->send_message = op->send_message;
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
if (stream_global->id != 0) {
grpc_chttp2_become_writable(transport_global, stream_global);
}
}
}
@ -858,7 +875,7 @@ static void perform_stream_op_locked(
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
}
@ -944,12 +961,10 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
unlock(exec_ctx, t);
}
static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_transport_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
int close_transport = 0;
lock(t);
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_transport_op *op) {
bool close_transport = false;
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
@ -968,8 +983,8 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
close_transport = !grpc_chttp2_has_streams(t);
}
if (op->set_accept_stream != NULL) {
t->channel_callback.accept_stream = op->set_accept_stream;
if (op->set_accept_stream) {
t->channel_callback.accept_stream = op->set_accept_stream_fn;
t->channel_callback.accept_stream_user_data =
op->set_accept_stream_user_data;
}
@ -990,16 +1005,31 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
close_transport_locked(exec_ctx, t);
}
unlock(exec_ctx, t);
if (close_transport) {
lock(t);
close_transport_locked(exec_ctx, t);
unlock(exec_ctx, t);
}
}
/*
static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_transport_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
lock(t);
/* If there's a set_accept_stream ensure that we're not parsing
to avoid changing things out from underneath */
if (t->parsing_active && op->set_accept_stream) {
GPR_ASSERT(t->post_parsing_op == NULL);
t->post_parsing_op = gpr_malloc(sizeof(*op));
memcpy(t->post_parsing_op, op, sizeof(*op));
} else {
perform_transport_op_locked(exec_ctx, t, op);
}
unlock(exec_ctx, t);
}
/*******************************************************************************
* INPUT PROCESSING
*/
@ -1064,7 +1094,6 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (!s) {
s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
}
grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
GPR_ASSERT(s);
s->global.in_stream_map = 0;
if (t->parsing.incoming_stream == &s->parsing) {
@ -1080,6 +1109,9 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
close_transport_locked(exec_ctx, t);
}
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
}
new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
grpc_chttp2_stream_map_size(&t->new_stream_map);
@ -1331,7 +1363,7 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
}
@ -1392,6 +1424,13 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
/* handle higher level things */
grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
t->parsing_active = 0;
/* handle delayed transport ops (if there is one) */
if (t->post_parsing_op) {
grpc_transport_op *op = t->post_parsing_op;
t->post_parsing_op = NULL;
perform_transport_op_locked(exec_ctx, t, op);
gpr_free(op);
}
/* if a stream is in the stream map, and gets cancelled, we need to ensure
* we are not parsing before continuing the cancellation to keep things in
* a sane state */
@ -1426,7 +1465,7 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
GPR_TIMER_END("recv_data", 0);
}
/*
/*******************************************************************************
* CALLBACK LOOP
*/
@ -1440,7 +1479,7 @@ static void connectivity_state_set(
state, reason);
}
/*
/*******************************************************************************
* POLLSET STUFF
*/
@ -1468,7 +1507,7 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
unlock(exec_ctx, t);
}
/*
/*******************************************************************************
* BYTE STREAM
*/
@ -1508,7 +1547,7 @@ static void incoming_byte_stream_update_flow_control(
add_max_recv_bytes);
grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
stream_global);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
}
}
@ -1623,7 +1662,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
return incoming_byte_stream;
}
/*
/*******************************************************************************
* TRACING
*/
@ -1709,7 +1748,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
gpr_free(prefix);
}
/*
/*******************************************************************************
* INTEGRATION GLUE
*/

@ -43,11 +43,13 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/profiling/timers.h"
#include "src/core/support/murmur_hash.h"
#include "src/core/support/string.h"
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/static_metadata.h"
#include "src/core/iomgr/iomgr_internal.h"
/* There are two kinds of mdelem and mdstr instances.
* Static instances are declared in static_metadata.{h,c} and
@ -227,6 +229,9 @@ void grpc_mdctx_global_shutdown(void) {
if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
}
gpr_free(shard->elems);
}
@ -237,6 +242,9 @@ void grpc_mdctx_global_shutdown(void) {
if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
}
gpr_free(shard->strs);
}

@ -45,7 +45,7 @@ void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
#else
void grpc_stream_ref(grpc_stream_refcount *refcount) {
#endif
gpr_ref(&refcount->refs);
gpr_ref_non_zero(&refcount->refs);
}
#ifdef GRPC_STREAM_REFCOUNT_DEBUG

@ -123,7 +123,7 @@ typedef struct grpc_transport_stream_op {
/** Transport op: a set of operations to perform on a transport as a whole */
typedef struct grpc_transport_op {
/** called when processing of this op is done */
/** Called when processing of this op is done. */
grpc_closure *on_consumed;
/** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
grpc_closure *on_connectivity_state_change;
@ -138,9 +138,13 @@ typedef struct grpc_transport_op {
grpc_status_code goaway_status;
gpr_slice *goaway_message;
/** set the callback for accepting new streams;
this is a permanent callback, unlike the other one-shot closures */
void (*set_accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_transport *transport, const void *server_data);
this is a permanent callback, unlike the other one-shot closures.
If true, the callback is set to set_accept_stream_fn, with its
user_data argument set to set_accept_stream_user_data */
bool set_accept_stream;
void (*set_accept_stream_fn)(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_transport *transport,
const void *server_data);
void *set_accept_stream_user_data;
/** add this transport to a pollset */
grpc_pollset *bind_pollset;

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,9 +33,18 @@
#include "src/core/tsi/ssl_transport_security.h"
#include <grpc/support/port_platform.h>
#include <limits.h>
#include <string.h>
/* TODO(jboeuf): refactor inet_ntop into a portability header. */
#ifdef GPR_WINSOCK_SOCKET
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
@ -197,13 +206,16 @@ static void ssl_info_callback(const SSL *ssl, int where, int ret) {
}
/* Returns 1 if name looks like an IP address, 0 otherwise.
This is a very rough heuristic as it does not handle IPV6 or things like:
0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */
This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
static int looks_like_ip_address(const char *name) {
size_t i;
size_t dot_count = 0;
size_t num_size = 0;
for (i = 0; i < strlen(name); i++) {
if (name[i] == ':') {
/* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
return 1;
}
if (name[i] >= '0' && name[i] <= '9') {
if (num_size > 3) return 0;
num_size++;
@ -296,21 +308,44 @@ static tsi_result add_subject_alt_names_properties_to_peer(
sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
/* Filter out the non-dns entries names. */
if (subject_alt_name->type == GEN_DNS) {
unsigned char *dns_name = NULL;
int dns_name_size =
ASN1_STRING_to_UTF8(&dns_name, subject_alt_name->d.dNSName);
if (dns_name_size < 0) {
unsigned char *name = NULL;
int name_size;
name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
if (name_size < 0) {
gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
result = TSI_INTERNAL_ERROR;
break;
}
result = tsi_construct_string_peer_property(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
(const char *)dns_name, (size_t)dns_name_size,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name,
(size_t)name_size, &peer->properties[peer->property_count++]);
OPENSSL_free(name);
} else if (subject_alt_name->type == GEN_IPADD) {
char ntop_buf[INET6_ADDRSTRLEN];
int af;
if (subject_alt_name->d.iPAddress->length == 4) {
af = AF_INET;
} else if (subject_alt_name->d.iPAddress->length == 16) {
af = AF_INET6;
} else {
gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
result = TSI_INTERNAL_ERROR;
break;
}
const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
ntop_buf, INET6_ADDRSTRLEN);
if (name == NULL) {
gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
result = TSI_INTERNAL_ERROR;
break;
}
result = tsi_construct_string_peer_property_from_cstring(
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
&peer->properties[peer->property_count++]);
OPENSSL_free(dns_name);
if (result != TSI_OK) break;
}
if (result != TSI_OK) break;
}
return result;
}
@ -1436,9 +1471,7 @@ int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
size_t i = 0;
size_t san_count = 0;
const tsi_peer_property *cn_property = NULL;
/* For now reject what looks like an IP address. */
if (looks_like_ip_address(name)) return 0;
int like_ip = looks_like_ip_address(name);
/* Check the SAN first. */
for (i = 0; i < peer->property_count; i++) {
@ -1447,8 +1480,15 @@ int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
if (strcmp(property->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
san_count++;
if (does_entry_match_name(property->value.data, property->value.length,
name)) {
if (!like_ip && does_entry_match_name(property->value.data,
property->value.length, name)) {
return 1;
} else if (like_ip &&
strncmp(name, property->value.data, property->value.length) ==
0 &&
strlen(name) == property->value.length) {
/* IP Addresses are exact matches only. */
return 1;
}
} else if (strcmp(property->name,
@ -1457,8 +1497,8 @@ int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
}
}
/* If there's no SAN, try the CN. */
if (san_count == 0 && cn_property != NULL) {
/* If there's no SAN, try the CN, but only if its not like an IP Address */
if (san_count == 0 && cn_property != NULL && !like_ip) {
if (does_entry_match_name(cn_property->value.data,
cn_property->value.length, name)) {
return 1;

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -162,8 +162,7 @@ void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self);
Still TODO(jboeuf):
- handle mixed case.
- handle %encoded chars.
- handle public suffix wildchar more strictly (e.g. *.co.uk)
- handle IP addresses in SAN. */
- handle public suffix wildchar more strictly (e.g. *.co.uk) */
int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name);
#ifdef __cplusplus

@ -6,3 +6,77 @@ This directory contains source code for C++ implementation of gRPC.
#Status
Beta
#Pre-requisites
##Linux
```sh
$ [sudo] apt-get install build-essential autoconf libtool
```
##Mac OSX
For a Mac system, git is not available by default. You will first need to
install Xcode from the Mac AppStore and then run the following command from a
terminal:
```sh
$ [sudo] xcode-select --install
```
##Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
you will need the `protoc` compiler to generate stub server and client code.
If you compile gRPC from source, as described below, this also installs the
`protoc` compiler.
If it hasn't been installed, you can run the following commands to install it.
```sh
$ cd grpc/third_party/protobuf
$ sudo make install # 'make' should have been run by core grpc
```
Alternatively, you can download `protoc` binaries from
[the protocol buffers Github repository](https://github.com/google/protobuf/releases).
#Installation
Currently to install gRPC for C++, you need to build from source as described
below.
#Build from Source
```sh
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git submodule update --init
$ make
$ [sudo] make install
```
#Documentation
You can find out how to build and run our simplest gRPC C++ example in our
[C++ quick start](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp).
For more detailed documentation on using gRPC in C++ , see our main
documentation site at [grpc.io](http://grpc.io), specifically:
* [Overview](http://www.grpc.io/docs/): An introduction to gRPC with a simple
Hello World example in all our supported languages, including C++.
* [gRPC Basics - C++](http://www.grpc.io/docs/tutorials/basic/c.html):
A tutorial that steps you through creating a simple gRPC C++ example
application.
* [Asynchronous Basics - C++](http://www.grpc.io/docs/tutorials/async/helloasync-cpp.html):
A tutorial that shows you how to use gRPC C++'s asynchronous/non-blocking
APIs.
# Examples
Code examples for gRPC C++ live in this repository's
[examples/cpp](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp) directory.

@ -62,7 +62,11 @@ class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface {
void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE;
bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
bool CheckCancelled(CompletionQueue* cq);
bool CheckCancelled(CompletionQueue* cq) {
cq->TryPluck(this);
return CheckCancelledNoPluck();
}
bool CheckCancelledAsync() { return CheckCancelledNoPluck(); }
void set_tag(void* tag) {
has_tag_ = true;
@ -72,6 +76,11 @@ class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface {
void Unref();
private:
bool CheckCancelledNoPluck() {
grpc::lock_guard<grpc::mutex> g(mu_);
return finalized_ ? (cancelled_ != 0) : false;
}
bool has_tag_;
void* tag_;
grpc::mutex mu_;
@ -88,12 +97,6 @@ void ServerContext::CompletionOp::Unref() {
}
}
bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) {
cq->TryPluck(this);
grpc::lock_guard<grpc::mutex> g(mu_);
return finalized_ ? cancelled_ != 0 : false;
}
void ServerContext::CompletionOp::FillOps(grpc_op* ops, size_t* nops) {
ops->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
ops->data.recv_close_on_server.cancelled = &cancelled_;
@ -182,7 +185,14 @@ void ServerContext::TryCancel() const {
}
bool ServerContext::IsCancelled() const {
return completion_op_ && completion_op_->CheckCancelled(cq_);
if (has_notify_when_done_tag_) {
// when using async API, but the result is only valid
// if the tag has already been delivered at the completion queue
return completion_op_ && completion_op_->CheckCancelledAsync();
} else {
// when using sync API
return completion_op_ && completion_op_->CheckCancelled(cq_);
}
}
void ServerContext::set_compression_level(grpc_compression_level level) {

@ -193,16 +193,6 @@ namespace Grpc.Core.Internal
lock (myLock)
{
finished = true;
if (cancelled)
{
// Once we cancel, we don't have to care that much
// about reads and writes.
// TODO(jtattermusch): is this still necessary?
Cancel();
}
ReleaseResourcesIfPossible();
}
// TODO(jtattermusch): handle error

@ -323,7 +323,7 @@ namespace Grpc.Core
private static string NormalizeKey(string key)
{
var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture);
var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant();
GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized),
"Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
return normalized;

@ -1,6 +1,6 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -140,14 +140,12 @@ namespace Grpc.IntegrationTesting
}
[Test]
[Ignore("TODO: see #4427")]
public async Task StatusCodeAndMessage()
{
await InteropClient.RunStatusCodeAndMessageAsync(client);
}
[Test]
[Ignore("TODO: see #4427")]
public void UnimplementedMethod()
{
InteropClient.RunUnimplementedMethod(UnimplementedService.NewClient(channel));

@ -5,7 +5,7 @@
Beta
## PREREQUISITES
- `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
- `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
## INSTALLATION

@ -290,6 +290,7 @@ function timeoutOnSleepingServer(client, done) {
call.write({
payload: {body: zeroBuffer(27182)}
});
call.on('data', function() {});
call.on('error', function(error) {
assert(error.code === grpc.status.DEADLINE_EXCEEDED ||
@ -336,6 +337,7 @@ function customMetadata(client, done) {
['test_initial_metadata_value']);
done();
});
stream.on('data', function() {});
stream.on('status', function(status) {
var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY);
assert(echo_trailer.length > 0);
@ -361,6 +363,7 @@ function statusCodeAndMessage(client, done) {
done();
});
var duplex = client.fullDuplexCall();
duplex.on('data', function() {});
duplex.on('status', function(status) {
assert(status);
assert.strictEqual(status.code, 2);

@ -131,8 +131,71 @@ function ClientReadableStream(call, deserialize) {
this.finished = false;
this.reading = false;
this.deserialize = common.wrapIgnoreNull(deserialize);
/* Status generated from reading messages from the server. Overrides the
* status from the server if not OK */
this.read_status = null;
/* Status received from the server. */
this.received_status = null;
}
/**
* Called when all messages from the server have been processed. The status
* parameter indicates that the call should end with that status. status
* defaults to OK if not provided.
* @param {Object!} status The status that the call should end with
*/
function _readsDone(status) {
/* jshint validthis: true */
if (!status) {
status = {code: grpc.status.OK, details: 'OK'};
}
if (status.code !== grpc.status.OK) {
this.call.cancelWithStatus(status.code, status.details);
}
this.finished = true;
this.read_status = status;
this._emitStatusIfDone();
}
ClientReadableStream.prototype._readsDone = _readsDone;
/**
* Called to indicate that we have received a status from the server.
*/
function _receiveStatus(status) {
/* jshint validthis: true */
this.received_status = status;
this._emitStatusIfDone();
}
ClientReadableStream.prototype._receiveStatus = _receiveStatus;
/**
* If we have both processed all incoming messages and received the status from
* the server, emit the status. Otherwise, do nothing.
*/
function _emitStatusIfDone() {
/* jshint validthis: true */
var status;
if (this.read_status && this.received_status) {
if (this.read_status.code !== grpc.status.OK) {
status = this.read_status;
} else {
status = this.received_status;
}
this.emit('status', status);
if (status.code !== grpc.status.OK) {
var error = new Error(status.details);
error.code = status.code;
error.metadata = status.metadata;
this.emit('error', error);
return;
}
}
}
ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone;
/**
* Read the next object from the stream.
* @access private
@ -150,6 +213,7 @@ function _read(size) {
if (err) {
// Something has gone wrong. Stop reading and wait for status
self.finished = true;
self._readsDone();
return;
}
var data = event.read;
@ -157,8 +221,11 @@ function _read(size) {
try {
deserialized = self.deserialize(data);
} catch (e) {
self.call.cancelWithStatus(grpc.status.INTERNAL,
'Failed to parse server response');
self._readsDone({code: grpc.status.INTERNAL,
details: 'Failed to parse server response'});
}
if (data === null) {
self._readsDone();
}
if (self.push(deserialized) && data !== null) {
var read_batch = {};
@ -198,6 +265,11 @@ function ClientDuplexStream(call, serialize, deserialize) {
this.serialize = common.wrapIgnoreNull(serialize);
this.deserialize = common.wrapIgnoreNull(deserialize);
this.call = call;
/* Status generated from reading messages from the server. Overrides the
* status from the server if not OK */
this.read_status = null;
/* Status received from the server. */
this.received_status = null;
this.on('finish', function() {
var batch = {};
batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
@ -205,6 +277,9 @@ function ClientDuplexStream(call, serialize, deserialize) {
});
}
ClientDuplexStream.prototype._readsDone = _readsDone;
ClientDuplexStream.prototype._receiveStatus = _receiveStatus;
ClientDuplexStream.prototype._emitStatusIfDone = _emitStatusIfDone;
ClientDuplexStream.prototype._read = _read;
ClientDuplexStream.prototype._write = _write;
@ -336,7 +411,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
}
}
if (status.code !== grpc.status.OK) {
error = new Error(response.status.details);
error = new Error(status.details);
error.code = status.code;
error.metadata = status.metadata;
callback(error);
@ -487,22 +562,13 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) {
response.status.metadata = Metadata._fromCoreRepresentation(
response.status.metadata);
stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
error.code = response.status.code;
error.metadata = response.status.metadata;
stream.emit('error', error);
if (err) {
stream.emit('error', err);
return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
stream.emit('error', err);
return;
}
}
response.status.metadata = Metadata._fromCoreRepresentation(
response.status.metadata);
stream._receiveStatus(response.status);
});
return stream;
}
@ -552,22 +618,13 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) {
response.status.metadata = Metadata._fromCoreRepresentation(
response.status.metadata);
stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
error.code = response.status.code;
error.metadata = response.status.metadata;
stream.emit('error', error);
if (err) {
stream.emit('error', err);
return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
stream.emit('error', err);
return;
}
}
response.status.metadata = Metadata._fromCoreRepresentation(
response.status.metadata);
stream._receiveStatus(response.status);
});
return stream;
}

@ -1000,6 +1000,7 @@ describe('Call propagation', function() {
proxy_impl.serverStream = function(parent) {
var child = client.serverStream(parent.request, null,
{parent: parent});
child.on('data', function() {});
child.on('error', function(err) {
assert(err);
assert.strictEqual(err.code, grpc.status.CANCELLED);
@ -1013,6 +1014,7 @@ describe('Call propagation', function() {
var proxy_client = new Client('localhost:' + proxy_port,
grpc.credentials.createInsecure());
call = proxy_client.serverStream({});
call.on('data', function() {});
call.on('error', function(err) {
done();
});
@ -1022,6 +1024,7 @@ describe('Call propagation', function() {
var call;
proxy_impl.bidiStream = function(parent) {
var child = client.bidiStream(null, {parent: parent});
child.on('data', function() {});
child.on('error', function(err) {
assert(err);
assert.strictEqual(err.code, grpc.status.CANCELLED);
@ -1035,6 +1038,7 @@ describe('Call propagation', function() {
var proxy_client = new Client('localhost:' + proxy_port,
grpc.credentials.createInsecure());
call = proxy_client.bidiStream();
call.on('data', function() {});
call.on('error', function(err) {
done();
});
@ -1074,6 +1078,7 @@ describe('Call propagation', function() {
proxy_impl.bidiStream = function(parent) {
var child = client.bidiStream(
null, {parent: parent, propagate_flags: deadline_flags});
child.on('data', function() {});
child.on('error', function(err) {
assert(err);
assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
@ -1089,6 +1094,7 @@ describe('Call propagation', function() {
var deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 1);
var call = proxy_client.bidiStream(null, {deadline: deadline});
call.on('data', function() {});
call.on('error', function(err) {
done();
});
@ -1130,6 +1136,7 @@ describe('Cancelling surface client', function() {
});
it('Should correctly cancel a server stream call', function(done) {
var call = client.fib({'limit': 5});
call.on('data', function() {});
call.on('error', function(error) {
assert.strictEqual(error.code, surface_client.status.CANCELLED);
done();
@ -1138,6 +1145,7 @@ describe('Cancelling surface client', function() {
});
it('Should correctly cancel a bidi stream call', function(done) {
var call = client.divMany();
call.on('data', function() {});
call.on('error', function(error) {
assert.strictEqual(error.code, surface_client.status.CANCELLED);
done();

@ -37,6 +37,8 @@
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
#import "private/GRPCConnectivityMonitor.h"
#import "private/GRPCHost.h"
#import "private/GRPCRequestHeaders.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
@ -71,8 +73,11 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
@implementation GRPCCall {
dispatch_queue_t _callQueue;
NSString *_host;
NSString *_path;
GRPCWrappedCall *_wrappedCall;
dispatch_once_t _callAlreadyInvoked;
GRPCConnectivityMonitor *_connectivityMonitor;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
@ -115,13 +120,11 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
format:@"The requests writer can't be already started."];
}
if ((self = [super init])) {
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:host path:path];
if (!_wrappedCall) {
return nil;
}
_host = [host copy];
_path = [path copy];
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("org.grpc.call", NULL);
_callQueue = dispatch_queue_create("io.grpc.call", NULL);
_requestWriter = requestWriter;
@ -156,7 +159,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
- (void)cancel {
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:nil]];
userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
[self cancelCall];
}
@ -354,8 +357,29 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
_retainSelf = self;
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
[self sendHeaders:_requestHeaders];
[self invokeCall];
// TODO(jcanizales): Extract this logic somewhere common.
NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
if (!host) {
// TODO(jcanizales): Check this on init.
[NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host];
}
__weak typeof(self) weakSelf = self;
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
[_connectivityMonitor handleLossWithHandler:^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
[[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
}
}];
}
- (void)setState:(GRXWriterState)newState {
@ -385,4 +409,5 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
return;
}
}
@end

@ -35,6 +35,7 @@
#include <grpc/grpc.h>
@class GRPCCompletionQueue;
struct grpc_channel_credentials;
@ -80,4 +81,6 @@ struct grpc_channel_credentials;
+ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
channelArgs:(nullable NSDictionary *)channelArgs;
- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path
completionQueue:(nonnull GRPCCompletionQueue *)queue;
@end

@ -38,6 +38,8 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#import "GRPCCompletionQueue.h"
/**
* Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
* be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
@ -205,4 +207,16 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
channelArgs:channelArgs];
}
- (grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue {
return grpc_channel_create_call(_unmanagedChannel,
NULL, GRPC_PROPAGATE_DEFAULTS,
queue.unmanagedQueue,
path.UTF8String,
// Get "host" from "host:port"
// TODO(jcanizales): Use NSURLs throughout, to clarify these.
[_host componentsSeparatedByString:@":"][0].UTF8String,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
@end

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,6 +36,8 @@
typedef void(^GRPCQueueCompletionHandler)(bool success);
extern const int64_t kGRPCCompletionQueueDefaultTimeoutSecs;
/**
* This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the
* |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for
@ -49,6 +51,11 @@ typedef void(^GRPCQueueCompletionHandler)(bool success);
*/
@interface GRPCCompletionQueue : NSObject
@property(nonatomic, readonly) grpc_completion_queue *unmanagedQueue;
@property(nonatomic, readonly) int64_t timeoutSecs;
+ (instancetype)completionQueue;
- (instancetype)init;
- (instancetype)initWithTimeout:(int64_t)timeoutSecs NS_DESIGNATED_INITIALIZER;
@end

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,15 +35,28 @@
#import <grpc/grpc.h>
const int64_t kGRPCCompletionQueueDefaultTimeoutSecs = 60;
@implementation GRPCCompletionQueue
+ (instancetype)completionQueue {
return [[self alloc] init];
static GRPCCompletionQueue *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[self alloc] init];
});
return singleton;
}
- (instancetype)init {
return [self initWithTimeout:kGRPCCompletionQueueDefaultTimeoutSecs];
}
- (instancetype)initWithTimeout:(int64_t)timeoutSecs {
if ((self = [super init])) {
_unmanagedQueue = grpc_completion_queue_create(NULL);
_timeoutSecs = timeoutSecs;
// This is for the following block to capture the pointer by value (instead
// of retaining self and doing self->_unmanagedQueue). This is essential
@ -61,22 +74,28 @@
gDefaultConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
});
dispatch_async(gDefaultConcurrentQueue, ^{
// Using a non-infinite deadline to re-enter grpc_completion_queue_next()
// alleviates https://github.com/grpc/grpc/issues/5593
gpr_timespec deadline = (timeoutSecs < 0)
? gpr_inf_future(GPR_CLOCK_REALTIME)
: gpr_time_from_seconds(timeoutSecs, GPR_CLOCK_REALTIME);
while (YES) {
// The following call blocks until an event is available.
grpc_event event = grpc_completion_queue_next(unmanagedQueue,
gpr_inf_future(GPR_CLOCK_REALTIME),
NULL);
// The following call blocks until an event is available or the deadline elapses.
grpc_event event = grpc_completion_queue_next(unmanagedQueue, deadline, NULL);
GRPCQueueCompletionHandler handler;
switch (event.type) {
case GRPC_OP_COMPLETE:
handler = (__bridge_transfer GRPCQueueCompletionHandler)event.tag;
handler(event.success);
break;
case GRPC_QUEUE_TIMEOUT:
// Nothing to do here
break;
case GRPC_QUEUE_SHUTDOWN:
grpc_completion_queue_destroy(unmanagedQueue);
return;
default:
[NSException raise:@"Unrecognized completion type" format:@""];
[NSException raise:@"Unrecognized completion type" format:@"type=%d", event.type];
}
};
});

@ -0,0 +1,77 @@
/*
*
* 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 <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
@interface GRPCReachabilityFlags : NSObject
+ (nonnull instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags;
/**
* One accessor method to query each of the different flags. Example:
@property(nonatomic, readonly) BOOL isCell;
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
@property(nonatomic, readonly) BOOL methodName;
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
@property(nonatomic, readonly) BOOL isHostReachable;
@end
@interface GRPCConnectivityMonitor : NSObject
+ (nullable instancetype)monitorWithHost:(nonnull NSString *)hostName;
- (nonnull instancetype)init NS_UNAVAILABLE;
/**
* Queue on which callbacks will be dispatched. Default is the main queue. Set it before calling
* handleLossWithHandler:.
*/
// TODO(jcanizales): Default to a serial background queue instead.
@property(nonatomic, strong, null_resettable) dispatch_queue_t queue;
/**
* Calls handler every time the connectivity to this instance's host is lost. If this instance is
* released before that happens, the handler won't be called.
* Only one handler is active at a time, so if this method is called again before the previous
* handler has been called, it might never be called at all (or yes, if it has already been queued).
*/
- (void)handleLossWithHandler:(nonnull void (^)())handler;
@end

@ -0,0 +1,192 @@
/*
*
* 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 "GRPCConnectivityMonitor.h"
#pragma mark Flags
@implementation GRPCReachabilityFlags {
SCNetworkReachabilityFlags _flags;
}
+ (instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags {
return [[self alloc] initWithFlags:flags];
}
- (instancetype)initWithFlags:(SCNetworkReachabilityFlags)flags {
if ((self = [super init])) {
_flags = flags;
}
return self;
}
/*
* One accessor method implementation per flag. Example:
- (BOOL)isCell { \
return !!(_flags & kSCNetworkReachabilityFlagsIsWWAN); \
}
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
- (BOOL)methodName { \
return !!(_flags & kSCNetworkReachabilityFlags ## FlagName); \
}
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
- (BOOL)isHostReachable {
// Note: connectionOnDemand means it'll be reachable only if using the CFSocketStream API or APIs
// on top of it.
// connectionRequired means we can't tell until a connection is attempted (e.g. for VPN on
// demand).
return self.reachable && !self.interventionRequired && !self.connectionOnDemand;
}
- (NSString *)description {
NSMutableArray *activeOptions = [NSMutableArray arrayWithCapacity:9];
/*
* For each flag, add its name to the array if it's ON. Example:
if (self.isCell) {
[activeOptions addObject:@"isCell"];
}
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
if (self.methodName) { \
[activeOptions addObject:@#methodName]; \
}
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
return activeOptions.count == 0 ? @"(none)" : [activeOptions componentsJoinedByString:@", "];
}
- (BOOL)isEqual:(id)object {
return [object isKindOfClass:[GRPCReachabilityFlags class]] &&
_flags == ((GRPCReachabilityFlags *)object)->_flags;
}
- (NSUInteger)hash {
return _flags;
}
@end
#pragma mark Connectivity Monitor
// Assumes the third argument is a block that accepts a GRPCReachabilityFlags object, and passes the
// received ones to it.
static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void *info) {
#pragma unused (target)
// This can be called many times with the same info. The info is retained by SCNetworkReachability
// while this function is being executed.
void (^handler)(GRPCReachabilityFlags *) = (__bridge void (^)(GRPCReachabilityFlags *))info;
handler([[GRPCReachabilityFlags alloc] initWithFlags:flags]);
}
@implementation GRPCConnectivityMonitor {
SCNetworkReachabilityRef _reachabilityRef;
}
- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
if (!reachability) {
return nil;
}
if ((self = [super init])) {
_reachabilityRef = CFRetain(reachability);
_queue = dispatch_get_main_queue();
}
return self;
}
+ (nullable instancetype)monitorWithHost:(nonnull NSString *)host {
const char *hostName = host.UTF8String;
if (!hostName) {
[NSException raise:NSInvalidArgumentException
format:@"host.UTF8String returns NULL for %@", host];
}
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, hostName);
GRPCConnectivityMonitor *returnValue = [[self alloc] initWithReachability:reachability];
if (reachability) {
CFRelease(reachability);
}
return returnValue;
}
- (void)handleLossWithHandler:(void (^)())handler {
[self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
if (!flags.isHostReachable) {
handler();
}
}];
}
- (void)startListeningWithHandler:(void (^)(GRPCReachabilityFlags *))handler {
// Copy to ensure the handler block is in the heap (and so can't be deallocated when this method
// returns).
void (^copiedHandler)(GRPCReachabilityFlags *) = [handler copy];
SCNetworkReachabilityContext context = {
.version = 0,
.info = (__bridge void *)copiedHandler,
.retain = CFRetain,
.release = CFRelease,
};
// The following will retain context.info, and release it when the callback is set to NULL.
SCNetworkReachabilitySetCallback(_reachabilityRef, PassFlagsToContextInfoBlock, &context);
SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _queue);
}
- (void)stopListening {
// This releases the block on context.info.
SCNetworkReachabilitySetCallback(_reachabilityRef, NULL, NULL);
SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL);
}
- (void)setQueue:(dispatch_queue_t)queue {
_queue = queue ?: dispatch_get_main_queue();
}
- (void)dealloc {
if (_reachabilityRef) {
[self stopListening];
CFRelease(_reachabilityRef);
}
}
@end

@ -33,27 +33,39 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class GRPCCompletionQueue;
struct grpc_call;
@interface GRPCHost : NSObject
@property(nonatomic, readonly) NSString *address;
@property(nonatomic, copy) NSString *userAgentPrefix;
@property(nonatomic, copy, nullable) NSString *userAgentPrefix;
/** The following properties should only be modified for testing: */
@property(nonatomic, getter=isSecure) BOOL secure;
@property(nonatomic, copy) NSString *pathToCertificates;
@property(nonatomic, copy) NSString *hostNameOverride;
@property(nonatomic, copy, nullable) NSString *pathToCertificates;
@property(nonatomic, copy, nullable) NSString *hostNameOverride;
- (nullable instancetype)init NS_UNAVAILABLE;
/** Host objects initialized with the same address are the same. */
+ (instancetype)hostWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
+ (nullable instancetype)hostWithAddress:(NSString *)address;
- (nullable instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
/** Create a grpc_call object to the provided path on this host. */
- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue;
- (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue;
// TODO: There's a race when a new RPC is coming through just as an existing one is getting
// notified that there's no connectivity. If connectivity comes back at that moment, the new RPC
// will have its channel destroyed by the other RPC, and will never get notified of a problem, so
// it'll hang (the C layer logs a timeout, with exponential back off). One solution could be to pass
// the GRPCChannel to the GRPCCall, renaming this as "disconnectChannel:channel", which would only
// act on that specific channel.
- (void)disconnect;
@end
NS_ASSUME_NONNULL_END

@ -34,33 +34,30 @@
#import "GRPCHost.h"
#include <grpc/grpc.h>
#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+ChannelArg.h>
#import "GRPCChannel.h"
#import "GRPCCompletionQueue.h"
#import "NSDictionary+GRPC.h"
NS_ASSUME_NONNULL_BEGIN
// TODO(jcanizales): Generate the version in a standalone header, from templates. Like
// templates/src/core/surface/version.c.template .
#define GRPC_OBJC_VERSION_STRING @"0.13.0"
@interface GRPCHost ()
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@property(nonatomic, strong) GRPCChannel *channel;
@end
@implementation GRPCHost
+ (instancetype)hostWithAddress:(NSString *)address {
return [[self alloc] initWithAddress:address];
@implementation GRPCHost {
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
GRPCChannel *_channel;
}
- (instancetype)init {
return [self initWithAddress:nil];
+ (nullable instancetype)hostWithAddress:(NSString *)address {
return [[self alloc] initWithAddress:address];
}
// Default initializer.
- (instancetype)initWithAddress:(NSString *)address {
- (nullable instancetype)initWithAddress:(NSString *)address {
if (!address) {
return nil;
}
@ -95,46 +92,45 @@
return self;
}
- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
if (!queue || !path || !self.channel) {
return NULL;
- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue {
GRPCChannel *channel;
// This is racing -[GRPCHost disconnect].
@synchronized(self) {
if (!_channel) {
_channel = [self newChannel];
}
channel = _channel;
}
return grpc_channel_create_call(self.channel.unmanagedChannel,
NULL, GRPC_PROPAGATE_DEFAULTS,
queue.unmanagedQueue,
path.UTF8String,
self.hostName.UTF8String,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
return [channel unmanagedCallWithPath:path completionQueue:queue];
}
- (GRPCChannel *)channel {
// Create it lazily, because we don't want to open a connection just because someone is
// configuring a host.
- (NSDictionary *)channelArgs {
NSMutableDictionary *args = [NSMutableDictionary dictionary];
if (!_channel) {
NSMutableDictionary *args = [NSMutableDictionary dictionary];
// TODO(jcanizales): Add OS and device information (see
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
if (_userAgentPrefix) {
userAgent = [_userAgentPrefix stringByAppendingFormat:@" %@", userAgent];
}
args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
// TODO(jcanizales): Add OS and device information (see
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
if (_userAgentPrefix) {
userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
}
args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
if (_secure) {
if (_hostNameOverride) {
args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
}
_channel = [GRPCChannel secureChannelWithHost:_address
pathToCertificates:_pathToCertificates
channelArgs:args];
} else {
_channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
}
if (_secure && _hostNameOverride) {
args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
}
return args;
}
- (GRPCChannel *)newChannel {
NSDictionary *args = [self channelArgs];
if (_secure) {
return [GRPCChannel secureChannelWithHost:_address
pathToCertificates:_pathToCertificates
channelArgs:args];
} else {
return [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
}
return _channel;
}
- (NSString *)hostName {
@ -142,7 +138,16 @@
return _hostNameOverride ?: _address;
}
- (void)disconnect {
// This is racing -[GRPCHost unmanagedCallWithPath:completionQueue:].
@synchronized(self) {
_channel = nil;
}
}
// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
// have been set. Don't let set either of the latter if |secure| has been set to |NO|.
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,65 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* "X-macro" file that lists the flags names of Apple's Network Reachability API, along with a nice
* Objective-C method name used to query each of them.
*
* Example usage: To generate a dictionary from flag value to name, one can do:
NSDictionary *flagNames = @{
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
@(kSCNetworkReachabilityFlags ## FlagName): @#methodName,
#include "GRXReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
};
XCTAssertEqualObjects(flagNames[@(kSCNetworkReachabilityFlagsIsWWAN)], @"isCell");
*/
#ifndef GRPC_XMACRO_ITEM
#error This file is to be used with the "X-macro" pattern: Please #define \
GRPC_XMACRO_ITEM(methodName, FlagName), then #include this file, and then #undef \
GRPC_XMACRO_ITEM.
#endif
GRPC_XMACRO_ITEM(isCell, IsWWAN)
GRPC_XMACRO_ITEM(reachable, Reachable)
GRPC_XMACRO_ITEM(transientConnection, TransientConnection)
GRPC_XMACRO_ITEM(connectionRequired, ConnectionRequired)
GRPC_XMACRO_ITEM(connectionOnTraffic, ConnectionOnTraffic)
GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
GRPC_XMACRO_ITEM(isDirect, IsDirect)

@ -34,7 +34,6 @@
#import <Foundation/Foundation.h>
#include <grpc/grpc.h>
#import "GRPCChannel.h"
#import "GRPCRequestHeaders.h"
@interface GRPCOperation : NSObject
@ -94,4 +93,5 @@
- (void)startBatchWithOperations:(NSArray *)ops;
- (void)cancel;
@end

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -42,11 +42,42 @@
if (!handler) {
return [[self alloc] init];
}
return [[self alloc] initWithValueHandler:^(id value) {
handler(value, nil);
} completionHandler:^(NSError *errorOrNil) {
if (errorOrNil) {
handler(nil, errorOrNil);
// We nilify this variable when the block is invoked, so that handler is only invoked once even if
// the writer tries to write multiple values.
__block GRXEventHandler eventHandler = ^(BOOL done, id value, NSError *error) {
// Nillify eventHandler before invoking handler, in case the latter causes the former to be
// executed recursively. Because blocks can be deallocated even during execution, we have to
// first retain handler locally to guarantee it's valid.
// TODO(jcanizales): Just turn this craziness into a simple subclass of GRXWriteable.
GRXSingleHandler singleHandler = handler;
eventHandler = nil;
if (value) {
singleHandler(value, nil);
} else if (error) {
singleHandler(nil, error);
} else {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: @"The writer finished without producing any value."
};
// Even though RxLibrary is independent of gRPC, the domain and code here are, for the moment,
// set to the values of kGRPCErrorDomain and GRPCErrorCodeInternal. This way, the error formed
// is the one user of gRPC would expect if the server failed to produce a response.
//
// TODO(jcanizales): Figure out a way to keep errors of RxLibrary generic without making users
// of gRPC take care of two different error domains and error code enums. A possibility is to
// add error handling to GRXWriters or GRXWriteables, and use them to translate errors between
// the two domains.
static NSString *kGRPCErrorDomain = @"io.grpc";
static NSUInteger kGRPCErrorCodeInternal = 13;
singleHandler(nil, [NSError errorWithDomain:kGRPCErrorDomain
code:kGRPCErrorCodeInternal
userInfo:userInfo]);
}
};
return [self writeableWithEventHandler:^(BOOL done, id value, NSError *error) {
if (eventHandler) {
eventHandler(done, value, error);
}
}];
}

@ -273,10 +273,12 @@ static ProtoMethod *kUnaryCallMethod;
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTAssertNotNil(value, @"nil value received as response.");
XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
/* This test needs to be more clever in regards to changing the version of the core.
XCTAssertEqualObjects(call.responseHeaders[@"x-grpc-test-echo-useragent"],
@"Foo grpc-objc/0.13.0 grpc-c/0.14.0-dev (ios)",
@"Did not receive expected user agent %@",
call.responseHeaders[@"x-grpc-test-echo-useragent"]);
*/
[response fulfill];
} completionHandler:^(NSError *errorOrNil) {
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);

@ -64,6 +64,8 @@
}
@end
// TODO(jcanizales): Split into one file per tested class.
@interface RxLibraryUnitTests : XCTestCase
@end
@ -79,6 +81,7 @@
// If:
id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
[writeable writeValue:anyValue];
[writeable writesFinishedWithError:nil];
// Then:
XCTAssertEqual(handler.timesCalled, 1);
@ -101,6 +104,54 @@
XCTAssertEqualObjects(handler.errorOrNil, anyError);
}
- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenError {
// Given:
CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
id anyValue = @7;
NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil];
// If:
id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
[writeable writeValue:anyValue];
[writeable writesFinishedWithError:anyError];
// Then:
XCTAssertEqual(handler.timesCalled, 1);
XCTAssertEqualObjects(handler.value, anyValue);
XCTAssertEqualObjects(handler.errorOrNil, nil);
}
- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenValue {
// Given:
CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
id anyValue = @7;
// If:
id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
[writeable writeValue:anyValue];
[writeable writeValue:anyValue];
[writeable writesFinishedWithError:nil];
// Then:
XCTAssertEqual(handler.timesCalled, 1);
XCTAssertEqualObjects(handler.value, anyValue);
XCTAssertEqualObjects(handler.errorOrNil, nil);
}
- (void)testWriteableSingleHandlerFailsOnEmptyWriter {
// Given:
CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
// If:
id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
[writeable writesFinishedWithError:nil];
// Then:
XCTAssertEqual(handler.timesCalled, 1);
XCTAssertEqualObjects(handler.value, nil);
XCTAssertNotNil(handler.errorOrNil);
}
#pragma mark BufferedPipe
- (void)testBufferedPipePropagatesValue {

@ -9,14 +9,21 @@ Beta
## Environment
Prerequisite: PHP 5.5 or later, `phpunit`, `pecl`
Prerequisite: `php` >=5.5, `phpize`, `pecl`, `phpunit`
**Linux:**
**Linux (Debian):**
```sh
$ sudo apt-get install php5 php5-dev php-pear
```
**Linux (CentOS):**
```sh
$ yum install php55w
$ yum --enablerepo=remi,remi-php55 install php-devel php-pear
```
**Mac OS X:**
```sh
@ -24,11 +31,11 @@ $ curl -O http://pear.php.net/go-pear.phar
$ sudo php -d detect_unicode=0 go-pear.phar
```
**PHPUnit: (Both Linux and Mac OS X)**
**PHPUnit:**
```sh
$ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar
$ chmod +x phpunit.phar
$ sudo mv phpunit.phar /usr/local/bin/phpunit
$ wget https://phar.phpunit.de/phpunit-old.phar
$ chmod +x phpunit-old.phar
$ sudo mv phpunit-old.phar /usr/bin/phpunit
```
## Quick Install
@ -39,15 +46,22 @@ Install the gRPC PHP extension
sudo pecl install grpc-beta
```
This will compile and install the gRPC PHP extension into the standard PHP extension directory. You should be able to run the [unit tests](#unit-tests), with the PHP extension installed.
To run tests with generated stub code from `.proto` files, you will also need the `composer`, `protoc` and `protoc-gen-php` binaries. You can find out how to get these [below](#generated-code-tests).
## Build from Source
### gRPC C core library
Clone this repository
```sh
$ git clone https://github.com/grpc/grpc.git
```
Build and install the gRPC C core libraries
Build and install the gRPC C core library
```sh
$ cd grpc
@ -56,20 +70,15 @@ $ make
$ sudo make install
```
Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
### gRPC PHP extension
```sh
$ cd grpc/third_party/protobuf
$ sudo make install # 'make' should have been run by core grpc
```
Install the gRPC PHP extension
Install the gRPC PHP extension from PECL
```sh
$ sudo pecl install grpc-beta
```
OR
Or, compile from source
```sh
$ cd grpc/src/php/ext/grpc
@ -79,58 +88,98 @@ $ make
$ sudo make install
```
### Update php.ini
Add this line to your `php.ini` file, e.g. `/etc/php5/cli/php.ini`
```sh
extension=grpc.so
```
Install Composer
## Unit Tests
You will need the source code to run tests
```sh
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git pull --recurse-submodules && git submodule update --init --recursive
```
Run unit tests
```sh
$ cd grpc/src/php
$ ./bin/run_tests.sh
```
## Generated Code Tests
This section specifies the prerequisites for running the generated code tests, as well as how to run the tests themselves.
### Composer
If you don't have it already, install `composer` to pull in some runtime dependencies based on the `composer.json` file.
```sh
$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer
$ cd grpc/src/php
$ composer install
```
## Unit Tests
### Protobuf compiler
Run unit tests
Again if you don't have it already, you need to install the protobuf compiler `protoc`, version 3.0.0+.
If you compiled the gRPC C core library from source above, the `protoc` binary should have been installed as well. If it hasn't been installed, you can run the following commands to install it.
```sh
$ cd grpc/src/php
$ ./bin/run_tests.sh
$ cd grpc/third_party/protobuf
$ sudo make install # 'make' should have been run by core grpc
```
## Generated Code Tests
Alternatively, you can download `protoc` binaries from [the protocol buffers Github repository](https://github.com/google/protobuf/releases).
Install `protoc-gen-php`
### PHP protobuf compiler
You need to install `protoc-gen-php` to generate stub class `.php` files from service definition `.proto` files.
```sh
$ cd grpc/src/php/vendor/datto/protobuf-php
$ cd grpc/src/php/vendor/datto/protobuf-php # if you had run `composer install` in the previous step
OR
$ git clone https://github.com/stanley-cheung/Protobuf-PHP # clone from github repo
$ gem install rake ronn
$ rake pear:package version=1.0
$ sudo pear install Protobuf-1.0.tgz
```
Generate client stub code
### Client Stub
Generate client stub classes from `.proto` files
```sh
$ cd grpc/src/php
$ ./bin/generate_proto_php.sh
```
Run a local server serving the math services
### Run test server
- Please see [Node][] on how to run an example server
Run a local server serving the math services. Please see [Node][] for how to run an example server.
```sh
$ cd grpc/src/node
$ cd grpc
$ npm install
$ nodejs examples/math_server.js
$ nodejs src/node/test/math/math_server.js
```
### Run test client
Run the generated code tests
```sh
@ -161,13 +210,15 @@ $ sudo service apache2 restart
Make sure the Node math server is still running, as above.
```sh
$ cd grpc/src/node
$ nodejs examples/math_server.js
$ cd grpc
$ npm install
$ nodejs src/node/test/math/math_server.js
```
Make sure you have run `composer install` to generate the `vendor/autoload.php` file
```sh
$ cd grpc/src/php
$ composer install
```
@ -229,13 +280,15 @@ $ sudo service php5-fpm restart
Make sure the Node math server is still running, as above.
```sh
$ cd grpc/src/node
$ nodejs examples/math_server.js
$ cd grpc
$ npm install
$ nodejs src/node/test/math/math_server.js
```
Make sure you have run `composer install` to generate the `vendor/autoload.php` file
```sh
$ cd grpc/src/php
$ composer install
```

@ -1,7 +1,9 @@
{
"name": "grpc/grpc",
"type": "library",
"description": "gRPC library for PHP",
"version": "0.6.0",
"version": "0.14.0",
"keywords": ["rpc"],
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",
"repositories": [
@ -13,7 +15,7 @@
"require": {
"php": ">=5.5.0",
"datto/protobuf-php": "dev-master",
"google/auth": "dev-master"
"google/auth": "v0.7"
},
"autoload": {
"psr-4": {

@ -1,67 +0,0 @@
gRPC PHP Extension
==================
# Requirements
* PHP 5.5+
* [gRPC core library](https://github.com/grpc/grpc) 0.11.0
# Installation
## Install PHP 5
```
$ sudo apt-get install git php5 php5-dev php-pear unzip
```
## Compile gRPC Core Library
Clone the gRPC source code repository
```
$ git clone https://github.com/grpc/grpc.git
```
Build and install the gRPC C core libraries
```sh
$ cd grpc
$ git checkout --track origin/release-0_11
$ git pull --recurse-submodules && git submodule update --init --recursive
$ make
$ sudo make install
```
Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
```sh
$ cd grpc/third_party/protobuf
$ sudo make install # 'make' should have been run by core grpc
```
## Install the gRPC PHP extension
Quick install
```sh
$ sudo pecl install grpc
```
Note: before a stable release, you may need to do
```sh
$ sudo pecl install grpc-beta
```
OR
Compile from source
```sh
$ # from grpc
$ cd src/php/ext/grpc
$ phpize
$ ./configure
$ make
$ sudo make install
```

@ -1,7 +1,7 @@
<?php
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,7 +43,9 @@ function p($line)
$host = 'localhost:50051';
p("Connecting to host: $host");
$client = new math\MathClient($host, []);
$client = new math\MathClient($host, [
'credentials' => Grpc\ChannelCredentials::createInsecure()
]);
p('Client class: '.get_class($client));
p('');

@ -42,6 +42,7 @@ message RequestParams {
bool echo_peer = 7;
string expected_client_identity = 8; // will force check_auth_context.
bool skip_cancelled_check = 9;
string expected_transport_security_type = 10;
}
message EchoRequest {

@ -6,7 +6,7 @@ Package for gRPC Python.
Installation
------------
gRPC Python is available for Linux and Mac OS X running Python 2.7.
gRPC Python is available for Linux, Mac OS X, and Windows running Python 2.7.
From PyPI
~~~~~~~~~
@ -23,11 +23,15 @@ Else system wide (on Ubuntu)...
$ sudo pip install grpcio
n.b. On Windows and on Mac OS X one *must* have a recent release of :code:`pip`
to retrieve the proper wheel from PyPI. Be sure to upgrade to the latest
version!
From Source
~~~~~~~~~~~
Building from source requires that you have the Python headers (usually a
package named `python-dev`).
package named :code:`python-dev`).
::
@ -36,5 +40,19 @@ package named `python-dev`).
$ cd $REPO_ROOT
$ pip install .
Note that `$REPO_ROOT` can be assigned to whatever directory name floats your
fancy.
Note that :code:`$REPO_ROOT` can be assigned to whatever directory name floats
your fancy.
Troubleshooting
~~~~~~~~~~~~~~~
Help, I ...
* **... see a** :code:`pkg_resources.VersionConflict` **when I try to install
grpc!**
This is likely because :code:`pip` doesn't own the offending dependency,
which in turn is likely because your operating system's package manager owns
it. You'll need to force the installation of the dependency:
:code:`pip install --ignore-installed $OFFENDING_DEPENDENCY`

@ -119,8 +119,7 @@ class SphinxDocumentation(setuptools.Command):
import sphinx
import sphinx.apidoc
metadata = self.distribution.metadata
src_dir = os.path.join(
PYTHON_STEM, self.distribution.package_dir[''], 'grpc')
src_dir = os.path.join(PYTHON_STEM, 'grpc')
sys.path.append(src_dir)
sphinx.apidoc.main([
'', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
@ -264,6 +263,42 @@ class Gather(setuptools.Command):
self.distribution.fetch_build_eggs(self.distribution.tests_require)
class TestLite(setuptools.Command):
"""Command to run tests without fetching or building anything."""
description = 'run tests without fetching or building anything.'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
# distutils requires this override.
pass
def run(self):
self._add_eggs_to_path()
import tests
loader = tests.Loader()
loader.loadTestsFromNames(['tests'])
runner = tests.Runner()
result = runner.run(loader.suite)
if not result.wasSuccessful():
sys.exit('Test failure')
def _add_eggs_to_path(self):
"""Adds all egg files under .eggs to sys.path"""
# TODO(jtattemusch): there has to be a cleaner way to do this
import pkg_resources
eggs_dir = os.path.join(PYTHON_STEM, '../../../.eggs')
eggs = [os.path.join(eggs_dir, filename)
for filename in os.listdir(eggs_dir)
if filename.endswith('.egg')]
for egg in eggs:
sys.path.insert(0, pkg_resources.normalize_path(egg))
class RunInterop(test.test):
description = 'run interop test client/server'

@ -95,7 +95,6 @@ cdef class Channel:
self, grpc_connectivity_state last_observed_state,
Timespec deadline not None, CompletionQueue queue not None, tag):
cdef OperationTag operation_tag = OperationTag(tag)
operation_tag.references = [self, queue]
cpython.Py_INCREF(operation_tag)
grpc_channel_watch_connectivity_state(
self.c_channel, last_observed_state, deadline.c_time,

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc.
# Copyright 2015-2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -31,8 +31,9 @@
cdef class CompletionQueue:
cdef grpc_completion_queue *c_completion_queue
cdef object poll_condition
cdef bint is_polling
cdef object pluck_condition
cdef int num_plucking
cdef int num_polling
cdef bint is_shutting_down
cdef bint is_shutdown

@ -39,8 +39,9 @@ cdef class CompletionQueue:
self.c_completion_queue = grpc_completion_queue_create(NULL)
self.is_shutting_down = False
self.is_shutdown = False
self.poll_condition = threading.Condition()
self.is_polling = False
self.pluck_condition = threading.Condition()
self.num_plucking = 0
self.num_polling = 0
cdef _interpret_event(self, grpc_event event):
cdef OperationTag tag = None
@ -87,19 +88,15 @@ cdef class CompletionQueue:
c_deadline = deadline.c_time
cdef grpc_event event
# Poll within a critical section
# TODO(atash) consider making queue polling contention a hard error to
# enable easier bug discovery
with self.poll_condition:
while self.is_polling:
self.poll_condition.wait(float(deadline) - time.time())
self.is_polling = True
# Poll within a critical section to detect contention
with self.pluck_condition:
assert self.num_plucking == 0, 'cannot simultaneously pluck and poll'
self.num_polling += 1
with nogil:
event = grpc_completion_queue_next(
self.c_completion_queue, c_deadline, NULL)
with self.poll_condition:
self.is_polling = False
self.poll_condition.notify()
with self.pluck_condition:
self.num_polling -= 1
return self._interpret_event(event)
def pluck(self, OperationTag tag, Timespec deadline=None):
@ -111,19 +108,18 @@ cdef class CompletionQueue:
c_deadline = deadline.c_time
cdef grpc_event event
# Poll within a critical section
# TODO(atash) consider making queue polling contention a hard error to
# enable easier bug discovery
with self.poll_condition:
while self.is_polling:
self.poll_condition.wait(float(deadline) - time.time())
self.is_polling = True
# Pluck within a critical section to detect contention
with self.pluck_condition:
assert self.num_polling == 0, 'cannot simultaneously pluck and poll'
assert self.num_plucking < GRPC_MAX_COMPLETION_QUEUE_PLUCKERS, (
'cannot pluck more than {} times simultaneously'.format(
GRPC_MAX_COMPLETION_QUEUE_PLUCKERS))
self.num_plucking += 1
with nogil:
event = grpc_completion_queue_pluck(
self.c_completion_queue, <cpython.PyObject *>tag, c_deadline, NULL)
with self.poll_condition:
self.is_polling = False
self.poll_condition.notify()
with self.pluck_condition:
self.num_plucking -= 1
return self._interpret_event(event)
def shutdown(self):
@ -144,7 +140,8 @@ cdef class CompletionQueue:
grpc_completion_queue_shutdown(self.c_completion_queue)
# Pump the queue
while not self.is_shutdown:
event = grpc_completion_queue_next(
self.c_completion_queue, c_deadline, NULL)
with nogil:
event = grpc_completion_queue_next(
self.c_completion_queue, c_deadline, NULL)
self._interpret_event(event)
grpc_completion_queue_destroy(self.c_completion_queue)

@ -138,6 +138,8 @@ cdef extern from "grpc/_cython/loader.h":
const int GRPC_WRITE_NO_COMPRESS
const int GRPC_WRITE_USED_MASK
const int GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
ctypedef struct grpc_completion_queue:
# We don't care about the internals (and in fact don't know them)
pass

@ -106,7 +106,6 @@ cdef class Server:
self.is_shutting_down = True
operation_tag = OperationTag(tag)
operation_tag.shutting_down_server = self
operation_tag.references.extend([self, queue])
cpython.Py_INCREF(operation_tag)
grpc_server_shutdown_and_notify(
self.c_server, queue.c_completion_queue,

@ -220,6 +220,7 @@ gpr_event_get_type gpr_event_get_import;
gpr_event_wait_type gpr_event_wait_import;
gpr_ref_init_type gpr_ref_init_import;
gpr_ref_type gpr_ref_import;
gpr_ref_non_zero_type gpr_ref_non_zero_import;
gpr_refn_type gpr_refn_import;
gpr_unref_type gpr_unref_import;
gpr_stats_init_type gpr_stats_init_import;
@ -485,6 +486,7 @@ void pygrpc_load_imports(HMODULE library) {
gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait");
gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init");
gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref");
gpr_ref_non_zero_import = (gpr_ref_non_zero_type) GetProcAddress(library, "gpr_ref_non_zero");
gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");

@ -610,6 +610,9 @@ extern gpr_ref_init_type gpr_ref_init_import;
typedef void(*gpr_ref_type)(gpr_refcount *r);
extern gpr_ref_type gpr_ref_import;
#define gpr_ref gpr_ref_import
typedef void(*gpr_ref_non_zero_type)(gpr_refcount *r);
extern gpr_ref_non_zero_type gpr_ref_non_zero_import;
#define gpr_ref_non_zero gpr_ref_non_zero_import
typedef void(*gpr_refn_type)(gpr_refcount *r, int n);
extern gpr_refn_type gpr_refn_import;
#define gpr_refn gpr_refn_import

@ -31,6 +31,7 @@ import os
import platform
import shutil
import sys
import sysconfig
import setuptools
@ -51,9 +52,15 @@ USE_PRECOMPILED_BINARIES = bool(int(os.environ.get(
def _tagged_ext_name(base):
uname = platform.uname()
tags = '-'.join((grpc_version.VERSION, uname[0], uname[4]))
flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
return '{base}-{tags}-{flavor}'.format(base=base, tags=tags, flavor=flavor)
tags = (
grpc_version.VERSION,
'py{}'.format(sysconfig.get_python_version()),
uname[0],
uname[4],
)
ucs = 'ucs{}'.format(sysconfig.get_config_var('Py_UNICODE_SIZE'))
return '{base}-{tags}-{ucs}'.format(
base=base, tags='-'.join(tags), ucs=ucs)
class BuildTaggedExt(setuptools.Command):

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc.
# Copyright 2015-2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -43,6 +43,13 @@ import uuid
from tests import _loader
from tests import _result
# This number needs to be large enough to outpace output on stdout and stderr
# from the gRPC core, otherwise we could end up in a potential deadlock. This
# stems from the OS waiting on someone to clear a filled pipe buffer while the
# GIL is held from a write to stderr from gRPC core, but said someone is in
# Python code thus necessitating GIL acquisition.
_READ_BYTES = 2**20
class CapturePipe(object):
"""A context-manager pipe to redirect output to a byte array.
@ -76,6 +83,10 @@ class CapturePipe(object):
flags = fcntl.fcntl(self._read_fd, fcntl.F_GETFL)
fcntl.fcntl(self._read_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
self._read_thread = threading.Thread(target=self._read)
# If the user wants to exit from the Python program and hits ctrl-C and the
# read thread is somehow deadlocked with something else, the Python code may
# refuse to exit. This prevents that by making the read thread second-class.
self._read_thread.daemon = True
self._read_thread.start()
def stop(self):
@ -93,7 +104,7 @@ class CapturePipe(object):
self.output = bytearray()
while True:
select.select([self._read_fd], [], [])
read_bytes = os.read(self._read_fd, 1024)
read_bytes = os.read(self._read_fd, _READ_BYTES)
if read_bytes:
self.output.extend(read_bytes)
else:
@ -143,10 +154,17 @@ class Runner(object):
def run(self, suite):
"""See setuptools' test_runner setup argument for information."""
# only run test cases with id starting with given prefix
testcase_filter = os.getenv('GRPC_PYTHON_TESTRUNNER_FILTER')
filtered_cases = []
for case in _loader.iterate_suite_cases(suite):
if not testcase_filter or case.id().startswith(testcase_filter):
filtered_cases.append(case)
# Ensure that every test case has no collision with any other test case in
# the augmented results.
augmented_cases = [AugmentedCase(case, uuid.uuid4())
for case in _loader.iterate_suite_cases(suite)]
for case in filtered_cases]
case_id_by_case = dict((augmented_case.case, augmented_case.id)
for augmented_case in augmented_cases)
result_out = StringIO.StringIO()

@ -0,0 +1,53 @@
[
"_base_interface_test.AsyncEasyTest",
"_base_interface_test.AsyncPeasyTest",
"_base_interface_test.SyncEasyTest",
"_base_interface_test.SyncPeasyTest",
"_beta_features_test.BetaFeaturesTest",
"_beta_features_test.ContextManagementAndLifecycleTest",
"_channel_test.ChannelTest",
"_connectivity_channel_test.ChannelConnectivityTest",
"_core_over_links_base_interface_test.AsyncEasyTest",
"_core_over_links_base_interface_test.AsyncPeasyTest",
"_core_over_links_base_interface_test.SyncEasyTest",
"_core_over_links_base_interface_test.SyncPeasyTest",
"_crust_over_core_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
"_crust_over_core_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
"_crust_over_core_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
"_crust_over_core_over_links_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_over_links_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
"_crust_over_core_over_links_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_over_links_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
"_crust_over_core_over_links_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
"_crust_over_core_over_links_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
"_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
"_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
"_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
"_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
"_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
"_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
"_implementations_test.ChannelCredentialsTest",
"_insecure_interop_test.InsecureInteropTest",
"_intermediary_low_test.CancellationTest",
"_intermediary_low_test.EchoTest",
"_intermediary_low_test.ExpirationTest",
"_intermediary_low_test.LonelyClientTest",
"_later_test.LaterTest",
"_logging_pool_test.LoggingPoolTest",
"_lonely_invocation_link_test.LonelyInvocationLinkTest",
"_low_test.HangingServerShutdown",
"_low_test.InsecureServerInsecureClient",
"_not_found_test.NotFoundTest",
"_sanity_test.Sanity",
"_secure_interop_test.SecureInteropTest",
"_transmission_test.RoundTripTest",
"_transmission_test.TransmissionTest",
"_utilities_test.ChannelConnectivityTest",
"beta_python_plugin_test.PythonPluginTest",
"cygrpc_test.InsecureServerInsecureClient",
"cygrpc_test.SecureServerSecureClient",
"cygrpc_test.TypeSmokeTest"
]

@ -0,0 +1,30 @@
# 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.

@ -0,0 +1,53 @@
# 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 json
import unittest
import tests
class Sanity(unittest.TestCase):
def testTestsJsonUpToDate(self):
"""Autodiscovers all test suites and checks that tests.json is up to date"""
loader = tests.Loader()
loader.loadTestsFromNames(['tests'])
test_suite_names = [
test_case_class.id().rsplit('.', 1)[0]
for test_case_class in tests._loader.iterate_suite_cases(loader.suite)]
test_suite_names = sorted(set(test_suite_names))
with open('src/python/grpcio/tests/tests.json') as tests_json_file:
tests_json = json.load(tests_json_file)
self.assertListEqual(test_suite_names, tests_json)
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -1,381 +0,0 @@
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Test code for the Face layer of RPC Framework."""
import abc
import unittest
# test_interfaces is referenced from specification in this module.
from grpc.framework.interfaces.face import face
from tests.unit.framework.common import test_constants
from tests.unit.framework.common import test_control
from tests.unit.framework.common import test_coverage
from tests.unit.framework.interfaces.face import _3069_test_constant
from tests.unit.framework.interfaces.face import _digest
from tests.unit.framework.interfaces.face import _receiver
from tests.unit.framework.interfaces.face import _stock_service
from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
class TestCase(test_coverage.Coverage, unittest.TestCase):
"""A test of the Face layer of RPC Framework.
Concrete subclasses must have an "implementation" attribute of type
test_interfaces.Implementation and an "invoker_constructor" attribute of type
_invocation.InvokerConstructor.
"""
__metaclass__ = abc.ABCMeta
NAME = 'EventInvocationSynchronousEventServiceTest'
def setUp(self):
"""See unittest.TestCase.setUp for full specification.
Overriding implementations must call this implementation.
"""
self._control = test_control.PauseFailControl()
self._digest = _digest.digest(
_stock_service.STOCK_TEST_SERVICE, self._control, None)
generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate(
self._digest.methods, self._digest.event_method_implementations, None)
self._invoker = self.invoker_constructor.construct_invoker(
generic_stub, dynamic_stubs, self._digest.methods)
def tearDown(self):
"""See unittest.TestCase.tearDown for full specification.
Overriding implementations must call this implementation.
"""
self._invoker = None
self.implementation.destantiate(self._memo)
def testSuccessfulUnaryRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
receiver.block_until_terminated()
response = receiver.unary_response()
test_messages.verify(request, response, self)
def testSuccessfulUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
receiver.block_until_terminated()
responses = receiver.stream_responses()
test_messages.verify(request, responses, self)
def testSuccessfulStreamRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
for request in requests:
call_consumer.consume(request)
call_consumer.terminate()
receiver.block_until_terminated()
response = receiver.unary_response()
test_messages.verify(requests, response, self)
def testSuccessfulStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
for request in requests:
call_consumer.consume(request)
call_consumer.terminate()
receiver.block_until_terminated()
responses = receiver.stream_responses()
test_messages.verify(requests, responses, self)
def testSequentialInvocations(self):
# pylint: disable=cell-var-from-loop
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
first_request = test_messages.request()
second_request = test_messages.request()
second_receiver = _receiver.Receiver()
def make_second_invocation():
self._invoker.event(group, method)(
second_request, second_receiver, second_receiver.abort,
test_constants.LONG_TIMEOUT)
class FirstReceiver(_receiver.Receiver):
def complete(self, terminal_metadata, code, details):
super(FirstReceiver, self).complete(
terminal_metadata, code, details)
make_second_invocation()
first_receiver = FirstReceiver()
self._invoker.event(group, method)(
first_request, first_receiver, first_receiver.abort,
test_constants.LONG_TIMEOUT)
second_receiver.block_until_terminated()
first_response = first_receiver.unary_response()
second_response = second_receiver.unary_response()
test_messages.verify(first_request, first_response, self)
test_messages.verify(second_request, second_response, self)
def testParallelInvocations(self):
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
first_request = test_messages.request()
first_receiver = _receiver.Receiver()
second_request = test_messages.request()
second_receiver = _receiver.Receiver()
self._invoker.event(group, method)(
first_request, first_receiver, first_receiver.abort,
test_constants.LONG_TIMEOUT)
self._invoker.event(group, method)(
second_request, second_receiver, second_receiver.abort,
test_constants.LONG_TIMEOUT)
first_receiver.block_until_terminated()
second_receiver.block_until_terminated()
first_response = first_receiver.unary_response()
second_response = second_receiver.unary_response()
test_messages.verify(first_request, first_response, self)
test_messages.verify(second_request, second_response, self)
@unittest.skip('TODO(nathaniel): implement.')
def testWaitingForSomeButNotAllParallelInvocations(self):
raise NotImplementedError()
def testCancelledUnaryRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
with self._control.pause():
call = self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
call.cancel()
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
def testCancelledUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
call = self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
call.cancel()
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
def testCancelledStreamRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
for request in requests:
call_consumer.consume(request)
call_consumer.cancel()
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
def testCancelledStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_stream_messages_sequences.iteritems()):
for unused_test_messages in test_messages_sequence:
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
call_consumer.cancel()
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
def testExpiredUnaryRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
with self._control.pause():
self._invoker.event(group, method)(
request, receiver, receiver.abort,
_3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
def testExpiredUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
with self._control.pause():
self._invoker.event(group, method)(
request, receiver, receiver.abort,
_3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
def testExpiredStreamRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_unary_messages_sequences.iteritems()):
for unused_test_messages in test_messages_sequence:
receiver = _receiver.Receiver()
self._invoker.event(group, method)(
receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
def testExpiredStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
for request in requests:
call_consumer.consume(request)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
def testFailedUnaryRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
with self._control.fail():
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(
face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
def testFailedUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.unary_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
request = test_messages.request()
receiver = _receiver.Receiver()
with self._control.fail():
self._invoker.event(group, method)(
request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(
face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
def testFailedStreamRequestUnaryResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_unary_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
with self._control.fail():
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
for request in requests:
call_consumer.consume(request)
call_consumer.terminate()
receiver.block_until_terminated()
self.assertIs(
face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
def testFailedStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
self._digest.stream_stream_messages_sequences.iteritems()):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
receiver = _receiver.Receiver()
with self._control.fail():
call_consumer = self._invoker.event(group, method)(
receiver, receiver.abort, test_constants.LONG_TIMEOUT)
for request in requests:
call_consumer.consume(request)
call_consumer.terminate()
receiver.block_until_terminated()
self.assertIs(
face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)

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

Loading…
Cancel
Save