Merge branch 'master' into poisson

Conflicts:
	Makefile
	test/cpp/qps/client_async.cc
	test/cpp/qps/qpstest.proto
pull/1948/head
vjpai 10 years ago
commit 675140ca1d
  1. 20
      .travis.yml
  2. 436
      Makefile
  3. 88
      build.json
  4. 12
      doc/interop-test-descriptions.md
  5. 3
      include/grpc++/config.h
  6. 6
      include/grpc++/stream.h
  7. 81
      include/grpc/grpc.h
  8. 10
      include/grpc/support/subprocess.h
  9. 221
      src/compiler/cpp_generator.cc
  10. 56
      src/compiler/csharp_generator.cc
  11. 110
      src/compiler/objective_c_generator.cc
  12. 87
      src/compiler/ruby_generator.cc
  13. 1
      src/core/channel/client_channel.c
  14. 10
      src/core/httpcli/httpcli.c
  15. 96
      src/core/iomgr/fd_posix.c
  16. 28
      src/core/iomgr/fd_posix.h
  17. 2
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  18. 13
      src/core/iomgr/pollset_posix.c
  19. 6
      src/core/iomgr/sockaddr_utils.c
  20. 6
      src/core/support/subprocess_posix.c
  21. 56
      src/core/surface/call.c
  22. 13
      src/core/surface/call.h
  23. 16
      src/core/surface/call_log_batch.c
  24. 1
      src/core/surface/lame_client.c
  25. 14
      src/core/surface/server.c
  26. 2
      src/core/surface/server.h
  27. 3
      src/core/transport/chttp2/alpn.c
  28. 4
      src/core/transport/chttp2/hpack_parser.c
  29. 2
      src/core/transport/chttp2/hpack_parser.h
  30. 10
      src/core/tsi/ssl_transport_security.c
  31. 2
      src/cpp/server/server.cc
  32. 1
      src/csharp/Grpc.Auth/Grpc.Auth.csproj
  33. 3
      src/csharp/Grpc.Auth/Grpc.Auth.nuspec
  34. 1
      src/csharp/Grpc.Core/Grpc.Core.csproj
  35. 5
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  36. 77
      src/csharp/README.md
  37. 4
      src/csharp/build_packages.bat
  38. 2
      src/node/examples/math_server.js
  39. 2
      src/node/examples/stock_server.js
  40. 6
      src/node/interop/interop_client.js
  41. 2
      src/node/package.json
  42. 58
      src/node/src/client.js
  43. 4
      src/objective-c/ProtoRPC/ProtoRPC.m
  44. 119
      src/objective-c/README.md
  45. 2
      src/objective-c/examples/Sample/Podfile
  46. 2
      src/objective-c/examples/Sample/Sample/ViewController.m
  47. 2
      src/objective-c/examples/Sample/SampleTests/RemoteTests.m
  48. 2
      src/objective-c/examples/Sample/SampleTests/SampleTests.m
  49. 2
      src/python/src/grpc/_adapter/_face_test_case.py
  50. 4
      src/python/src/grpc/_adapter/_links_test.py
  51. 2
      src/python/src/grpc/_adapter/_lonely_rear_link_test.py
  52. 2
      src/python/src/grpc/_adapter/fore.py
  53. 2
      src/python/src/grpc/_adapter/rear.py
  54. 2
      src/python/src/grpc/early_adopter/implementations.py
  55. 2
      src/python/src/grpc/framework/base/implementations_test.py
  56. 2
      src/python/src/grpc/framework/face/_test_case.py
  57. 2
      src/python/src/grpc/framework/face/demonstration.py
  58. 2
      src/python/src/grpc/framework/face/testing/base_util.py
  59. 2
      src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
  60. 2
      src/python/src/setup.py
  61. 6
      src/ruby/.rubocop_todo.yml
  62. BIN
      src/ruby/core
  63. 4
      src/ruby/ext/grpc/rb_server.c
  64. 60
      src/ruby/lib/grpc/generic/rpc_server.rb
  65. 2
      src/ruby/lib/grpc/version.rb
  66. 4
      src/ruby/spec/generic/rpc_server_pool_spec.rb
  67. 42
      src/ruby/spec/generic/rpc_server_spec.rb
  68. 24
      templates/Makefile.template
  69. 2
      templates/tools/doxygen/Doxyfile.c++.template
  70. 2
      templates/tools/doxygen/Doxyfile.core.template
  71. 2375
      templates/tools/doxygen/Doxyfile.include
  72. 29
      templates/vsprojects/generate_debug_projects.sh
  73. 136
      test/core/bad_client/bad_client.c
  74. 52
      test/core/bad_client/bad_client.h
  75. 79
      test/core/bad_client/gen_build_json.py
  76. 79
      test/core/bad_client/tests/connection_prefix.c
  77. 4
      test/core/channel/channel_stack_test.c
  78. 2
      test/core/end2end/tests/bad_hostname.c
  79. 2
      test/core/end2end/tests/cancel_after_accept.c
  80. 2
      test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
  81. 2
      test/core/end2end/tests/cancel_after_invoke.c
  82. 2
      test/core/end2end/tests/cancel_before_invoke.c
  83. 2
      test/core/end2end/tests/cancel_in_a_vacuum.c
  84. 2
      test/core/end2end/tests/census_simple_request.c
  85. 2
      test/core/end2end/tests/disappearing_server.c
  86. 2
      test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
  87. 2
      test/core/end2end/tests/early_server_shutdown_finishes_tags.c
  88. 2
      test/core/end2end/tests/empty_batch.c
  89. 2
      test/core/end2end/tests/graceful_server_shutdown.c
  90. 2
      test/core/end2end/tests/invoke_large_request.c
  91. 2
      test/core/end2end/tests/max_concurrent_streams.c
  92. 2
      test/core/end2end/tests/max_message_length.c
  93. 2
      test/core/end2end/tests/no_op.c
  94. 2
      test/core/end2end/tests/ping_pong_streaming.c
  95. 4
      test/core/end2end/tests/registered_call.c
  96. 2
      test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
  97. 2
      test/core/end2end/tests/request_response_with_metadata_and_payload.c
  98. 4
      test/core/end2end/tests/request_response_with_payload.c
  99. 8
      test/core/end2end/tests/request_response_with_payload_and_call_creds.c
  100. 2
      test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -17,20 +17,22 @@ env:
- CPPFLAGS=-I/tmp/prebuilt/include - CPPFLAGS=-I/tmp/prebuilt/include
- NUGET="mono nuget.exe" - NUGET="mono nuget.exe"
matrix: matrix:
- CONFIG=opt TEST=sanity - CONFIG=opt TEST=sanity JOBS=1
- CONFIG=gcov TEST="c c++" - CONFIG=gcov TEST=c JOBS=16
- CONFIG=opt TEST="c c++" - CONFIG=gcov TEST=c++ JOBS=16
- CONFIG=opt TEST=node - CONFIG=opt TEST=c JOBS=16
- CONFIG=opt TEST=ruby - CONFIG=opt TEST=c++ JOBS=16
- CONFIG=opt TEST=python - CONFIG=opt TEST=node JOBS=16
- CONFIG=opt TEST=csharp - CONFIG=opt TEST=ruby JOBS=16
- USE_GCC=4.4 CONFIG=opt TEST=build - CONFIG=opt TEST=python JOBS=1
- CONFIG=opt TEST=csharp JOBS=16
- USE_GCC=4.4 CONFIG=opt TEST=build JOBS=16
script: script:
- rvm use $RUBY_VERSION - rvm use $RUBY_VERSION
- gem install bundler - gem install bundler
- ./tools/run_tests/prepare_travis.sh - ./tools/run_tests/prepare_travis.sh
- if [ ! -z "$USE_GCC" ] ; then export CC=gcc-$USE_GCC ; export CXX=g++-$USE_GCC ; fi - if [ ! -z "$USE_GCC" ] ; then export CC=gcc-$USE_GCC ; export CXX=g++-$USE_GCC ; fi
- ./tools/run_tests/run_tests.py -l $TEST -t -j 16 -c $CONFIG -s 4.0 - ./tools/run_tests/run_tests.py -l $TEST -t -j $JOBS -c $CONFIG -s 4.0
after_success: after_success:
- if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens --exclude test --exclude src/compiler -b. --gcov-options '\-p' ; fi - if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens --exclude test --exclude src/compiler -b. --gcov-options '\-p' ; fi
notifications: notifications:

File diff suppressed because one or more lines are too long

@ -525,6 +525,16 @@
"secure": "check", "secure": "check",
"vs_project_guid": "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}" "vs_project_guid": "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
}, },
{
"name": "grpc++_benchmark_config",
"build": "private",
"language": "c++",
"src": [
"test/cpp/qps/qpstest.proto",
"test/cpp/qps/report.cc",
"test/cpp/util/benchmark_config.cc"
]
},
{ {
"name": "grpc++_test_config", "name": "grpc++_test_config",
"build": "private", "build": "private",
@ -543,7 +553,8 @@
"test/cpp/util/echo_duplicate.proto", "test/cpp/util/echo_duplicate.proto",
"test/cpp/util/cli_call.cc", "test/cpp/util/cli_call.cc",
"test/cpp/util/create_test_channel.cc", "test/cpp/util/create_test_channel.cc",
"test/cpp/util/fake_credentials.cc" "test/cpp/util/fake_credentials.cc",
"test/cpp/util/subprocess.cc"
] ]
}, },
{ {
@ -694,7 +705,6 @@
"test/cpp/qps/client_sync.cc", "test/cpp/qps/client_sync.cc",
"test/cpp/qps/driver.cc", "test/cpp/qps/driver.cc",
"test/cpp/qps/qps_worker.cc", "test/cpp/qps/qps_worker.cc",
"test/cpp/qps/report.cc",
"test/cpp/qps/server_async.cc", "test/cpp/qps/server_async.cc",
"test/cpp/qps/server_sync.cc", "test/cpp/qps/server_sync.cc",
"test/cpp/qps/timer.cc" "test/cpp/qps/timer.cc"
@ -1821,6 +1831,7 @@
"deps": [ "deps": [
"qps", "qps",
"grpc++_test_util", "grpc++_test_util",
"grpc++_benchmark_config",
"grpc_test_util", "grpc_test_util",
"grpc++", "grpc++",
"grpc", "grpc",
@ -1838,6 +1849,7 @@
"deps": [ "deps": [
"qps", "qps",
"grpc++_test_util", "grpc++_test_util",
"grpc++_benchmark_config",
"grpc_test_util", "grpc_test_util",
"grpc++", "grpc++",
"grpc", "grpc",
@ -1874,6 +1886,39 @@
"gpr" "gpr"
] ]
}, },
{
"name": "client_crash_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/end2end/client_crash_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "client_crash_test_server",
"build": "test",
"run": false,
"language": "c++",
"src": [
"test/cpp/end2end/client_crash_test_server.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{ {
"name": "credentials_test", "name": "credentials_test",
"build": "test", "build": "test",
@ -2145,7 +2190,8 @@
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr", "gpr",
"grpc++_test_config" "grpc++_test_config",
"grpc++_benchmark_config"
] ]
}, },
{ {
@ -2176,6 +2222,7 @@
"deps": [ "deps": [
"qps", "qps",
"grpc++_test_util", "grpc++_test_util",
"grpc++_benchmark_config",
"grpc_test_util", "grpc_test_util",
"grpc++", "grpc++",
"grpc", "grpc",
@ -2206,6 +2253,39 @@
"grpc++_test_config" "grpc++_test_config"
] ]
}, },
{
"name": "server_crash_test",
"build": "test",
"language": "c++",
"src": [
"test/cpp/end2end/server_crash_test.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "server_crash_test_client",
"build": "test",
"run": false,
"language": "c++",
"src": [
"test/cpp/end2end/server_crash_test_client.cc"
],
"deps": [
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{ {
"name": "status_test", "name": "status_test",
"build": "test", "build": "test",
@ -2231,6 +2311,7 @@
"deps": [ "deps": [
"qps", "qps",
"grpc++_test_util", "grpc++_test_util",
"grpc++_benchmark_config",
"grpc_test_util", "grpc_test_util",
"grpc++", "grpc++",
"grpc", "grpc",
@ -2248,6 +2329,7 @@
"deps": [ "deps": [
"qps", "qps",
"grpc++_test_util", "grpc++_test_util",
"grpc++_benchmark_config",
"grpc_test_util", "grpc_test_util",
"grpc++", "grpc++",
"grpc", "grpc",

@ -558,20 +558,14 @@ pushback (i.e., attempts to send succeed only after appropriate delays).
Propagation of status code and message (yangg) Propagation of status code and message (yangg)
Cancel after sent headers (ctiller - done) Multiple thousand simultaneous calls on same Channel (ctiller)
Cancel after received first message (ctiller - done)
Zero-message streams (ejona)
Multiple thousand simultaneous calls on same Channel (ctiller - done)
OAuth2 tokens + Service Credentials from GCE metadata server (GCE->prod only) OAuth2 tokens + Service Credentials from GCE metadata server (GCE->prod only)
(abhishek) (abhishek)
OAuth2 tokens + JWT signing key (GCE->prod only) (abhishek) OAuth2 tokens + JWT signing key (GCE->prod only) (abhishek)
Metadata: client headers, server headers + trailers, binary+ascii (chenw) Metadata: client headers, server headers + trailers, binary+ascii
#### Normal priority: #### Normal priority:
@ -600,6 +594,8 @@ Multiple thousand simultaneous calls on different Channels (ctiller)
Failed TLS hostname verification (ejona?) Failed TLS hostname verification (ejona?)
Large amount of headers to cause CONTINUATIONs; 63K of 'X's, all in one header.
#### To priorize: #### To priorize:
Start streaming RPC but don't send any requests, server responds Start streaming RPC but don't send any requests, server responds

@ -112,6 +112,9 @@ public:
template <class T> operator std::unique_ptr<T>() const { template <class T> operator std::unique_ptr<T>() const {
return std::unique_ptr<T>(static_cast<T *>(0)); return std::unique_ptr<T>(static_cast<T *>(0));
} }
template <class T> operator std::shared_ptr<T>() const {
return std::shared_ptr<T>(static_cast<T *>(0));
}
operator bool() const {return false;} operator bool() const {return false;}
private: private:
void operator&() const = delete; void operator&() const = delete;

@ -114,7 +114,7 @@ class ClientReader GRPC_FINAL : public ClientReaderInterface<R> {
CallOpBuffer buf; CallOpBuffer buf;
buf.AddRecvInitialMetadata(context_); buf.AddRecvInitialMetadata(context_);
call_.PerformOps(&buf); call_.PerformOps(&buf);
GPR_ASSERT(cq_.Pluck(&buf)); cq_.Pluck(&buf); // status ignored
} }
bool Read(R* msg) GRPC_OVERRIDE { bool Read(R* msg) GRPC_OVERRIDE {
@ -216,7 +216,7 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
CallOpBuffer buf; CallOpBuffer buf;
buf.AddSendInitialMetadata(&context->send_initial_metadata_); buf.AddSendInitialMetadata(&context->send_initial_metadata_);
call_.PerformOps(&buf); call_.PerformOps(&buf);
GPR_ASSERT(cq_.Pluck(&buf)); cq_.Pluck(&buf);
} }
// Blocking wait for initial metadata from server. The received metadata // Blocking wait for initial metadata from server. The received metadata
@ -229,7 +229,7 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
CallOpBuffer buf; CallOpBuffer buf;
buf.AddRecvInitialMetadata(context_); buf.AddRecvInitialMetadata(context_);
call_.PerformOps(&buf); call_.PerformOps(&buf);
GPR_ASSERT(cq_.Pluck(&buf)); cq_.Pluck(&buf); // status ignored
} }
bool Read(R* msg) GRPC_OVERRIDE { bool Read(R* msg) GRPC_OVERRIDE {

@ -92,12 +92,13 @@ typedef struct {
} value; } value;
} grpc_arg; } grpc_arg;
/* An array of arguments that can be passed around. /** An array of arguments that can be passed around.
Used to set optional channel-level configuration.
These configuration options are modelled as key-value pairs as defined Used to set optional channel-level configuration.
by grpc_arg; keys are strings to allow easy backwards-compatible extension These configuration options are modelled as key-value pairs as defined
by arbitrary parties. by grpc_arg; keys are strings to allow easy backwards-compatible extension
All evaluation is performed at channel creation time. */ by arbitrary parties.
All evaluation is performed at channel creation time. */
typedef struct { typedef struct {
size_t num_args; size_t num_args;
grpc_arg *args; grpc_arg *args;
@ -192,15 +193,27 @@ typedef struct grpc_metadata {
} internal_data; } internal_data;
} grpc_metadata; } grpc_metadata;
/** The type of completion (for grpc_event) */
typedef enum grpc_completion_type { typedef enum grpc_completion_type {
GRPC_QUEUE_SHUTDOWN, /* Shutting down */ /** Shutting down */
GRPC_QUEUE_TIMEOUT, /* No event before timeout */ GRPC_QUEUE_SHUTDOWN,
GRPC_OP_COMPLETE /* operation completion */ /** No event before timeout */
GRPC_QUEUE_TIMEOUT,
/** Operation completion */
GRPC_OP_COMPLETE
} grpc_completion_type; } grpc_completion_type;
/** The result of an operation.
Returned by a completion queue when the operation started with tag. */
typedef struct grpc_event { typedef struct grpc_event {
/** The type of the completion. */
grpc_completion_type type; grpc_completion_type type;
/** non-zero if the operation was successful, 0 upon failure.
Only GRPC_OP_COMPLETE can succeed or fail. */
int success; int success;
/** The tag passed to grpc_call_start_batch etc to start this operation.
Only GRPC_OP_COMPLETE has a tag. */
void *tag; void *tag;
} grpc_event; } grpc_event;
@ -244,7 +257,10 @@ typedef enum {
GRPC_OP_RECV_INITIAL_METADATA, GRPC_OP_RECV_INITIAL_METADATA,
/* Receive a message: 0 or more of these operations can occur for each call */ /* Receive a message: 0 or more of these operations can occur for each call */
GRPC_OP_RECV_MESSAGE, GRPC_OP_RECV_MESSAGE,
/* Receive status on the client: one and only one must be made on the client /* Receive status on the client: one and only one must be made on the client.
This operation always succeeds, meaning ops paired with this operation
will also appear to succeed, even though they may not have. In that case
the status will indicate some failure.
*/ */
GRPC_OP_RECV_STATUS_ON_CLIENT, GRPC_OP_RECV_STATUS_ON_CLIENT,
/* Receive status on the server: one and only one must be made on the server /* Receive status on the server: one and only one must be made on the server
@ -319,37 +335,42 @@ typedef struct grpc_op {
} data; } data;
} grpc_op; } grpc_op;
/* Initialize the grpc library. /** Initialize the grpc library.
It is not safe to call any other grpc functions before calling this.
(To avoid overhead, little checking is done, and some things may work. We It is not safe to call any other grpc functions before calling this.
do not warrant that they will continue to do so in future revisions of this (To avoid overhead, little checking is done, and some things may work. We
library). */ do not warrant that they will continue to do so in future revisions of this
library). */
void grpc_init(void); void grpc_init(void);
/* Shut down the grpc library. /** Shut down the grpc library.
No memory is used by grpc after this call returns, nor are any instructions
executing within the grpc library. No memory is used by grpc after this call returns, nor are any instructions
Prior to calling, all application owned grpc objects must have been executing within the grpc library.
destroyed. */ Prior to calling, all application owned grpc objects must have been
destroyed. */
void grpc_shutdown(void); void grpc_shutdown(void);
/** Create a completion queue */
grpc_completion_queue *grpc_completion_queue_create(void); grpc_completion_queue *grpc_completion_queue_create(void);
/* Blocks until an event is available, the completion queue is being shut down, /** Blocks until an event is available, the completion queue is being shut down,
or deadline is reached. Returns NULL on timeout, otherwise the event that or deadline is reached.
occurred.
Returns NULL on timeout, otherwise the event that occurred.
Callers must not call grpc_completion_queue_next and Callers must not call grpc_completion_queue_next and
grpc_completion_queue_pluck simultaneously on the same completion queue. */ grpc_completion_queue_pluck simultaneously on the same completion queue. */
grpc_event grpc_completion_queue_next(grpc_completion_queue *cq, grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
gpr_timespec deadline); gpr_timespec deadline);
/* Blocks until an event with tag 'tag' is available, the completion queue is /** Blocks until an event with tag 'tag' is available, the completion queue is
being shutdown or deadline is reached. Returns NULL on timeout, or a pointer being shutdown or deadline is reached.
to the event that occurred.
Returns NULL on timeout, or a pointer to the event that occurred.
Callers must not call grpc_completion_queue_next and Callers must not call grpc_completion_queue_next and
grpc_completion_queue_pluck simultaneously on the same completion queue. */ grpc_completion_queue_pluck simultaneously on the same completion queue. */
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag, grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
gpr_timespec deadline); gpr_timespec deadline);

@ -34,16 +34,24 @@
#ifndef GRPC_SUPPORT_SUBPROCESS_H #ifndef GRPC_SUPPORT_SUBPROCESS_H
#define GRPC_SUPPORT_SUBPROCESS_H #define GRPC_SUPPORT_SUBPROCESS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpr_subprocess gpr_subprocess; typedef struct gpr_subprocess gpr_subprocess;
/* .exe on windows, empty on unices */ /* .exe on windows, empty on unices */
const char *gpr_subprocess_binary_extension(); const char *gpr_subprocess_binary_extension();
gpr_subprocess *gpr_subprocess_create(int argc, char **argv); gpr_subprocess *gpr_subprocess_create(int argc, const char **argv);
/* if subprocess has not been joined, kill it */ /* if subprocess has not been joined, kill it */
void gpr_subprocess_destroy(gpr_subprocess *p); void gpr_subprocess_destroy(gpr_subprocess *p);
/* returns exit status; can be called at most once */ /* returns exit status; can be called at most once */
int gpr_subprocess_join(gpr_subprocess *p); int gpr_subprocess_join(gpr_subprocess *p);
void gpr_subprocess_interrupt(gpr_subprocess *p); void gpr_subprocess_interrupt(gpr_subprocess *p);
#ifdef __cplusplus
} // extern "C"
#endif
#endif #endif

@ -86,23 +86,25 @@ grpc::string FilenameIdentifier(const grpc::string &filename) {
grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file, grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
vars["filename"] = file->name(); std::map<grpc::string, grpc::string> vars;
vars["filename_identifier"] = FilenameIdentifier(file->name());
vars["filename_base"] = grpc_generator::StripProto(file->name()); vars["filename"] = file->name();
vars["filename_identifier"] = FilenameIdentifier(file->name());
printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n"); vars["filename_base"] = grpc_generator::StripProto(file->name());
printer.Print(vars, "// If you make any local change, they will be lost.\n");
printer.Print(vars, "// source: $filename$\n"); printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n"); printer.Print(vars, "// If you make any local change, they will be lost.\n");
printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n"); printer.Print(vars, "// source: $filename$\n");
printer.Print(vars, "\n"); printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
printer.Print(vars, "#include \"$filename_base$.pb.h\"\n"); printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
printer.Print(vars, "\n"); printer.Print(vars, "\n");
printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
printer.Print(vars, "\n");
}
return output; return output;
} }
@ -626,100 +628,108 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file, grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
if (!params.services_namespace.empty()) { std::map<grpc::string, grpc::string> vars;
vars["services_namespace"] = params.services_namespace;
printer.Print(vars, "\nnamespace $services_namespace$ {\n\n"); if (!params.services_namespace.empty()) {
} vars["services_namespace"] = params.services_namespace;
printer.Print(vars, "\nnamespace $services_namespace$ {\n\n");
}
for (int i = 0; i < file->service_count(); ++i) { for (int i = 0; i < file->service_count(); ++i) {
PrintHeaderService(&printer, file->service(i), &vars); PrintHeaderService(&printer, file->service(i), &vars);
printer.Print("\n"); printer.Print("\n");
} }
if (!params.services_namespace.empty()) { if (!params.services_namespace.empty()) {
printer.Print(vars, "} // namespace $services_namespace$\n\n"); printer.Print(vars, "} // namespace $services_namespace$\n\n");
}
} }
return output; return output;
} }
grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file, grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
vars["filename"] = file->name(); std::map<grpc::string, grpc::string> vars;
vars["filename_identifier"] = FilenameIdentifier(file->name());
vars["filename"] = file->name();
if (!file->package().empty()) { vars["filename_identifier"] = FilenameIdentifier(file->name());
std::vector<grpc::string> parts =
grpc_generator::tokenize(file->package(), "."); if (!file->package().empty()) {
std::vector<grpc::string> parts =
for (auto part = parts.rbegin(); part != parts.rend(); part++) { grpc_generator::tokenize(file->package(), ".");
vars["part"] = *part;
printer.Print(vars, "} // namespace $part$\n"); for (auto part = parts.rbegin(); part != parts.rend(); part++) {
vars["part"] = *part;
printer.Print(vars, "} // namespace $part$\n");
}
printer.Print(vars, "\n");
} }
printer.Print(vars, "\n"); printer.Print(vars, "\n");
printer.Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
} }
printer.Print(vars, "\n");
printer.Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
return output; return output;
} }
grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file, grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
vars["filename"] = file->name(); std::map<grpc::string, grpc::string> vars;
vars["filename_base"] = grpc_generator::StripProto(file->name());
vars["filename"] = file->name();
printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n"); vars["filename_base"] = grpc_generator::StripProto(file->name());
printer.Print(vars, "// If you make any local change, they will be lost.\n");
printer.Print(vars, "// source: $filename$\n\n"); printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
printer.Print(vars, "#include \"$filename_base$.pb.h\"\n"); printer.Print(vars, "// If you make any local change, they will be lost.\n");
printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n"); printer.Print(vars, "// source: $filename$\n\n");
printer.Print(vars, "\n"); printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
printer.Print(vars, "\n");
}
return output; return output;
} }
grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file, grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
const Parameters &param) { const Parameters &param) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
printer.Print(vars, "#include <grpc++/async_unary_call.h>\n"); std::map<grpc::string, grpc::string> vars;
printer.Print(vars, "#include <grpc++/channel_interface.h>\n");
printer.Print(vars, "#include <grpc++/impl/client_unary_call.h>\n"); printer.Print(vars, "#include <grpc++/async_unary_call.h>\n");
printer.Print(vars, "#include <grpc++/impl/rpc_service_method.h>\n"); printer.Print(vars, "#include <grpc++/channel_interface.h>\n");
printer.Print(vars, "#include <grpc++/impl/service_type.h>\n"); printer.Print(vars, "#include <grpc++/impl/client_unary_call.h>\n");
printer.Print(vars, "#include <grpc++/stream.h>\n"); printer.Print(vars, "#include <grpc++/impl/rpc_service_method.h>\n");
printer.Print(vars, "#include <grpc++/impl/service_type.h>\n");
if (!file->package().empty()) { printer.Print(vars, "#include <grpc++/stream.h>\n");
std::vector<grpc::string> parts =
grpc_generator::tokenize(file->package(), "."); if (!file->package().empty()) {
std::vector<grpc::string> parts =
for (auto part = parts.begin(); part != parts.end(); part++) { grpc_generator::tokenize(file->package(), ".");
vars["part"] = *part;
printer.Print(vars, "namespace $part$ {\n"); for (auto part = parts.begin(); part != parts.end(); part++) {
vars["part"] = *part;
printer.Print(vars, "namespace $part$ {\n");
}
} }
}
printer.Print(vars, "\n");
printer.Print(vars, "\n");
}
return output; return output;
} }
@ -1077,26 +1087,29 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file, grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string output; grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
grpc::protobuf::io::Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
std::map<grpc::string, grpc::string> vars; grpc::protobuf::io::StringOutputStream output_stream(&output);
// Package string is empty or ends with a dot. It is used to fully qualify grpc::protobuf::io::Printer printer(&output_stream, '$');
// method names. std::map<grpc::string, grpc::string> vars;
vars["Package"] = file->package(); // Package string is empty or ends with a dot. It is used to fully qualify
if (!file->package().empty()) { // method names.
vars["Package"].append("."); vars["Package"] = file->package();
} if (!file->package().empty()) {
if (!params.services_namespace.empty()) { vars["Package"].append(".");
vars["ns"] = params.services_namespace + "::"; }
vars["prefix"] = params.services_namespace; if (!params.services_namespace.empty()) {
} else { vars["ns"] = params.services_namespace + "::";
vars["ns"] = ""; vars["prefix"] = params.services_namespace;
vars["prefix"] = ""; } else {
} vars["ns"] = "";
vars["prefix"] = "";
}
for (int i = 0; i < file->service_count(); ++i) { for (int i = 0; i < file->service_count(); ++i) {
PrintSourceService(&printer, file->service(i), &vars); PrintSourceService(&printer, file->service(i), &vars);
printer.Print("\n"); printer.Print("\n");
}
} }
return output; return output;
} }

@ -474,35 +474,39 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
grpc::string GetServices(const FileDescriptor *file) { grpc::string GetServices(const FileDescriptor *file) {
grpc::string output; grpc::string output;
StringOutputStream output_stream(&output); {
Printer out(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
// Don't write out any output if there no services, to avoid empty service StringOutputStream output_stream(&output);
// files being generated for proto files that don't declare any. Printer out(&output_stream, '$');
if (file->service_count() == 0) {
return output; // Don't write out any output if there no services, to avoid empty service
} // files being generated for proto files that don't declare any.
if (file->service_count() == 0) {
return output;
}
// Write out a file header. // Write out a file header.
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n"); out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("// source: $filename$\n", "filename", file->name()); out.Print("// source: $filename$\n", "filename", file->name());
out.Print("#region Designer generated code\n"); out.Print("#region Designer generated code\n");
out.Print("\n"); out.Print("\n");
out.Print("using System;\n"); out.Print("using System;\n");
out.Print("using System.Threading;\n"); out.Print("using System.Threading;\n");
out.Print("using System.Threading.Tasks;\n"); out.Print("using System.Threading.Tasks;\n");
out.Print("using Grpc.Core;\n"); out.Print("using Grpc.Core;\n");
// TODO(jtattermusch): add using for protobuf message classes // TODO(jtattermusch): add using for protobuf message classes
out.Print("\n"); out.Print("\n");
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file)); out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
out.Indent(); out.Indent();
for (int i = 0; i < file->service_count(); i++) { for (int i = 0; i < file->service_count(); i++) {
GenerateService(&out, file->service(i)); GenerateService(&out, file->service(i));
}
out.Outdent();
out.Print("}\n");
out.Print("#endregion\n");
} }
out.Outdent();
out.Print("}\n");
out.Print("#endregion\n");
return output; return output;
} }

@ -176,65 +176,71 @@ void PrintMethodImplementations(Printer *printer,
string GetHeader(const ServiceDescriptor *service, const string prefix) { string GetHeader(const ServiceDescriptor *service, const string prefix) {
string output; string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
printer.Print("@protocol GRXWriteable;\n"); Printer printer(&output_stream, '$');
printer.Print("@protocol GRXWriter;\n\n");
printer.Print("@protocol GRXWriteable;\n");
map<string, string> vars = {{"service_name", service->name()}, printer.Print("@protocol GRXWriter;\n\n");
{"prefix", prefix}};
printer.Print(vars, "@protocol $prefix$$service_name$ <NSObject>\n\n"); map<string, string> vars = {{"service_name", service->name()},
{"prefix", prefix}};
for (int i = 0; i < service->method_count(); i++) { printer.Print(vars, "@protocol $prefix$$service_name$ <NSObject>\n\n");
PrintMethodDeclarations(&printer, service->method(i), vars);
for (int i = 0; i < service->method_count(); i++) {
PrintMethodDeclarations(&printer, service->method(i), vars);
}
printer.Print("@end\n\n");
printer.Print("// Basic service implementation, over gRPC, that only does"
" marshalling and parsing.\n");
printer.Print(vars, "@interface $prefix$$service_name$ :"
" ProtoService<$prefix$$service_name$>\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("@end\n");
} }
printer.Print("@end\n\n");
printer.Print("// Basic service implementation, over gRPC, that only does"
" marshalling and parsing.\n");
printer.Print(vars, "@interface $prefix$$service_name$ :"
" ProtoService<$prefix$$service_name$>\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("@end\n");
return output; return output;
} }
string GetSource(const ServiceDescriptor *service, const string prefix) { string GetSource(const ServiceDescriptor *service, const string prefix) {
string output; string output;
grpc::protobuf::io::StringOutputStream output_stream(&output); {
Printer printer(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
map<string, string> vars = {{"service_name", service->name()}, Printer printer(&output_stream, '$');
{"package", service->file()->package()},
{"prefix", prefix}}; map<string, string> vars = {{"service_name", service->name()},
{"package", service->file()->package()},
printer.Print(vars, {"prefix", prefix}};
"static NSString *const kPackageName = @\"$package$\";\n");
printer.Print(vars, printer.Print(vars,
"static NSString *const kServiceName = @\"$service_name$\";\n\n"); "static NSString *const kPackageName = @\"$package$\";\n");
printer.Print(vars,
printer.Print(vars, "@implementation $prefix$$service_name$\n\n"); "static NSString *const kServiceName = @\"$service_name$\";\n\n");
printer.Print("// Designated initializer\n"); printer.Print(vars, "@implementation $prefix$$service_name$\n\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
printer.Print(" return (self = [super initWithHost:host" printer.Print("// Designated initializer\n");
" packageName:kPackageName serviceName:kServiceName]);\n"); printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
printer.Print("}\n\n"); printer.Print(" return (self = [super initWithHost:host"
printer.Print("// Override superclass initializer to disallow different" " packageName:kPackageName serviceName:kServiceName]);\n");
" package and service names.\n"); printer.Print("}\n\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host\n"); printer.Print("// Override superclass initializer to disallow different"
printer.Print(" packageName:(NSString *)packageName\n"); " package and service names.\n");
printer.Print(" serviceName:(NSString *)serviceName {\n"); printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
printer.Print(" return [self initWithHost:host];\n"); printer.Print(" packageName:(NSString *)packageName\n");
printer.Print("}\n\n\n"); printer.Print(" serviceName:(NSString *)serviceName {\n");
printer.Print(" return [self initWithHost:host];\n");
for (int i = 0; i < service->method_count(); i++) { printer.Print("}\n\n\n");
PrintMethodImplementations(&printer, service->method(i), vars);
for (int i = 0; i < service->method_count(); i++) {
PrintMethodImplementations(&printer, service->method(i), vars);
}
printer.Print("@end\n");
} }
printer.Print("@end\n");
return output; return output;
} }

@ -119,49 +119,52 @@ void PrintService(const ServiceDescriptor *service, const grpc::string &package,
grpc::string GetServices(const FileDescriptor *file) { grpc::string GetServices(const FileDescriptor *file) {
grpc::string output; grpc::string output;
StringOutputStream output_stream(&output); {
Printer out(&output_stream, '$'); // Scope the output stream so it closes and finalizes output to the string.
// Don't write out any output if there no services, to avoid empty service StringOutputStream output_stream(&output);
// files being generated for proto files that don't declare any. Printer out(&output_stream, '$');
if (file->service_count() == 0) {
return output; // Don't write out any output if there no services, to avoid empty service
} // files being generated for proto files that don't declare any.
if (file->service_count() == 0) {
// Write out a file header. return output;
std::map<grpc::string, grpc::string> header_comment_vars = ListToDict( }
{"file.name", file->name(), "file.package", file->package(), });
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n"); // Write out a file header.
out.Print(header_comment_vars, std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
"# Source: $file.name$ for package '$file.package$'\n"); {"file.name", file->name(), "file.package", file->package(), });
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("\n"); out.Print(header_comment_vars,
out.Print("require 'grpc'\n"); "# Source: $file.name$ for package '$file.package$'\n");
// Write out require statemment to import the separately generated file
// that defines the messages used by the service. This is generated by the out.Print("\n");
// main ruby plugin. out.Print("require 'grpc'\n");
std::map<grpc::string, grpc::string> dep_vars = // Write out require statemment to import the separately generated file
ListToDict({"dep.name", MessagesRequireName(file), }); // that defines the messages used by the service. This is generated by the
out.Print(dep_vars, "require '$dep.name$'\n"); // main ruby plugin.
std::map<grpc::string, grpc::string> dep_vars =
// Write out services within the modules ListToDict({"dep.name", MessagesRequireName(file), });
out.Print("\n"); out.Print(dep_vars, "require '$dep.name$'\n");
std::vector<grpc::string> modules = Split(file->package(), '.');
for (size_t i = 0; i < modules.size(); ++i) { // Write out services within the modules
std::map<grpc::string, grpc::string> module_vars = out.Print("\n");
ListToDict({"module.name", CapitalizeFirst(modules[i]), }); std::vector<grpc::string> modules = Split(file->package(), '.');
out.Print(module_vars, "module $module.name$\n"); for (size_t i = 0; i < modules.size(); ++i) {
out.Indent(); std::map<grpc::string, grpc::string> module_vars =
ListToDict({"module.name", CapitalizeFirst(modules[i]), });
out.Print(module_vars, "module $module.name$\n");
out.Indent();
}
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
PrintService(service, file->package(), &out);
}
for (size_t i = 0; i < modules.size(); ++i) {
out.Outdent();
out.Print("end\n");
}
} }
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
PrintService(service, file->package(), &out);
}
for (size_t i = 0; i < modules.size(); ++i) {
out.Outdent();
out.Print("end\n");
}
return output; return output;
} }

@ -144,6 +144,7 @@ static void handle_op_after_cancellation(grpc_call_element *elem,
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
if (op->send_ops) { if (op->send_ops) {
grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
op->on_done_send(op->send_user_data, 0); op->on_done_send(op->send_user_data, 0);
} }
if (op->recv_ops) { if (op->recv_ops) {

@ -67,7 +67,6 @@ static grpc_httpcli_post_override g_post_override = NULL;
static void next_address(internal_request *req); static void next_address(internal_request *req);
static void finish(internal_request *req, int success) { static void finish(internal_request *req, int success) {
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
req->on_response(req->user_data, success ? &req->parser.r : NULL); req->on_response(req->user_data, success ? &req->parser.r : NULL);
grpc_httpcli_parser_destroy(&req->parser); grpc_httpcli_parser_destroy(&req->parser);
if (req->addresses != NULL) { if (req->addresses != NULL) {
@ -86,8 +85,6 @@ static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
internal_request *req = user_data; internal_request *req = user_data;
size_t i; size_t i;
gpr_log(GPR_DEBUG, "%s nslices=%d status=%d", __FUNCTION__, nslices, status);
for (i = 0; i < nslices; i++) { for (i = 0; i < nslices; i++) {
if (GPR_SLICE_LENGTH(slices[i])) { if (GPR_SLICE_LENGTH(slices[i])) {
req->have_read_byte = 1; req->have_read_byte = 1;
@ -120,13 +117,11 @@ done:
} }
static void on_written(internal_request *req) { static void on_written(internal_request *req) {
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
grpc_endpoint_notify_on_read(req->ep, on_read, req); grpc_endpoint_notify_on_read(req->ep, on_read, req);
} }
static void done_write(void *arg, grpc_endpoint_cb_status status) { static void done_write(void *arg, grpc_endpoint_cb_status status) {
internal_request *req = arg; internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
switch (status) { switch (status) {
case GRPC_ENDPOINT_CB_OK: case GRPC_ENDPOINT_CB_OK:
on_written(req); on_written(req);
@ -141,7 +136,6 @@ static void done_write(void *arg, grpc_endpoint_cb_status status) {
static void start_write(internal_request *req) { static void start_write(internal_request *req) {
gpr_slice_ref(req->request_text); gpr_slice_ref(req->request_text);
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
switch ( switch (
grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) { grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) {
case GRPC_ENDPOINT_WRITE_DONE: case GRPC_ENDPOINT_WRITE_DONE:
@ -159,7 +153,6 @@ static void on_secure_transport_setup_done(void *rp,
grpc_security_status status, grpc_security_status status,
grpc_endpoint *secure_endpoint) { grpc_endpoint *secure_endpoint) {
internal_request *req = rp; internal_request *req = rp;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status); gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
finish(req, 0); finish(req, 0);
@ -172,7 +165,6 @@ static void on_secure_transport_setup_done(void *rp,
static void on_connected(void *arg, grpc_endpoint *tcp) { static void on_connected(void *arg, grpc_endpoint *tcp) {
internal_request *req = arg; internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (!tcp) { if (!tcp) {
next_address(req); next_address(req);
return; return;
@ -200,7 +192,6 @@ static void on_connected(void *arg, grpc_endpoint *tcp) {
static void next_address(internal_request *req) { static void next_address(internal_request *req) {
grpc_resolved_address *addr; grpc_resolved_address *addr;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (req->next_address == req->addresses->naddrs) { if (req->next_address == req->addresses->naddrs) {
finish(req, 0); finish(req, 0);
return; return;
@ -212,7 +203,6 @@ static void next_address(internal_request *req) {
static void on_resolved(void *arg, grpc_resolved_addresses *addresses) { static void on_resolved(void *arg, grpc_resolved_addresses *addresses) {
internal_request *req = arg; internal_request *req = arg;
gpr_log(GPR_DEBUG, "%s", __FUNCTION__);
if (!addresses) { if (!addresses) {
finish(req, 0); finish(req, 0);
return; return;

@ -96,8 +96,10 @@ static grpc_fd *alloc_fd(int fd) {
gpr_atm_rel_store(&r->writest, NOT_READY); gpr_atm_rel_store(&r->writest, NOT_READY);
gpr_atm_rel_store(&r->shutdown, 0); gpr_atm_rel_store(&r->shutdown, 0);
r->fd = fd; r->fd = fd;
r->watcher_root.next = r->watcher_root.prev = &r->watcher_root; r->inactive_watcher_root.next = r->inactive_watcher_root.prev =
&r->inactive_watcher_root;
r->freelist_next = NULL; r->freelist_next = NULL;
r->read_watcher = r->write_watcher = NULL;
return r; return r;
} }
@ -147,14 +149,34 @@ int grpc_fd_is_orphaned(grpc_fd *fd) {
return (gpr_atm_acq_load(&fd->refst) & 1) == 0; return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
} }
static void wake_watchers(grpc_fd *fd) { static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
grpc_fd_watcher *watcher; if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) {
grpc_pollset_force_kick(fd->inactive_watcher_root.next->pollset);
} else if (fd->read_watcher) {
grpc_pollset_force_kick(fd->read_watcher->pollset);
} else if (fd->write_watcher) {
grpc_pollset_force_kick(fd->write_watcher->pollset);
}
}
static void maybe_wake_one_watcher(grpc_fd *fd) {
gpr_mu_lock(&fd->watcher_mu); gpr_mu_lock(&fd->watcher_mu);
for (watcher = fd->watcher_root.next; watcher != &fd->watcher_root; maybe_wake_one_watcher_locked(fd);
watcher = watcher->next) { gpr_mu_unlock(&fd->watcher_mu);
}
static void wake_all_watchers(grpc_fd *fd) {
grpc_fd_watcher *watcher;
for (watcher = fd->inactive_watcher_root.next;
watcher != &fd->inactive_watcher_root; watcher = watcher->next) {
grpc_pollset_force_kick(watcher->pollset); grpc_pollset_force_kick(watcher->pollset);
} }
gpr_mu_unlock(&fd->watcher_mu); if (fd->read_watcher) {
grpc_pollset_force_kick(fd->read_watcher->pollset);
}
if (fd->write_watcher && fd->write_watcher != fd->read_watcher) {
grpc_pollset_force_kick(fd->write_watcher->pollset);
}
} }
void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) { void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) {
@ -162,7 +184,7 @@ void grpc_fd_orphan(grpc_fd *fd, grpc_iomgr_cb_func on_done, void *user_data) {
fd->on_done_user_data = user_data; fd->on_done_user_data = user_data;
shutdown(fd->fd, SHUT_RDWR); shutdown(fd->fd, SHUT_RDWR);
ref_by(fd, 1); /* remove active status, but keep referenced */ ref_by(fd, 1); /* remove active status, but keep referenced */
wake_watchers(fd); wake_all_watchers(fd);
unref_by(fd, 2); /* drop the reference */ unref_by(fd, 2); /* drop the reference */
} }
@ -204,7 +226,7 @@ static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure,
set_ready call. NOTE: we don't have an ABA problem here, set_ready call. NOTE: we don't have an ABA problem here,
since we should never have concurrent calls to the same since we should never have concurrent calls to the same
notify_on function. */ notify_on function. */
wake_watchers(fd); maybe_wake_one_watcher(fd);
return; return;
} }
/* swap was unsuccessful due to an intervening set_ready call. /* swap was unsuccessful due to an intervening set_ready call.
@ -290,29 +312,65 @@ void grpc_fd_notify_on_write(grpc_fd *fd, grpc_iomgr_closure *closure) {
gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset, gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
gpr_uint32 read_mask, gpr_uint32 write_mask, gpr_uint32 read_mask, gpr_uint32 write_mask,
grpc_fd_watcher *watcher) { grpc_fd_watcher *watcher) {
gpr_uint32 mask = 0;
/* keep track of pollers that have requested our events, in case they change /* keep track of pollers that have requested our events, in case they change
*/ */
grpc_fd_ref(fd); grpc_fd_ref(fd);
gpr_mu_lock(&fd->watcher_mu); gpr_mu_lock(&fd->watcher_mu);
watcher->next = &fd->watcher_root; /* if there is nobody polling for read, but we need to, then start doing so */
watcher->prev = watcher->next->prev; if (!fd->read_watcher && gpr_atm_acq_load(&fd->readst) > READY) {
watcher->next->prev = watcher->prev->next = watcher; fd->read_watcher = watcher;
mask |= read_mask;
}
/* if there is nobody polling for write, but we need to, then start doing so
*/
if (!fd->write_watcher && gpr_atm_acq_load(&fd->writest) > READY) {
fd->write_watcher = watcher;
mask |= write_mask;
}
/* if not polling, remember this watcher in case we need someone to later */
if (mask == 0) {
watcher->next = &fd->inactive_watcher_root;
watcher->prev = watcher->next->prev;
watcher->next->prev = watcher->prev->next = watcher;
}
watcher->pollset = pollset; watcher->pollset = pollset;
watcher->fd = fd; watcher->fd = fd;
gpr_mu_unlock(&fd->watcher_mu); gpr_mu_unlock(&fd->watcher_mu);
return (gpr_atm_acq_load(&fd->readst) != READY ? read_mask : 0) | return mask;
(gpr_atm_acq_load(&fd->writest) != READY ? write_mask : 0);
} }
void grpc_fd_end_poll(grpc_fd_watcher *watcher) { void grpc_fd_end_poll(grpc_fd_watcher *watcher, int got_read, int got_write) {
gpr_mu_lock(&watcher->fd->watcher_mu); int was_polling = 0;
watcher->next->prev = watcher->prev; int kick = 0;
watcher->prev->next = watcher->next; grpc_fd *fd = watcher->fd;
gpr_mu_unlock(&watcher->fd->watcher_mu);
gpr_mu_lock(&fd->watcher_mu);
if (watcher == fd->read_watcher) {
/* remove read watcher, kick if we still need a read */
was_polling = 1;
kick = kick || !got_read;
fd->read_watcher = NULL;
}
if (watcher == fd->write_watcher) {
/* remove write watcher, kick if we still need a write */
was_polling = 1;
kick = kick || !got_write;
fd->write_watcher = NULL;
}
if (!was_polling) {
/* remove from inactive list */
watcher->next->prev = watcher->prev;
watcher->prev->next = watcher->next;
}
if (kick) {
maybe_wake_one_watcher_locked(fd);
}
gpr_mu_unlock(&fd->watcher_mu);
grpc_fd_unref(watcher->fd); grpc_fd_unref(fd);
} }
void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) { void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) {

@ -66,8 +66,32 @@ struct grpc_fd {
gpr_mu set_state_mu; gpr_mu set_state_mu;
gpr_atm shutdown; gpr_atm shutdown;
/* The watcher list.
The following watcher related fields are protected by watcher_mu.
An fd_watcher is an ephemeral object created when an fd wants to
begin polling, and destroyed after the poll.
It denotes the fd's interest in whether to read poll or write poll
or both or neither on this fd.
If a watcher is asked to poll for reads or writes, the read_watcher
or write_watcher fields are set respectively. A watcher may be asked
to poll for both, in which case both fields will be set.
read_watcher and write_watcher may be NULL if no watcher has been
asked to poll for reads or writes.
If an fd_watcher is not asked to poll for reads or writes, it's added
to a linked list of inactive watchers, rooted at inactive_watcher_root.
If at a later time there becomes need of a poller to poll, one of
the inactive pollers may be kicked out of their poll loops to take
that responsibility. */
gpr_mu watcher_mu; gpr_mu watcher_mu;
grpc_fd_watcher watcher_root; grpc_fd_watcher inactive_watcher_root;
grpc_fd_watcher *read_watcher;
grpc_fd_watcher *write_watcher;
gpr_atm readst; gpr_atm readst;
gpr_atm writest; gpr_atm writest;
@ -103,7 +127,7 @@ gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
gpr_uint32 read_mask, gpr_uint32 write_mask, gpr_uint32 read_mask, gpr_uint32 write_mask,
grpc_fd_watcher *rec); grpc_fd_watcher *rec);
/* Complete polling previously started with grpc_fd_begin_poll */ /* Complete polling previously started with grpc_fd_begin_poll */
void grpc_fd_end_poll(grpc_fd_watcher *rec); void grpc_fd_end_poll(grpc_fd_watcher *rec, int got_read, int got_write);
/* Return 1 if this fd is orphaned, 0 otherwise */ /* Return 1 if this fd is orphaned, 0 otherwise */
int grpc_fd_is_orphaned(grpc_fd *fd); int grpc_fd_is_orphaned(grpc_fd *fd);

@ -98,7 +98,7 @@ static void end_polling(grpc_pollset *pollset) {
pollset_hdr *h; pollset_hdr *h;
h = pollset->data.ptr; h = pollset->data.ptr;
for (i = 1; i < h->pfd_count; i++) { for (i = 1; i < h->pfd_count; i++) {
grpc_fd_end_poll(&h->watchers[i]); grpc_fd_end_poll(&h->watchers[i], h->pfds[i].revents & POLLIN, h->pfds[i].revents & POLLOUT);
} }
} }

@ -174,6 +174,8 @@ void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
/* pollset->mu already held */ /* pollset->mu already held */
gpr_timespec now = gpr_now(); gpr_timespec now = gpr_now();
/* FIXME(ctiller): see below */
gpr_timespec maximum_deadline = gpr_time_add(now, gpr_time_from_seconds(1));
int r; int r;
if (gpr_time_cmp(now, deadline) > 0) { if (gpr_time_cmp(now, deadline) > 0) {
return 0; return 0;
@ -184,6 +186,11 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
if (grpc_alarm_check(&pollset->mu, now, &deadline)) { if (grpc_alarm_check(&pollset->mu, now, &deadline)) {
return 1; return 1;
} }
/* FIXME(ctiller): we should not clamp deadline, however we have some
stuck at shutdown bugs that this resolves */
if (gpr_time_cmp(deadline, maximum_deadline) > 0) {
deadline = maximum_deadline;
}
gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset); gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
r = pollset->vtable->maybe_work(pollset, deadline, now, 1); r = pollset->vtable->maybe_work(pollset, deadline, now, 1);
gpr_tls_set(&g_current_thread_poller, 0); gpr_tls_set(&g_current_thread_poller, 0);
@ -413,10 +420,12 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher); pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout); /* poll fd count (argument 2) is shortened by one if we have no events
to poll on - such that it only includes the kicker */
r = poll(pfd, GPR_ARRAY_SIZE(pfd) - (pfd[1].events == 0), timeout);
GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r); GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r);
grpc_fd_end_poll(&fd_watcher); grpc_fd_end_poll(&fd_watcher, pfd[1].revents & POLLIN, pfd[1].revents & POLLOUT);
if (r < 0) { if (r < 0) {
if (errno != EINTR) { if (errno != EINTR) {

@ -169,8 +169,7 @@ int grpc_sockaddr_get_port(const struct sockaddr *addr) {
case AF_UNIX: case AF_UNIX:
return 1; return 1;
default: default:
gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family, gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family);
__FUNCTION__);
return 0; return 0;
} }
} }
@ -184,8 +183,7 @@ int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) {
((struct sockaddr_in6 *)addr)->sin6_port = htons(port); ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
return 1; return 1;
default: default:
gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family, gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", addr->sa_family);
__FUNCTION__);
return 0; return 0;
} }
} }

@ -57,7 +57,7 @@ struct gpr_subprocess {
const char *gpr_subprocess_binary_extension() { return ""; } const char *gpr_subprocess_binary_extension() { return ""; }
gpr_subprocess *gpr_subprocess_create(int argc, char **argv) { gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
gpr_subprocess *r; gpr_subprocess *r;
int pid; int pid;
char **exec_args; char **exec_args;
@ -92,7 +92,11 @@ void gpr_subprocess_destroy(gpr_subprocess *p) {
int gpr_subprocess_join(gpr_subprocess *p) { int gpr_subprocess_join(gpr_subprocess *p) {
int status; int status;
retry:
if (waitpid(p->pid, &status, 0) == -1) { if (waitpid(p->pid, &status, 0) == -1) {
if (errno == EINTR) {
goto retry;
}
gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno)); gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno));
return -1; return -1;
} }

@ -536,9 +536,8 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
switch ((grpc_ioreq_op)i) { switch ((grpc_ioreq_op)i) {
case GRPC_IOREQ_RECV_MESSAGE: case GRPC_IOREQ_RECV_MESSAGE:
case GRPC_IOREQ_SEND_MESSAGE: case GRPC_IOREQ_SEND_MESSAGE:
if (master->success) { call->request_set[i] = REQSET_EMPTY;
call->request_set[i] = REQSET_EMPTY; if (!master->success) {
} else {
call->write_state = WRITE_STATE_WRITE_CLOSED; call->write_state = WRITE_STATE_WRITE_CLOSED;
} }
break; break;
@ -583,11 +582,29 @@ static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op, int success) {
} }
} }
static void early_out_write_ops(grpc_call *call) {
switch (call->write_state) {
case WRITE_STATE_WRITE_CLOSED:
finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1);
/* fallthrough */
case WRITE_STATE_STARTED:
finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, 0);
/* fallthrough */
case WRITE_STATE_INITIAL:
/* do nothing */
break;
}
}
static void call_on_done_send(void *pc, int success) { static void call_on_done_send(void *pc, int success) {
grpc_call *call = pc; grpc_call *call = pc;
lock(call); lock(call);
if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) { if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) {
finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, success);
call->write_state = WRITE_STATE_STARTED;
} }
if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) { if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) {
finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, success);
@ -596,6 +613,11 @@ static void call_on_done_send(void *pc, int success) {
finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, success);
finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, success); finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, success);
finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1); finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1);
call->write_state = WRITE_STATE_WRITE_CLOSED;
}
if (!success) {
call->write_state = WRITE_STATE_WRITE_CLOSED;
early_out_write_ops(call);
} }
call->send_ops.nops = 0; call->send_ops.nops = 0;
call->last_send_contains = 0; call->last_send_contains = 0;
@ -811,7 +833,6 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
op->send_ops = &call->send_ops; op->send_ops = &call->send_ops;
op->bind_pollset = grpc_cq_pollset(call->cq); op->bind_pollset = grpc_cq_pollset(call->cq);
call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA;
call->write_state = WRITE_STATE_STARTED;
call->send_initial_metadata_count = 0; call->send_initial_metadata_count = 0;
/* fall through intended */ /* fall through intended */
case WRITE_STATE_STARTED: case WRITE_STATE_STARTED:
@ -827,7 +848,6 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
op->is_last_send = 1; op->is_last_send = 1;
op->send_ops = &call->send_ops; op->send_ops = &call->send_ops;
call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE;
call->write_state = WRITE_STATE_WRITE_CLOSED;
if (!call->is_client) { if (!call->is_client) {
/* send trailing metadata */ /* send trailing metadata */
data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA]; data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA];
@ -919,23 +939,6 @@ static void finish_read_ops(grpc_call *call) {
} }
} }
static void early_out_write_ops(grpc_call *call) {
switch (call->write_state) {
case WRITE_STATE_WRITE_CLOSED:
finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, 0);
finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, 1);
/* fallthrough */
case WRITE_STATE_STARTED:
finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, 0);
/* fallthrough */
case WRITE_STATE_INITIAL:
/* do nothing */
break;
}
}
static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs, static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
size_t nreqs, size_t nreqs,
grpc_ioreq_completion_func completion, grpc_ioreq_completion_func completion,
@ -1176,6 +1179,10 @@ static void set_cancelled_value(grpc_status_code status, void *dest) {
} }
static void finish_batch(grpc_call *call, int success, void *tag) { static void finish_batch(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, success);
}
static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
grpc_cq_end_op(call->cq, tag, call, 1); grpc_cq_end_op(call->cq, tag, call, 1);
} }
@ -1186,6 +1193,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
size_t out; size_t out;
const grpc_op *op; const grpc_op *op;
grpc_ioreq *req; grpc_ioreq *req;
void (*finish_func)(grpc_call *, int, void *) = finish_batch;
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag); GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
@ -1269,6 +1277,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
op->data.recv_status_on_client.trailing_metadata; op->data.recv_status_on_client.trailing_metadata;
req = &reqs[out++]; req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_CLOSE; req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break; break;
case GRPC_OP_RECV_CLOSE_ON_SERVER: case GRPC_OP_RECV_CLOSE_ON_SERVER:
req = &reqs[out++]; req = &reqs[out++];
@ -1278,13 +1287,14 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
op->data.recv_close_on_server.cancelled; op->data.recv_close_on_server.cancelled;
req = &reqs[out++]; req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_CLOSE; req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;
break; break;
} }
} }
grpc_cq_begin_op(call->cq, call); grpc_cq_begin_op(call->cq, call);
return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_batch, return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func,
tag); tag);
} }

@ -122,6 +122,16 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
grpc_call *call, const grpc_op *ops, size_t nops, grpc_call *call, const grpc_op *ops, size_t nops,
void *tag); void *tag);
void grpc_server_log_request_call(char *file, int line,
gpr_log_severity severity,
grpc_server *server,
grpc_call **call,
grpc_call_details *details,
grpc_metadata_array *initial_metadata,
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification,
void *tag);
/* Set a context pointer. /* Set a context pointer.
No thread safety guarantees are made wrt this value. */ No thread safety guarantees are made wrt this value. */
void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value, void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value,
@ -132,6 +142,9 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag) if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
#define GRPC_SERVER_LOG_REQUEST_CALL(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag) \
if (grpc_trace_batch) grpc_server_log_request_call(sev, server, call, details, initial_metadata, cq_bound_to_call, cq_for_notifications, tag)
gpr_uint8 grpc_call_is_client(grpc_call *call); gpr_uint8 grpc_call_is_client(grpc_call *call);
#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */ #endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */

@ -119,3 +119,19 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
gpr_free(tmp); gpr_free(tmp);
} }
} }
void grpc_server_log_request_call(char *file, int line,
gpr_log_severity severity,
grpc_server *server,
grpc_call **call,
grpc_call_details *details,
grpc_metadata_array *initial_metadata,
grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification,
void *tag) {
gpr_log(file, line, severity,
"grpc_server_request_call(server=%p, call=%p, details=%p, "
"initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
"tag=%p)", server, call, details, initial_metadata,
cq_bound_to_call, cq_for_notification, tag);
}

@ -55,6 +55,7 @@ static void lame_start_transport_op(grpc_call_element *elem,
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op); GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
if (op->send_ops) { if (op->send_ops) {
grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
op->on_done_send(op->send_user_data, 0); op->on_done_send(op->send_user_data, 0);
} }
if (op->recv_ops) { if (op->recv_ops) {

@ -665,7 +665,7 @@ void *grpc_server_register_method(grpc_server *server, const char *method,
const char *host) { const char *host) {
registered_method *m; registered_method *m;
if (!method) { if (!method) {
gpr_log(GPR_ERROR, "%s method string cannot be NULL", __FUNCTION__); gpr_log(GPR_ERROR, "grpc_server_register_method method string cannot be NULL");
return NULL; return NULL;
} }
for (m = server->registered_methods; m; m = m->next) { for (m = server->registered_methods; m; m = m->next) {
@ -1010,6 +1010,9 @@ grpc_call_error grpc_server_request_call(
grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_bound_to_call,
grpc_completion_queue *cq_for_notification, void *tag) { grpc_completion_queue *cq_for_notification, void *tag) {
requested_call rc; requested_call rc;
GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
initial_metadata, cq_bound_to_call,
cq_for_notification, tag);
grpc_cq_begin_op(cq_for_notification, NULL); grpc_cq_begin_op(cq_for_notification, NULL);
rc.type = BATCH_CALL; rc.type = BATCH_CALL;
rc.tag = tag; rc.tag = tag;
@ -1128,3 +1131,12 @@ static void publish_registered_or_batch(grpc_call *call, int success,
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) { const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
return server->channel_args; return server->channel_args;
} }
int grpc_server_has_open_connections(grpc_server *server) {
int r;
gpr_mu_lock(&server->mu);
r = server->root_channel_data.next != &server->root_channel_data;
gpr_mu_unlock(&server->mu);
return r;
}

@ -62,4 +62,6 @@ grpc_transport_setup_result grpc_server_setup_transport(
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
int grpc_server_has_open_connections(grpc_server *server);
#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */ #endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */

@ -36,7 +36,8 @@
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
/* in order of preference */ /* in order of preference */
static const char *const supported_versions[] = {"h2-16", "h2-15", "h2-14"}; static const char *const supported_versions[] = {"h2", "h2-17", "h2-16",
"h2-15", "h2-14"};
int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) { int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) {
size_t i; size_t i;

@ -654,7 +654,7 @@ static int parse_stream_weight(grpc_chttp2_hpack_parser *p,
return 1; return 1;
} }
return parse_begin(p, cur + 1, end); return p->after_prioritization(p, cur + 1, end);
} }
static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur, static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
@ -1349,7 +1349,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p,
} }
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) { void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
GPR_ASSERT(p->state == parse_begin); p->after_prioritization = p->state;
p->state = parse_stream_dep0; p->state = parse_stream_dep0;
} }

@ -62,6 +62,8 @@ struct grpc_chttp2_hpack_parser {
grpc_chttp2_hpack_parser_state state; grpc_chttp2_hpack_parser_state state;
/* future states dependent on the opening op code */ /* future states dependent on the opening op code */
const grpc_chttp2_hpack_parser_state *next_state; const grpc_chttp2_hpack_parser_state *next_state;
/* what to do after skipping prioritization data */
grpc_chttp2_hpack_parser_state after_prioritization;
/* the value we're currently parsing */ /* the value we're currently parsing */
union { union {
gpr_uint32 *value; gpr_uint32 *value;

@ -639,7 +639,7 @@ static tsi_result ssl_protector_protect(tsi_frame_protector* self,
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
/* First see if we have some pending data in the SSL BIO. */ /* First see if we have some pending data in the SSL BIO. */
size_t pending_in_ssl = BIO_ctrl_pending(impl->from_ssl); size_t pending_in_ssl = BIO_pending(impl->from_ssl);
if (pending_in_ssl > 0) { if (pending_in_ssl > 0) {
*unprotected_bytes_size = 0; *unprotected_bytes_size = 0;
read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
@ -694,7 +694,7 @@ static tsi_result ssl_protector_protect_flush(
impl->buffer_offset = 0; impl->buffer_offset = 0;
} }
*still_pending_size = BIO_ctrl_pending(impl->from_ssl); *still_pending_size = BIO_pending(impl->from_ssl);
if (*still_pending_size == 0) return TSI_OK; if (*still_pending_size == 0) return TSI_OK;
read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
@ -704,7 +704,7 @@ static tsi_result ssl_protector_protect_flush(
return TSI_INTERNAL_ERROR; return TSI_INTERNAL_ERROR;
} }
*protected_output_frames_size = read_from_ssl; *protected_output_frames_size = read_from_ssl;
*still_pending_size = BIO_ctrl_pending(impl->from_ssl); *still_pending_size = BIO_pending(impl->from_ssl);
return TSI_OK; return TSI_OK;
} }
@ -782,7 +782,7 @@ static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
} }
} }
*bytes_size = (size_t)bytes_read_from_ssl; *bytes_size = (size_t)bytes_read_from_ssl;
return BIO_ctrl_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA; return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
} }
static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) { static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
@ -818,7 +818,7 @@ static tsi_result ssl_handshaker_process_bytes_from_peer(
ssl_result = SSL_get_error(impl->ssl, ssl_result); ssl_result = SSL_get_error(impl->ssl, ssl_result);
switch (ssl_result) { switch (ssl_result) {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
if (BIO_ctrl_pending(impl->from_ssl) == 0) { if (BIO_pending(impl->from_ssl) == 0) {
/* We need more data. */ /* We need more data. */
return TSI_INCOMPLETE_DATA; return TSI_INCOMPLETE_DATA;
} else { } else {

@ -149,7 +149,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
} }
buf.AddServerSendStatus(&ctx_.trailing_metadata_, status); buf.AddServerSendStatus(&ctx_.trailing_metadata_, status);
call_.PerformOps(&buf); call_.PerformOps(&buf);
GPR_ASSERT(cq_.Pluck(&buf)); cq_.Pluck(&buf); /* status ignored */
void* ignored_tag; void* ignored_tag;
bool ignored_ok; bool ignored_ok;
cq_.Shutdown(); cq_.Shutdown();

@ -10,6 +10,7 @@
<RootNamespace>Grpc.Auth</RootNamespace> <RootNamespace>Grpc.Auth</RootNamespace>
<AssemblyName>Grpc.Auth</AssemblyName> <AssemblyName>Grpc.Auth</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>

@ -22,5 +22,8 @@
</metadata> </metadata>
<files> <files>
<file src="bin/Release/Grpc.Auth.dll" target="lib/net45" /> <file src="bin/Release/Grpc.Auth.dll" target="lib/net45" />
<file src="bin/Release/Grpc.Auth.pdb" target="lib/net45" />
<file src="bin/Release/Grpc.Auth.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files> </files>
</package> </package>

@ -13,6 +13,7 @@
<AssemblyName>Grpc.Core</AssemblyName> <AssemblyName>Grpc.Core</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<NuGetPackageImportStamp>8bb563fb</NuGetPackageImportStamp> <NuGetPackageImportStamp>8bb563fb</NuGetPackageImportStamp>
<DocumentationFile>bin\$(Configuration)\Grpc.Core.Xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>

@ -17,10 +17,13 @@
<dependencies> <dependencies>
<dependency id="Microsoft.Bcl.Immutable" version="1.0.34" /> <dependency id="Microsoft.Bcl.Immutable" version="1.0.34" />
<dependency id="Ix-Async" version="1.2.3" /> <dependency id="Ix-Async" version="1.2.3" />
<dependency id="grpc.native.csharp_ext" version="0.8.0.0" /> <dependency id="grpc.native.csharp_ext" version="0.9.0.0" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>
<file src="bin/Release/Grpc.Core.dll" target="lib/net45" /> <file src="bin/Release/Grpc.Core.dll" target="lib/net45" />
<file src="bin/Release/Grpc.Core.pdb" target="lib/net45" />
<file src="bin/Release/Grpc.Core.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files> </files>
</package> </package>

@ -6,7 +6,7 @@ A C# implementation of gRPC.
Status Status
------ ------
Ready for early adopters. Alpha : Ready for early adopters.
Usage: Windows Usage: Windows
-------------- --------------
@ -19,22 +19,60 @@ Usage: Windows
That will also pull all the transitive dependencies (including the native libraries that That will also pull all the transitive dependencies (including the native libraries that
gRPC C# is internally using). gRPC C# is internally using).
- TODO: link to Helloworld example - Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
Usage: Linux (Mono) Usage: Linux (Mono)
-------------- --------------
- Prerequisites: Mono framework, MonoDevelop 5.9 with NuGet add-in installed. - Prerequisites: Mono 3.2.8+, MonoDevelop 5.9 with NuGet add-in installed.
- Install gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc - Install Linuxbrew and gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc
- TODO: explain using LD_LIBRARY_PATH or installation to /usr/local - gRPC C# depends on native shared library libgrpc_csharp_ext.so (Unix flavor of grpc_csharp_ext.dll).
This library will be installed to `~/.linuxbrew/lib` by the previous step.
To make it visible to mono, you need to:
- (preferred approach) add `libgrpc_csharp_ext.so` to `/etc/ld.so.cache` by running:
```sh
echo "$HOME/.linuxbrew/lib" | sudo tee /etc/ld.so.conf.d/zzz_brew_lib.conf
sudo ldconfig
```
- (adhoc approach) set `LD_LIBRARY_PATH` environment variable to point to directory containing `libgrpc_csharp_ext.so`:
```sh
export LD_LIBRARY_PATH=$HOME/.linuxbrew/lib:${LD_LIBRARY_PATH}
```
- Open MonoDevelop and start a new project/solution. - Open MonoDevelop and start a new project/solution.
- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages). - Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
- TODO: link to Helloworld example - Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
Usage: MacOS (Mono)
--------------
- WARNING: As of now gRPC C# only works on 64bit version of Mono (because we don't compile
the native extension for C# in 32bit mode yet). That means your development experience
with Xamarin Studio on MacOS will not be great, as you won't be able to run your
code directly from Xamarin Studio (which requires 32bit version of Mono).
- Prerequisites: Xamarin Studio with NuGet add-in installed.
- Install Homebrew and gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc
- Install 64-bit version of mono with command `brew install mono` (assumes you've already installed Homebrew).
- Open Xamarin Studio and start a new project/solution.
- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
- *You will be able to build your project in Xamarin Studio, but to run or test it,
you will need to run it under 64-bit version of Mono.*
- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
Building: Windows Building: Windows
----------------- -----------------
@ -47,9 +85,10 @@ If you are a user of gRPC C#, go to Usage section above.
- The grpc_csharp_ext native library needs to be built so you can build the Grpc C# solution. You can - The grpc_csharp_ext native library needs to be built so you can build the Grpc C# solution. You can
either build the native solution in `vsprojects/grpc.sln` from Visual Studio manually, or you can use either build the native solution in `vsprojects/grpc.sln` from Visual Studio manually, or you can use
a convenience batch script that builds everything for you. a convenience batch script that builds everything for you.
```
buildall.bat ```
``` buildall.bat
```
- Open Grpc.sln using Visual Studio 2013. NuGet dependencies will be restored - Open Grpc.sln using Visual Studio 2013. NuGet dependencies will be restored
upon build (you need to have NuGet add-in installed). upon build (you need to have NuGet add-in installed).
@ -61,11 +100,12 @@ Building: Linux & Mono
You only need to go through these steps if you are planning to develop gRPC C#. You only need to go through these steps if you are planning to develop gRPC C#.
If you are a user of gRPC C#, go to Usage section above. If you are a user of gRPC C#, go to Usage section above.
- Prerequisites for development: Mono framework, MonoDevelop 5.9 with NuGet and Nunit add-ins installed. - Prerequisites for development: Mono 3.2.8+, MonoDevelop 5.9 with NuGet and NUnit add-ins installed.
```
sudo apt-get install mono-devel ```sh
sudo apt-get install nunit nunit-console sudo apt-get install mono-devel
``` sudo apt-get install nunit nunit-console
```
You can use older versions of MonoDevelop, but then you might need to restore You can use older versions of MonoDevelop, but then you might need to restore
NuGet dependencies manually (by `nuget restore`), because older versions of MonoDevelop NuGet dependencies manually (by `nuget restore`), because older versions of MonoDevelop
@ -73,10 +113,10 @@ don't support NuGet add-in.
- Compile and install the gRPC C# extension library (that will be used via - Compile and install the gRPC C# extension library (that will be used via
P/Invoke from C#). P/Invoke from C#).
``` ```sh
make grpc_csharp_ext make grpc_csharp_ext
sudo make install_grpc_csharp_ext sudo make install_grpc_csharp_ext
``` ```
- Use MonoDevelop to open the solution Grpc.sln - Use MonoDevelop to open the solution Grpc.sln
@ -95,7 +135,6 @@ Then you should be able to run all the test from the Test View.
After building the solution, you can also run the tests from command line After building the solution, you can also run the tests from command line
using nunit-console tool. using nunit-console tool.
``` ```
# from Grpc.Core.Test/bin/Debug directory # from Grpc.Core.Test/bin/Debug directory
nunit-console Grpc.Core.Tests.dll nunit-console Grpc.Core.Tests.dll

@ -11,8 +11,8 @@ endlocal
@call buildall.bat || goto :error @call buildall.bat || goto :error
%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec || goto :error %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec || goto :error %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols || goto :error
%NUGET% pack Grpc.nuspec || goto :error %NUGET% pack Grpc.nuspec || goto :error
goto :EOF goto :EOF

@ -119,7 +119,7 @@ var server = new Server({
}); });
if (require.main === module) { if (require.main === module) {
server.bind('0.0.0.0:7070'); server.bind('0.0.0.0:50051');
server.listen(); server.listen();
} }

@ -83,7 +83,7 @@ var stockServer = new StockServer({
}); });
if (require.main === module) { if (require.main === module) {
stockServer.bind('0.0.0.0:8080'); stockServer.bind('0.0.0.0:50051');
stockServer.listen(); stockServer.listen();
} }

@ -154,13 +154,15 @@ function serverStreaming(client, done) {
arg.response_parameters[resp_index].size); arg.response_parameters[resp_index].size);
resp_index += 1; resp_index += 1;
}); });
call.on('status', function(status) { call.on('end', function() {
assert.strictEqual(status.code, grpc.status.OK);
assert.strictEqual(resp_index, 4); assert.strictEqual(resp_index, 4);
if (done) { if (done) {
done(); done();
} }
}); });
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
});
} }
/** /**

@ -1,6 +1,6 @@
{ {
"name": "grpc", "name": "grpc",
"version": "0.8.0", "version": "0.9.0",
"author": "Google Inc.", "author": "Google Inc.",
"description": "gRPC Library for Node", "description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/", "homepage": "http://www.grpc.io/",

@ -81,7 +81,8 @@ function _write(chunk, encoding, callback) {
batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk); batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
this.call.startBatch(batch, function(err, event) { this.call.startBatch(batch, function(err, event) {
if (err) { if (err) {
throw err; // Something has gone wrong. Stop writing by failing to call callback
return;
} }
callback(); callback();
}); });
@ -120,10 +121,8 @@ function _read(size) {
*/ */
function readCallback(err, event) { function readCallback(err, event) {
if (err) { if (err) {
throw err; // Something has gone wrong. Stop reading and wait for status
} self.finished = true;
if (self.finished) {
self.push(null);
return; return;
} }
var data = event.read; var data = event.read;
@ -237,10 +236,6 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
client_batch[grpc.opType.RECV_MESSAGE] = true; client_batch[grpc.opType.RECV_MESSAGE] = true;
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(client_batch, function(err, response) { call.startBatch(client_batch, function(err, response) {
if (err) {
callback(err);
return;
}
emitter.emit('status', response.status); emitter.emit('status', response.status);
if (response.status.code !== grpc.status.OK) { if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details); var error = new Error(response.status.details);
@ -248,6 +243,12 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
error.metadata = response.status.metadata; error.metadata = response.status.metadata;
callback(error); callback(error);
return; return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
callback(err);
return;
}
} }
emitter.emit('metadata', response.metadata); emitter.emit('metadata', response.metadata);
callback(null, deserialize(response.read)); callback(null, deserialize(response.read));
@ -300,7 +301,8 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true; metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
call.startBatch(metadata_batch, function(err, response) { call.startBatch(metadata_batch, function(err, response) {
if (err) { if (err) {
callback(err); // The call has stopped for some reason. A non-OK status will arrive
// in the other batch.
return; return;
} }
stream.emit('metadata', response.metadata); stream.emit('metadata', response.metadata);
@ -309,10 +311,6 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
client_batch[grpc.opType.RECV_MESSAGE] = true; client_batch[grpc.opType.RECV_MESSAGE] = true;
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(client_batch, function(err, response) { call.startBatch(client_batch, function(err, response) {
if (err) {
callback(err);
return;
}
stream.emit('status', response.status); stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) { if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details); var error = new Error(response.status.details);
@ -320,6 +318,12 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
error.metadata = response.status.metadata; error.metadata = response.status.metadata;
callback(error); callback(error);
return; return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
callback(err);
return;
}
} }
callback(null, deserialize(response.read)); callback(null, deserialize(response.read));
}); });
@ -373,16 +377,15 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
call.startBatch(start_batch, function(err, response) { call.startBatch(start_batch, function(err, response) {
if (err) { if (err) {
throw err; // The call has stopped for some reason. A non-OK status will arrive
// in the other batch.
return;
} }
stream.emit('metadata', response.metadata); stream.emit('metadata', response.metadata);
}); });
var status_batch = {}; var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) { call.startBatch(status_batch, function(err, response) {
if (err) {
throw err;
}
stream.emit('status', response.status); stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) { if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details); var error = new Error(response.status.details);
@ -390,6 +393,12 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
error.metadata = response.status.metadata; error.metadata = response.status.metadata;
stream.emit('error', error); stream.emit('error', error);
return; return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
stream.emit('error', err);
return;
}
} }
}); });
}); });
@ -438,16 +447,15 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
call.startBatch(start_batch, function(err, response) { call.startBatch(start_batch, function(err, response) {
if (err) { if (err) {
throw err; // The call has stopped for some reason. A non-OK status will arrive
// in the other batch.
return;
} }
stream.emit('metadata', response.metadata); stream.emit('metadata', response.metadata);
}); });
var status_batch = {}; var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) { call.startBatch(status_batch, function(err, response) {
if (err) {
throw err;
}
stream.emit('status', response.status); stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) { if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details); var error = new Error(response.status.details);
@ -455,6 +463,12 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
error.metadata = response.status.metadata; error.metadata = response.status.metadata;
stream.emit('error', error); stream.emit('error', error);
return; return;
} else {
if (err) {
// Got a batch error, but OK status. Something went wrong
stream.emit('error', err);
return;
}
} }
}); });
}); });

@ -59,7 +59,7 @@
responseClass:(Class)responseClass responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable { responsesWriteable:(id<GRXWriteable>)responsesWriteable {
// Because we can't tell the type system to constrain the class, we need to check at runtime: // Because we can't tell the type system to constrain the class, we need to check at runtime:
if (![responseClass respondsToSelector:@selector(parseFromData:)]) { if (![responseClass respondsToSelector:@selector(parseFromData:error:)]) {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException
format:@"A protobuf class to parse the responses must be provided."]; format:@"A protobuf class to parse the responses must be provided."];
} }
@ -71,7 +71,7 @@
if ((self = [super initWithHost:host method:method requestsWriter:bytesWriter])) { if ((self = [super initWithHost:host method:method requestsWriter:bytesWriter])) {
// A writeable that parses the proto messages received. // A writeable that parses the proto messages received.
_responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
[responsesWriteable writeValue:[responseClass parseFromData:value]]; [responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]];
} completionHandler:^(NSError *errorOrNil) { } completionHandler:^(NSError *errorOrNil) {
[responsesWriteable writesFinishedWithError:errorOrNil]; [responsesWriteable writesFinishedWithError:errorOrNil];
}]; }];

@ -1,43 +1,119 @@
# gRPC for Objective-C # gRPC for Objective-C
## How to generate a client library from a Protocol Buffers definition - [Install protoc with the gRPC plugin](#install)
- [Use protoc to generate a gRPC library](#protoc)
- [Integrate the generated gRPC library in your project](#cocoapods)
- [Use the generated library in your code](#use)
- [Alternative methods](#alternatives)
- [Install protoc and the gRPC plugin without using Homebrew](#nohomebrew)
- [Integrate the generated gRPC library without using Cocoapods](#nococoapods)
First install v3 of the Protocol Buffers compiler (_protoc_), by cloning [its Git repository](https://github.com/google/protobuf) and following these [installation instructions](https://github.com/google/protobuf#c-installation---unix) (the ones titled C++; don't miss the note for Mac users). <a name="install"></a>
## Install protoc with the gRPC plugin
Then clone this repository and execute the following commands from the root directory where it was cloned. On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
Compile the gRPC plugins for _protoc_: Run the following command to install the Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin:
```sh ```sh
make plugins $ curl -fsSL https://goo.gl/getgrpc | bash -
``` ```
This will download and run the [gRPC install script][]. After the command completes, you're ready to proceed.
<a name="protoc"></a>
## Use protoc to generate a gRPC library
Run _protoc_ with the following flags to generate the client library for your `.proto` files:
Create a symbolic link to the compiled plugin binary somewhere in your `$PATH`:
```sh ```sh
ln -s `pwd`/bins/opt/grpc_objective_c_plugin /usr/local/bin/protoc-gen-objcgrpc protoc --objc_out=. --objcgrpc_out=. *.proto
``` ```
(Notice that the name of the created link must begin with "protoc-gen-" for _protoc_ to recognize it as a plugin).
If you don't want to create the symbolic link, you can alternatively copy the binary (with the appropriate name). Or you might prefer instead to specify the plugin's path as a flag when invoking _protoc_, in which case no system modification nor renaming is necessary. This will generate a pair of `.pbobjc.h`/`.pbobjc.m` files for each `.proto` file, with the messages and enums defined in them. And a pair of `.pbrpc.h`/`.pbrpc.m` files for each `.proto` file with services defined. The latter contains the code to make remote calls to the specified API.
<a name="cocoapods"></a>
## Integrate the generated gRPC library in your project
Install [Cocoapods](https://cocoapods.org/#install).
You need to create a Podspec file for the generated library. You may simply copy the following example to the directory where the source files were generated, updating the name and other metadata of the Podspec as necessary:
```ruby
Pod::Spec.new do |s|
s.name = '<Podspec file name>'
s.version = '...'
s.summary = 'Client library to make RPCs to <my proto API>'
s.homepage = '...'
s.license = '...'
s.authors = { '<my name>' => '<my email>' }
s.ios.deployment_target = '6.0'
s.osx.deployment_target = '10.8'
s.subspec 'Messages' do |ms|
ms.source_files = '*.pbobjc.{h,m}'
ms.requires_arc = false
ms.dependency 'Protobuf', '~> 3.0'
end
s.subspec 'Services' do |ss|
ss.source_files = '*.pbrpc.{h,m}'
ss.requires_arc = true
ss.dependency 'gRPC', '~> 0.0'
ss.dependency '<Podspec file name>/Messages'
end
end
```
Finally, run _protoc_ with the following flags to generate the client library for your `.proto` files: The file should be named `<Podspec file name>.podspec`. You can refer to this [example Podspec][]. Once your library has a Podspec, Cocoapods can install it into any XCode project. For that, go into your project's directory and create a Podfile by running:
```sh ```sh
protoc --objc_out=. --objcrpc_out=. *.proto pod init
``` ```
This will generate a pair of `.pbobjc.h`/`.pbobjc.m` files for each `.proto` file, with the messages and enums defined in them. And a pair of `.pbrpc.h`/`.pbrpc.m` files for each `.proto` file with services defined. The latter contains the code to make remote calls to the specified API. Next add a line to your Podfile to refer to your library's Podspec. Use `:path` as described [here](https://guides.cocoapods.org/using/the-podfile.html#using-the-files-from-a-folder-local-to-the-machine):
```ruby
pod '<Podspec file name>', :path => 'path/to/the/directory/of/your/podspec'
```
You can look at this [example Podfile][].
Finally, in your project's directory, run:
```sh
pod install
```
## How to integrate a generated gRPC library in your project <a name="use"></a>
## Use the generated library in your code
### If you use Cocoapods Please check this [sample app][] for examples of how to use a generated gRPC library.
This is the recommended approach. <a name="alternatives"></a>
## Alternative methods
You need to create a Podspec file for the generated library. This is simply a matter of copying an example like [this one](https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec) to the directory where the source files were generated. Update the name and other metadata of the Podspec as suitable. <a name="nohomebrew"></a>
### Install protoc and the gRPC plugin without using Homebrew
Once your library has a Podspec, refer to it from your Podfile using `:path` as described [here](https://guides.cocoapods.org/using/the-podfile.html#using-the-files-from-a-folder-local-to-the-machine). First install v3 of the Protocol Buffers compiler (_protoc_), by cloning [its Git repository](https://github.com/google/protobuf) and following these [installation instructions](https://github.com/google/protobuf#c-installation---unix) (the ones titled C++; don't miss the note for Mac users).
Then clone this repository and execute the following commands from the root directory where it was cloned.
### If you don't use Cocoapods Compile the gRPC plugins for _protoc_:
```sh
make plugins
```
Create a symbolic link to the compiled plugin binary somewhere in your `$PATH`:
```sh
ln -s `pwd`/bins/opt/grpc_objective_c_plugin /usr/local/bin/protoc-gen-objcgrpc
```
(Notice that the name of the created link must begin with "protoc-gen-" for _protoc_ to recognize it as a plugin).
If you don't want to create the symbolic link, you can alternatively copy the binary (with the appropriate name). Or you might prefer instead to specify the plugin's path as a flag when invoking _protoc_, in which case no system modification nor renaming is necessary.
<a name="nococoapods"></a>
### Integrate the generated gRPC library without using Cocoapods
You need to compile the generated `.pbpbjc.*` files (the enums and messages) without ARC support, and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on v0.3+ of the Objective-C gRPC runtime library and v3.0+ of the Objective-C Protobuf runtime library. You need to compile the generated `.pbpbjc.*` files (the enums and messages) without ARC support, and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on v0.3+ of the Objective-C gRPC runtime library and v3.0+ of the Objective-C Protobuf runtime library.
@ -45,3 +121,10 @@ These libraries need to be integrated into your project as described in their re
* [Podspec](https://github.com/grpc/grpc/blob/master/gRPC.podspec) for the Objective-C gRPC runtime library. This can be tedious to configure manually. * [Podspec](https://github.com/grpc/grpc/blob/master/gRPC.podspec) for the Objective-C gRPC runtime library. This can be tedious to configure manually.
* [Podspec](https://github.com/jcanizales/protobuf/blob/add-podspec/Protobuf.podspec) for the Objective-C Protobuf runtime library. * [Podspec](https://github.com/jcanizales/protobuf/blob/add-podspec/Protobuf.podspec) for the Objective-C Protobuf runtime library.
[homebrew]:http://brew.sh
[linuxbrew]:https://github.com/Homebrew/linuxbrew
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[example Podspec]:https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
[example Podfile]:https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/Podfile
[sample app]: https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample

@ -2,7 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
pod 'gRPC', :path => "../../../.." pod 'gRPC', :path => "../../../.."
pod 'Protobuf', :git => 'https://github.com/jcanizales/protobuf.git', :branch => 'add-podspec' pod 'Protobuf', :git => 'https://github.com/google/protobuf.git'
pod 'Route_guide', :path => "RouteGuideClient" pod 'Route_guide', :path => "RouteGuideClient"
pod 'RemoteTest', :path => "RemoteTestClient" pod 'RemoteTest', :path => "RemoteTestClient"

@ -80,7 +80,7 @@
requestsWriter:requestsWriter]; requestsWriter:requestsWriter];
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value]; RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value error:NULL];
NSLog(@"Received response:\n%@", response); NSLog(@"Received response:\n%@", response);
} completionHandler:^(NSError *errorOrNil) { } completionHandler:^(NSError *errorOrNil) {
if (errorOrNil) { if (errorOrNil) {

@ -125,7 +125,7 @@
XCTAssertNotNil(value, @"nil value received as response."); XCTAssertNotNil(value, @"nil value received as response.");
[response fulfill]; [response fulfill];
XCTAssertGreaterThan(value.length, 0, @"Empty response received."); XCTAssertGreaterThan(value.length, 0, @"Empty response received.");
RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value]; RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value error:NULL];
// We expect empty strings, not nil: // We expect empty strings, not nil:
XCTAssertNotNil(response.username, @"Response's username is nil."); XCTAssertNotNil(response.username, @"Response's username is nil.");
XCTAssertNotNil(response.oauthScope, @"Response's OAuth scope is nil."); XCTAssertNotNil(response.oauthScope, @"Response's OAuth scope is nil.");

@ -123,7 +123,7 @@
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTAssertNotNil(value, @"nil value received as response."); XCTAssertNotNil(value, @"nil value received as response.");
RGDFeature *feature = [RGDFeature parseFromData:value]; RGDFeature *feature = [RGDFeature parseFromData:value error:NULL];
XCTAssertEqualObjects(point, feature.location); XCTAssertEqualObjects(point, feature.location);
XCTAssertNotNil(feature.name, @"Response's name is nil."); XCTAssertNotNil(feature.name, @"Response's name is nil.");
[response fulfill]; [response fulfill];

@ -43,7 +43,7 @@ from grpc.framework.foundation import logging_pool
_TIMEOUT = 3 _TIMEOUT = 3
_MAXIMUM_TIMEOUT = 90 _MAXIMUM_TIMEOUT = 90
_MAXIMUM_POOL_SIZE = 400 _MAXIMUM_POOL_SIZE = 4
class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage): class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage):

@ -54,8 +54,8 @@ def _transform_metadata(unused_metadata):
class RoundTripTest(unittest.TestCase): class RoundTripTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.fore_link_pool = logging_pool.pool(80) self.fore_link_pool = logging_pool.pool(8)
self.rear_link_pool = logging_pool.pool(80) self.rear_link_pool = logging_pool.pool(8)
def tearDown(self): def tearDown(self):
self.rear_link_pool.shutdown(wait=True) self.rear_link_pool.shutdown(wait=True)

@ -43,7 +43,7 @@ _TIMEOUT = 2
class LonelyRearLinkTest(unittest.TestCase): class LonelyRearLinkTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.pool = logging_pool.pool(80) self.pool = logging_pool.pool(8)
def tearDown(self): def tearDown(self):
self.pool.shutdown(wait=True) self.pool.shutdown(wait=True)

@ -41,7 +41,7 @@ from grpc.framework.base import null
from grpc.framework.foundation import activated from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_THREAD_POOL_SIZE = 100 _THREAD_POOL_SIZE = 10
@enum.unique @enum.unique

@ -41,7 +41,7 @@ from grpc.framework.base import null
from grpc.framework.foundation import activated from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_THREAD_POOL_SIZE = 100 _THREAD_POOL_SIZE = 10
_INVOCATION_EVENT_KINDS = ( _INVOCATION_EVENT_KINDS = (
_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.METADATA_ACCEPTED,

@ -41,7 +41,7 @@ from grpc.framework.base import util as _base_utilities
from grpc.framework.face import implementations as _face_implementations from grpc.framework.face import implementations as _face_implementations
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_THREAD_POOL_SIZE = 80 _THREAD_POOL_SIZE = 8
_ONE_DAY_IN_SECONDS = 24 * 60 * 60 _ONE_DAY_IN_SECONDS = 24 * 60 * 60

@ -36,7 +36,7 @@ from grpc.framework.base import interfaces_test_case
from grpc.framework.base import util from grpc.framework.base import util
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
POOL_MAX_WORKERS = 100 POOL_MAX_WORKERS = 10
DEFAULT_TIMEOUT = 30 DEFAULT_TIMEOUT = 30
MAXIMUM_TIMEOUT = 60 MAXIMUM_TIMEOUT = 60

@ -35,7 +35,7 @@ from grpc.framework.face.testing import test_case
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_TIMEOUT = 3 _TIMEOUT = 3
_MAXIMUM_POOL_SIZE = 100 _MAXIMUM_POOL_SIZE = 10
class FaceTestCase(test_case.FaceTestCase): class FaceTestCase(test_case.FaceTestCase):

@ -34,7 +34,7 @@ from grpc.framework.base import implementations as _base_implementations
from grpc.framework.face import implementations from grpc.framework.face import implementations
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_POOL_SIZE_LIMIT = 20 _POOL_SIZE_LIMIT = 5
_MAXIMUM_TIMEOUT = 90 _MAXIMUM_TIMEOUT = 90

@ -38,7 +38,7 @@ from grpc.framework.base import in_memory
from grpc.framework.base import interfaces # pylint: disable=unused-import from grpc.framework.base import interfaces # pylint: disable=unused-import
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_POOL_SIZE_LIMIT = 20 _POOL_SIZE_LIMIT = 5
_MAXIMUM_TIMEOUT = 90 _MAXIMUM_TIMEOUT = 90

@ -44,7 +44,7 @@ from grpc.framework.foundation import future
from grpc.framework.foundation import logging_pool from grpc.framework.foundation import logging_pool
_TIMEOUT = 3 _TIMEOUT = 3
_MAXIMUM_POOL_SIZE = 100 _MAXIMUM_POOL_SIZE = 10
class _PauseableIterator(object): class _PauseableIterator(object):

@ -86,7 +86,7 @@ _PACKAGE_DIRECTORIES = {
setuptools.setup( setuptools.setup(
name='grpcio', name='grpcio',
version='0.5.0a2', version='0.9.0a0',
ext_modules=[_EXTENSION_MODULE], ext_modules=[_EXTENSION_MODULE],
packages=list(_PACKAGES), packages=list(_PACKAGES),
package_dir=_PACKAGE_DIRECTORIES, package_dir=_PACKAGE_DIRECTORIES,

@ -1,5 +1,5 @@
# This configuration was generated by `rubocop --auto-gen-config` # This configuration was generated by `rubocop --auto-gen-config`
# on 2015-04-17 14:43:27 -0700 using RuboCop version 0.30.0. # on 2015-05-22 13:23:34 -0700 using RuboCop version 0.30.1.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
@ -7,12 +7,12 @@
# Offense count: 30 # Offense count: 30
Metrics/AbcSize: Metrics/AbcSize:
Max: 40 Max: 38
# Offense count: 3 # Offense count: 3
# Configuration parameters: CountComments. # Configuration parameters: CountComments.
Metrics/ClassLength: Metrics/ClassLength:
Max: 184 Max: 192
# Offense count: 35 # Offense count: 35
# Configuration parameters: CountComments. # Configuration parameters: CountComments.

Binary file not shown.

@ -282,12 +282,12 @@ static VALUE grpc_rb_server_destroy(VALUE self) {
call-seq: call-seq:
// insecure port // insecure port
insecure_server = Server.new(cq, {'arg1': 'value1'}) insecure_server = Server.new(cq, {'arg1': 'value1'})
insecure_server.add_http2_port('mydomain:7575') insecure_server.add_http2_port('mydomain:50051')
// secure port // secure port
server_creds = ... server_creds = ...
secure_server = Server.new(cq, {'arg1': 'value1'}) secure_server = Server.new(cq, {'arg1': 'value1'})
secure_server.add_http_port('mydomain:7575', server_creds) secure_server.add_http_port('mydomain:50051', server_creds)
Adds a http2 port to server */ Adds a http2 port to server */
static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {

@ -76,7 +76,7 @@ module GRPC
@jobs = Queue.new @jobs = Queue.new
@size = size @size = size
@stopped = false @stopped = false
@stop_mutex = Mutex.new @stop_mutex = Mutex.new # needs to be held when accessing @stopped
@stop_cond = ConditionVariable.new @stop_cond = ConditionVariable.new
@workers = [] @workers = []
@keep_alive = keep_alive @keep_alive = keep_alive
@ -92,10 +92,15 @@ module GRPC
# @param args the args passed blk when it is called # @param args the args passed blk when it is called
# @param blk the block to call # @param blk the block to call
def schedule(*args, &blk) def schedule(*args, &blk)
fail 'already stopped' if @stopped
return if blk.nil? return if blk.nil?
GRPC.logger.info('schedule another job') @stop_mutex.synchronize do
@jobs << [blk, args] if @stopped
GRPC.logger.warn('did not schedule job, already stopped')
return
end
GRPC.logger.info('schedule another job')
@jobs << [blk, args]
end
end end
# Starts running the jobs in the thread pool. # Starts running the jobs in the thread pool.
@ -116,8 +121,8 @@ module GRPC
def stop def stop
GRPC.logger.info('stopping, will wait for all the workers to exit') GRPC.logger.info('stopping, will wait for all the workers to exit')
@workers.size.times { schedule { throw :exit } } @workers.size.times { schedule { throw :exit } }
@stopped = true
@stop_mutex.synchronize do # wait @keep_alive for works to stop @stop_mutex.synchronize do # wait @keep_alive for works to stop
@stopped = true
@stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0 @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
end end
forcibly_stop_workers forcibly_stop_workers
@ -249,15 +254,18 @@ module GRPC
server_override:nil, server_override:nil,
connect_md_proc:nil, connect_md_proc:nil,
**kw) **kw)
@cq = RpcServer.setup_cq(completion_queue_override)
@server = RpcServer.setup_srv(server_override, @cq, **kw)
@connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc) @connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
@pool_size = pool_size @cq = RpcServer.setup_cq(completion_queue_override)
@max_waiting_requests = max_waiting_requests @max_waiting_requests = max_waiting_requests
@poll_period = poll_period @poll_period = poll_period
@run_mutex = Mutex.new @pool_size = pool_size
@run_cond = ConditionVariable.new
@pool = Pool.new(@pool_size) @pool = Pool.new(@pool_size)
@run_cond = ConditionVariable.new
@run_mutex = Mutex.new
@running = false
@server = RpcServer.setup_srv(server_override, @cq, **kw)
@stopped = false
@stop_mutex = Mutex.new
end end
# stops a running server # stops a running server
@ -266,20 +274,23 @@ module GRPC
# server's current call loop is it's last. # server's current call loop is it's last.
def stop def stop
return unless @running return unless @running
@stopped = true @stop_mutex.synchronize do
@stopped = true
end
@pool.stop @pool.stop
@server.close
end
# TODO: uncomment this: # determines if the server has been stopped
# def stopped?
# This segfaults in the c layer, so its commented out for now. Shutdown @stop_mutex.synchronize do
# still occurs, but the c layer has to do the cleanup. return @stopped
# end
# @server.close
end end
# determines if the server is currently running # determines if the server is currently running
def running? def running?
@running ||= false @running
end end
# Is called from other threads to wait for #run to start up the server. # Is called from other threads to wait for #run to start up the server.
@ -311,11 +322,6 @@ module GRPC
t.join t.join
end end
# Determines if the server is currently stopped
def stopped?
@stopped ||= false
end
# handle registration of classes # handle registration of classes
# #
# service is either a class that includes GRPC::GenericService and whose # service is either a class that includes GRPC::GenericService and whose
@ -407,7 +413,13 @@ module GRPC
request_call_tag = Object.new request_call_tag = Object.new
until stopped? until stopped?
deadline = from_relative_time(@poll_period) deadline = from_relative_time(@poll_period)
an_rpc = @server.request_call(@cq, request_call_tag, deadline) begin
an_rpc = @server.request_call(@cq, request_call_tag, deadline)
rescue Core::CallError, RuntimeError => e
# can happen during server shutdown
GRPC.logger.warn("server call failed: #{e}")
next
end
c = new_active_server_call(an_rpc) c = new_active_server_call(an_rpc)
unless c.nil? unless c.nil?
mth = an_rpc.method.to_sym mth = an_rpc.method.to_sym

@ -29,5 +29,5 @@
# GRPC contains the General RPC module. # GRPC contains the General RPC module.
module GRPC module GRPC
VERSION = '0.6.1' VERSION = '0.9.0'
end end

@ -74,11 +74,11 @@ describe GRPC::Pool do
end end
describe '#schedule' do describe '#schedule' do
it 'throws if the pool is already stopped' do it 'return if the pool is already stopped' do
p = Pool.new(1) p = Pool.new(1)
p.stop p.stop
job = proc {} job = proc {}
expect { p.schedule(&job) }.to raise_error expect { p.schedule(&job) }.to_not raise_error
end end
it 'adds jobs that get run by the pool' do it 'adds jobs that get run by the pool' do

@ -212,10 +212,14 @@ describe GRPC::RpcServer do
describe '#stopped?' do describe '#stopped?' do
before(:each) do before(:each) do
opts = { a_channel_arg: 'an_arg', poll_period: 1 } opts = { a_channel_arg: 'an_arg', poll_period: 1.5 }
@srv = RpcServer.new(**opts) @srv = RpcServer.new(**opts)
end end
after(:each) do
@srv.stop
end
it 'starts out false' do it 'starts out false' do
expect(@srv.stopped?).to be(false) expect(@srv.stopped?).to be(false)
end end
@ -225,7 +229,7 @@ describe GRPC::RpcServer do
expect(@srv.stopped?).to be(false) expect(@srv.stopped?).to be(false)
end end
it 'stays false after the server starts running' do it 'stays false after the server starts running', server: true do
@srv.handle(EchoService) @srv.handle(EchoService)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@srv.wait_till_running @srv.wait_till_running
@ -234,7 +238,7 @@ describe GRPC::RpcServer do
t.join t.join
end end
it 'is true after a running server is stopped' do it 'is true after a running server is stopped', server: true do
@srv.handle(EchoService) @srv.handle(EchoService)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@srv.wait_till_running @srv.wait_till_running
@ -251,21 +255,22 @@ describe GRPC::RpcServer do
expect(r.running?).to be(false) expect(r.running?).to be(false)
end end
it 'is false after run is called with no services registered' do it 'is false if run is called with no services registered', server: true do
opts = { opts = {
a_channel_arg: 'an_arg', a_channel_arg: 'an_arg',
poll_period: 1, poll_period: 2,
server_override: @server server_override: @server
} }
r = RpcServer.new(**opts) r = RpcServer.new(**opts)
r.run r.run
expect(r.running?).to be(false) expect(r.running?).to be(false)
r.stop
end end
it 'is true after run is called with a registered service' do it 'is true after run is called with a registered service' do
opts = { opts = {
a_channel_arg: 'an_arg', a_channel_arg: 'an_arg',
poll_period: 1, poll_period: 2.5,
server_override: @server server_override: @server
} }
r = RpcServer.new(**opts) r = RpcServer.new(**opts)
@ -284,6 +289,10 @@ describe GRPC::RpcServer do
@srv = RpcServer.new(**@opts) @srv = RpcServer.new(**@opts)
end end
after(:each) do
@srv.stop
end
it 'raises if #run has already been called' do it 'raises if #run has already been called' do
@srv.handle(EchoService) @srv.handle(EchoService)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@ -335,6 +344,10 @@ describe GRPC::RpcServer do
@srv = RpcServer.new(**server_opts) @srv = RpcServer.new(**server_opts)
end end
after(:each) do
@srv.stop
end
it 'should return NOT_FOUND status on unknown methods', server: true do it 'should return NOT_FOUND status on unknown methods', server: true do
@srv.handle(EchoService) @srv.handle(EchoService)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@ -376,7 +389,7 @@ describe GRPC::RpcServer do
t.join t.join
end end
it 'should receive metadata when a deadline is specified', server: true do it 'should receive metadata if a deadline is specified', server: true do
service = SlowService.new service = SlowService.new
@srv.handle(service) @srv.handle(service)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@ -445,11 +458,11 @@ describe GRPC::RpcServer do
it 'should handle multiple parallel requests', server: true do it 'should handle multiple parallel requests', server: true do
@srv.handle(EchoService) @srv.handle(EchoService)
Thread.new { @srv.run } t = Thread.new { @srv.run }
@srv.wait_till_running @srv.wait_till_running
req, q = EchoMsg.new, Queue.new req, q = EchoMsg.new, Queue.new
n = 5 # arbitrary n = 5 # arbitrary
threads = [] threads = [t]
n.times do n.times do
threads << Thread.new do threads << Thread.new do
stub = EchoStub.new(@host, **client_opts) stub = EchoStub.new(@host, **client_opts)
@ -472,7 +485,7 @@ describe GRPC::RpcServer do
} }
alt_srv = RpcServer.new(**opts) alt_srv = RpcServer.new(**opts)
alt_srv.handle(SlowService) alt_srv.handle(SlowService)
Thread.new { alt_srv.run } t = Thread.new { alt_srv.run }
alt_srv.wait_till_running alt_srv.wait_till_running
req = EchoMsg.new req = EchoMsg.new
n = 5 # arbitrary, use as many to ensure the server pool is exceeded n = 5 # arbitrary, use as many to ensure the server pool is exceeded
@ -490,6 +503,7 @@ describe GRPC::RpcServer do
end end
threads.each(&:join) threads.each(&:join)
alt_srv.stop alt_srv.stop
t.join
expect(one_failed_as_unavailable).to be(true) expect(one_failed_as_unavailable).to be(true)
end end
end end
@ -513,6 +527,10 @@ describe GRPC::RpcServer do
@srv = RpcServer.new(**server_opts) @srv = RpcServer.new(**server_opts)
end end
after(:each) do
@srv.stop
end
it 'should send connect metadata to the client', server: true do it 'should send connect metadata to the client', server: true do
service = EchoService.new service = EchoService.new
@srv.handle(service) @srv.handle(service)
@ -545,6 +563,10 @@ describe GRPC::RpcServer do
@srv = RpcServer.new(**server_opts) @srv = RpcServer.new(**server_opts)
end end
after(:each) do
@srv.stop
end
it 'should be added to BadStatus when requests fail', server: true do it 'should be added to BadStatus when requests fail', server: true do
service = FailingService.new service = FailingService.new
@srv.handle(service) @srv.handle(service)

@ -767,9 +767,20 @@ buildtests_cxx: privatelibs_cxx\
test: test_c test_cxx test: test_c test_cxx
flaky_test: flaky_test_c flaky_test_cxx
test_c: buildtests_c test_c: buildtests_c
% for tgt in targets: % for tgt in targets:
% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++': % if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and not tgt.get('flaky', False):
$(E) "[RUN] Testing ${tgt.name}"
$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
% endif
% endfor
flaky_test_c: buildtests_c
% for tgt in targets:
% if tgt.build == 'test' and tgt.get('run', True) and not tgt.language == 'c++' and tgt.get('flaky', False):
$(E) "[RUN] Testing ${tgt.name}" $(E) "[RUN] Testing ${tgt.name}"
$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
% endif % endif
@ -778,7 +789,16 @@ test_c: buildtests_c
test_cxx: buildtests_cxx test_cxx: buildtests_cxx
% for tgt in targets: % for tgt in targets:
% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++': % if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and not tgt.get('flaky', False):
$(E) "[RUN] Testing ${tgt.name}"
$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
% endif
% endfor
flaky_test_cxx: buildtests_cxx
% for tgt in targets:
% if tgt.build == 'test' and tgt.get('run', True) and tgt.language == 'c++' and tgt.get('flaky', False):
$(E) "[RUN] Testing ${tgt.name}" $(E) "[RUN] Testing ${tgt.name}"
$(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/${tgt.name} || ( echo test ${tgt.name} failed ; exit 1 )
% endif % endif

@ -0,0 +1,2 @@
<%namespace file="Doxyfile.include" import="gen_doxyfile"/>\
${gen_doxyfile(['grpc++'], 'C++', libs)}

@ -0,0 +1,2 @@
<%namespace file="Doxyfile.include" import="gen_doxyfile"/>\
${gen_doxyfile(['grpc', 'gpr'], 'Core', libs)}

File diff suppressed because it is too large Load Diff

@ -1,5 +1,34 @@
#!/bin/sh #!/bin/sh
# 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.
# To properly use this, you'll need to add: # To properly use this, you'll need to add:
# #
# "debug": true # "debug": true

@ -0,0 +1,136 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/bad_client/bad_client.h"
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/iomgr/endpoint_pair.h"
#include "src/core/surface/completion_queue.h"
#include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
typedef struct {
grpc_server *server;
grpc_completion_queue *cq;
grpc_bad_client_server_side_validator validator;
gpr_event done_thd;
gpr_event done_write;
} thd_args;
static void thd_func(void *arg) {
thd_args *a = arg;
a->validator(a->server, a->cq);
gpr_event_set(&a->done_thd, (void *)1);
}
static void done_write(void *arg, grpc_endpoint_cb_status status) {
thd_args *a = arg;
gpr_event_set(&a->done_write, (void *)1);
}
static grpc_transport_setup_result server_setup_transport(
void *ts, grpc_transport *transport, grpc_mdctx *mdctx) {
thd_args *a = ts;
static grpc_channel_filter const *extra_filters[] = {
&grpc_http_server_filter};
return grpc_server_setup_transport(a->server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx);
}
void grpc_run_bad_client_test(const char *name, const char *client_payload,
size_t client_payload_length,
grpc_bad_client_server_side_validator validator) {
grpc_endpoint_pair sfd;
thd_args a;
gpr_thd_id id;
gpr_slice slice =
gpr_slice_from_copied_buffer(client_payload, client_payload_length);
/* Add a debug log */
gpr_log(GPR_INFO, "TEST: %s", name);
/* Init grpc */
grpc_init();
/* Create endpoints */
sfd = grpc_iomgr_create_endpoint_pair(65536);
/* Create server, completion events */
a.server = grpc_server_create_from_filters(NULL, 0, NULL);
a.cq = grpc_completion_queue_create();
gpr_event_init(&a.done_thd);
gpr_event_init(&a.done_write);
a.validator = validator;
grpc_server_register_completion_queue(a.server, a.cq);
grpc_server_start(a.server);
grpc_create_chttp2_transport(server_setup_transport, &a, NULL, sfd.server,
NULL, 0, grpc_mdctx_create(), 0);
/* Bind everything into the same pollset */
grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
/* Check a ground truth */
GPR_ASSERT(grpc_server_has_open_connections(a.server));
/* Start validator */
gpr_thd_new(&id, thd_func, &a, NULL);
/* Write data */
switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) {
case GRPC_ENDPOINT_WRITE_DONE:
done_write(&a, 1);
break;
case GRPC_ENDPOINT_WRITE_PENDING:
break;
case GRPC_ENDPOINT_WRITE_ERROR:
done_write(&a, 0);
break;
}
/* Await completion */
GPR_ASSERT(
gpr_event_wait(&a.done_write, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
GPR_ASSERT(gpr_event_wait(&a.done_thd, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
/* Shutdown */
grpc_endpoint_destroy(sfd.client);
grpc_server_destroy(a.server);
grpc_completion_queue_destroy(a.cq);
grpc_shutdown();
}

@ -0,0 +1,52 @@
/*
*
* 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.
*
*/
#ifndef GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H
#define GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H
#include <grpc/grpc.h>
#include "test/core/util/test_config.h"
typedef void (*grpc_bad_client_server_side_validator)(
grpc_server *server, grpc_completion_queue *cq);
/* Test runner.
Create a server, and send client_payload to it as bytes from a client.
Execute validator in a separate thread to assert that the bytes are
handled as expected. */
void grpc_run_bad_client_test(const char *name, const char *client_payload,
size_t client_payload_length,
grpc_bad_client_server_side_validator validator);
#endif /* GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H */

@ -0,0 +1,79 @@
#!/usr/bin/env python
# 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.
"""Generates the appropriate build.json data for all the end2end tests."""
import simplejson
import collections
TestOptions = collections.namedtuple('TestOptions', 'flaky')
default_test_options = TestOptions(False)
# maps test names to options
BAD_CLIENT_TESTS = {
'connection_prefix': default_test_options,
}
def main():
json = {
'#': 'generated with test/bad_client/gen_build_json.py',
'libs': [
{
'name': 'bad_client_test',
'build': 'private',
'language': 'c',
'src': [
'test/core/bad_client/bad_client.c'
]
}],
'targets': [
{
'name': '%s_bad_client_test' % t,
'build': 'test',
'language': 'c',
'secure': 'no',
'src': ['test/core/bad_client/tests/%s.c' % t],
'flaky': 'invoke_large_request' in t,
'deps': [
'bad_client_test',
'grpc_test_util_unsecure',
'grpc_unsecure',
'gpr_test_util',
'gpr'
]
}
for t in sorted(BAD_CLIENT_TESTS.keys())]}
print simplejson.dumps(json, sort_keys=True, indent=2 * ' ')
if __name__ == '__main__':
main()

@ -0,0 +1,79 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/bad_client/bad_client.h"
#include "src/core/surface/server.h"
static void verifier(grpc_server *server, grpc_completion_queue *cq) {
while (grpc_server_has_open_connections(server)) {
GPR_ASSERT(grpc_completion_queue_next(
cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20)).type ==
GRPC_QUEUE_TIMEOUT);
}
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_run_bad_client_test("conpfx_1", "X", 1, verifier);
grpc_run_bad_client_test("conpfx_2", "PX", 2, verifier);
grpc_run_bad_client_test("conpfx_3", "PRX", 3, verifier);
grpc_run_bad_client_test("conpfx_4", "PRIX", 4, verifier);
grpc_run_bad_client_test("conpfx_5", "PRI X", 5, verifier);
grpc_run_bad_client_test("conpfx_6", "PRI *X", 6, verifier);
grpc_run_bad_client_test("conpfx_7", "PRI * X", 7, verifier);
grpc_run_bad_client_test("conpfx_8", "PRI * HX", 8, verifier);
grpc_run_bad_client_test("conpfx_9", "PRI * HTX", 9, verifier);
grpc_run_bad_client_test("conpfx_10", "PRI * HTTX", 10, verifier);
grpc_run_bad_client_test("conpfx_11", "PRI * HTTPX", 11, verifier);
grpc_run_bad_client_test("conpfx_12", "PRI * HTTP/X", 12, verifier);
grpc_run_bad_client_test("conpfx_13", "PRI * HTTP/2X", 13, verifier);
grpc_run_bad_client_test("conpfx_14", "PRI * HTTP/2.X", 14, verifier);
grpc_run_bad_client_test("conpfx_15", "PRI * HTTP/2.0X", 15, verifier);
grpc_run_bad_client_test("conpfx_16", "PRI * HTTP/2.0\rX", 16, verifier);
grpc_run_bad_client_test("conpfx_17", "PRI * HTTP/2.0\r\nX", 17, verifier);
grpc_run_bad_client_test("conpfx_18", "PRI * HTTP/2.0\r\n\rX", 18, verifier);
grpc_run_bad_client_test("conpfx_19", "PRI * HTTP/2.0\r\n\r\nX", 19,
verifier);
grpc_run_bad_client_test("conpfx_20", "PRI * HTTP/2.0\r\n\r\nSX", 20,
verifier);
grpc_run_bad_client_test("conpfx_21", "PRI * HTTP/2.0\r\n\r\nSMX", 21,
verifier);
grpc_run_bad_client_test("conpfx_22", "PRI * HTTP/2.0\r\n\r\nSM\rX", 22,
verifier);
grpc_run_bad_client_test("conpfx_23", "PRI * HTTP/2.0\r\n\r\nSM\r\nX", 23,
verifier);
grpc_run_bad_client_test("conpfx_24", "PRI * HTTP/2.0\r\n\r\nSM\r\n\rX", 24,
verifier);
return 0;
}

@ -39,8 +39,6 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
#define LOG_TEST_NAME() gpr_log(GPR_INFO, "%s", __FUNCTION__)
static void channel_init_func(grpc_channel_element *elem, static void channel_init_func(grpc_channel_element *elem,
const grpc_channel_args *args, const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first, grpc_mdctx *metadata_context, int is_first,
@ -91,8 +89,6 @@ static void test_create_channel_stack(void) {
int *channel_data; int *channel_data;
int *call_data; int *call_data;
LOG_TEST_NAME();
metadata_context = grpc_mdctx_create(); metadata_context = grpc_mdctx_create();
arg.type = GRPC_ARG_INTEGER; arg.type = GRPC_ARG_INTEGER;

@ -158,7 +158,7 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
static void test_invoke_simple_request(grpc_end2end_test_config config) { static void test_invoke_simple_request(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
f = begin_test(config, __FUNCTION__, NULL, NULL); f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
simple_request_body(f); simple_request_body(f);
end_test(&f); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);

@ -105,7 +105,7 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_call *s; grpc_call *s;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "cancel_after_accept", NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);

@ -105,7 +105,7 @@ static void test_cancel_after_accept_and_writes_closed(
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_call *s; grpc_call *s;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_cancel_after_accept_and_writes_closed", NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);

@ -106,7 +106,7 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_end2end_test_fixture f = grpc_end2end_test_fixture f =
begin_test(config, __FUNCTION__, mode, NULL, NULL); begin_test(config, "test_cancel_after_invoke", mode, NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
grpc_metadata_array initial_metadata_recv; grpc_metadata_array initial_metadata_recv;

@ -103,7 +103,7 @@ static void test_cancel_before_invoke(grpc_end2end_test_config config,
grpc_op ops[6]; grpc_op ops[6];
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "cancel_before_invoke", NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
grpc_metadata_array initial_metadata_recv; grpc_metadata_array initial_metadata_recv;

@ -100,7 +100,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void test_cancel_in_a_vacuum(grpc_end2end_test_config config, static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
cancellation_mode mode) { cancellation_mode mode) {
grpc_call *c; grpc_call *c;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_cancel_in_a_vacuum", NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);

@ -204,7 +204,7 @@ static void test_invoke_request_with_census(
server_args.num_args = 1; server_args.num_args = 1;
server_args.args = &server_arg; server_args.args = &server_arg;
gpr_asprintf(&fullname, "%s/%s", __FUNCTION__, name); gpr_asprintf(&fullname, "%s/%s", "test_invoke_request_with_census", name);
f = begin_test(config, fullname, &client_args, &server_args); f = begin_test(config, fullname, &client_args, &server_args);
body(f); body(f);
end_test(&f); end_test(&f);

@ -180,7 +180,7 @@ static void disappearing_server_test(grpc_end2end_test_config config) {
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
gpr_log(GPR_INFO, "%s/%s", __FUNCTION__, config.name); gpr_log(GPR_INFO, "%s/%s", "disappearing_server_test", config.name);
config.init_client(&f, NULL); config.init_client(&f, NULL);
config.init_server(&f, NULL); config.init_server(&f, NULL);

@ -102,7 +102,7 @@ static void test_early_server_shutdown_finishes_inflight_calls(
grpc_call *c; grpc_call *c;
grpc_call *s; grpc_call *s;
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_op ops[6]; grpc_op ops[6];

@ -99,7 +99,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void test_early_server_shutdown_finishes_tags( static void test_early_server_shutdown_finishes_tags(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_tags", NULL, NULL);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_call *s = (void *)1; grpc_call *s = (void *)1;
grpc_call_details call_details; grpc_call_details call_details;

@ -121,7 +121,7 @@ static void empty_batch_body(grpc_end2end_test_fixture f) {
static void test_invoke_empty_body(grpc_end2end_test_config config) { static void test_invoke_empty_body(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
f = begin_test(config, __FUNCTION__, NULL, NULL); f = begin_test(config, "test_invoke_empty_body", NULL, NULL);
empty_batch_body(f); empty_batch_body(f);
end_test(&f); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);

@ -101,7 +101,7 @@ static void test_early_server_shutdown_finishes_inflight_calls(
grpc_call *c; grpc_call *c;
grpc_call *s; grpc_call *s;
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_op ops[6]; grpc_op ops[6];

@ -102,7 +102,7 @@ static gpr_slice large_slice(void) {
} }
static void test_invoke_large_request(grpc_end2end_test_config config) { static void test_invoke_large_request(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_invoke_large_request", NULL, NULL);
gpr_slice request_payload_slice = large_slice(); gpr_slice request_payload_slice = large_slice();
gpr_slice response_payload_slice = large_slice(); gpr_slice response_payload_slice = large_slice();

@ -222,7 +222,7 @@ static void test_max_concurrent_streams(grpc_end2end_test_config config) {
server_args.num_args = 1; server_args.num_args = 1;
server_args.args = &server_arg; server_args.args = &server_arg;
f = begin_test(config, __FUNCTION__, NULL, &server_args); f = begin_test(config, "test_max_concurrent_streams", NULL, &server_args);
v_client = cq_verifier_create(f.client_cq); v_client = cq_verifier_create(f.client_cq);
v_server = cq_verifier_create(f.server_cq); v_server = cq_verifier_create(f.server_cq);

@ -126,7 +126,7 @@ static void test_max_message_length(grpc_end2end_test_config config) {
server_args.num_args = 1; server_args.num_args = 1;
server_args.args = &server_arg; server_args.args = &server_arg;
f = begin_test(config, __FUNCTION__, NULL, &server_args); f = begin_test(config, "test_max_message_length", NULL, &server_args);
v_client = cq_verifier_create(f.client_cq); v_client = cq_verifier_create(f.client_cq);
v_server = cq_verifier_create(f.server_cq); v_server = cq_verifier_create(f.server_cq);

@ -96,7 +96,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
} }
static void test_no_op(grpc_end2end_test_config config) { static void test_no_op(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "no-op", NULL, NULL);
end_test(&f); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);
} }

@ -100,7 +100,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
/* Client pings and server pongs. Repeat messages rounds before finishing. */ /* Client pings and server pongs. Repeat messages rounds before finishing. */
static void test_pingpong_streaming(grpc_end2end_test_config config, static void test_pingpong_streaming(grpc_end2end_test_config config,
int messages) { int messages) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_pingpong_streaming", NULL, NULL);
grpc_call *c; grpc_call *c;
grpc_call *s; grpc_call *s;
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();

@ -188,7 +188,7 @@ static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
} }
static void test_invoke_simple_request(grpc_end2end_test_config config) { static void test_invoke_simple_request(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_invoke_simple_request", NULL, NULL);
void *rc = void *rc =
grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234"); grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234");
@ -199,7 +199,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) {
static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
int i; int i;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_invoke_10_simple_requests", NULL, NULL);
void *rc = void *rc =
grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234"); grpc_channel_register_call(f.client, "/foo", "foo.test.google.fr:1234");

@ -127,7 +127,7 @@ static void test_request_response_with_metadata_and_payload(
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
16, 16,
{{NULL, NULL, NULL}}}}; {{NULL, NULL, NULL}}}};
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_op ops[6]; grpc_op ops[6];

@ -113,7 +113,7 @@ static void test_request_response_with_metadata_and_payload(
{"key2", "val2", 4, {{NULL, NULL, NULL}}}}; {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}}, grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}},
{"key4", "val4", 4, {{NULL, NULL, NULL}}}}; {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_op ops[6]; grpc_op ops[6];

@ -223,7 +223,7 @@ static void request_response_with_payload(grpc_end2end_test_fixture f) {
payload and status. */ payload and status. */
static void test_invoke_request_response_with_payload( static void test_invoke_request_response_with_payload(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_invoke_request_response_with_payload", NULL, NULL);
request_response_with_payload(f); request_response_with_payload(f);
end_test(&f); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);
@ -232,7 +232,7 @@ static void test_invoke_request_response_with_payload(
static void test_invoke_10_request_response_with_payload( static void test_invoke_10_request_response_with_payload(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
int i; int i;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_invoke_10_request_response_with_payload", NULL, NULL);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
request_response_with_payload(f); request_response_with_payload(f);
} }

@ -114,7 +114,7 @@ static void end_test(grpc_end2end_test_fixture *f) {
static void test_call_creds_failure(grpc_end2end_test_config config) { static void test_call_creds_failure(grpc_end2end_test_config config) {
grpc_call *c; grpc_call *c;
grpc_credentials *creds = NULL; grpc_credentials *creds = NULL;
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_call_creds_failure", NULL, NULL);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
c = grpc_channel_create_call(f.client, f.client_cq, "/foo", c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
"foo.test.google.fr", deadline); "foo.test.google.fr", deadline);
@ -318,17 +318,17 @@ static void request_response_with_payload_and_call_creds(
void test_request_response_with_payload_and_call_creds( void test_request_response_with_payload_and_call_creds(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
request_response_with_payload_and_call_creds(__FUNCTION__, config, NONE); request_response_with_payload_and_call_creds("test_request_response_with_payload_and_call_creds", config, NONE);
} }
void test_request_response_with_payload_and_overridden_call_creds( void test_request_response_with_payload_and_overridden_call_creds(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
request_response_with_payload_and_call_creds(__FUNCTION__, config, OVERRIDE); request_response_with_payload_and_call_creds("test_request_response_with_payload_and_overridden_call_creds", config, OVERRIDE);
} }
void test_request_response_with_payload_and_deleted_call_creds( void test_request_response_with_payload_and_deleted_call_creds(
grpc_end2end_test_config config) { grpc_end2end_test_config config) {
request_response_with_payload_and_call_creds(__FUNCTION__, config, DESTROY); request_response_with_payload_and_call_creds("test_request_response_with_payload_and_deleted_call_creds", config, DESTROY);
} }
void grpc_end2end_tests(grpc_end2end_test_config config) { void grpc_end2end_tests(grpc_end2end_test_config config) {

@ -112,7 +112,7 @@ static void test_request_response_with_metadata_and_payload(
grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}}, {"key2", "val2", 4, {{NULL, NULL, NULL}}}}; grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}}, {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}}, {"key4", "val4", 4, {{NULL, NULL, NULL}}}}; grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}}, {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
grpc_metadata meta_t[2] = {{"key5", "val5", 4, {{NULL, NULL, NULL}}}, {"key6", "val6", 4, {{NULL, NULL, NULL}}}}; grpc_metadata meta_t[2] = {{"key5", "val5", 4, {{NULL, NULL, NULL}}}, {"key6", "val6", 4, {{NULL, NULL, NULL}}}};
grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL); grpc_end2end_test_fixture f = begin_test(config, "test_request_response_with_metadata_and_payload", NULL, NULL);
cq_verifier *v_client = cq_verifier_create(f.client_cq); cq_verifier *v_client = cq_verifier_create(f.client_cq);
cq_verifier *v_server = cq_verifier_create(f.server_cq); cq_verifier *v_server = cq_verifier_create(f.server_cq);
grpc_op ops[6]; grpc_op ops[6];

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

Loading…
Cancel
Save