Merge commit '5e623b8d8d8d106bd4ab9a6d77ef43b1a134d8ec' into p0-advance-protobuf-version

pull/7475/head
Jorge Canizales 9 years ago
commit 7a2bc14fc0
  1. 48
      .travis.yml
  2. 36
      Makefile
  3. 15
      build.yaml
  4. 2
      composer.json
  5. 2
      doc/.gitignore
  6. 4
      examples/cpp/helloworld/Makefile
  7. 4
      examples/cpp/route_guide/Makefile
  8. 32
      examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
  9. 2
      examples/php/composer.json
  10. 27
      include/grpc++/impl/codegen/async_stream.h
  11. 9
      include/grpc++/impl/codegen/async_unary_call.h
  12. 12
      include/grpc++/impl/codegen/call.h
  13. 15
      include/grpc++/impl/codegen/method_handler_impl.h
  14. 9
      include/grpc++/impl/codegen/server_context.h
  15. 15
      include/grpc++/impl/codegen/sync_stream.h
  16. 3
      include/grpc++/server.h
  17. 17
      include/grpc/impl/codegen/compression_types.h
  18. 38
      include/grpc/impl/codegen/grpc_types.h
  19. 2
      include/grpc/impl/codegen/port_platform.h
  20. 10
      include/grpc/module.modulemap
  21. 40
      package.xml
  22. 2
      setup.cfg
  23. 6
      setup.py
  24. 4
      src/compiler/ruby_generator_helpers-inl.h
  25. 6
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
  26. 3
      src/core/ext/transport/chttp2/transport/chttp2_plugin.c
  27. 369
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  28. 65
      src/core/ext/transport/chttp2/transport/internal.h
  29. 11
      src/core/ext/transport/chttp2/transport/parsing.c
  30. 20
      src/core/ext/transport/chttp2/transport/stream_lists.c
  31. 16
      src/core/ext/transport/chttp2/transport/writing.c
  32. 4
      src/core/lib/iomgr/endpoint.c
  33. 4
      src/core/lib/iomgr/endpoint.h
  34. 277
      src/core/lib/iomgr/ev_epoll_linux.c
  35. 3
      src/core/lib/iomgr/ev_poll_and_epoll_posix.c
  36. 3
      src/core/lib/iomgr/ev_poll_posix.c
  37. 4
      src/core/lib/iomgr/ev_posix.c
  38. 4
      src/core/lib/iomgr/ev_posix.h
  39. 10
      src/core/lib/iomgr/exec_ctx.c
  40. 6
      src/core/lib/iomgr/exec_ctx.h
  41. 3
      src/core/lib/iomgr/iomgr.c
  42. 15
      src/core/lib/iomgr/network_status_tracker.c
  43. 4
      src/core/lib/iomgr/network_status_tracker.h
  44. 18
      src/core/lib/iomgr/tcp_posix.c
  45. 3
      src/core/lib/iomgr/tcp_server_posix.c
  46. 13
      src/core/lib/iomgr/tcp_windows.c
  47. 39
      src/core/lib/iomgr/workqueue.h
  48. 8
      src/core/lib/iomgr/workqueue_posix.c
  49. 5
      src/core/lib/iomgr/workqueue_posix.h
  50. 22
      src/core/lib/iomgr/workqueue_windows.c
  51. 18
      src/core/lib/security/transport/secure_endpoint.c
  52. 19
      src/core/lib/support/log.c
  53. 76
      src/core/lib/surface/server.c
  54. 3
      src/core/lib/transport/connectivity_state.c
  55. 8
      src/cpp/server/server.cc
  56. 15
      src/cpp/server/server_context.cc
  57. 6
      src/csharp/.nuget/packages.config
  58. 5
      src/csharp/Grpc.Core.Tests/packages.config
  59. 5
      src/csharp/Grpc.Core.Tests/project.json
  60. 3
      src/csharp/Grpc.Examples.MathClient/packages.config
  61. 3
      src/csharp/Grpc.Examples.MathServer/packages.config
  62. 3
      src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config
  63. 3
      src/csharp/Grpc.IntegrationTesting.StressClient/packages.config
  64. 30
      src/node/ext/call_credentials.cc
  65. 4
      src/node/health_check/package.json
  66. 5
      src/node/src/credentials.js
  67. 44
      src/objective-c/examples/RemoteTestClient/empty.proto
  68. 4
      src/objective-c/examples/RemoteTestClient/test.proto
  69. 2
      src/objective-c/examples/Sample/Podfile
  70. 13
      src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
  71. 2
      src/objective-c/examples/Sample/Sample/Info.plist
  72. 6
      src/objective-c/examples/Sample/Sample/ViewController.m
  73. 45
      src/objective-c/examples/SwiftSample/Bridging-Header.h
  74. 2
      src/objective-c/examples/SwiftSample/Info.plist
  75. 2
      src/objective-c/examples/SwiftSample/Podfile
  76. 19
      src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
  77. 6
      src/objective-c/examples/SwiftSample/ViewController.swift
  78. 27
      src/objective-c/tests/build_example_test.sh
  79. 4
      src/objective-c/tests/build_one_example.sh
  80. 26
      src/objective-c/tests/build_tests.sh
  81. 14
      src/objective-c/tests/run_tests.sh
  82. 43
      src/php/README.md
  83. 6
      src/php/bin/determine_extension_dir.sh
  84. 4
      src/php/composer.json
  85. 541
      src/php/ext/grpc/call.c
  86. 31
      src/php/ext/grpc/call.h
  87. 91
      src/php/ext/grpc/call_credentials.c
  88. 24
      src/php/ext/grpc/call_credentials.h
  89. 164
      src/php/ext/grpc/channel.c
  90. 27
      src/php/ext/grpc/channel.h
  91. 75
      src/php/ext/grpc/channel_credentials.c
  92. 24
      src/php/ext/grpc/channel_credentials.h
  93. 156
      src/php/ext/grpc/package.xml
  94. 218
      src/php/ext/grpc/php7_wrapper.h
  95. 54
      src/php/ext/grpc/php_grpc.c
  96. 6
      src/php/ext/grpc/php_grpc.h
  97. 111
      src/php/ext/grpc/server.c
  98. 23
      src/php/ext/grpc/server.h
  99. 55
      src/php/ext/grpc/server_credentials.c
  100. 24
      src/php/ext/grpc/server_credentials.h
  101. Some files were not shown because too many files have changed in this diff Show More

@ -8,33 +8,37 @@ env:
- TEST=objc
- JOBS=1
matrix:
- SCHEME="RxLibraryUnitTests" WORKSPACE="Tests.xcworkspace"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
- SCHEME="RxLibraryUnitTests"
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
INTEROP_SERVER="false"
- SCHEME="InteropTestsLocalSSL" WORKSPACE="Tests.xcworkspace"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" INTEROP_SERVER="true"
- SCHEME="InteropTestsLocalCleartext" WORKSPACE="Tests.xcworkspace"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
- SCHEME="InteropTestsLocalSSL"
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
INTEROP_SERVER="true"
- SCHEME="InteropTestsLocalCleartext"
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
INTEROP_SERVER="true"
# TODO(jcanizales): Make tests an app project (instead of library), so the following will work.
# - SCHEME="InteropTestsRemote" WORKSPACE="Tests.xcworkspace"
# TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
# - SCHEME="InteropTestsRemote"
# WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
# INTEROP_SERVER="true"
- SCHEME="HelloWorld" WORKSPACE="HelloWorld.xcworkspace"
TEST_PATH="examples/objective-c/helloworld" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="RouteGuideClient" WORKSPACE="RouteGuideClient.xcworkspace"
TEST_PATH="examples/objective-c/route_guide" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="AuthSample" WORKSPACE="AuthSample.xcworkspace"
TEST_PATH="examples/objective-c/auth_sample" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="Sample" WORKSPACE="Sample.xcworkspace"
TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="SwiftSample" WORKSPACE="SwiftSample.xcworkspace"
TEST_PATH="src/objective-c/examples/SwiftSample" BUILD_ONLY="true"
- SCHEME="HelloWorld"
WORKSPACE="HelloWorld.xcworkspace" TEST_PATH="examples/objective-c/helloworld"
BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="RouteGuideClient"
WORKSPACE="RouteGuideClient.xcworkspace" TEST_PATH="examples/objective-c/route_guide"
BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="AuthSample"
WORKSPACE="AuthSample.xcworkspace" TEST_PATH="examples/objective-c/auth_sample"
BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="Sample"
WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="Sample"
WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true"
INTEROP_SERVER="false" FRAMEWORKS="YES"
- SCHEME="SwiftSample"
WORKSPACE="SwiftSample.xcworkspace" TEST_PATH="src/objective-c/examples/SwiftSample"
BUILD_ONLY="true" INTEROP_SERVER="false"
before_install:
# Until Travis upgrades from Cocoapods 0.39, we need to do it here.
- pod --version

@ -991,7 +991,6 @@ transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
workqueue_test: $(BINDIR)/$(CONFIG)/workqueue_test
alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
@ -1295,7 +1294,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/transport_security_test \
$(BINDIR)/$(CONFIG)/udp_server_test \
$(BINDIR)/$(CONFIG)/uri_parser_test \
$(BINDIR)/$(CONFIG)/workqueue_test \
$(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
$(BINDIR)/$(CONFIG)/badreq_bad_client_test \
$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
@ -1674,8 +1672,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/udp_server_test || ( echo test udp_server_test failed ; exit 1 )
$(E) "[RUN] Testing uri_parser_test"
$(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 )
$(E) "[RUN] Testing workqueue_test"
$(Q) $(BINDIR)/$(CONFIG)/workqueue_test || ( echo test workqueue_test failed ; exit 1 )
$(E) "[RUN] Testing public_headers_must_be_c89"
$(Q) $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 || ( echo test public_headers_must_be_c89 failed ; exit 1 )
$(E) "[RUN] Testing badreq_bad_client_test"
@ -10175,38 +10171,6 @@ endif
endif
WORKQUEUE_TEST_SRC = \
test/core/iomgr/workqueue_test.c \
WORKQUEUE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WORKQUEUE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/workqueue_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/workqueue_test: $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/workqueue_test
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/workqueue_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_workqueue_test: $(WORKQUEUE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(WORKQUEUE_TEST_OBJS:.o=.dep)
endif
endif
ALARM_CPP_TEST_SRC = \
test/cpp/common/alarm_cpp_test.cc \

@ -2430,20 +2430,6 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: workqueue_test
build: test
language: c
src:
- test/core/iomgr/workqueue_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
platforms:
- mac
- linux
- posix
- name: alarm_cpp_test
gtest: true
build: test
@ -3367,6 +3353,7 @@ php_config_m4:
- src/php/ext/grpc/channel.h
- src/php/ext/grpc/channel_credentials.h
- src/php/ext/grpc/completion_queue.h
- src/php/ext/grpc/php7_wrapper.h
- src/php/ext/grpc/php_grpc.h
- src/php/ext/grpc/server.h
- src/php/ext/grpc/server_credentials.h

@ -7,7 +7,7 @@
"license": "BSD-3-Clause",
"require": {
"php": ">=5.5.0",
"stanley-cheung/protobuf-php": "dev-master"
"stanley-cheung/protobuf-php": "v0.6"
},
"require-dev": {
"google/auth": "v0.9"

2
doc/.gitignore vendored

@ -0,0 +1,2 @@
build/
src/

@ -32,7 +32,9 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc` -lprotobuf -lpthread -ldl
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc` \
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
-lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -32,7 +32,9 @@
CXX = g++
CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` \
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
-lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -2,9 +2,39 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AD_UNIT_ID_FOR_BANNER_TEST</key>
<string>redacted</string>
<key>AD_UNIT_ID_FOR_INTERSTITIAL_TEST</key>
<string>redacted</string>
<key>CLIENT_ID</key>
<string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
<key>API_KEY</key>
<string>redacted</string>
<key>GCM_SENDER_ID</key>
<string>redacted</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>io.grpc.AuthSample</string>
<key>PROJECT_ID</key>
<string>grpc-authsample</string>
<key>STORAGE_BUCKET</key>
<string>grpc-authsample.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false/>
<key>IS_ANALYTICS_ENABLED</key>
<false/>
<key>IS_APPINVITE_ENABLED</key>
<false/>
<key>IS_GCM_ENABLED</key>
<false/>
<key>IS_SIGNIN_ENABLED</key>
<true/>
<key>GOOGLE_APP_ID</key>
<string>1:15087385131:ios:d547168abe3c362f</string>
<key>DATABASE_URL</key>
<string>https://grpc-authsample.firebaseio.com</string>
</dict>
</plist>
</plist>

@ -3,6 +3,6 @@
"description": "gRPC example for PHP",
"minimum-stability": "dev",
"require": {
"grpc/grpc": "v0.15.0"
"grpc/grpc": "v0.15.2"
}
}

@ -330,6 +330,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_);
}
@ -345,6 +348,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
@ -363,6 +369,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@ -400,6 +409,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_);
}
@ -409,6 +421,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// TODO(ctiller): don't assert
@ -421,6 +436,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@ -459,6 +477,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_);
}
@ -474,6 +495,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// TODO(ctiller): don't assert
@ -486,6 +510,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);

@ -126,6 +126,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
meta_buf_.set_output_tag(tag);
meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_buf_);
}
@ -135,6 +138,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
// The response is dropped if the status is not OK.
@ -153,6 +159,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);

@ -180,17 +180,23 @@ class CallNoOp {
class CallOpSendInitialMetadata {
public:
CallOpSendInitialMetadata() : send_(false) {}
CallOpSendInitialMetadata() : send_(false) {
maybe_compression_level_.is_set = false;
}
void SendInitialMetadata(
const std::multimap<grpc::string, grpc::string>& metadata,
uint32_t flags) {
maybe_compression_level_.is_set = false;
send_ = true;
flags_ = flags;
initial_metadata_count_ = metadata.size();
initial_metadata_ = FillMetadataArray(metadata);
// TODO(dgq): expose compression level in API so it can be properly set.
maybe_compression_level_.is_set = false;
}
void set_compression_level(grpc_compression_level level) {
maybe_compression_level_.is_set = true;
maybe_compression_level_.level = level;
}
protected:

@ -65,6 +65,9 @@ class RpcMethodHandler : public MethodHandler {
ops;
ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (status.ok()) {
status = ops.SendMessage(rsp);
}
@ -104,6 +107,9 @@ class ClientStreamingHandler : public MethodHandler {
ops;
ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (status.ok()) {
status = ops.SendMessage(rsp);
}
@ -144,6 +150,9 @@ class ServerStreamingHandler : public MethodHandler {
if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
@ -177,6 +186,9 @@ class BidiStreamingHandler : public MethodHandler {
if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
}
ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops);
@ -199,6 +211,9 @@ class UnknownMethodHandler : public MethodHandler {
if (!context->sent_initial_metadata_) {
ops->SendInitialMetadata(context->initial_metadata_,
context->initial_metadata_flags());
if (context->compression_level_set()) {
ops->set_compression_level(context->compression_level());
}
context->sent_initial_metadata_ = true;
}
ops->ServerSendStatus(context->trailing_metadata_, status);

@ -130,7 +130,13 @@ class ServerContext {
grpc_compression_level compression_level() const {
return compression_level_;
}
void set_compression_level(grpc_compression_level level);
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
}
bool compression_level_set() const { return compression_level_set_; }
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
@ -217,6 +223,7 @@ class ServerContext {
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
bool compression_level_set_;
grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_;
};

@ -347,6 +347,9 @@ class ServerReader GRPC_FINAL : public ReaderInterface<R> {
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
@ -375,6 +378,9 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> {
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
@ -389,6 +395,9 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> {
if (!ctx_->sent_initial_metadata_) {
ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ops);
@ -413,6 +422,9 @@ class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops);
call_->cq()->Pluck(&ops);
@ -434,6 +446,9 @@ class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
if (!ctx_->sent_initial_metadata_) {
ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true;
}
call_->PerformOps(&ops);

@ -179,10 +179,13 @@ class Server GRPC_FINAL : public ServerInterface, private GrpcLibraryCodegen {
grpc::mutex mu_;
bool started_;
bool shutdown_;
bool shutdown_notified_;
// The number of threads which are running callbacks.
int num_running_cb_;
grpc::condition_variable callback_cv_;
grpc::condition_variable shutdown_cv_;
std::shared_ptr<GlobalCallbacks> global_callbacks_;
std::list<SyncRequest>* sync_methods_;

@ -46,12 +46,27 @@ extern "C" {
#define GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY \
"grpc-internal-encoding-request"
/** To be used in channel arguments */
/** To be used in channel arguments.
*
* \addtogroup grpc_arg_keys
* \{ */
/** Default compression algorithm for the channel.
* Its value is an int from the \a grpc_compression_algorithm enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \
"grpc.default_compression_algorithm"
/** Default compression level for the channel.
* Its value is an int from the \a grpc_compression_level enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level"
/** Compression algorithms supported by the channel.
* Its value is a bitset (an int). Bits correspond to algorithms in \a
* grpc_compression_algorithm. For example, its LSB corresponds to
* GRPC_COMPRESS_NONE, the next bit to GRPC_COMPRESS_DEFLATE, etc.
* Unset bits disable support for the algorithm. By default all algorithms are
* supported. It's not possible to disable GRPC_COMPRESS_NONE (the attempt will
* be ignored). */
#define GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET \
"grpc.compression_enabled_algorithms_bitset"
/** \} */
/* The various compression algorithms supported by gRPC */
typedef enum {

@ -106,58 +106,66 @@ typedef struct {
by grpc_arg; keys are strings to allow easy backwards-compatible extension
by arbitrary parties.
All evaluation is performed at channel creation time (i.e. the values in
this structure need only live through the creation invocation). */
this structure need only live through the creation invocation).
See the description of the \ref grpc_arg_keys "available args" for more
details. */
typedef struct {
size_t num_args;
grpc_arg *args;
} grpc_channel_args;
/* Channel argument keys: */
/** Enable census for tracing and stats collection */
/** \defgroup grpc_arg_keys
* Channel argument keys.
* \{
*/
/** If non-zero, enable census for tracing and stats collection. */
#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
/** Enable load reporting */
/** If non-zero, enable load reporting. */
#define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting"
/** Maximum number of concurrent incoming streams to allow on a http2
connection */
connection. Int valued. */
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
/** Maximum message length that the channel can receive */
/** Maximum message length that the channel can receive. Int valued, bytes. */
#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
/** Initial sequence number for http2 transports */
/** Initial sequence number for http2 transports. Int valued. */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Amount to read ahead on individual streams. Defaults to 64kb, larger
values can help throughput on high-latency connections.
NOTE: at some point we'd like to auto-tune this, and this parameter
will become a no-op. */
will become a no-op. Int valued, bytes. */
#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
/** How much memory to use for hpack decoding */
/** How much memory to use for hpack decoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
"grpc.http2.hpack_table_size.decoder"
/** How much memory to use for hpack encoding */
/** How much memory to use for hpack encoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
"grpc.http2.hpack_table_size.encoder"
/** Default authority to pass if none specified on call construction */
/** Default authority to pass if none specified on call construction. A string.
* */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
/** Primary user agent: goes at the start of the user-agent metadata
sent on each request */
sent on each request. A string. */
#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
/** Secondary user agent: goes at the end of the user-agent metadata
sent on each request */
sent on each request. A string. */
#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
/** The maximum time between subsequent connection attempts, in ms */
#define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
/* The caller of the secure_channel_create functions may override the target
name used for SSL host name checking using this channel argument which is of
type GRPC_ARG_STRING. This *should* be used for testing only.
type \a GRPC_ARG_STRING. This *should* be used for testing only.
If this argument is not specified, the name used for SSL host name checking
will be the target parameter (assuming that the secure channel is an SSL
channel). If this parameter is specified and the underlying is not an SSL
channel, it will just be ignored. */
#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
/* Maximum metadata size */
/* Maximum metadata size, in bytes. */
#define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK.

@ -119,7 +119,7 @@
// libraries; it should be integrated with the `__linux__` definitions below.
#define GPR_PLATFORM_STRING "manylinux"
#define GPR_POSIX_CRASH_HANDLER 1
#define GPR_CPU_LINUX 1
#define GPR_CPU_POSIX 1
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#define GPR_LINUX 1

@ -1,5 +1,15 @@
framework module grpc {
umbrella header "grpc.h"
header "byte_buffer_reader.h"
header "grpc_security.h"
header "grpc_security_constants.h"
header "impl/codegen/alloc.h"
header "impl/codegen/byte_buffer_reader.h"
header "support/alloc.h"
header "support/port_platform.h"
header "support/string_util.h"
export *
module * { export * }
}

@ -10,7 +10,7 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
<date>2016-07-13</date>
<date>2016-07-28</date>
<time>16:06:07</time>
<version>
<release>1.0.0</release>
@ -22,8 +22,7 @@
</stability>
<license>BSD</license>
<notes>
- GA release
- Fix shutdown hang problem #4017
- PHP7 Support continued, reduce code duplication #7543
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@ -47,6 +46,7 @@
<file baseinstalldir="/" name="src/php/ext/grpc/channel.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/channel_credentials.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/completion_queue.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/php7_wrapper.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/php_grpc.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/server.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
@ -1087,8 +1087,8 @@ Update to wrap gRPC C Core version 0.10.0
</release>
<release>
<version>
<release>1.0.0</release>
<api>1.0.0</api>
<release>1.0.0RC1</release>
<api>1.0.0RC1</api>
</version>
<stability>
<release>stable</release>
@ -1101,5 +1101,35 @@ Update to wrap gRPC C Core version 0.10.0
- Fix shutdown hang problem #4017
</notes>
</release>
<release>
<version>
<release>1.0.0RC2</release>
<api>1.0.0RC2</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2016-07-21</date>
<license>BSD</license>
<notes>
- PHP7 Support #7464
</notes>
</release>
<release>
<version>
<release>1.0.0RC3</release>
<api>1.0.0RC3</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2016-07-28</date>
<license>BSD</license>
<notes>
- PHP7 Support continued, reduce code duplication #7543
</notes>
</release>
</changelog>
</package>

@ -9,5 +9,5 @@ build_base=python_build
[build_ext]
inplace=1
[build_proto_modules]
[build_package_protos]
exclude=.*protoc_plugin/protoc_plugin_test\.proto$

@ -30,10 +30,12 @@
"""A setup module for the GRPC Python package."""
from distutils import extension as _extension
from distutils import util
import os
import os.path
import pkg_resources
import platform
import re
import shlex
import shutil
import sys
@ -133,6 +135,10 @@ if 'darwin' in sys.platform and PY3:
if mac_target and (pkg_resources.parse_version(mac_target) <
pkg_resources.parse_version('10.7.0')):
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
r'macosx-[0-9]+\.[0-9]+-(.+)',
r'macosx-10.7-\1',
util.get_platform())
def cython_extensions(module_names, extra_sources, include_dirs,

@ -48,7 +48,7 @@ inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
file->name().find_last_of(".proto") == file->name().size() - 1) {
*file_name_or_error =
file->name().substr(0, file->name().size() - proto_suffix_length) +
"_services.rb";
"_services_pb.rb";
return true;
} else {
*file_name_or_error = "Invalid proto file name: must end with .proto";
@ -58,7 +58,7 @@ inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
inline grpc::string MessagesRequireName(
const grpc::protobuf::FileDescriptor *file) {
return Replace(file->name(), ".proto", "");
return Replace(file->name(), ".proto", "_pb");
}
// Get leading or trailing comments in a string. Comment lines start with "# ".

@ -91,11 +91,13 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
connector *c = arg;
grpc_closure *notify;
gpr_mu_lock(&c->mu);
grpc_error *error = GRPC_ERROR_NONE;
if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result));
gpr_mu_unlock(&c->mu);
} else if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
error = grpc_error_set_int(GRPC_ERROR_CREATE("Secure handshake failed"),
GRPC_ERROR_INT_SECURITY_STATUS, status);
memset(c->result, 0, sizeof(*c->result));
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
@ -113,7 +115,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
}
notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,

@ -36,11 +36,14 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/metadata.h"
extern int grpc_http_write_state_trace;
void grpc_chttp2_plugin_init(void) {
grpc_chttp2_base64_encode_and_huffman_compress =
grpc_chttp2_base64_encode_and_huffman_compress_impl;
grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("flowctl", &grpc_flowctl_trace);
grpc_register_tracer("http_write_state", &grpc_http_write_state_trace);
}
void grpc_chttp2_plugin_shutdown(void) {}

@ -48,6 +48,7 @@
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
@ -60,9 +61,9 @@
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define MAX_CLIENT_STREAM_ID 0x7fffffffu
int grpc_http_trace = 0;
int grpc_flowctl_trace = 0;
int grpc_http_write_state_trace = 0;
#define TRANSPORT_FROM_WRITING(tw) \
((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
@ -88,10 +89,16 @@ static const grpc_transport_vtable vtable;
static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void initiate_writing(grpc_exec_ctx *exec_ctx, void *t,
grpc_error *error);
static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_error *error);
/** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value);
static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_setting_id id, uint32_t value);
/** Start disconnection chain */
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@ -137,7 +144,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global,
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
size_t have_already);
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
@ -201,6 +208,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
gpr_free(t);
}
/*#define REFCOUNTING_DEBUG 1*/
#ifdef REFCOUNTING_DEBUG
#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
@ -231,7 +239,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
const grpc_channel_args *channel_args,
grpc_endpoint *ep, uint8_t is_client) {
grpc_endpoint *ep, bool is_client) {
size_t i;
int j;
@ -273,6 +281,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->writing_action, writing_action, t);
grpc_closure_init(&t->reading_action, reading_action, t);
grpc_closure_init(&t->parsing_action, parsing_action, t);
grpc_closure_init(&t->initiate_writing, initiate_writing, t);
gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
@ -286,6 +295,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_slice_buffer_add(
&t->global.qbuf,
gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write");
}
/* 8 is a random stab in the dark as to a good initial size: it's small enough
that it shouldn't waste memory for infrequently used connections, yet
@ -311,11 +321,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* configure http2 the way we like it */
if (is_client) {
push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
}
push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
DEFAULT_WINDOW);
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
DEFAULT_MAX_HEADER_LIST_SIZE);
if (channel_args) {
@ -329,7 +340,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be an integer",
GRPC_ARG_MAX_CONCURRENT_STREAMS);
} else {
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
(uint32_t)channel_args->args[i].value.integer);
}
} else if (0 == strcmp(channel_args->args[i].key,
@ -368,7 +379,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be non-negative",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
} else {
push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
(uint32_t)channel_args->args[i].value.integer);
}
} else if (0 == strcmp(channel_args->args[i].key,
@ -393,7 +404,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be non-negative",
GRPC_ARG_MAX_METADATA_SIZE);
} else {
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
(uint32_t)channel_args->args[i].value.integer);
}
}
@ -444,6 +455,9 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_error *error) {
if (!t->closed) {
if (grpc_http_write_state_trace) {
gpr_log(GPR_DEBUG, "W:%p close transport", t);
}
t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(error), "close_transport");
@ -590,7 +604,8 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_metadata_buffer_destroy(
&s->global.received_trailing_metadata);
gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
GRPC_ERROR_UNREF(s->global.removal_error);
GRPC_ERROR_UNREF(s->global.read_closed_error);
GRPC_ERROR_UNREF(s->global.write_closed_error);
UNREF_TRANSPORT(exec_ctx, t, "stream");
@ -634,6 +649,36 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
* LOCK MANAGEMENT
*/
static const char *write_state_name(grpc_chttp2_write_state state) {
switch (state) {
case GRPC_CHTTP2_WRITING_INACTIVE:
return "INACTIVE";
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
return "REQUESTED[p=0]";
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
return "REQUESTED[p=1]";
case GRPC_CHTTP2_WRITE_SCHEDULED:
return "SCHEDULED";
case GRPC_CHTTP2_WRITING:
return "WRITING";
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
return "WRITING[p=1]";
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
return "WRITING[p=0]";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
static void set_write_state(grpc_chttp2_transport *t,
grpc_chttp2_write_state state, const char *reason) {
if (grpc_http_write_state_trace) {
gpr_log(GPR_DEBUG, "W:%p %s -> %s because %s", t,
write_state_name(t->executor.write_state), write_state_name(state),
reason);
}
t->executor.write_state = state;
}
static void finish_global_actions(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
grpc_chttp2_executor_action_header *hdr;
@ -642,13 +687,6 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
GPR_TIMER_BEGIN("finish_global_actions", 0);
for (;;) {
if (!t->executor.writing_active && !t->closed &&
grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
t->executor.writing_active = 1;
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
}
check_read_ops(exec_ctx, &t->global);
gpr_mu_lock(&t->executor.mu);
@ -669,8 +707,28 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
continue;
} else {
t->executor.global_active = false;
switch (t->executor.write_state) {
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking");
REF_TRANSPORT(t, "initiate_writing");
gpr_mu_unlock(&t->executor.mu);
grpc_exec_ctx_sched(
exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE,
t->ep != NULL ? grpc_endpoint_get_workqueue(t->ep) : NULL);
break;
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
start_writing(exec_ctx, t);
gpr_mu_unlock(&t->executor.mu);
break;
case GRPC_CHTTP2_WRITING_INACTIVE:
case GRPC_CHTTP2_WRITING:
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
case GRPC_CHTTP2_WRITE_SCHEDULED:
gpr_mu_unlock(&t->executor.mu);
break;
}
}
gpr_mu_unlock(&t->executor.mu);
break;
}
@ -741,16 +799,118 @@ void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
* OUTPUT PROCESSING
*/
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
bool covered_by_poller, const char *reason) {
/* Perform state checks, and transition to a scheduled state if appropriate.
Each time we finish the global lock execution, we check if we need to
write. If we do:
- (if there is a poller surrounding the write) schedule
initiate_writing, which locks and calls initiate_writing_locked to...
- call start_writing, which verifies (under the global lock) that there
are things that need to be written by calling
grpc_chttp2_unlocking_check_writes, and if so schedules writing_action
against the current exec_ctx, to be executed OUTSIDE of the global lock
- eventually writing_action results in grpc_chttp2_terminate_writing being
called, which re-takes the global lock, updates state, checks if we need
to do *another* write immediately, and if so loops back to
start_writing.
Current problems:
- too much lock entry/exiting
- the writing thread can become stuck indefinitely (punt through the
workqueue periodically to fix) */
grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
switch (t->executor.write_state) {
case GRPC_CHTTP2_WRITING_INACTIVE:
set_write_state(t, covered_by_poller
? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER
: GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
reason);
break;
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
/* nothing to do: write already requested */
break;
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
if (covered_by_poller) {
/* upgrade to note poller is available to cover the write */
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason);
}
break;
case GRPC_CHTTP2_WRITE_SCHEDULED:
/* nothing to do: write already scheduled */
break;
case GRPC_CHTTP2_WRITING:
set_write_state(t,
covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER
: GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
reason);
break;
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
/* nothing to do: write already requested */
break;
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
if (covered_by_poller) {
/* upgrade to note poller is available to cover the write */
set_write_state(t, GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, reason);
}
break;
}
}
static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED ||
t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER);
if (!t->closed &&
grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing");
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
} else {
if (t->closed) {
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
"start_writing:transport_closed");
} else {
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
"start_writing:nothing_to_write");
}
end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write"));
if (t->ep && !t->endpoint_reading) {
destroy_endpoint(exec_ctx, t);
}
}
}
static void initiate_writing_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused,
void *arg_ignored) {
start_writing(exec_ctx, t);
UNREF_TRANSPORT(exec_ctx, t, "initiate_writing");
}
static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked,
NULL, 0);
}
void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
bool covered_by_poller, const char *reason) {
if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
grpc_chttp2_initiate_write(exec_ctx, transport_global, covered_by_poller,
reason);
}
}
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value) {
static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_setting_id id, uint32_t value) {
const grpc_chttp2_setting_parameters *sp =
&grpc_chttp2_settings_parameters[id];
uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
@ -761,9 +921,22 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
t->global.dirtied_local_settings = 1;
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "push_setting");
}
}
static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_error *error) {
grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
fail_pending_writes(exec_ctx, &t->global, stream_global,
GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
}
GRPC_ERROR_UNREF(error);
}
static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored,
@ -778,24 +951,32 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
fail_pending_writes(exec_ctx, &t->global, stream_global,
GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
end_waiting_for_write(exec_ctx, t, error);
switch (t->executor.write_state) {
case GRPC_CHTTP2_WRITING_INACTIVE:
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
case GRPC_CHTTP2_WRITE_SCHEDULED:
GPR_UNREACHABLE_CODE(break);
case GRPC_CHTTP2_WRITING:
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing");
break;
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
"terminate_writing");
break;
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
"terminate_writing");
break;
}
/* leave the writing flag up on shutdown to prevent further writes in
unlock()
from starting */
t->executor.writing_active = 0;
if (t->ep && !t->endpoint_reading) {
destroy_endpoint(exec_ctx, t);
}
UNREF_TRANSPORT(exec_ctx, t, "writing");
GRPC_ERROR_UNREF(error);
}
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
@ -878,7 +1059,8 @@ static void maybe_start_some_streams(
stream_global->id, STREAM_FROM_GLOBAL(stream_global));
stream_global->in_stream_map = true;
transport_global->concurrent_stream_count++;
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, true,
"new_stream");
}
/* cancel out streams that will never be started */
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@ -1018,9 +1200,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
maybe_start_some_streams(exec_ctx, transport_global);
} else {
GPR_ASSERT(stream_global->id != 0);
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_initial_metadata");
}
} else {
stream_global->send_trailing_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished,
@ -1042,7 +1226,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} else {
stream_global->send_message = op->send_message;
if (stream_global->id != 0) {
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_message");
}
}
}
@ -1075,6 +1260,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
if (stream_global->write_closed) {
stream_global->send_trailing_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished,
@ -1085,7 +1271,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_trailing_metadata");
}
}
}
@ -1106,8 +1293,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
(stream_global->incoming_frames.head == NULL ||
stream_global->incoming_frames.head->is_tail)) {
incoming_byte_stream_update_flow_control(
transport_global, stream_global, transport_global->stream_lookahead,
0);
exec_ctx, transport_global, stream_global,
transport_global->stream_lookahead, 0);
}
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
@ -1135,7 +1322,8 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
sizeof(*op));
}
static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure *on_recv) {
grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
p->next = &t->global.pings;
p->prev = p->next->prev;
@ -1150,6 +1338,7 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
p->on_recv = on_recv;
gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping");
}
static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@ -1209,6 +1398,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
close_transport = grpc_chttp2_has_streams(t)
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("GOAWAY sent");
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "goaway_sent");
}
if (op->set_accept_stream) {
@ -1226,7 +1416,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
}
if (op->send_ping) {
send_ping_locked(t, op->send_ping);
send_ping_locked(exec_ctx, t, op->send_ping);
}
if (close_transport != GRPC_ERROR_NONE) {
@ -1414,6 +1604,8 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
&transport_global->qbuf,
grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error,
&stream_global->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"rst_stream");
}
const char *msg =
@ -1473,10 +1665,39 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
}
}
static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
if (error == GRPC_ERROR_NONE) return;
for (size_t i = 0; i < *nrefs; i++) {
if (error == refs[i]) {
return;
}
}
refs[*nrefs] = error;
++*nrefs;
}
static grpc_error *removal_error(grpc_error *extra_error,
grpc_chttp2_stream_global *stream_global) {
grpc_error *refs[3];
size_t nrefs = 0;
add_error(stream_global->read_closed_error, refs, &nrefs);
add_error(stream_global->write_closed_error, refs, &nrefs);
add_error(extra_error, refs, &nrefs);
grpc_error *error = GRPC_ERROR_NONE;
if (nrefs > 0) {
error = GRPC_ERROR_CREATE_REFERENCING("Failed due to stream removal", refs,
nrefs);
}
GRPC_ERROR_UNREF(extra_error);
return error;
}
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
grpc_error *error) {
error = removal_error(error, stream_global);
stream_global->send_message = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
@ -1499,14 +1720,17 @@ void grpc_chttp2_mark_stream_closed(
}
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
if (close_reads && !stream_global->read_closed) {
stream_global->read_closed_error = GRPC_ERROR_REF(error);
stream_global->read_closed = true;
stream_global->published_initial_metadata = true;
stream_global->published_trailing_metadata = true;
decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
}
if (close_writes && !stream_global->write_closed) {
stream_global->write_closed_error = GRPC_ERROR_REF(error);
stream_global->write_closed = true;
if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.writing_active) {
if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.write_state !=
GRPC_CHTTP2_WRITING_INACTIVE) {
GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global);
@ -1516,7 +1740,6 @@ void grpc_chttp2_mark_stream_closed(
}
}
if (stream_global->read_closed && stream_global->write_closed) {
stream_global->removal_error = GRPC_ERROR_REF(error);
if (stream_global->id != 0 &&
TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
@ -1524,7 +1747,8 @@ void grpc_chttp2_mark_stream_closed(
} else {
if (stream_global->id != 0) {
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
stream_global->id, GRPC_ERROR_REF(error));
stream_global->id,
removal_error(GRPC_ERROR_REF(error), stream_global));
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
@ -1649,6 +1873,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1, error);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"close_from_api");
}
typedef struct {
@ -1678,8 +1904,14 @@ static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
/** update window from a settings change */
typedef struct {
grpc_chttp2_transport *t;
grpc_exec_ctx *exec_ctx;
} update_global_window_args;
static void update_global_window(void *args, uint32_t id, void *stream) {
grpc_chttp2_transport *t = args;
update_global_window_args *a = args;
grpc_chttp2_transport *t = a->t;
grpc_chttp2_stream *s = stream;
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_stream_global *stream_global = &s->global;
@ -1693,7 +1925,8 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(a->exec_ctx, transport_global, stream_global,
true, "update_global_window");
}
}
@ -1801,14 +2034,19 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
/* copy parsing qbuf to global qbuf */
gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
if (t->parsing.qbuf.count > 0) {
gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"parsing_qbuf");
}
/* merge stream lists */
grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
transport_global->concurrent_stream_count =
(uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
if (transport_parsing->initial_window_update != 0) {
update_global_window_args args = {t, exec_ctx};
grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
update_global_window, t);
update_global_window, &args);
transport_parsing->initial_window_update = 0;
}
/* handle higher level things */
@ -1831,7 +2069,7 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed);
remove_stream(exec_ctx, t, stream_global->id,
GRPC_ERROR_REF(stream_global->removal_error));
removal_error(GRPC_ERROR_NONE, stream_global));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
@ -1854,11 +2092,12 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
}
drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0;
if (!t->executor.writing_active && t->ep) {
grpc_endpoint_destroy(exec_ctx, t->ep);
t->ep = NULL;
/* safe as we still have a ref for read */
UNREF_TRANSPORT(exec_ctx, t, "disconnect");
if (grpc_http_write_state_trace) {
gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t,
write_state_name(t->executor.write_state));
}
if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) {
destroy_endpoint(exec_ctx, t);
}
} else if (!t->closed) {
keep_reading = true;
@ -1942,7 +2181,7 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
}
static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global,
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
size_t have_already) {
uint32_t max_recv_bytes;
@ -1977,7 +2216,8 @@ static void incoming_byte_stream_update_flow_control(
add_max_recv_bytes);
grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
stream_global);
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "read_incoming_stream");
}
}
@ -1999,8 +2239,9 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global = &bs->stream->global;
if (bs->is_tail) {
incoming_byte_stream_update_flow_control(
transport_global, stream_global, arg->max_size_hint, bs->slices.length);
incoming_byte_stream_update_flow_control(exec_ctx, transport_global,
stream_global, arg->max_size_hint,
bs->slices.length);
}
if (bs->slices.count > 0) {
*arg->slice = gpr_slice_buffer_take_first(&bs->slices);
@ -2184,7 +2425,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
if (context == NULL) {
*scope = NULL;
gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
result = gpr_leftpad(buf, ' ', 40);
result = gpr_leftpad(buf, ' ', 60);
gpr_free(buf);
return result;
}
@ -2197,7 +2438,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
gpr_free(tmp);
}
gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
result = gpr_leftpad(buf, ' ', 40);
result = gpr_leftpad(buf, ' ', 60);
gpr_free(buf);
return result;
}
@ -2230,7 +2471,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
tmp_phase = gpr_leftpad(phase, ' ', 8);
tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1);
gpr_asprintf(&prefix, "FLOW %s: %s %s ", tmp_phase, clisvr, scope1);
gpr_free(tmp_phase);
gpr_free(tmp_scope1);

@ -305,6 +305,22 @@ typedef struct grpc_chttp2_executor_action_header {
void *arg;
} grpc_chttp2_executor_action_header;
typedef enum {
/** no writing activity */
GRPC_CHTTP2_WRITING_INACTIVE,
/** write has been requested, but not scheduled yet */
GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
/** write has been requested and scheduled against the workqueue */
GRPC_CHTTP2_WRITE_SCHEDULED,
/** write has been initiated after being reaped from the workqueue */
GRPC_CHTTP2_WRITING,
/** write has been initiated, AND another write needs to be started once it's
done */
GRPC_CHTTP2_WRITING_STALE_WITH_POLLER,
GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
} grpc_chttp2_write_state;
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
gpr_refcount refs;
@ -319,10 +335,10 @@ struct grpc_chttp2_transport {
/** is a thread currently in the global lock */
bool global_active;
/** is a thread currently writing */
bool writing_active;
/** is a thread currently parsing */
bool parsing_active;
/** write execution state of the transport */
grpc_chttp2_write_state write_state;
grpc_chttp2_executor_action_header *pending_actions_head;
grpc_chttp2_executor_action_header *pending_actions_tail;
@ -342,7 +358,8 @@ struct grpc_chttp2_transport {
/** global state for reading/writing */
grpc_chttp2_transport_global global;
/** state only accessible by the chain of execution that
set writing_active=1 */
set writing_state >= GRPC_WRITING, and only by the writing closure
chain. */
grpc_chttp2_transport_writing writing;
/** state only accessible by the chain of execution that
set parsing_active=1 */
@ -363,6 +380,8 @@ struct grpc_chttp2_transport {
grpc_closure reading_action;
/** closure to actually do parsing */
grpc_closure parsing_action;
/** closure to initiate writing */
grpc_closure initiate_writing;
/** incoming read bytes */
gpr_slice_buffer read_buffer;
@ -436,8 +455,10 @@ typedef struct {
bool seen_error;
bool exceeded_metadata_size;
/** the error that resulted in this stream being removed */
grpc_error *removal_error;
/** the error that resulted in this stream being read-closed */
grpc_error *read_closed_error;
/** the error that resulted in this stream being write-closed */
grpc_error *write_closed_error;
bool published_initial_metadata;
bool published_trailing_metadata;
@ -514,15 +535,20 @@ struct grpc_chttp2_stream {
};
/** Transport writing call flow:
chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes
are required;
if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the
writes.
Once writes have been completed (meaning another write could potentially be
started),
grpc_chttp2_terminate_writing is called. This will call
grpc_chttp2_cleanup_writing, at which
point the write phase is complete. */
grpc_chttp2_initiate_write() is called anywhere that we know bytes need to
go out on the wire.
If no other write has been started, a task is enqueued onto our workqueue.
When that task executes, it obtains the global lock, and gathers the data
to write.
The global lock is dropped and we do the syscall to write.
After writing, a follow-up check is made to see if another round of writing
should be performed.
The actual call chain is documented in the implementation of this function.
*/
void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
bool covered_by_poller, const char *reason);
/** Someone is unlocking the transport mutex: check to see if writes
are required, and schedule them if so */
@ -610,9 +636,8 @@ int grpc_chttp2_list_pop_check_read_ops(
void grpc_chttp2_list_add_writing_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing);
void grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
bool is_window_available);
bool grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing);
void grpc_chttp2_list_add_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing,
@ -822,7 +847,9 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
/** add a ref to the stream and add it to the writable list;
ref will be dropped in writing.c */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
bool covered_by_poller, const char *reason);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -154,10 +154,8 @@ void grpc_chttp2_publish_reads(
transport_parsing, outgoing_window);
is_zero = transport_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
&stream_global)) {
grpc_chttp2_become_writable(transport_global, stream_global);
}
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"new_global_flow_control");
}
if (transport_parsing->incoming_window <
@ -168,6 +166,8 @@ void grpc_chttp2_publish_reads(
announce_incoming_window, announce_bytes);
GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
incoming_window, announce_bytes);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"global incoming window");
}
/* for each stream that saw an update, fixup global state */
@ -190,7 +190,8 @@ void grpc_chttp2_publish_reads(
outgoing_window);
is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_become_writable(transport_global, stream_global);
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "stream.read_flow_control");
}
stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(

@ -329,6 +329,7 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) {
grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
gpr_log(GPR_DEBUG, "writing stalled %d", stream->global.id);
if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
}
@ -336,27 +337,28 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
}
void grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
bool is_window_available) {
bool grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing) {
grpc_chttp2_stream *stream;
bool out = false;
grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
while (stream_list_pop(transport, &stream,
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
if (is_window_available) {
grpc_chttp2_become_writable(&transport->global, &stream->global);
} else {
grpc_chttp2_list_add_stalled_by_transport(transport_writing,
&stream->writing);
}
gpr_log(GPR_DEBUG, "move %d from writing stalled to just stalled",
stream->global.id);
grpc_chttp2_list_add_stalled_by_transport(transport_writing,
&stream->writing);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
"chttp2_writing_stalled");
out = true;
}
return out;
}
void grpc_chttp2_list_add_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) {
gpr_log(GPR_DEBUG, "stalled %d", stream_writing->id);
stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
STREAM_FROM_WRITING(stream_writing),
GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);

@ -75,9 +75,13 @@ int grpc_chttp2_unlocking_check_writes(
GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
transport_global, outgoing_window);
bool is_window_available = transport_writing->outgoing_window > 0;
grpc_chttp2_list_flush_writing_stalled_by_transport(
exec_ctx, transport_writing, is_window_available);
if (transport_writing->outgoing_window > 0) {
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
&stream_global)) {
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "transport.read_flow_control");
}
}
/* for each grpc_chttp2_stream that's become writable, frame it's data
(according to available window sizes) and add to the output buffer */
@ -331,6 +335,12 @@ void grpc_chttp2_cleanup_writing(
grpc_chttp2_stream_writing *stream_writing;
grpc_chttp2_stream_global *stream_global;
if (grpc_chttp2_list_flush_writing_stalled_by_transport(exec_ctx,
transport_writing)) {
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"resume_stalled_stream");
}
while (grpc_chttp2_list_pop_written_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_writing->sent_initial_metadata) {

@ -65,3 +65,7 @@ void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
return ep->vtable->get_peer(ep);
}
grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) {
return ep->vtable->get_workqueue(ep);
}

@ -51,6 +51,7 @@ struct grpc_endpoint_vtable {
gpr_slice_buffer *slices, grpc_closure *cb);
void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer *slices, grpc_closure *cb);
grpc_workqueue *(*get_workqueue)(grpc_endpoint *ep);
void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@ -69,6 +70,9 @@ void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
char *grpc_endpoint_get_peer(grpc_endpoint *ep);
/* Retrieve a reference to the workqueue associated with this endpoint */
grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep);
/* Write slices out to the socket.
If the connection is ready for more data after the end of the call, it

@ -57,6 +57,7 @@
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/block_annotate.h"
@ -113,9 +114,7 @@ struct grpc_fd {
grpc_closure *read_closure;
grpc_closure *write_closure;
/* The polling island to which this fd belongs to and the mutex protecting the
the field */
gpr_mu pi_mu;
/* The polling island to which this fd belongs to (protected by mu) */
struct polling_island *polling_island;
struct grpc_fd *freelist_next;
@ -152,16 +151,17 @@ static void fd_global_shutdown(void);
* Polling island Declarations
*/
// #define GRPC_PI_REF_COUNT_DEBUG
//#define GRPC_PI_REF_COUNT_DEBUG
#ifdef GRPC_PI_REF_COUNT_DEBUG
#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__)
#define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__)
#define PI_UNREF(exec_ctx, p, r) \
pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__)
#else /* defined(GRPC_PI_REF_COUNT_DEBUG) */
#define PI_ADD_REF(p, r) pi_add_ref((p))
#define PI_UNREF(p, r) pi_unref((p))
#define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p))
#endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */
@ -172,7 +172,7 @@ typedef struct polling_island {
Once the ref count becomes zero, this structure is destroyed which means
we should ensure that there is never a scenario where a PI_ADD_REF() is
racing with a PI_UNREF() that just made the ref_count zero. */
gpr_refcount ref_count;
gpr_atm ref_count;
/* Pointer to the polling_island this merged into.
* merged_to value is only set once in polling_island's lifetime (and that too
@ -184,6 +184,9 @@ typedef struct polling_island {
* (except mu and ref_count) are invalid and must be ignored. */
gpr_atm merged_to;
/* The workqueue associated with this polling island */
grpc_workqueue *workqueue;
/* The fd of the underlying epoll set */
int epoll_fd;
@ -191,11 +194,6 @@ typedef struct polling_island {
size_t fd_cnt;
size_t fd_capacity;
grpc_fd **fds;
/* Polling islands that are no longer needed are kept in a freelist so that
they can be reused. This field points to the next polling island in the
free list */
struct polling_island *next_free;
} polling_island;
/*******************************************************************************
@ -253,13 +251,14 @@ struct grpc_pollset_set {
* Common helpers
*/
static void append_error(grpc_error **composite, grpc_error *error,
static bool append_error(grpc_error **composite, grpc_error *error,
const char *desc) {
if (error == GRPC_ERROR_NONE) return;
if (error == GRPC_ERROR_NONE) return true;
if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE(desc);
}
*composite = grpc_error_add_child(*composite, error);
return false;
}
/*******************************************************************************
@ -275,11 +274,8 @@ static void append_error(grpc_error **composite, grpc_error *error,
threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */
static grpc_wakeup_fd polling_island_wakeup_fd;
/* Polling island freelist */
static gpr_mu g_pi_freelist_mu;
static polling_island *g_pi_freelist = NULL;
static void polling_island_delete(); /* Forward declaration */
/* Forward declaration */
static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi);
#ifdef GRPC_TSAN
/* Currently TSAN may incorrectly flag data races between epoll_ctl and
@ -293,28 +289,35 @@ gpr_atm g_epoll_sync;
#endif /* defined(GRPC_TSAN) */
#ifdef GRPC_PI_REF_COUNT_DEBUG
void pi_add_ref(polling_island *pi);
void pi_unref(polling_island *pi);
static void pi_add_ref(polling_island *pi);
static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi);
void pi_add_ref_dbg(polling_island *pi, char *reason, char *file, int line) {
long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count));
static void pi_add_ref_dbg(polling_island *pi, char *reason, char *file,
int line) {
long old_cnt = gpr_atm_acq_load(&pi->ref_count);
pi_add_ref(pi);
gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)",
(void *)pi, old_cnt, old_cnt + 1, reason, file, line);
}
void pi_unref_dbg(polling_island *pi, char *reason, char *file, int line) {
long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count));
pi_unref(pi);
static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi,
char *reason, char *file, int line) {
long old_cnt = gpr_atm_acq_load(&pi->ref_count);
pi_unref(exec_ctx, pi);
gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)",
(void *)pi, old_cnt, (old_cnt - 1), reason, file, line);
}
#endif
void pi_add_ref(polling_island *pi) { gpr_ref(&pi->ref_count); }
static void pi_add_ref(polling_island *pi) {
gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1);
}
void pi_unref(polling_island *pi) {
/* If ref count went to zero, delete the polling island.
static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) {
/* If ref count went to one, we're back to just the workqueue owning a ref.
Unref the workqueue to break the loop.
If ref count went to zero, delete the polling island.
Note that this deletion not be done under a lock. Once the ref count goes
to zero, we are guaranteed that no one else holds a reference to the
polling island (and that there is no racing pi_add_ref() call either).
@ -322,12 +325,20 @@ void pi_unref(polling_island *pi) {
Also, if we are deleting the polling island and the merged_to field is
non-empty, we should remove a ref to the merged_to polling island
*/
if (gpr_unref(&pi->ref_count)) {
polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to);
polling_island_delete(pi);
if (next != NULL) {
PI_UNREF(next, "pi_delete"); /* Recursive call */
switch (gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
case 2: /* last external ref: the only one now owned is by the workqueue */
GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
break;
case 1: {
polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to);
polling_island_delete(exec_ctx, pi);
if (next != NULL) {
PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */
}
break;
}
case 0:
GPR_UNREACHABLE_CODE(return );
}
}
@ -462,69 +473,68 @@ static void polling_island_remove_fd_locked(polling_island *pi, grpc_fd *fd,
}
/* Might return NULL in case of an error */
static polling_island *polling_island_create(grpc_fd *initial_fd,
static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx,
grpc_fd *initial_fd,
grpc_error **error) {
polling_island *pi = NULL;
char *err_msg;
const char *err_desc = "polling_island_create";
/* Try to get one from the polling island freelist */
gpr_mu_lock(&g_pi_freelist_mu);
if (g_pi_freelist != NULL) {
pi = g_pi_freelist;
g_pi_freelist = g_pi_freelist->next_free;
pi->next_free = NULL;
}
gpr_mu_unlock(&g_pi_freelist_mu);
*error = GRPC_ERROR_NONE;
/* Create new polling island if we could not get one from the free list */
if (pi == NULL) {
pi = gpr_malloc(sizeof(*pi));
gpr_mu_init(&pi->mu);
pi->fd_cnt = 0;
pi->fd_capacity = 0;
pi->fds = NULL;
}
pi = gpr_malloc(sizeof(*pi));
gpr_mu_init(&pi->mu);
pi->fd_cnt = 0;
pi->fd_capacity = 0;
pi->fds = NULL;
pi->epoll_fd = -1;
pi->workqueue = NULL;
gpr_ref_init(&pi->ref_count, 0);
gpr_atm_rel_store(&pi->ref_count, 0);
gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL);
pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (pi->epoll_fd < 0) {
gpr_asprintf(&err_msg, "epoll_create1 failed with error %d (%s)", errno,
strerror(errno));
append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
gpr_free(err_msg);
} else {
polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
pi->next_free = NULL;
append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc);
goto done;
}
if (initial_fd != NULL) {
/* Lock the polling island here just in case we got this structure from
the freelist and the polling island lock was not released yet (by the
code that adds the polling island to the freelist) */
gpr_mu_lock(&pi->mu);
polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
gpr_mu_unlock(&pi->mu);
}
polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
if (initial_fd != NULL) {
polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
}
if (append_error(error, grpc_workqueue_create(exec_ctx, &pi->workqueue),
err_desc) &&
*error == GRPC_ERROR_NONE) {
polling_island_add_fds_locked(pi, &pi->workqueue->wakeup_read_fd, 1, true,
error);
GPR_ASSERT(pi->workqueue->wakeup_read_fd->polling_island == NULL);
pi->workqueue->wakeup_read_fd->polling_island = pi;
PI_ADD_REF(pi, "fd");
}
done:
if (*error != GRPC_ERROR_NONE) {
if (pi->workqueue != NULL) {
GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
}
polling_island_delete(exec_ctx, pi);
pi = NULL;
}
return pi;
}
static void polling_island_delete(polling_island *pi) {
static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) {
GPR_ASSERT(pi->fd_cnt == 0);
gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL);
close(pi->epoll_fd);
pi->epoll_fd = -1;
gpr_mu_lock(&g_pi_freelist_mu);
pi->next_free = g_pi_freelist;
g_pi_freelist = pi;
gpr_mu_unlock(&g_pi_freelist_mu);
if (pi->epoll_fd >= 0) {
close(pi->epoll_fd);
}
gpr_mu_destroy(&pi->mu);
gpr_free(pi->fds);
gpr_free(pi);
}
/* Attempts to gets the last polling island in the linked list (liked by the
@ -704,9 +714,6 @@ static polling_island *polling_island_merge(polling_island *p,
static grpc_error *polling_island_global_init() {
grpc_error *error = GRPC_ERROR_NONE;
gpr_mu_init(&g_pi_freelist_mu);
g_pi_freelist = NULL;
error = grpc_wakeup_fd_init(&polling_island_wakeup_fd);
if (error == GRPC_ERROR_NONE) {
error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd);
@ -716,18 +723,6 @@ static grpc_error *polling_island_global_init() {
}
static void polling_island_global_shutdown() {
polling_island *next;
gpr_mu_lock(&g_pi_freelist_mu);
gpr_mu_unlock(&g_pi_freelist_mu);
while (g_pi_freelist != NULL) {
next = g_pi_freelist->next_free;
gpr_mu_destroy(&g_pi_freelist->mu);
gpr_free(g_pi_freelist->fds);
gpr_free(g_pi_freelist);
g_pi_freelist = next;
}
gpr_mu_destroy(&g_pi_freelist_mu);
grpc_wakeup_fd_destroy(&polling_island_wakeup_fd);
}
@ -845,7 +840,6 @@ static grpc_fd *fd_create(int fd, const char *name) {
if (new_fd == NULL) {
new_fd = gpr_malloc(sizeof(grpc_fd));
gpr_mu_init(&new_fd->mu);
gpr_mu_init(&new_fd->pi_mu);
}
/* Note: It is not really needed to get the new_fd->mu lock here. If this is a
@ -896,6 +890,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
const char *reason) {
bool is_fd_closed = false;
grpc_error *error = GRPC_ERROR_NONE;
polling_island *unref_pi = NULL;
gpr_mu_lock(&fd->mu);
fd->on_done_closure = on_done;
@ -923,21 +918,26 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- Unlock the latest polling island
- Set fd->polling_island to NULL (but remove the ref on the polling island
before doing this.) */
gpr_mu_lock(&fd->pi_mu);
if (fd->polling_island != NULL) {
polling_island *pi_latest = polling_island_lock(fd->polling_island);
polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error);
gpr_mu_unlock(&pi_latest->mu);
PI_UNREF(fd->polling_island, "fd_orphan");
unref_pi = fd->polling_island;
fd->polling_island = NULL;
}
gpr_mu_unlock(&fd->pi_mu);
grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, error, NULL);
gpr_mu_unlock(&fd->mu);
UNREF_BY(fd, 2, reason); /* Drop the reference */
if (unref_pi != NULL) {
/* Unref stale polling island here, outside the fd lock above.
The polling island owns a workqueue which owns an fd, and unreffing
inside the lock can cause an eventual lock loop that makes TSAN very
unhappy. */
PI_UNREF(exec_ctx, unref_pi, "fd_orphan");
}
GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error));
}
@ -1037,6 +1037,17 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
gpr_mu_unlock(&fd->mu);
}
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
grpc_workqueue *workqueue = NULL;
if (fd->polling_island != NULL) {
workqueue =
GRPC_WORKQUEUE_REF(fd->polling_island->workqueue, "get_workqueue");
}
gpr_mu_unlock(&fd->mu);
return workqueue;
}
/*******************************************************************************
* Pollset Definitions
*/
@ -1227,9 +1238,10 @@ static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_unlock(&fd->mu);
}
static void pollset_release_polling_island(grpc_pollset *ps, char *reason) {
static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx,
grpc_pollset *ps, char *reason) {
if (ps->polling_island != NULL) {
PI_UNREF(ps->polling_island, reason);
PI_UNREF(exec_ctx, ps->polling_island, reason);
}
ps->polling_island = NULL;
}
@ -1242,7 +1254,7 @@ static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
pollset->finish_shutdown_called = true;
/* Release the ref and set pollset->polling_island to NULL */
pollset_release_polling_island(pollset, "ps_shutdown");
pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown");
grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
}
@ -1281,7 +1293,7 @@ static void pollset_reset(grpc_pollset *pollset) {
pollset->finish_shutdown_called = false;
pollset->kicked_without_pollers = false;
pollset->shutdown_done = NULL;
pollset_release_polling_island(pollset, "ps_reset");
GPR_ASSERT(pollset->polling_island == NULL);
}
#define GRPC_EPOLL_MAX_EVENTS 1000
@ -1309,7 +1321,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
this function (i.e pollset_work_and_unlock()) is called */
if (pollset->polling_island == NULL) {
pollset->polling_island = polling_island_create(NULL, error);
pollset->polling_island = polling_island_create(exec_ctx, NULL, error);
if (pollset->polling_island == NULL) {
GPR_TIMER_END("pollset_work_and_unlock", 0);
return; /* Fatal error. We cannot continue */
@ -1329,7 +1341,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
/* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
polling island to be deleted */
PI_ADD_REF(pi, "ps");
PI_UNREF(pollset->polling_island, "ps");
PI_UNREF(exec_ctx, pollset->polling_island, "ps");
pollset->polling_island = pi;
}
@ -1400,7 +1412,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
that we got before releasing the polling island lock). This is because
pollset->polling_island pointer might get udpated in other parts of the
code when there is an island merge while we are doing epoll_wait() above */
PI_UNREF(pi, "ps_work");
PI_UNREF(exec_ctx, pi, "ps_work");
GPR_TIMER_END("pollset_work_and_unlock", 0);
}
@ -1517,10 +1529,11 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_error *error = GRPC_ERROR_NONE;
gpr_mu_lock(&pollset->mu);
gpr_mu_lock(&fd->pi_mu);
gpr_mu_lock(&fd->mu);
polling_island *pi_new = NULL;
retry:
/* 1) If fd->polling_island and pollset->polling_island are both non-NULL and
* equal, do nothing.
* 2) If fd->polling_island and pollset->polling_island are both NULL, create
@ -1535,15 +1548,44 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
* polling_island fields in both fd and pollset to point to the merged
* polling island.
*/
if (fd->orphaned) {
gpr_mu_unlock(&fd->mu);
gpr_mu_unlock(&pollset->mu);
/* early out */
return;
}
if (fd->polling_island == pollset->polling_island) {
pi_new = fd->polling_island;
if (pi_new == NULL) {
pi_new = polling_island_create(fd, &error);
GRPC_POLLING_TRACE(
"pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
"pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset);
/* Unlock before creating a new polling island: the polling island will
create a workqueue which creates a file descriptor, and holding an fd
lock here can eventually cause a loop to appear to TSAN (making it
unhappy). We don't think it's a real loop (there's an epoch point where
that loop possibility disappears), but the advantages of keeping TSAN
happy outweigh any performance advantage we might have by keeping the
lock held. */
gpr_mu_unlock(&fd->mu);
pi_new = polling_island_create(exec_ctx, fd, &error);
gpr_mu_lock(&fd->mu);
/* Need to reverify any assumptions made between the initial lock and
getting to this branch: if they've changed, we need to throw away our
work and figure things out again. */
if (fd->polling_island != NULL) {
GRPC_POLLING_TRACE(
"pollset_add_fd: Raced creating new polling island. pi_new: %p "
"(fd: %d, pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset);
PI_ADD_REF(pi_new, "dance_of_destruction");
PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
goto retry;
} else {
GRPC_POLLING_TRACE(
"pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
"pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset);
}
}
} else if (fd->polling_island == NULL) {
pi_new = polling_island_lock(pollset->polling_island);
@ -1579,7 +1621,7 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (fd->polling_island != pi_new) {
PI_ADD_REF(pi_new, "fd");
if (fd->polling_island != NULL) {
PI_UNREF(fd->polling_island, "fd");
PI_UNREF(exec_ctx, fd->polling_island, "fd");
}
fd->polling_island = pi_new;
}
@ -1587,13 +1629,15 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (pollset->polling_island != pi_new) {
PI_ADD_REF(pi_new, "ps");
if (pollset->polling_island != NULL) {
PI_UNREF(pollset->polling_island, "ps");
PI_UNREF(exec_ctx, pollset->polling_island, "ps");
}
pollset->polling_island = pi_new;
}
gpr_mu_unlock(&fd->pi_mu);
gpr_mu_unlock(&fd->mu);
gpr_mu_unlock(&pollset->mu);
GRPC_LOG_IF_ERROR("pollset_add_fd", error);
}
/*******************************************************************************
@ -1744,9 +1788,9 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
void *grpc_fd_get_polling_island(grpc_fd *fd) {
polling_island *pi;
gpr_mu_lock(&fd->pi_mu);
gpr_mu_lock(&fd->mu);
pi = fd->polling_island;
gpr_mu_unlock(&fd->pi_mu);
gpr_mu_unlock(&fd->mu);
return pi;
}
@ -1794,6 +1838,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown,

@ -725,6 +725,8 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
GRPC_FD_UNREF(fd, "poll");
}
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
/*******************************************************************************
* pollset_posix.c
*/
@ -2006,6 +2008,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown,

@ -617,6 +617,8 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
GRPC_FD_UNREF(fd, "poll");
}
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
/*******************************************************************************
* pollset_posix.c
*/
@ -1234,6 +1236,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown,

@ -148,6 +148,10 @@ grpc_fd *grpc_fd_create(int fd, const char *name) {
return g_event_engine->fd_create(fd, name);
}
grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd) {
return g_event_engine->fd_get_workqueue(fd);
}
int grpc_fd_wrapped_fd(grpc_fd *fd) {
return g_event_engine->fd_wrapped_fd(fd);
}

@ -56,6 +56,7 @@ typedef struct grpc_event_engine_vtable {
void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure);
bool (*fd_is_shutdown)(grpc_fd *fd);
grpc_workqueue *(*fd_get_workqueue)(grpc_fd *fd);
grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx,
grpc_fd *fd);
@ -107,6 +108,9 @@ const char *grpc_get_poll_strategy_name();
This takes ownership of closing fd. */
grpc_fd *grpc_fd_create(int fd, const char *name);
/* Get a workqueue that's associated with this fd */
grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd);
/* Return the wrapped fd, or -1 if it has been released or closed. */
int grpc_fd_wrapped_fd(grpc_fd *fd);

@ -37,6 +37,7 @@
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) {
@ -85,14 +86,17 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error,
grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL);
grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
if (offload_target_or_null == NULL) {
grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
} else {
grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error);
GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
}
}
void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
grpc_closure_list *list,
grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL);
grpc_closure_list_move(list, &exec_ctx->closure_list);
}

@ -93,7 +93,11 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
/** Finish any pending work for a grpc_exec_ctx. Must be called before
* the instance is destroyed, or work may be lost. */
void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
/** Add a closure to be executed at the next flush/finish point */
/** Add a closure to be executed in the future.
If \a offload_target_or_null is NULL, the closure will be executed at the
next exec_ctx.{finish,flush} point.
If \a offload_target_or_null is non-NULL, the closure will be scheduled
against the workqueue, and a reference to the workqueue will be consumed. */
void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error,
grpc_workqueue *offload_target_or_null);

@ -45,6 +45,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/network_status_tracker.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
@ -62,6 +63,7 @@ void grpc_iomgr_init(void) {
grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = "root";
grpc_network_status_init();
grpc_iomgr_platform_init();
}
@ -140,6 +142,7 @@ void grpc_iomgr_shutdown(void) {
grpc_iomgr_platform_shutdown();
grpc_exec_ctx_global_shutdown();
grpc_network_status_shutdown();
gpr_mu_destroy(&g_mu);
gpr_cv_destroy(&g_rcv);
}

@ -42,10 +42,16 @@ typedef struct endpoint_ll_node {
static endpoint_ll_node *head = NULL;
static gpr_mu g_endpoint_mutex;
static bool g_init_done = false;
void grpc_initialize_network_status_monitor() {
g_init_done = true;
void grpc_network_status_shutdown(void) {
if (head != NULL) {
gpr_log(GPR_ERROR,
"Memory leaked as all network endpoints were not shut down");
}
gpr_mu_destroy(&g_endpoint_mutex);
}
void grpc_network_status_init(void) {
gpr_mu_init(&g_endpoint_mutex);
// TODO(makarandd): Install callback with OS to monitor network status.
}
@ -60,9 +66,6 @@ void grpc_destroy_network_status_monitor() {
}
void grpc_network_status_register_endpoint(grpc_endpoint *ep) {
if (!g_init_done) {
grpc_initialize_network_status_monitor();
}
gpr_mu_lock(&g_endpoint_mutex);
if (head == NULL) {
head = (endpoint_ll_node *)gpr_malloc(sizeof(endpoint_ll_node));

@ -35,7 +35,11 @@
#define GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H
#include "src/core/lib/iomgr/endpoint.h"
void grpc_network_status_init(void);
void grpc_network_status_shutdown(void);
void grpc_network_status_register_endpoint(grpc_endpoint *ep);
void grpc_network_status_unregister_endpoint(grpc_endpoint *ep);
void grpc_network_status_shutdown_all_endpoints();
#endif /* GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H */

@ -284,7 +284,7 @@ static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
}
/* returns true if done, false if pending; if returning true, *error is set */
#define MAX_WRITE_IOVEC 16
#define MAX_WRITE_IOVEC 1024
static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
@ -450,9 +450,19 @@ static char *tcp_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string);
}
static const grpc_endpoint_vtable vtable = {
tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set,
tcp_shutdown, tcp_destroy, tcp_get_peer};
static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return grpc_fd_get_workqueue(tcp->em_fd);
}
static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_write,
tcp_get_workqueue,
tcp_add_to_pollset,
tcp_add_to_pollset_set,
tcp_shutdown,
tcp_destroy,
tcp_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
const char *peer_string) {

@ -491,7 +491,8 @@ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
}
for (unsigned i = 0; i < count; i++) {
int fd, port;
int fd = -1;
int port = -1;
grpc_dualstack_mode dsmode;
err = grpc_create_dualstack_socket(&listener->addr.sockaddr, SOCK_STREAM, 0,
&dsmode, &fd);

@ -389,9 +389,16 @@ static char *win_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string);
}
static grpc_endpoint_vtable vtable = {
win_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
win_shutdown, win_destroy, win_get_peer};
static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; }
static grpc_endpoint_vtable vtable = {win_read,
win_write,
win_get_workqueue,
win_add_to_pollset,
win_add_to_pollset_set,
win_shutdown,
win_destroy,
win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));

@ -38,6 +38,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#ifdef GPR_POSIX_SOCKET
#include "src/core/lib/iomgr/workqueue_posix.h"
@ -49,35 +50,45 @@
/* grpc_workqueue is forward declared in exec_ctx.h */
/** Create a work queue */
grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
grpc_workqueue **workqueue);
/* Deprecated: do not use.
This has *already* been removed in a future commit. */
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
/* Reference counting functions. Use the macro's always
(GRPC_WORKQUEUE_{REF,UNREF}).
Pass in a descriptive reason string for reffing/unreffing as the last
argument to each macro. When GRPC_WORKQUEUE_REFCOUNT_DEBUG is defined, that
string will be printed alongside the refcount. When it is not defined, the
string will be discarded at compilation time. */
//#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
#define GRPC_WORKQUEUE_REF(p, r) \
grpc_workqueue_ref((p), __FILE__, __LINE__, (r))
#define GRPC_WORKQUEUE_UNREF(cl, p, r) \
grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r))
(grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p))
#define GRPC_WORKQUEUE_UNREF(exec_ctx, p, r) \
grpc_workqueue_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
const char *reason);
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
const char *file, int line, const char *reason);
#else
#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p))
#define GRPC_WORKQUEUE_REF(p, r) (grpc_workqueue_ref((p)), (p))
#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p))
void grpc_workqueue_ref(grpc_workqueue *workqueue);
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
#endif
/** Bind this workqueue to a pollset */
void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
grpc_workqueue *workqueue,
grpc_pollset *pollset);
/** Add a work item to a workqueue. Items added to a work queue will be started
in approximately the order they were enqueued, on some thread that may or
may not be the current thread. Successive closures enqueued onto a workqueue
MAY be executed concurrently.
It is generally more expensive to add a closure to a workqueue than to the
execution context, both in terms of CPU work and in execution latency.
/** Add a work item to a workqueue */
Use work queues when it's important that other threads be given a chance to
tackle some workload. */
void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
grpc_closure *closure, grpc_error *error);

@ -70,7 +70,7 @@ grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
grpc_workqueue *workqueue) {
GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list));
grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
}
@ -100,12 +100,6 @@ void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
}
}
void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
grpc_workqueue *workqueue,
grpc_pollset *pollset) {
grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd);
}
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
gpr_mu_lock(&workqueue->mu);
grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);

@ -50,4 +50,9 @@ struct grpc_workqueue {
grpc_closure read_closure;
};
/** Create a work queue. Returns an error if creation fails. If creation
succeeds, sets *workqueue to point to it. */
grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
grpc_workqueue **workqueue);
#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H */

@ -37,4 +37,26 @@
#include "src/core/lib/iomgr/workqueue.h"
// Minimal implementation of grpc_workqueue for Windows
// Works by directly enqueuing workqueue items onto the current execution
// context, which is at least correct, if not performant or in the spirit of
// workqueues.
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
const char *reason) {}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
const char *file, int line, const char *reason) {}
#else
void grpc_workqueue_ref(grpc_workqueue *workqueue) {}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
#endif
void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
grpc_closure *closure, grpc_error *error) {
grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
}
#endif /* GPR_WINDOWS */

@ -360,11 +360,19 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
return grpc_endpoint_get_peer(ep->wrapped_ep);
}
static const grpc_endpoint_vtable vtable = {
endpoint_read, endpoint_write,
endpoint_add_to_pollset, endpoint_add_to_pollset_set,
endpoint_shutdown, endpoint_destroy,
endpoint_get_peer};
static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
return grpc_endpoint_get_workqueue(ep->wrapped_ep);
}
static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_write,
endpoint_get_workqueue,
endpoint_add_to_pollset,
endpoint_add_to_pollset_set,
endpoint_shutdown,
endpoint_destroy,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport,

@ -79,17 +79,18 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) {
void gpr_log_verbosity_init() {
char *verbosity = gpr_getenv("GRPC_VERBOSITY");
if (verbosity == NULL) return;
gpr_atm min_severity_to_print = GPR_LOG_VERBOSITY_UNSET;
if (strcmp(verbosity, "DEBUG") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG;
} else if (strcmp(verbosity, "INFO") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO;
} else if (strcmp(verbosity, "ERROR") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR;
gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR;
if (verbosity != NULL) {
if (strcmp(verbosity, "DEBUG") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG;
} else if (strcmp(verbosity, "INFO") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO;
} else if (strcmp(verbosity, "ERROR") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR;
}
gpr_free(verbosity);
}
gpr_free(verbosity);
if ((gpr_atm_no_barrier_load(&g_min_severity_to_print)) ==
GPR_LOG_VERBOSITY_UNSET) {
gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print);

@ -73,6 +73,7 @@ typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
typedef struct requested_call {
requested_call_type type;
size_t cq_idx;
void *tag;
grpc_server *server;
grpc_completion_queue *cq_bound_to_call;
@ -206,11 +207,11 @@ struct grpc_server {
registered_method *registered_methods;
/** one request matcher for unregistered methods */
request_matcher unregistered_request_matcher;
/** free list of available requested_calls indices */
gpr_stack_lockfree *request_freelist;
/** free list of available requested_calls_per_cq indices */
gpr_stack_lockfree **request_freelist_per_cq;
/** requested call backing data */
requested_call *requested_calls;
size_t max_requested_calls;
requested_call **requested_calls_per_cq;
int max_requested_calls_per_cq;
gpr_atm shutdown_flag;
uint8_t shutdown_published;
@ -357,7 +358,8 @@ static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx,
for (size_t i = 0; i < server->cq_count; i++) {
while ((request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[i])) !=
-1) {
fail_call(exec_ctx, server, i, &server->requested_calls[request_id],
fail_call(exec_ctx, server, i,
&server->requested_calls_per_cq[i][request_id],
GRPC_ERROR_REF(error));
}
}
@ -392,12 +394,16 @@ static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) {
}
for (i = 0; i < server->cq_count; i++) {
GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server");
if (server->started) {
gpr_stack_lockfree_destroy(server->request_freelist_per_cq[i]);
gpr_free(server->requested_calls_per_cq[i]);
}
}
gpr_stack_lockfree_destroy(server->request_freelist);
gpr_free(server->request_freelist_per_cq);
gpr_free(server->requested_calls_per_cq);
gpr_free(server->cqs);
gpr_free(server->pollsets);
gpr_free(server->shutdown_tags);
gpr_free(server->requested_calls);
gpr_free(server);
}
@ -460,11 +466,13 @@ static void done_request_event(grpc_exec_ctx *exec_ctx, void *req,
requested_call *rc = req;
grpc_server *server = rc->server;
if (rc >= server->requested_calls &&
rc < server->requested_calls + server->max_requested_calls) {
GPR_ASSERT(rc - server->requested_calls <= INT_MAX);
gpr_stack_lockfree_push(server->request_freelist,
(int)(rc - server->requested_calls));
if (rc >= server->requested_calls_per_cq[rc->cq_idx] &&
rc < server->requested_calls_per_cq[rc->cq_idx] +
server->max_requested_calls_per_cq) {
GPR_ASSERT(rc - server->requested_calls_per_cq[rc->cq_idx] <= INT_MAX);
gpr_stack_lockfree_push(
server->request_freelist_per_cq[rc->cq_idx],
(int)(rc - server->requested_calls_per_cq[rc->cq_idx]));
} else {
gpr_free(req);
}
@ -540,7 +548,7 @@ static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg,
calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state);
publish_call(exec_ctx, server, calld, cq_idx,
&server->requested_calls[request_id]);
&server->requested_calls_per_cq[cq_idx][request_id]);
return; /* early out */
}
}
@ -979,8 +987,6 @@ void grpc_server_register_non_listening_completion_queue(
}
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
size_t i;
GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
grpc_server *server = gpr_malloc(sizeof(grpc_server));
@ -998,15 +1004,7 @@ grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
&server->root_channel_data;
/* TODO(ctiller): expose a channel_arg for this */
server->max_requested_calls = 32768;
server->request_freelist =
gpr_stack_lockfree_create(server->max_requested_calls);
for (i = 0; i < (size_t)server->max_requested_calls; i++) {
gpr_stack_lockfree_push(server->request_freelist, (int)i);
}
server->requested_calls = gpr_malloc(server->max_requested_calls *
sizeof(*server->requested_calls));
server->max_requested_calls_per_cq = 32768;
server->channel_args = grpc_channel_args_copy(args);
return server;
@ -1066,16 +1064,28 @@ void grpc_server_start(grpc_server *server) {
server->started = true;
size_t pollset_count = 0;
server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
server->request_freelist_per_cq =
gpr_malloc(sizeof(*server->request_freelist_per_cq) * server->cq_count);
server->requested_calls_per_cq =
gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
for (i = 0; i < server->cq_count; i++) {
if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) {
server->pollsets[pollset_count++] = grpc_cq_pollset(server->cqs[i]);
}
server->request_freelist_per_cq[i] =
gpr_stack_lockfree_create((size_t)server->max_requested_calls_per_cq);
for (int j = 0; j < server->max_requested_calls_per_cq; j++) {
gpr_stack_lockfree_push(server->request_freelist_per_cq[i], j);
}
server->requested_calls_per_cq[i] =
gpr_malloc((size_t)server->max_requested_calls_per_cq *
sizeof(*server->requested_calls_per_cq[i]));
}
request_matcher_init(&server->unregistered_request_matcher,
server->max_requested_calls, server);
(size_t)server->max_requested_calls_per_cq, server);
for (registered_method *rm = server->registered_methods; rm; rm = rm->next) {
request_matcher_init(&rm->request_matcher, server->max_requested_calls,
server);
request_matcher_init(&rm->request_matcher,
(size_t)server->max_requested_calls_per_cq, server);
}
for (l = server->listeners; l; l = l->next) {
@ -1307,11 +1317,13 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_CREATE("Server Shutdown"));
return GRPC_CALL_OK;
}
request_id = gpr_stack_lockfree_pop(server->request_freelist);
request_id = gpr_stack_lockfree_pop(server->request_freelist_per_cq[cq_idx]);
if (request_id == -1) {
/* out of request ids: just fail this one */
fail_call(exec_ctx, server, cq_idx, rc,
GRPC_ERROR_CREATE("Server Shutdown"));
grpc_error_set_int(GRPC_ERROR_CREATE("Out of request ids"),
GRPC_ERROR_INT_LIMIT,
server->max_requested_calls_per_cq));
return GRPC_CALL_OK;
}
switch (rc->type) {
@ -1322,7 +1334,7 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
rm = &rc->data.registered.registered_method->request_matcher;
break;
}
server->requested_calls[request_id] = *rc;
server->requested_calls_per_cq[cq_idx][request_id] = *rc;
gpr_free(rc);
if (gpr_stack_lockfree_push(rm->requests_per_cq[cq_idx], request_id)) {
/* this was the first queued request: we need to lock and start
@ -1346,7 +1358,7 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state);
publish_call(exec_ctx, server, calld, cq_idx,
&server->requested_calls[request_id]);
&server->requested_calls_per_cq[cq_idx][request_id]);
}
gpr_mu_lock(&server->mu_call);
}
@ -1382,6 +1394,7 @@ grpc_call_error grpc_server_request_call(
}
grpc_cq_begin_op(cq_for_notification, tag);
details->reserved = NULL;
rc->cq_idx = cq_idx;
rc->type = BATCH_CALL;
rc->server = server;
rc->tag = tag;
@ -1430,6 +1443,7 @@ grpc_call_error grpc_server_request_registered_call(
goto done;
}
grpc_cq_begin_op(cq_for_notification, tag);
rc->cq_idx = cq_idx;
rc->type = REGISTERED_CALL;
rc->server = server;
rc->tag = tag;

@ -179,6 +179,9 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
while ((w = tracker->watchers) != NULL) {
*w->current = tracker->current_state;
tracker->watchers = w->next;
if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "NOTIFY: %p", w->notify);
}
grpc_exec_ctx_sched(exec_ctx, w->notify,
GRPC_ERROR_REF(tracker->current_error), NULL);
gpr_free(w);

@ -281,6 +281,7 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
: max_message_size_(max_message_size),
started_(false),
shutdown_(false),
shutdown_notified_(false),
num_running_cb_(0),
sync_methods_(new std::list<SyncRequest>),
has_generic_service_(false),
@ -462,13 +463,16 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
while (num_running_cb_ != 0) {
callback_cv_.wait(lock);
}
shutdown_notified_ = true;
shutdown_cv_.notify_all();
}
}
void Server::Wait() {
grpc::unique_lock<grpc::mutex> lock(mu_);
while (num_running_cb_ != 0) {
callback_cv_.wait(lock);
while (started_ && !shutdown_notified_) {
shutdown_cv_.wait(lock);
}
}

@ -129,7 +129,8 @@ ServerContext::ServerContext()
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
call_(nullptr),
cq_(nullptr),
sent_initial_metadata_(false) {}
sent_initial_metadata_(false),
compression_level_set_(false) {}
ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
size_t metadata_count)
@ -139,7 +140,8 @@ ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
deadline_(deadline),
call_(nullptr),
cq_(nullptr),
sent_initial_metadata_(false) {
sent_initial_metadata_(false),
compression_level_set_(false) {
for (size_t i = 0; i < metadata_count; i++) {
client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
metadata[i].key,
@ -194,15 +196,6 @@ bool ServerContext::IsCancelled() const {
}
}
void ServerContext::set_compression_level(grpc_compression_level level) {
// TODO(dgq): get rid of grpc_call_compression_for_level and propagate the
// compression level by adding a new argument to
// CallOpSendInitialMetadata::SendInitialMetadata.
const grpc_compression_algorithm algorithm_for_level =
grpc_call_compression_for_level(call_, level);
set_compression_algorithm(algorithm_for_level);
}
void ServerContext::set_compression_algorithm(
grpc_compression_algorithm algorithm) {
char* algorithm_name = NULL;

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit.ConsoleRunner" version="3.2.0" />
<package id="OpenCover" version="4.6.519" />
<package id="ReportGenerator" version="2.4.4.0" />
</packages>

@ -4,4 +4,7 @@
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NUnit" version="3.2.0" targetFramework="net45" />
<package id="NUnitLite" version="3.2.0" targetFramework="net45" />
</packages>
<package id="NUnit.ConsoleRunner" version="3.2.0" />
<package id="OpenCover" version="4.6.519" />
<package id="ReportGenerator" version="2.4.4.0" />
</packages>

@ -54,7 +54,10 @@
},
"Newtonsoft.Json": "8.0.3",
"NUnit": "3.2.0",
"NUnitLite": "3.2.0-*"
"NUnitLite": "3.2.0-*",
"NUnit.ConsoleRunner": "3.2.0",
"OpenCover": "4.6.519",
"ReportGenerator": "2.4.4.0"
},
"frameworks": {
"net45": { },

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
</packages>

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
</packages>

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
</packages>

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
</packages>

@ -68,6 +68,8 @@ using v8::Value;
Nan::Callback *CallCredentials::constructor;
Persistent<FunctionTemplate> CallCredentials::fun_tpl;
static Callback *plugin_callback;
CallCredentials::CallCredentials(grpc_call_credentials *credentials)
: wrapped_credentials(credentials) {}
@ -88,6 +90,11 @@ void CallCredentials::Init(Local<Object> exports) {
Nan::New<FunctionTemplate>(CreateFromPlugin)).ToLocalChecked());
Nan::Set(exports, Nan::New("CallCredentials").ToLocalChecked(), ctr);
constructor = new Nan::Callback(ctr);
Local<FunctionTemplate> callback_tpl =
Nan::New<FunctionTemplate>(PluginCallback);
plugin_callback = new Callback(
Nan::GetFunction(callback_tpl).ToLocalChecked());
}
bool CallCredentials::HasInstance(Local<Value> val) {
@ -195,23 +202,28 @@ NAN_METHOD(PluginCallback) {
return Nan::ThrowTypeError(
"The callback's third argument must be an object");
}
if (!info[3]->IsObject()) {
return Nan::ThrowTypeError(
"The callback's fourth argument must be an object");
}
shared_ptr<Resources> resources(new Resources);
grpc_status_code code = static_cast<grpc_status_code>(
Nan::To<uint32_t>(info[0]).FromJust());
Utf8String details_utf8_str(info[1]);
char *details = *details_utf8_str;
grpc_metadata_array array;
Local<Object> callback_data = Nan::To<Object>(info[3]).ToLocalChecked();
if (!CreateMetadataArray(Nan::To<Object>(info[2]).ToLocalChecked(),
&array, resources)){
return Nan::ThrowError("Failed to parse metadata");
}
grpc_credentials_plugin_metadata_cb cb =
reinterpret_cast<grpc_credentials_plugin_metadata_cb>(
Nan::Get(info.Callee(),
Nan::Get(callback_data,
Nan::New("cb").ToLocalChecked()
).ToLocalChecked().As<External>()->Value());
void *user_data =
Nan::Get(info.Callee(),
Nan::Get(callback_data,
Nan::New("user_data").ToLocalChecked()
).ToLocalChecked().As<External>()->Value();
cb(user_data, array.metadata, array.count, code, details);
@ -227,17 +239,17 @@ NAUV_WORK_CB(SendPluginCallback) {
while (!callbacks.empty()) {
plugin_callback_data *data = callbacks.front();
callbacks.pop_front();
// Attach cb and user_data to plugin_callback so that it can access them later
v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
Local<Object> callback_data = Nan::New<Object>();
Nan::Set(callback_data, Nan::New("cb").ToLocalChecked(),
Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
Nan::Set(callback_data, Nan::New("user_data").ToLocalChecked(),
Nan::New<v8::External>(data->user_data));
const int argc = 2;
const int argc = 3;
v8::Local<v8::Value> argv[argc] = {
Nan::New(data->service_url).ToLocalChecked(),
plugin_callback
callback_data,
// Get Local<Function> from Nan::Callback*
**plugin_callback
};
Nan::Callback *callback = state->callback;
callback->Call(argc, argv);

@ -19,11 +19,11 @@
"lodash": "^3.9.3",
"google-protobuf": "^3.0.0-alpha.5"
},
"files": {
"files": [
"LICENSE",
"health.js",
"v1"
},
],
"main": "src/node/index.js",
"license": "BSD-3-Clause"
}

@ -92,7 +92,8 @@ exports.createSsl = ChannelCredentials.createSsl;
* @return {CallCredentials} The credentials object
*/
exports.createFromMetadataGenerator = function(metadata_generator) {
return CallCredentials.createFromPlugin(function(service_url, callback) {
return CallCredentials.createFromPlugin(function(service_url, cb_data,
callback) {
metadata_generator({service_url: service_url}, function(error, metadata) {
var code = grpc.status.OK;
var message = '';
@ -107,7 +108,7 @@ exports.createFromMetadataGenerator = function(metadata_generator) {
metadata = new Metadata();
}
}
callback(code, message, metadata._getCoreRepresentation());
callback(code, message, metadata._getCoreRepresentation(), cb_data);
});
});
};

@ -1,44 +0,0 @@
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package grpc.testing;
option objc_class_prefix = "RMT";
// An empty message that you can re-use to avoid defining duplicated empty
// messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance:
//
// service Foo {
// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
// };
//
message Empty {}

@ -31,7 +31,7 @@
// of unary/streaming requests/responses.
syntax = "proto3";
import "empty.proto";
import "google/protobuf/empty.proto";
import "messages.proto";
package grpc.testing;
@ -42,7 +42,7 @@ option objc_class_prefix = "RMT";
// performance with various types of payload.
service TestService {
// One empty request followed by one empty response.
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
rpc EmptyCall(google.protobuf.Empty) returns (google.protobuf.Empty);
// One request followed by one response.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);

@ -3,6 +3,8 @@ platform :ios, '8.0'
install! 'cocoapods', :deterministic_uuids => false
use_frameworks! if ENV['FRAMEWORKS'] == 'YES'
# Location of gRPC's repo root relative to this file.
GRPC_LOCAL_SRC = '../../../..'

@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C20055928615A6F8434E26B4 /* libPods-Sample.a */; };
3F035697392F601049D3DDE1 /* Pods_Sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC1B27EA0C428429B07BC34B /* Pods_Sample.framework */; };
6369A2701A9322E20015FC5C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A26F1A9322E20015FC5C /* main.m */; };
6369A2731A9322E20015FC5C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2721A9322E20015FC5C /* AppDelegate.m */; };
6369A2761A9322E20015FC5C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2751A9322E20015FC5C /* ViewController.m */; };
@ -26,7 +26,7 @@
6369A2751A9322E20015FC5C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
6369A2781A9322E20015FC5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
6369A27A1A9322E20015FC5C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
C20055928615A6F8434E26B4 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
CC1B27EA0C428429B07BC34B /* Pods_Sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -35,7 +35,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */,
3F035697392F601049D3DDE1 /* Pods_Sample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -95,7 +95,7 @@
C4C2C5219053E079C9EFB930 /* Frameworks */ = {
isa = PBXGroup;
children = (
C20055928615A6F8434E26B4 /* libPods-Sample.a */,
CC1B27EA0C428429B07BC34B /* Pods_Sample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -129,7 +129,7 @@
6369A2621A9322E20015FC5C /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
6369A2691A9322E20015FC5C = {
@ -260,6 +260,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@ -325,6 +326,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@ -336,6 +338,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.grpc.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

@ -66,9 +66,9 @@
// Same example call using the generic gRPC client library:
ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:@"grpc.testing"
service:@"TestService"
method:@"UnaryCall"];
GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing"
service:@"TestService"
method:@"UnaryCall"];
GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];

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

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>io.grpc.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

@ -3,6 +3,8 @@ platform :ios, '8.0'
install! 'cocoapods', :deterministic_uuids => false
use_frameworks!
# Location of gRPC's repo root relative to this file.
GRPC_LOCAL_SRC = '../../../..'

@ -7,11 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
2C0B024CB798839E17F76126 /* Pods_SwiftSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B394F343BDE186C5436DBDB9 /* Pods_SwiftSample.framework */; };
633BFFC81B950B210007E424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC71B950B210007E424 /* AppDelegate.swift */; };
633BFFCA1B950B210007E424 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC91B950B210007E424 /* ViewController.swift */; };
633BFFCD1B950B210007E424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCB1B950B210007E424 /* Main.storyboard */; };
633BFFCF1B950B210007E424 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCE1B950B210007E424 /* Images.xcassets */; };
92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -21,9 +21,8 @@
633BFFC91B950B210007E424 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
633BFFCC1B950B210007E424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
633BFFCE1B950B210007E424 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
6367AD231B951655007FD3A4 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.debug.xcconfig"; sourceTree = "<group>"; };
B394F343BDE186C5436DBDB9 /* Pods_SwiftSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -32,7 +31,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */,
2C0B024CB798839E17F76126 /* Pods_SwiftSample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -74,7 +73,6 @@
633BFFCB1B950B210007E424 /* Main.storyboard */,
633BFFCE1B950B210007E424 /* Images.xcassets */,
633BFFC51B950B210007E424 /* Supporting Files */,
6367AD231B951655007FD3A4 /* Bridging-Header.h */,
);
name = SwiftSample;
sourceTree = SOURCE_ROOT;
@ -90,7 +88,7 @@
9D63A7F6423989BA306810CA /* Frameworks */ = {
isa = PBXGroup;
children = (
69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */,
B394F343BDE186C5436DBDB9 /* Pods_SwiftSample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -125,7 +123,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0640;
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
633BFFC11B950B210007E424 = {
@ -256,6 +254,7 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -325,8 +324,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "";
USER_HEADER_SEARCH_PATHS = "";
};
name = Debug;
@ -338,8 +338,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h";
SWIFT_OBJC_BRIDGING_HEADER = "";
USER_HEADER_SEARCH_PATHS = "";
};
name = Release;

@ -33,6 +33,8 @@
import UIKit
import RemoteTest
class ViewController: UIViewController {
override func viewDidLoad() {
@ -60,7 +62,7 @@ class ViewController: UIViewController {
// Same but manipulating headers:
var RPC : ProtoRPC! // Needed to convince Swift to capture by reference (__block)
var RPC : GRPCProtoCall! // Needed to convince Swift to capture by reference (__block)
RPC = service.RPCToUnaryCallWithRequest(request) { response, error in
if let response = response {
NSLog("2. Finished successfully with response:\n\(response)")
@ -79,7 +81,7 @@ class ViewController: UIViewController {
// Same example call using the generic gRPC client library:
let method = ProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")
let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")
let requestsWriter = GRXWriter(value: request.data())

@ -31,44 +31,33 @@
# Don't run this script standalone. Instead, run from the repository root:
# ./tools/run_tests/run_tests.py -l objc
set -eo pipefail
set -evo pipefail
cd `dirname $0`
BINDIR=`pwd`/../../../bins/$CONFIG
TMP_PATH=$PATH
# If `protoc` is not found, add bins/$CONFIG/protobuf/protoc to the search path
hash protoc 2>/dev/null || TMP_PATH=$BINDIR/protobuf:$TMP_PATH
# If `protoc-gen-objcgrpc` is not found, make a symlink from
# bins/$CONGIF/grpc_objective_c_plugin and add it to the search path
PATH=$TMP_PATH hash protoc-gen-objcgrpc 2>/dev/null || {
ln -sf $BINDIR/grpc_objective_c_plugin $BINDIR/protoc-gen-objcgrpc
TMP_PATH=$BINDIR:$TMP_PATH
}
SCHEME=HelloWorld \
EXAMPLE_PATH=examples/objective-c/helloworld \
PATH=$TMP_PATH \
./build_one_example.sh
SCHEME=RouteGuideClient \
EXAMPLE_PATH=examples/objective-c/route_guide \
PATH=$TMP_PATH \
./build_one_example.sh
SCHEME=AuthSample \
EXAMPLE_PATH=examples/objective-c/auth_sample \
PATH=$TMP_PATH \
./build_one_example.sh
rm -f ../examples/RemoteTestClient/*.{h,m}
SCHEME=Sample \
EXAMPLE_PATH=src/objective-c/examples/Sample \
./build_one_example.sh
SCHEME=Sample \
EXAMPLE_PATH=src/objective-c/examples/Sample \
PATH=$TMP_PATH \
FRAMEWORKS=YES \
./build_one_example.sh
SCHEME=SwiftSample \
EXAMPLE_PATH=src/objective-c/examples/SwiftSample \
PATH=$TMP_PATH \
./build_one_example.sh

@ -31,7 +31,7 @@
# Don't run this script standalone. Instead, run from the repository root:
# ./tools/run_tests/run_tests.py -l objc
set -e
set -ev
# Params:
# EXAMPLE_PATH - directory of the example
@ -54,7 +54,7 @@ pod install
set -o pipefail
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)'
xcodebuild \
clean build \
build \
-workspace *.xcworkspace \
-scheme $SCHEME \
-destination name="iPhone 6" \

@ -44,26 +44,10 @@ hash xcodebuild 2>/dev/null || {
exit 1
}
BINDIR=../../../bins/$CONFIG
if [ ! -f $BINDIR/protobuf/protoc ]; then
hash protoc 2>/dev/null || {
echo >&2 "Can't find protoc. Make sure run_tests.py is making" \
"grpc_objective_c_plugin before calling this script."
exit 1
}
# When protoc is already installed, make doesn't compile one. Put a link
# there so the podspecs can do codegen using that path.
mkdir -p $BINDIR/protobuf
ln -s `which protoc` $BINDIR/protobuf/protoc
fi
[ -f $BINDIR/interop_server ] || {
echo >&2 "Can't find the test server. Make sure run_tests.py is making" \
"interop_server before calling this script. It needs to be done" \
"before because pod install of gRPC renames some C gRPC files" \
"and not the server's code references to them."
exit 1
}
# clean the directory
rm -rf Pods
rm -rf Tests.xcworkspace
rm -f Podfile.lock
rm -f RemoteTestClient/*.{h,m}
pod install

@ -31,13 +31,21 @@
# Don't run this script standalone. Instead, run from the repository root:
# ./tools/run_tests/run_tests.py -l objc
set -e
set -ev
cd $(dirname $0)
# Run the tests server.
../../../bins/$CONFIG/interop_server --port=5050 &
../../../bins/$CONFIG/interop_server --port=5051 --use_tls &
BINDIR=../../../bins/$CONFIG
[ -f $BINDIR/interop_server ] || {
echo >&2 "Can't find the test server. Make sure run_tests.py is making" \
"interop_server before calling this script."
exit 1
}
$BINDIR/interop_server --port=5050 &
$BINDIR/interop_server --port=5051 --use_tls &
# Kill them when this script exits.
trap 'kill -9 `jobs -p`' EXIT

@ -9,23 +9,12 @@ GA
## Environment
Prerequisite: `php` >=5.5, `phpize`, `pecl`, `phpunit`
**Linux (Debian):**
```sh
$ sudo apt-get install php5 php5-dev php-pear
```
**Linux (CentOS):**
```sh
$ yum install php55w
$ yum --enablerepo=remi,remi-php55 install php-devel php-pear
```
**Mac OS X:**
Prerequisite:
* `php` 5.5 or above, 7.0 or above
* `pear` and `pecl`
* `phpunit`
**PEAR:**
```sh
$ curl -O http://pear.php.net/go-pear.phar
$ sudo php -d detect_unicode=0 go-pear.phar
@ -72,13 +61,7 @@ $ sudo make install
### gRPC PHP extension
Install the gRPC PHP extension from PECL
```sh
$ sudo pecl install grpc
```
Or, compile from source
Compile the gRPC PHP extension
```sh
$ cd grpc/src/php/ext/grpc
@ -148,12 +131,8 @@ Alternatively, you can download `protoc` binaries from [the protocol buffers Git
You need to install `protoc-gen-php` to generate stub class `.php` files from service definition `.proto` files.
```sh
$ cd grpc/src/php/vendor/stanley-cheung/protobuf-php # if you had run `composer install` in the previous step
OR
$ git clone https://github.com/stanley-cheung/Protobuf-PHP # clone from github repo
$ git clone https://github.com/stanley-cheung/Protobuf-PHP
$ cd Protobuf-PHP
$ gem install rake ronn
$ rake pear:package version=1.0
$ sudo pear install Protobuf-1.0.tgz
@ -175,7 +154,7 @@ Run a local server serving the math services. Please see [Node][] for how to run
```sh
$ cd grpc
$ npm install
$ nodejs src/node/test/math/math_server.js
$ node src/node/test/math/math_server.js
```
### Run test client
@ -212,7 +191,7 @@ Make sure the Node math server is still running, as above.
```sh
$ cd grpc
$ npm install
$ nodejs src/node/test/math/math_server.js
$ node src/node/test/math/math_server.js
```
Make sure you have run `composer install` to generate the `vendor/autoload.php` file
@ -282,7 +261,7 @@ Make sure the Node math server is still running, as above.
```sh
$ cd grpc
$ npm install
$ nodejs src/node/test/math/math_server.js
$ node src/node/test/math/math_server.js
```
Make sure you have run `composer install` to generate the `vendor/autoload.php` file

@ -29,11 +29,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
default_extension_dir=$(php-config --extension-dir)
if command -v brew > /dev/null && \
brew ls --versions | grep php5[56]-grpc > /dev/null; then
# the grpc php extension was installed by homebrew
:
elif [ ! -e $default_extension_dir/grpc.so ]; then
if [ ! -e $default_extension_dir/grpc.so ]; then
# the grpc extension is not found in the default PHP extension dir
# try the source modules directory
module_dir=../ext/grpc/modules

@ -8,7 +8,9 @@
"version": "1.0.0",
"require": {
"php": ">=5.5.0",
"stanley-cheung/protobuf-php": "dev-master",
"stanley-cheung/protobuf-php": "v0.6"
},
"require-dev": {
"google/auth": "v0.9"
},
"autoload": {

@ -58,63 +58,44 @@
#include "byte_buffer.h"
zend_class_entry *grpc_ce_call;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers call_ce_handlers;
#endif
/* Frees and destroys an instance of wrapped_grpc_call */
void free_wrapped_grpc_call(void *object TSRMLS_DC) {
wrapped_grpc_call *call = (wrapped_grpc_call *)object;
if (call->owned && call->wrapped != NULL) {
grpc_call_destroy(call->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call)
if (p->owned && p->wrapped != NULL) {
grpc_call_destroy(p->wrapped);
}
efree(call);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_call to be associated with an object
* of a class specified by class_type */
zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type
TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_call *intern;
intern = (wrapped_grpc_call *)emalloc(sizeof(wrapped_grpc_call));
memset(intern, 0, sizeof(wrapped_grpc_call));
php_grpc_zend_object create_wrapped_grpc_call(zend_class_entry *class_type
TSRMLS_DC) {
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_call, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
should be destroyed at the end of the object's lifecycle */
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC) {
zval *call_object;
MAKE_STD_ZVAL(call_object);
object_init_ex(call_object, grpc_ce_call);
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
call->wrapped = wrapped;
call->owned = owned;
return call_object;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call, call_ce_handlers);
}
/* Creates and returns a PHP array object with the data in a
* grpc_metadata_array. Returns NULL on failure */
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC) {
zval *grpc_parse_metadata_array(grpc_metadata_array
*metadata_array TSRMLS_DC) {
int count = metadata_array->count;
grpc_metadata *elements = metadata_array->metadata;
int i;
zval *array;
zval **data = NULL;
PHP_GRPC_MAKE_STD_ZVAL(array);
array_init(array);
int i;
HashTable *array_hash;
zval *inner_array;
char *str_key;
char *str_val;
size_t key_len;
MAKE_STD_ZVAL(array);
array_init(array);
zval *data = NULL;
array_hash = Z_ARRVAL_P(array);
grpc_metadata *elem;
for (i = 0; i < count; i++) {
@ -124,9 +105,9 @@ zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC) {
memcpy(str_key, elem->key, key_len);
str_val = ecalloc(elem->value_length + 1, sizeof(char));
memcpy(str_val, elem->value, elem->value_length);
if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
SUCCESS) {
if (Z_TYPE_P(*data) != IS_ARRAY) {
if (php_grpc_zend_hash_find(array_hash, str_key, key_len, (void **)&data)
== SUCCESS) {
if (Z_TYPE_P(data) != IS_ARRAY) {
zend_throw_exception(zend_exception_get_default(TSRMLS_C),
"Metadata hash somehow contains wrong types.",
1 TSRMLS_CC);
@ -134,11 +115,13 @@ zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC) {
efree(str_val);
return NULL;
}
add_next_index_stringl(*data, str_val, elem->value_length, false);
php_grpc_add_next_index_stringl(data, str_val, elem->value_length,
false);
} else {
MAKE_STD_ZVAL(inner_array);
PHP_GRPC_MAKE_STD_ZVAL(inner_array);
array_init(inner_array);
add_next_index_stringl(inner_array, str_val, elem->value_length, false);
php_grpc_add_next_index_stringl(inner_array, str_val,
elem->value_length, false);
add_assoc_zval(array, str_key, inner_array);
}
}
@ -148,61 +131,65 @@ zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC) {
/* Populates a grpc_metadata_array with the data in a PHP array object.
Returns true on success and false on failure */
bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
zval **inner_array;
zval **value;
HashTable *array_hash;
HashPosition array_pointer;
HashTable *inner_array_hash;
HashPosition inner_array_pointer;
char *key;
uint key_len;
ulong index;
zval *value;
zval *inner_array;
if (Z_TYPE_P(array) != IS_ARRAY) {
return false;
}
grpc_metadata_array_init(metadata);
array_hash = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
char *key;
int key_type;
PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type,
inner_array)
if (key_type != HASH_KEY_IS_STRING || key == NULL) {
return false;
}
if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
if (Z_TYPE_P(inner_array) != IS_ARRAY) {
return false;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
inner_array_hash = Z_ARRVAL_P(inner_array);
metadata->capacity += zend_hash_num_elements(inner_array_hash);
}
PHP_GRPC_HASH_FOREACH_END()
metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
char *key1 = NULL;
int key_type1;
PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key1, key_type1,
inner_array)
if (key_type1 != HASH_KEY_IS_STRING) {
return false;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
&inner_array_pointer);
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
&inner_array_pointer) == SUCCESS;
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
if (Z_TYPE_P(*value) != IS_STRING) {
inner_array_hash = Z_ARRVAL_P(inner_array);
PHP_GRPC_HASH_FOREACH_VAL_START(inner_array_hash, value)
if (Z_TYPE_P(value) != IS_STRING) {
return false;
}
metadata->metadata[metadata->count].key = key;
metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
metadata->metadata[metadata->count].key = key1;
metadata->metadata[metadata->count].value = Z_STRVAL_P(value);
metadata->metadata[metadata->count].value_length = Z_STRLEN_P(value);
metadata->count += 1;
}
}
PHP_GRPC_HASH_FOREACH_END()
PHP_GRPC_HASH_FOREACH_END()
return true;
}
/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the
struct should be destroyed at the end of the object's lifecycle */
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC) {
zval *call_object;
PHP_GRPC_MAKE_STD_ZVAL(call_object);
object_init_ex(call_object, grpc_ce_call);
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(call_object);
call->wrapped = wrapped;
call->owned = owned;
return call_object;
}
/**
* Constructs a new instance of the Call class.
* @param Channel $channel The channel to associate the call with. Must not be
@ -211,30 +198,25 @@ bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
* @param Timeval $absolute_deadline The deadline for completing the call
*/
PHP_METHOD(Call, __construct) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *channel_obj;
char *method;
int method_len;
php_grpc_int method_len;
zval *deadline_obj;
char *host_override = NULL;
int host_override_len = 0;
php_grpc_int host_override_len = 0;
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
/* "OsO|s" == 1 Object, 1 string, 1 Object, 1 optional string */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s",
&channel_obj, grpc_ce_channel,
&method, &method_len,
&deadline_obj, grpc_ce_timeval,
&host_override, &host_override_len)
== FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"Call expects a Channel, a String, a Timeval and an optional String",
1 TSRMLS_CC);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s", &channel_obj,
grpc_ce_channel, &method, &method_len,
&deadline_obj, grpc_ce_timeval, &host_override,
&host_override_len) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Call expects a Channel, a String, a Timeval and "
"an optional String", 1 TSRMLS_CC);
return;
}
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(
channel_obj TSRMLS_CC);
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(channel_obj);
if (channel->wrapped == NULL) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Call cannot be constructed from a closed Channel",
@ -242,12 +224,11 @@ PHP_METHOD(Call, __construct) {
return;
}
add_property_zval(getThis(), "channel", channel_obj);
wrapped_grpc_timeval *deadline =
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
call->wrapped = grpc_channel_create_call(
channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method,
host_override, deadline->wrapped, NULL);
wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
call->wrapped =
grpc_channel_create_call(channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS,
completion_queue, method, host_override,
deadline->wrapped, NULL);
call->owned = true;
}
@ -257,22 +238,26 @@ PHP_METHOD(Call, __construct) {
* @return object Object with results of all actions
*/
PHP_METHOD(Call, startBatch) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *result;
PHP_GRPC_MAKE_STD_ZVAL(result);
object_init(result);
php_grpc_ulong index;
zval *recv_status;
PHP_GRPC_MAKE_STD_ZVAL(recv_status);
object_init(recv_status);
zval *value;
zval *inner_value;
zval *message_value;
zval *message_flags;
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
grpc_op ops[8];
size_t op_num = 0;
zval *array;
zval **value;
zval **inner_value;
HashTable *array_hash;
HashPosition array_pointer;
HashTable *status_hash;
HashTable *message_hash;
zval **message_value;
zval **message_flags;
char *key;
uint key_len;
ulong index;
grpc_metadata_array metadata;
grpc_metadata_array trailing_metadata;
grpc_metadata_array recv_metadata;
@ -283,17 +268,15 @@ PHP_METHOD(Call, startBatch) {
grpc_byte_buffer *message;
int cancelled;
grpc_call_error error;
zval *result;
char *message_str;
size_t message_len;
zval *recv_status;
grpc_metadata_array_init(&metadata);
grpc_metadata_array_init(&trailing_metadata);
grpc_metadata_array_init(&recv_metadata);
grpc_metadata_array_init(&recv_trailing_metadata);
MAKE_STD_ZVAL(result);
object_init(result);
memset(ops, 0, sizeof(ops));
/* "a" == 1 array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
FAILURE) {
@ -301,136 +284,136 @@ PHP_METHOD(Call, startBatch) {
"start_batch expects an array", 1 TSRMLS_CC);
goto cleanup;
}
array_hash = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&value,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_LONG) {
char *key = NULL;
int key_type;
PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(array_hash, key, key_type, index,
value)
if (key_type != HASH_KEY_IS_LONG || key != NULL) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"batch keys must be integers", 1 TSRMLS_CC);
goto cleanup;
}
switch(index) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!create_metadata_array(*value, &metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad metadata value given", 1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_initial_metadata.count =
metadata.count;
ops[op_num].data.send_initial_metadata.metadata =
metadata.metadata;
break;
case GRPC_OP_SEND_MESSAGE:
if (Z_TYPE_PP(value) != IS_ARRAY) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!create_metadata_array(value, &metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad metadata value given", 1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_initial_metadata.count = metadata.count;
ops[op_num].data.send_initial_metadata.metadata = metadata.metadata;
break;
case GRPC_OP_SEND_MESSAGE:
if (Z_TYPE_P(value) != IS_ARRAY) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected an array for send message",
1 TSRMLS_CC);
goto cleanup;
}
message_hash = Z_ARRVAL_P(value);
if (php_grpc_zend_hash_find(message_hash, "flags", sizeof("flags"),
(void **)&message_flags) == SUCCESS) {
if (Z_TYPE_P(message_flags) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected an array for send message",
"Expected an int for message flags",
1 TSRMLS_CC);
goto cleanup;
}
message_hash = Z_ARRVAL_PP(value);
if (zend_hash_find(message_hash, "flags", sizeof("flags"),
(void **)&message_flags) == SUCCESS) {
if (Z_TYPE_PP(message_flags) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected an int for message flags",
1 TSRMLS_CC);
}
ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
}
if (zend_hash_find(message_hash, "message", sizeof("message"),
(void **)&message_value) != SUCCESS ||
Z_TYPE_PP(message_value) != IS_STRING) {
ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
}
if (php_grpc_zend_hash_find(message_hash, "message", sizeof("message"),
(void **)&message_value) != SUCCESS ||
Z_TYPE_P(message_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected a string for send message",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_message =
string_to_byte_buffer(Z_STRVAL_P(message_value),
Z_STRLEN_P(message_value));
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
status_hash = Z_ARRVAL_P(value);
if (php_grpc_zend_hash_find(status_hash, "metadata", sizeof("metadata"),
(void **)&inner_value) == SUCCESS) {
if (!create_metadata_array(inner_value, &trailing_metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected a string for send message",
"Bad trailing metadata value given",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_message =
string_to_byte_buffer(Z_STRVAL_PP(message_value),
Z_STRLEN_PP(message_value));
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
status_hash = Z_ARRVAL_PP(value);
if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
(void **)&inner_value) == SUCCESS) {
if (!create_metadata_array(*inner_value, &trailing_metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad trailing metadata value given",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.trailing_metadata =
trailing_metadata.metadata;
ops[op_num].data.send_status_from_server.trailing_metadata_count =
trailing_metadata.count;
}
if (zend_hash_find(status_hash, "code", sizeof("code"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_PP(inner_value) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Status code must be an integer",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.status =
Z_LVAL_PP(inner_value);
} else {
ops[op_num].data.send_status_from_server.trailing_metadata =
trailing_metadata.metadata;
ops[op_num].data.send_status_from_server.trailing_metadata_count =
trailing_metadata.count;
}
if (php_grpc_zend_hash_find(status_hash, "code", sizeof("code"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_P(inner_value) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Integer status code is required",
"Status code must be an integer",
1 TSRMLS_CC);
goto cleanup;
}
if (zend_hash_find(status_hash, "details", sizeof("details"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_PP(inner_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Status details must be a string",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.status_details =
Z_STRVAL_PP(inner_value);
} else {
ops[op_num].data.send_status_from_server.status =
Z_LVAL_P(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Integer status code is required",
1 TSRMLS_CC);
goto cleanup;
}
if (php_grpc_zend_hash_find(status_hash, "details", sizeof("details"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_P(inner_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"String status details is required",
"Status details must be a string",
1 TSRMLS_CC);
goto cleanup;
}
break;
case GRPC_OP_RECV_INITIAL_METADATA:
ops[op_num].data.recv_initial_metadata = &recv_metadata;
break;
case GRPC_OP_RECV_MESSAGE:
ops[op_num].data.recv_message = &message;
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
ops[op_num].data.recv_status_on_client.trailing_metadata =
&recv_trailing_metadata;
ops[op_num].data.recv_status_on_client.status = &status;
ops[op_num].data.recv_status_on_client.status_details =
&status_details;
ops[op_num].data.recv_status_on_client.status_details_capacity =
&status_details_capacity;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
break;
default:
ops[op_num].data.send_status_from_server.status_details =
Z_STRVAL_P(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Unrecognized key in batch", 1 TSRMLS_CC);
"String status details is required",
1 TSRMLS_CC);
goto cleanup;
}
break;
case GRPC_OP_RECV_INITIAL_METADATA:
ops[op_num].data.recv_initial_metadata = &recv_metadata;
break;
case GRPC_OP_RECV_MESSAGE:
ops[op_num].data.recv_message = &message;
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
ops[op_num].data.recv_status_on_client.trailing_metadata =
&recv_trailing_metadata;
ops[op_num].data.recv_status_on_client.status = &status;
ops[op_num].data.recv_status_on_client.status_details =
&status_details;
ops[op_num].data.recv_status_on_client.status_details_capacity =
&status_details_capacity;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
break;
default:
zend_throw_exception(spl_ce_InvalidArgumentException,
"Unrecognized key in batch", 1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].op = (grpc_op_type)index;
ops[op_num].flags = 0;
ops[op_num].reserved = NULL;
op_num++;
}
PHP_GRPC_HASH_FOREACH_END()
error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
NULL);
if (error != GRPC_CALL_OK) {
@ -441,52 +424,65 @@ PHP_METHOD(Call, startBatch) {
}
grpc_completion_queue_pluck(completion_queue, call->wrapped,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
#if PHP_MAJOR_VERSION >= 7
zval recv_md;
#endif
for (int i = 0; i < op_num; i++) {
switch(ops[i].op) {
case GRPC_OP_SEND_INITIAL_METADATA:
add_property_bool(result, "send_metadata", true);
break;
case GRPC_OP_SEND_MESSAGE:
add_property_bool(result, "send_message", true);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
add_property_bool(result, "send_close", true);
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
add_property_bool(result, "send_status", true);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
add_property_zval(result, "metadata", array);
Z_DELREF_P(array);
break;
case GRPC_OP_RECV_MESSAGE:
byte_buffer_to_string(message, &message_str, &message_len);
if (message_str == NULL) {
add_property_null(result, "message");
} else {
add_property_stringl(result, "message", message_str, message_len,
false);
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
MAKE_STD_ZVAL(recv_status);
object_init(recv_status);
array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
add_property_zval(recv_status, "metadata", array);
Z_DELREF_P(array);
add_property_long(recv_status, "code", status);
add_property_string(recv_status, "details", status_details, true);
add_property_zval(result, "status", recv_status);
Z_DELREF_P(recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(result, "cancelled", cancelled);
break;
default:
break;
case GRPC_OP_SEND_INITIAL_METADATA:
add_property_bool(result, "send_metadata", true);
break;
case GRPC_OP_SEND_MESSAGE:
add_property_bool(result, "send_message", true);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
add_property_bool(result, "send_close", true);
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
add_property_bool(result, "send_status", true);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
#if PHP_MAJOR_VERSION < 7
array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
add_property_zval(result, "metadata", array);
#else
recv_md = *grpc_parse_metadata_array(&recv_metadata);
add_property_zval(result, "metadata", &recv_md);
#endif
PHP_GRPC_DELREF(array);
break;
case GRPC_OP_RECV_MESSAGE:
byte_buffer_to_string(message, &message_str, &message_len);
if (message_str == NULL) {
add_property_null(result, "message");
} else {
php_grpc_add_property_stringl(result, "message", message_str,
message_len, false);
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
#if PHP_MAJOR_VERSION < 7
array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
add_property_zval(recv_status, "metadata", array);
#else
recv_md = *grpc_parse_metadata_array(&recv_trailing_metadata);
add_property_zval(recv_status, "metadata", &recv_md);
#endif
PHP_GRPC_DELREF(array);
add_property_long(recv_status, "code", status);
php_grpc_add_property_string(recv_status, "details", status_details,
true);
add_property_zval(result, "status", recv_status);
PHP_GRPC_DELREF(recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(result, "cancelled", cancelled);
break;
default:
break;
}
}
cleanup:
grpc_metadata_array_destroy(&metadata);
grpc_metadata_array_destroy(&trailing_metadata);
@ -511,9 +507,8 @@ cleanup:
* @return string The URI of the endpoint
*/
PHP_METHOD(Call, getPeer) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
PHP_GRPC_RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
}
/**
@ -521,8 +516,7 @@ PHP_METHOD(Call, getPeer) {
* has not already ended with another status.
*/
PHP_METHOD(Call, cancel) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
grpc_call_cancel(call->wrapped, NULL);
}
@ -544,11 +538,8 @@ PHP_METHOD(Call, setCredentials) {
}
wrapped_grpc_call_credentials *creds =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
creds_obj TSRMLS_CC);
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
Z_WRAPPED_GRPC_CALL_CREDS_P(creds_obj);
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
grpc_call_error error = GRPC_CALL_ERROR;
error = grpc_call_set_credentials(call->wrapped, creds->wrapped);
@ -556,16 +547,18 @@ PHP_METHOD(Call, setCredentials) {
}
static zend_function_entry call_methods[] = {
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, setCredentials, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END};
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, setCredentials, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END
};
void grpc_init_call(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods);
ce.create_object = create_wrapped_grpc_call;
grpc_ce_call = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_call, call_ce_handlers);
}

@ -49,23 +49,38 @@
extern zend_class_entry *grpc_ce_call;
/* Wrapper struct for grpc_call that can be associated with a PHP object */
typedef struct wrapped_grpc_call {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_call)
bool owned;
grpc_call *wrapped;
} wrapped_grpc_call;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_call)
/* Initializes the Call PHP class */
void grpc_init_call(TSRMLS_D);
#if PHP_MAJOR_VERSION < 7
/* Creates a Call object that wraps the given grpc_call struct */
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
#define Z_WRAPPED_GRPC_CALL_P(zv) \
(wrapped_grpc_call *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_call
*wrapped_grpc_call_from_obj(zend_object *obj) {
return (wrapped_grpc_call*)((char*)(obj) -
XtOffsetOf(wrapped_grpc_call, std));
}
#define Z_WRAPPED_GRPC_CALL_P(zv) wrapped_grpc_call_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Creates and returns a PHP associative array of metadata from a C array of
* call metadata */
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC);
/* Creates a Call object that wraps the given grpc_call struct */
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
/* Initializes the Call PHP class */
void grpc_init_call(TSRMLS_D);
/* Populates a grpc_metadata_array with the data in a PHP array object.
Returns true on success and false on failure */
bool create_metadata_array(zval *array, grpc_metadata_array *metadata);

@ -52,44 +52,35 @@
#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_call_credentials;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers call_credentials_ce_handlers;
#endif
/* Frees and destroys an instance of wrapped_grpc_call_credentials */
void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
wrapped_grpc_call_credentials *creds =
(wrapped_grpc_call_credentials *)object;
if (creds->wrapped != NULL) {
grpc_call_credentials_release(creds->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call_credentials)
if (p->wrapped != NULL) {
grpc_call_credentials_release(p->wrapped);
}
efree(creds);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_call_credentials to be
* associated with an object of a class specified by class_type */
zend_object_value create_wrapped_grpc_call_credentials(
php_grpc_zend_object create_wrapped_grpc_call_credentials(
zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_call_credentials *intern;
intern = (wrapped_grpc_call_credentials *)emalloc(
sizeof(wrapped_grpc_call_credentials));
memset(intern, 0, sizeof(wrapped_grpc_call_credentials));
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_call_credentials, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call_credentials,
call_credentials_ce_handlers);
}
zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped TSRMLS_DC) {
zval *grpc_php_wrap_call_credentials(grpc_call_credentials
*wrapped TSRMLS_DC) {
zval *credentials_object;
MAKE_STD_ZVAL(credentials_object);
PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
object_init_ex(credentials_object, grpc_ce_call_credentials);
wrapped_grpc_call_credentials *credentials =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
credentials_object TSRMLS_CC);
Z_WRAPPED_GRPC_CALL_CREDS_P(credentials_object);
credentials->wrapped = wrapped;
return credentials_object;
}
@ -114,15 +105,15 @@ PHP_METHOD(CallCredentials, createComposite) {
return;
}
wrapped_grpc_call_credentials *cred1 =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
cred1_obj TSRMLS_CC);
Z_WRAPPED_GRPC_CALL_CREDS_P(cred1_obj);
wrapped_grpc_call_credentials *cred2 =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
cred2_obj TSRMLS_CC);
Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
grpc_call_credentials *creds =
grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -141,13 +132,10 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
memset(fci_cache, 0, sizeof(zend_fcall_info_cache));
/* "f" == 1 function */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", fci,
fci_cache,
fci->params,
fci->param_count) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", fci, fci_cache,
fci->params, fci->param_count) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"createFromPlugin expects 1 callback",
1 TSRMLS_CC);
"createFromPlugin expects 1 callback", 1 TSRMLS_CC);
return;
}
@ -165,9 +153,11 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
plugin.state = (void *)state;
plugin.type = "";
grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
plugin, NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
grpc_call_credentials *creds =
grpc_metadata_credentials_create_from_plugin(plugin, NULL);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -181,17 +171,23 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
/* prepare to call the user callback function with info from the
* grpc_auth_metadata_context */
zval **params[1];
zval *arg;
zval *retval;
MAKE_STD_ZVAL(arg);
PHP_GRPC_MAKE_STD_ZVAL(arg);
object_init(arg);
add_property_string(arg, "service_url", context.service_url, true);
add_property_string(arg, "method_name", context.method_name, true);
php_grpc_add_property_string(arg, "service_url", context.service_url, true);
php_grpc_add_property_string(arg, "method_name", context.method_name, true);
zval *retval;
PHP_GRPC_MAKE_STD_ZVAL(retval);
#if PHP_MAJOR_VERSION < 7
zval **params[1];
params[0] = &arg;
state->fci->param_count = 1;
state->fci->params = params;
state->fci->retval_ptr_ptr = &retval;
#else
state->fci->params = arg;
state->fci->retval = retval;
#endif
state->fci->param_count = 1;
/* call the user callback function */
zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
@ -200,6 +196,7 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
zend_throw_exception(spl_ce_InvalidArgumentException,
"plugin callback must return metadata array",
1 TSRMLS_CC);
return;
}
grpc_metadata_array metadata;
@ -207,6 +204,7 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
zend_throw_exception(spl_ce_InvalidArgumentException,
"invalid metadata", 1 TSRMLS_CC);
grpc_metadata_array_destroy(&metadata);
return;
}
/* TODO: handle error */
@ -229,11 +227,14 @@ static zend_function_entry call_credentials_methods[] = {
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(CallCredentials, createFromPlugin, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END};
PHP_FE_END
};
void grpc_init_call_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
ce.create_object = create_wrapped_grpc_call_credentials;
grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
call_credentials_ce_handlers);
}

@ -51,11 +51,27 @@ extern zend_class_entry *grpc_ce_call_credentials;
/* Wrapper struct for grpc_call_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_call_credentials {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_call_credentials)
grpc_call_credentials *wrapped;
} wrapped_grpc_call_credentials;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_call_credentials)
#if PHP_MAJOR_VERSION < 7
#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv) \
(wrapped_grpc_call_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_call_credentials
*wrapped_grpc_call_credentials_from_obj(zend_object *obj) {
return (wrapped_grpc_call_credentials*)(
(char*)(obj) - XtOffsetOf(wrapped_grpc_call_credentials, std));
}
#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv) \
wrapped_grpc_call_credentials_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Struct to hold callback function for plugin creds API */
typedef struct plugin_state {

@ -56,72 +56,68 @@
#include "timeval.h"
zend_class_entry *grpc_ce_channel;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers channel_ce_handlers;
#endif
/* Frees and destroys an instance of wrapped_grpc_channel */
void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
wrapped_grpc_channel *channel = (wrapped_grpc_channel *)object;
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
if (p->wrapped != NULL) {
grpc_channel_destroy(p->wrapped);
}
efree(channel);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_channel to be associated with an
* object of a class specified by class_type */
zend_object_value create_wrapped_grpc_channel(zend_class_entry *class_type
TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_channel *intern;
intern = (wrapped_grpc_channel *)emalloc(sizeof(wrapped_grpc_channel));
memset(intern, 0, sizeof(wrapped_grpc_channel));
php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
TSRMLS_DC) {
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_channel, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
}
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_DC) {
void php_grpc_read_args_array(zval *args_array,
grpc_channel_args *args TSRMLS_DC) {
HashTable *array_hash;
HashPosition array_pointer;
int args_index;
zval **data;
char *key;
uint key_len;
ulong index;
array_hash = Z_ARRVAL_P(args_array);
if (!array_hash) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"array_hash is NULL", 1 TSRMLS_CC);
return;
}
args->num_args = zend_hash_num_elements(array_hash);
args->args = ecalloc(args->num_args, sizeof(grpc_arg));
args_index = 0;
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void **)&data,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
char *key = NULL;
zval *data;
int key_type;
PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
if (key_type != HASH_KEY_IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"args keys must be strings", 1 TSRMLS_CC);
return;
}
args->args[args_index].key = key;
switch (Z_TYPE_P(*data)) {
case IS_LONG:
args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
args->args[args_index].type = GRPC_ARG_INTEGER;
break;
case IS_STRING:
args->args[args_index].value.string = Z_STRVAL_P(*data);
args->args[args_index].type = GRPC_ARG_STRING;
break;
default:
zend_throw_exception(spl_ce_InvalidArgumentException,
"args values must be int or string", 1 TSRMLS_CC);
return;
switch (Z_TYPE_P(data)) {
case IS_LONG:
args->args[args_index].value.integer = (int)Z_LVAL_P(data);
args->args[args_index].type = GRPC_ARG_INTEGER;
break;
case IS_STRING:
args->args[args_index].value.string = Z_STRVAL_P(data);
args->args[args_index].type = GRPC_ARG_STRING;
break;
default:
zend_throw_exception(spl_ce_InvalidArgumentException,
"args values must be int or string", 1 TSRMLS_CC);
return;
}
args_index++;
}
PHP_GRPC_HASH_FOREACH_END()
}
/**
@ -132,16 +128,15 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_D
* @param array $args The arguments to pass to the Channel (optional)
*/
PHP_METHOD(Channel, __construct) {
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(
getThis() TSRMLS_CC);
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
zval *creds_obj = NULL;
char *target;
int target_length;
php_grpc_int target_length;
zval *args_array = NULL;
grpc_channel_args args;
HashTable *array_hash;
zval **creds_obj = NULL;
wrapped_grpc_channel_credentials *creds = NULL;
/* "sa" == 1 string, 1 array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &target,
&target_length, &args_array) == FAILURE) {
@ -150,21 +145,20 @@ PHP_METHOD(Channel, __construct) {
return;
}
array_hash = Z_ARRVAL_P(args_array);
if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
(void **)&creds_obj) == SUCCESS) {
if (Z_TYPE_P(*creds_obj) == IS_NULL) {
if (Z_TYPE_P(creds_obj) == IS_NULL) {
creds = NULL;
zend_hash_del(array_hash, "credentials", 12);
} else if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
grpc_ce_channel_credentials) {
php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
} else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
grpc_ce_channel_credentials) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"credentials must be a ChannelCredentials object",
1 TSRMLS_CC);
return;
} else {
creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
*creds_obj TSRMLS_CC);
zend_hash_del(array_hash, "credentials", 12);
creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
}
}
php_grpc_read_args_array(args_array, &args TSRMLS_CC);
@ -182,9 +176,8 @@ PHP_METHOD(Channel, __construct) {
* @return string The URI of the endpoint
*/
PHP_METHOD(Channel, getTarget) {
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
PHP_GRPC_RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
}
/**
@ -193,12 +186,12 @@ PHP_METHOD(Channel, getTarget) {
* @return long The grpc connectivity state
*/
PHP_METHOD(Channel, getConnectivityState) {
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
bool try_to_connect;
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
bool try_to_connect = false;
/* "|b" == 1 optional bool */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect) ==
FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect)
== FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"getConnectivityState expects a bool", 1 TSRMLS_CC);
return;
@ -215,28 +208,26 @@ PHP_METHOD(Channel, getConnectivityState) {
* before deadline
*/
PHP_METHOD(Channel, watchConnectivityState) {
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
long last_state;
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
php_grpc_long last_state;
zval *deadline_obj;
/* "lO" == 1 long 1 object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
&last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"watchConnectivityState expects 1 long 1 timeval",
1 TSRMLS_CC);
"watchConnectivityState expects 1 long 1 timeval", 1 TSRMLS_CC);
return;
}
wrapped_grpc_timeval *deadline =
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
grpc_channel_watch_connectivity_state(
channel->wrapped, (grpc_connectivity_state)last_state,
deadline->wrapped, completion_queue, NULL);
grpc_event event = grpc_completion_queue_pluck(
completion_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
grpc_channel_watch_connectivity_state(channel->wrapped,
(grpc_connectivity_state)last_state,
deadline->wrapped, completion_queue,
NULL);
grpc_event event =
grpc_completion_queue_pluck(completion_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
RETURN_BOOL(event.success);
}
@ -244,8 +235,7 @@ PHP_METHOD(Channel, watchConnectivityState) {
* Close the channel
*/
PHP_METHOD(Channel, close) {
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
channel->wrapped = NULL;
@ -253,16 +243,18 @@ PHP_METHOD(Channel, close) {
}
static zend_function_entry channel_methods[] = {
PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END};
PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END
};
void grpc_init_channel(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
ce.create_object = create_wrapped_grpc_channel;
grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
}

@ -49,16 +49,33 @@
extern zend_class_entry *grpc_ce_channel;
/* Wrapper struct for grpc_channel that can be associated with a PHP object */
typedef struct wrapped_grpc_channel {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_channel)
grpc_channel *wrapped;
} wrapped_grpc_channel;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_channel)
#if PHP_MAJOR_VERSION < 7
#define Z_WRAPPED_GRPC_CHANNEL_P(zv) \
(wrapped_grpc_channel *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_channel
*wrapped_grpc_channel_from_obj(zend_object *obj) {
return (wrapped_grpc_channel*)((char*)(obj) -
XtOffsetOf(wrapped_grpc_channel, std));
}
#define Z_WRAPPED_GRPC_CHANNEL_P(zv) \
wrapped_grpc_channel_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the Channel class */
void grpc_init_channel(TSRMLS_D);
/* Iterates through a PHP array and populates args with the contents */
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_DC);
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args
TSRMLS_DC);
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */

@ -52,7 +52,9 @@
#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_channel_credentials;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers channel_credentials_ce_handlers;
#endif
static char *default_pem_root_certs = NULL;
static grpc_ssl_roots_override_result get_ssl_roots_override(
@ -65,42 +67,30 @@ static grpc_ssl_roots_override_result get_ssl_roots_override(
}
/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
wrapped_grpc_channel_credentials *creds =
(wrapped_grpc_channel_credentials *)object;
if (creds->wrapped != NULL) {
grpc_channel_credentials_release(creds->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel_credentials)
if (p->wrapped != NULL) {
grpc_channel_credentials_release(p->wrapped);
}
efree(creds);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_channel_credentials to be
* associated with an object of a class specified by class_type */
zend_object_value create_wrapped_grpc_channel_credentials(
php_grpc_zend_object create_wrapped_grpc_channel_credentials(
zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_channel_credentials *intern;
intern = (wrapped_grpc_channel_credentials *)emalloc(
sizeof(wrapped_grpc_channel_credentials));
memset(intern, 0, sizeof(wrapped_grpc_channel_credentials));
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel_credentials);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_channel_credentials, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel_credentials,
channel_credentials_ce_handlers);
}
zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS_DC) {
zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials
*wrapped TSRMLS_DC) {
zval *credentials_object;
MAKE_STD_ZVAL(credentials_object);
PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
object_init_ex(credentials_object, grpc_ce_channel_credentials);
wrapped_grpc_channel_credentials *credentials =
(wrapped_grpc_channel_credentials *)zend_object_store_get_object(
credentials_object TSRMLS_CC);
Z_WRAPPED_GRPC_CHANNEL_CREDS_P(credentials_object);
credentials->wrapped = wrapped;
return credentials_object;
}
@ -112,7 +102,9 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
*/
PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
char *pem_roots;
int pem_roots_length;
php_grpc_int pem_roots_length;
/* "s" == 1 string */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pem_roots,
&pem_roots_length) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
@ -129,7 +121,9 @@ PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
*/
PHP_METHOD(ChannelCredentials, createDefault) {
grpc_channel_credentials *creds = grpc_google_default_credentials_create();
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -146,11 +140,13 @@ PHP_METHOD(ChannelCredentials, createSsl) {
char *pem_root_certs = NULL;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
php_grpc_int root_certs_length = 0;
php_grpc_int private_key_length = 0;
php_grpc_int cert_chain_length = 0;
pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
/* "|s!s!s! == 3 optional nullable strings */
/* "|s!s!s!" == 3 optional nullable strings */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!",
&pem_root_certs, &root_certs_length,
&pem_key_cert_pair.private_key,
@ -164,7 +160,9 @@ PHP_METHOD(ChannelCredentials, createSsl) {
grpc_channel_credentials *creds = grpc_ssl_credentials_create(
pem_root_certs,
pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -178,7 +176,7 @@ PHP_METHOD(ChannelCredentials, createComposite) {
zval *cred1_obj;
zval *cred2_obj;
/* "OO" == 3 Objects */
/* "OO" == 2 Objects */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
grpc_ce_channel_credentials, &cred2_obj,
grpc_ce_call_credentials) == FAILURE) {
@ -187,15 +185,15 @@ PHP_METHOD(ChannelCredentials, createComposite) {
return;
}
wrapped_grpc_channel_credentials *cred1 =
(wrapped_grpc_channel_credentials *)zend_object_store_get_object(
cred1_obj TSRMLS_CC);
Z_WRAPPED_GRPC_CHANNEL_CREDS_P(cred1_obj);
wrapped_grpc_call_credentials *cred2 =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
cred2_obj TSRMLS_CC);
Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
grpc_channel_credentials *creds =
grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
NULL);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
@ -218,7 +216,8 @@ static zend_function_entry channel_credentials_methods[] = {
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(ChannelCredentials, createInsecure, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END};
PHP_FE_END
};
void grpc_init_channel_credentials(TSRMLS_D) {
zend_class_entry ce;
@ -227,4 +226,6 @@ void grpc_init_channel_credentials(TSRMLS_D) {
grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
ce.create_object = create_wrapped_grpc_channel_credentials;
grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel_credentials,
channel_credentials_ce_handlers);
}

@ -51,11 +51,27 @@ extern zend_class_entry *grpc_ce_channel_credentials;
/* Wrapper struct for grpc_channel_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_channel_credentials {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_channel_credentials)
grpc_channel_credentials *wrapped;
} wrapped_grpc_channel_credentials;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_channel_credentials)
#if PHP_MAJOR_VERSION < 7
#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv) \
(wrapped_grpc_channel_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_channel_credentials
*wrapped_grpc_channel_credentials_from_obj(zend_object *obj) {
return (wrapped_grpc_channel_credentials *)(
(char*)(obj) - XtOffsetOf(wrapped_grpc_channel_credentials, std));
}
#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv) \
wrapped_grpc_channel_credentials_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the ChannelCredentials PHP class */
void grpc_init_channel_credentials(TSRMLS_D);

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
<name>grpc</name>
<channel>pecl.php.net</channel>
<summary>A high performance, open source, general RPC framework that puts mobile and HTTP/2 first.</summary>
<description>Remote Procedure Calls (RPCs) provide a useful abstraction for building distributed applications and services. The libraries in this repository provide a concrete implementation of the gRPC protocol, layered over HTTP/2. These libraries enable communication between clients and servers using any combination of the supported languages.</description>
<lead>
<name>Stanley Cheung</name>
<user>stanleycheung</user>
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
<date>2016-01-13</date>
<time>16:06:07</time>
<version>
<release>0.7.0</release>
<api>0.7.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license>BSD</license>
<notes>
- Breaking change to Credentials class (removed) #3765
- Replaced by ChannelCredentials and CallCredentials class #3765
- New plugin based metadata auth API #4394
- Explicit ChannelCredentials::createInsecure() call
</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file baseinstalldir="/" md5sum="f201d644fdbd8228ffd1d4a69cc44f1f" name="tests/grpc-basic.phpt" role="test" />
<file baseinstalldir="/" md5sum="6f19828fb869b7b8a590cbb76b4f996d" name="byte_buffer.c" role="src" />
<file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" />
<file baseinstalldir="/" md5sum="ee7eb7757f9e6f0e36f8f616b6bd0af5" name="call.c" role="src" />
<file baseinstalldir="/" md5sum="44c56bd9912d2538cbd6059e3e0452b6" name="call.h" role="src" />
<file baseinstalldir="/" md5sum="ff90f6c03ed44b5f4170bf3259a6704e" name="call_credentials.c" role="src" />
<file baseinstalldir="/" md5sum="3c3860e1d84f43cb6b2fbaa8d2ae1ab7" name="call_credentials.h" role="src" />
<file baseinstalldir="/" md5sum="aee9b63f790522aec2c682055240cc61" name="channel.c" role="src" />
<file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
<file baseinstalldir="/" md5sum="1a51c76d0b7b7d3ab570ed7d60c2ea46" name="channel_credentials.c" role="src" />
<file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" />
<file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
<file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
<file baseinstalldir="/" md5sum="cafed254127007ff2271dad7d56a06c8" name="config.m4" role="src" />
<file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
<file baseinstalldir="/" md5sum="8847cf67b1b54c981d47ecbb0d139a0c" name="LICENSE" role="doc" />
<file baseinstalldir="/" md5sum="3131a8af38fe5918e5409016b89d6cdb" name="php_grpc.c" role="src" />
<file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
<file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
<file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
<file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
<file baseinstalldir="/" md5sum="34ea881f1fe960d190d0713422cf8916" name="server_credentials.c" role="src" />
<file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
<file baseinstalldir="/" md5sum="7646ec78cb133f66ba59e03c6f451e39" name="timeval.c" role="src" />
<file baseinstalldir="/" md5sum="496e27a100b4d93ca3fb35c924c5e163" name="timeval.h" role="src" />
</dir>
</contents>
<dependencies>
<required>
<php>
<min>5.5.0</min>
</php>
<pearinstaller>
<min>1.4.0</min>
</pearinstaller>
</required>
</dependencies>
<providesextension>grpc</providesextension>
<extsrcrelease />
<changelog>
<release>
<version>
<release>0.5.0</release>
<api>0.5.0</api>
</version>
<stability>
<release>alpha</release>
<api>alpha</api>
</stability>
<date>2015-06-16</date>
<license>BSD</license>
<notes>
First alpha release
</notes>
</release>
<release>
<version>
<release>0.5.1</release>
<api>0.5.1</api>
</version>
<stability>
<release>alpha</release>
<api>alpha</api>
</stability>
<date>2015-07-09</date>
<license>BSD</license>
<notes>
Update to wrap gRPC C Core version 0.10.0
</notes>
</release>
<release>
<version>
<release>0.6.0</release>
<api>0.6.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2015-09-24</date>
<license>BSD</license>
<notes>
- support per message compression disable
- expose per-call host override option
- expose connectivity API
- expose channel target and call peer
- add user-agent
- update to wrap gRPC C core library beta version 0.11.0
</notes>
</release>
<release>
<version>
<release>0.6.1</release>
<api>0.6.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2015-10-21</date>
<license>BSD</license>
<notes>
- fixed undefined constant fatal error when run with apache/nginx #2275
</notes>
</release>
<release>
<version>
<release>0.7.0</release>
<api>0.7.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2016-01-13</date>
<license>BSD</license>
<notes>
- Breaking change to Credentials class (removed) #3765
- Replaced by ChannelCredentials and CallCredentials class #3765
- New plugin based metadata auth API #4394
- Explicit ChannelCredentials::createInsecure() call
</notes>
</release>
</changelog>
</package>

@ -0,0 +1,218 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef PHP7_WRAPPER_GRPC_H
#define PHP7_WRAPPER_GRPC_H
#if PHP_MAJOR_VERSION < 7
#define php_grpc_int int
#define php_grpc_long long
#define php_grpc_ulong ulong
#define php_grpc_zend_object zend_object_value
#define php_grpc_add_property_string(arg, name, context, b) \
add_property_string(arg, name, context, b)
#define php_grpc_add_property_stringl(res, name, str, len, b) \
add_property_stringl(res, name, str, len, b)
#define php_grpc_add_next_index_stringl(data, str, len, b) \
add_next_index_stringl(data, str, len, b)
#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
#define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
#define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
#define PHP_GRPC_WRAP_OBJECT_START(name) \
typedef struct name { \
zend_object std;
#define PHP_GRPC_WRAP_OBJECT_END(name) \
} name;
#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
void free_##class_object(void *object TSRMLS_DC) { \
class_object *p = (class_object *)object;
#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
zend_object_std_dtor(&p->std TSRMLS_CC); \
efree(p); \
}
#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
class_object *intern; \
zend_object_value retval; \
intern = (class_object *)emalloc(sizeof(class_object)); \
memset(intern, 0, sizeof(class_object));
#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
retval.handle = zend_objects_store_put( \
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \
free_##class_object, NULL TSRMLS_CC); \
retval.handlers = zend_get_std_object_handlers(); \
return retval;
#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
zval **tmp_data = NULL; \
for (zend_hash_internal_pointer_reset(ht); \
zend_hash_get_current_data(ht, (void**)&tmp_data) == SUCCESS; \
zend_hash_move_forward(ht)) { \
data = *tmp_data;
#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
zval **tmp##key = NULL; \
ulong index##key; \
uint len##key; \
for (zend_hash_internal_pointer_reset(ht); \
zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
zend_hash_move_forward(ht)) { \
key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index##key,\
0, NULL); \
data = *tmp##key;
#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index,\
data) \
zval **tmp##key = NULL; \
uint len##key; \
for (zend_hash_internal_pointer_reset(ht); \
zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
zend_hash_move_forward(ht)) { \
key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index,\
0, NULL); \
data = *tmp##key;
#define PHP_GRPC_HASH_FOREACH_END() }
static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
void **value) {
zval **data = NULL;
if (zend_hash_find(ht, key, len, (void **)&data) == SUCCESS) {
*value = *data;
return SUCCESS;
} else {
*value = NULL;
return FAILURE;
}
}
#define php_grpc_zend_hash_del zend_hash_del
#define PHP_GRPC_GET_CLASS_ENTRY(object) zend_get_class_entry(object TSRMLS_CC)
#define PHP_GRPC_INIT_HANDLER(class_object, handler_name)
#else
#define php_grpc_int size_t
#define php_grpc_long zend_long
#define php_grpc_ulong zend_ulong
#define php_grpc_zend_object zend_object*
#define php_grpc_add_property_string(arg, name, context, b) \
add_property_string(arg, name, context)
#define php_grpc_add_property_stringl(res, name, str, len, b) \
add_property_stringl(res, name, str, len)
#define php_grpc_add_next_index_stringl(data, str, len, b) \
add_next_index_stringl(data, str, len)
#define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val)
#define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
zval _stack_zval_##pzv; \
pzv = &(_stack_zval_##pzv)
#define PHP_GRPC_DELREF(zv)
#define PHP_GRPC_WRAP_OBJECT_START(name) \
typedef struct name {
#define PHP_GRPC_WRAP_OBJECT_END(name) \
zend_object std; \
} name;
#define WRAPPED_OBJECT_FROM_OBJ(class_object, obj) \
class_object##_from_obj(obj);
#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
static void free_##class_object(zend_object *object) { \
class_object *p = WRAPPED_OBJECT_FROM_OBJ(class_object, object)
#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
zend_object_std_dtor(&p->std); \
}
#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
class_object *intern; \
intern = ecalloc(1, sizeof(class_object) + \
zend_object_properties_size(class_type));
#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
intern->std.handlers = &handler; \
return &intern->std;
#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
ZEND_HASH_FOREACH_VAL(ht, data) {
#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
zend_string *(zs_##key); \
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, (zs_##key), data) { \
if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index, \
data) \
zend_string *(zs_##key); \
ZEND_HASH_FOREACH_KEY_VAL(ht, index, zs_##key, data) { \
if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
#define PHP_GRPC_HASH_FOREACH_END() } ZEND_HASH_FOREACH_END();
static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
void **value) {
zval *value_tmp = zend_hash_str_find(ht, key, len -1);
if (value_tmp == NULL) {
return FAILURE;
} else {
*value = (void *)value_tmp;
return SUCCESS;
}
}
static inline int php_grpc_zend_hash_del(HashTable *ht, char *key, int len) {
return zend_hash_str_del(ht, key, len - 1);
}
#define PHP_GRPC_GET_CLASS_ENTRY(object) Z_OBJ_P(object)->ce
#define PHP_GRPC_INIT_HANDLER(class_object, handler_name) \
memcpy(&handler_name, zend_get_std_object_handlers(), \
sizeof(zend_object_handlers)); \
handler_name.offset = XtOffsetOf(class_object, std); \
handler_name.free_obj = free_##class_object
#endif /* PHP_MAJOR_VERSION */
#endif /* PHP7_WRAPPER_GRPC_H */

@ -64,15 +64,19 @@ const zend_function_entry grpc_functions[] = {
*/
zend_module_entry grpc_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
STANDARD_MODULE_HEADER,
#endif
"grpc", grpc_functions, PHP_MINIT(grpc),
PHP_MSHUTDOWN(grpc), NULL, NULL,
PHP_MINFO(grpc),
"grpc",
grpc_functions,
PHP_MINIT(grpc),
PHP_MSHUTDOWN(grpc),
NULL,
NULL,
PHP_MINFO(grpc),
#if ZEND_MODULE_API_NO >= 20010901
PHP_GRPC_VERSION,
PHP_GRPC_VERSION,
#endif
STANDARD_MODULE_PROPERTIES};
STANDARD_MODULE_PROPERTIES};
/* }}} */
#ifdef COMPILE_DL_GRPC
@ -82,23 +86,24 @@ ZEND_GET_MODULE(grpc)
/* {{{ PHP_INI
*/
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong,
global_value, zend_grpc_globals, grpc_globals)
STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
OnUpdateString, global_string, zend_grpc_globals, grpc_globals)
PHP_INI_END()
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong,
global_value, zend_grpc_globals, grpc_globals)
STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
OnUpdateString, global_string, zend_grpc_globals,
grpc_globals)
PHP_INI_END()
*/
/* }}} */
/* {{{ php_grpc_init_globals
*/
/* Uncomment this function if you have INI entries
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
{
grpc_globals->global_value = 0;
grpc_globals->global_string = NULL;
}
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
{
grpc_globals->global_value = 0;
grpc_globals->global_string = NULL;
}
*/
/* }}} */
@ -106,7 +111,7 @@ static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
*/
PHP_MINIT_FUNCTION(grpc) {
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
REGISTER_INI_ENTRIES();
*/
/* Register call error constants */
grpc_init();
@ -246,7 +251,7 @@ PHP_MINIT_FUNCTION(grpc) {
*/
PHP_MSHUTDOWN_FUNCTION(grpc) {
/* uncomment this line if you have INI entries
UNREGISTER_INI_ENTRIES();
UNREGISTER_INI_ENTRIES();
*/
// WARNING: This function IS being called by PHP when the extension
// is unloaded but the logs were somehow suppressed.
@ -265,7 +270,7 @@ PHP_MINFO_FUNCTION(grpc) {
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
@ -274,12 +279,3 @@ PHP_MINFO_FUNCTION(grpc) {
function definition, where the functions purpose is also documented. Please
follow this convention for the convenience of others editing your code.
*/
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

@ -57,6 +57,8 @@ extern zend_module_entry grpc_module_entry;
#include "php.h"
#include "php7_wrapper.h"
#include "grpc/grpc.h"
#define RETURN_DESTROY_ZVAL(val) \
@ -72,8 +74,8 @@ PHP_MSHUTDOWN_FUNCTION(grpc);
PHP_MINFO_FUNCTION(grpc);
/*
Declare any global variables you may need between the BEGIN
and END macros here:
Declare any global variables you may need between the BEGIN
and END macros here:
ZEND_BEGIN_MODULE_GLOBALS(grpc)
ZEND_END_MODULE_GLOBALS(grpc)

@ -57,37 +57,29 @@
#include "timeval.h"
zend_class_entry *grpc_ce_server;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers server_ce_handlers;
#endif
/* Frees and destroys an instance of wrapped_grpc_server */
void free_wrapped_grpc_server(void *object TSRMLS_DC) {
wrapped_grpc_server *server = (wrapped_grpc_server *)object;
if (server->wrapped != NULL) {
grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
grpc_server_cancel_all_calls(server->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server)
if (p->wrapped != NULL) {
grpc_server_shutdown_and_notify(p->wrapped, completion_queue, NULL);
grpc_server_cancel_all_calls(p->wrapped);
grpc_completion_queue_pluck(completion_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
grpc_server_destroy(server->wrapped);
grpc_server_destroy(p->wrapped);
}
efree(server);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_call to be associated with an object
* of a class specified by class_type */
zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_server *intern;
intern = (wrapped_grpc_server *)emalloc(sizeof(wrapped_grpc_server));
memset(intern, 0, sizeof(wrapped_grpc_server));
php_grpc_zend_object create_wrapped_grpc_server(zend_class_entry *class_type
TSRMLS_DC) {
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_server, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server, server_ce_handlers);
}
/**
@ -95,10 +87,10 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
* @param array $args The arguments to pass to the server (optional)
*/
PHP_METHOD(Server, __construct) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
zval *args_array = NULL;
grpc_channel_args args;
/* "|a" == 1 optional array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) ==
FAILURE) {
@ -110,6 +102,8 @@ PHP_METHOD(Server, __construct) {
if (args_array == NULL) {
server->wrapped = grpc_server_create(NULL, NULL);
} else {
//TODO(thinkerou): deal it if key of array is long, crash now on php7
// and update unit test case
php_grpc_read_args_array(args_array, &args TSRMLS_CC);
server->wrapped = grpc_server_create(&args, NULL);
efree(args.args);
@ -126,15 +120,16 @@ PHP_METHOD(Server, __construct) {
*/
PHP_METHOD(Server, requestCall) {
grpc_call_error error_code;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_call *call;
grpc_call_details details;
grpc_metadata_array metadata;
zval *result;
grpc_event event;
MAKE_STD_ZVAL(result);
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
zval *result;
PHP_GRPC_MAKE_STD_ZVAL(result);
object_init(result);
grpc_call_details_init(&details);
grpc_metadata_array_init(&metadata);
error_code =
@ -146,20 +141,37 @@ PHP_METHOD(Server, requestCall) {
goto cleanup;
}
event = grpc_completion_queue_pluck(completion_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
gpr_inf_future(GPR_CLOCK_REALTIME),
NULL);
if (!event.success) {
zend_throw_exception(spl_ce_LogicException,
"Failed to request a call for some reason",
1 TSRMLS_CC);
goto cleanup;
}
php_grpc_add_property_string(result, "method", details.method, true);
php_grpc_add_property_string(result, "host", details.host, true);
#if PHP_MAJOR_VERSION < 7
add_property_zval(result, "call", grpc_php_wrap_call(call, true TSRMLS_CC));
add_property_string(result, "method", details.method, true);
add_property_string(result, "host", details.host, true);
add_property_zval(result, "absolute_deadline",
grpc_php_wrap_timeval(details.deadline TSRMLS_CC));
add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata TSRMLS_CC));
cleanup:
add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata
TSRMLS_CC));
#else
zval zv_call;
zval zv_timeval;
zval zv_md;
//TODO(thinkerou): why use zval* to unit test error?
zv_call = *grpc_php_wrap_call(call, true);
zv_timeval = *grpc_php_wrap_timeval(details.deadline);
zv_md = *grpc_parse_metadata_array(&metadata);
add_property_zval(result, "call", &zv_call);
add_property_zval(result, "absolute_deadline", &zv_timeval);
add_property_zval(result, "metadata", &zv_md);
#endif
cleanup:
grpc_call_details_destroy(&details);
grpc_metadata_array_destroy(&metadata);
RETURN_DESTROY_ZVAL(result);
@ -171,13 +183,13 @@ cleanup:
* @return true on success, false on failure
*/
PHP_METHOD(Server, addHttp2Port) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
int addr_len;
php_grpc_int addr_len;
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
/* "s" == 1 string */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len) ==
FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len)
== FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"add_http2_port expects a string", 1 TSRMLS_CC);
return;
@ -186,11 +198,11 @@ PHP_METHOD(Server, addHttp2Port) {
}
PHP_METHOD(Server, addSecureHttp2Port) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
int addr_len;
php_grpc_int addr_len;
zval *creds_obj;
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
/* "sO" == 1 string, 1 object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
&creds_obj, grpc_ce_server_credentials) ==
@ -201,8 +213,7 @@ PHP_METHOD(Server, addSecureHttp2Port) {
return;
}
wrapped_grpc_server_credentials *creds =
(wrapped_grpc_server_credentials *)zend_object_store_get_object(
creds_obj TSRMLS_CC);
Z_WRAPPED_GRPC_SERVER_CREDS_P(creds_obj);
RETURN_LONG(grpc_server_add_secure_http2_port(server->wrapped, addr,
creds->wrapped));
}
@ -212,21 +223,23 @@ PHP_METHOD(Server, addSecureHttp2Port) {
* @return Void
*/
PHP_METHOD(Server, start) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
grpc_server_start(server->wrapped);
}
static zend_function_entry server_methods[] = {
PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END
};
void grpc_init_server(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods);
ce.create_object = create_wrapped_grpc_server;
grpc_ce_server = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_server, server_ce_handlers);
}

@ -49,11 +49,26 @@
extern zend_class_entry *grpc_ce_server;
/* Wrapper struct for grpc_server that can be associated with a PHP object */
typedef struct wrapped_grpc_server {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_server)
grpc_server *wrapped;
} wrapped_grpc_server;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_server)
#if PHP_MAJOR_VERSION < 7
#define Z_WRAPPED_GRPC_SERVER_P(zv) \
(wrapped_grpc_server *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_server
*wrapped_grpc_server_from_obj(zend_object *obj) {
return (wrapped_grpc_server*)((char*)(obj) -
XtOffsetOf(wrapped_grpc_server, std));
}
#define Z_WRAPPED_GRPC_SERVER_P(zv) wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the Server class */
void grpc_init_server(TSRMLS_D);

@ -50,44 +50,35 @@
#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_server_credentials;
#if PHP_MAJOR_VERSION >= 7
static zend_object_handlers server_credentials_ce_handlers;
#endif
/* Frees and destroys an instace of wrapped_grpc_server_credentials */
void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
wrapped_grpc_server_credentials *creds =
(wrapped_grpc_server_credentials *)object;
if (creds->wrapped != NULL) {
grpc_server_credentials_release(creds->wrapped);
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server_credentials)
if (p->wrapped != NULL) {
grpc_server_credentials_release(p->wrapped);
}
efree(creds);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instace of wrapped_grpc_server_credentials to be associated
* with an object of a class specified by class_type */
zend_object_value create_wrapped_grpc_server_credentials(
php_grpc_zend_object create_wrapped_grpc_server_credentials(
zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_server_credentials *intern;
intern = (wrapped_grpc_server_credentials *)emalloc(
sizeof(wrapped_grpc_server_credentials));
memset(intern, 0, sizeof(wrapped_grpc_server_credentials));
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server_credentials);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
free_wrapped_grpc_server_credentials, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server_credentials,
server_credentials_ce_handlers);
}
zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped TSRMLS_DC) {
zval *grpc_php_wrap_server_credentials(grpc_server_credentials
*wrapped TSRMLS_DC) {
zval *server_credentials_object;
MAKE_STD_ZVAL(server_credentials_object);
PHP_GRPC_MAKE_STD_ZVAL(server_credentials_object);
object_init_ex(server_credentials_object, grpc_ce_server_credentials);
wrapped_grpc_server_credentials *server_credentials =
(wrapped_grpc_server_credentials *)zend_object_store_get_object(
server_credentials_object TSRMLS_CC);
Z_WRAPPED_GRPC_SERVER_CREDS_P(server_credentials_object);
server_credentials->wrapped = wrapped;
return server_credentials_object;
}
@ -103,7 +94,9 @@ PHP_METHOD(ServerCredentials, createSsl) {
char *pem_root_certs = 0;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
int root_certs_length = 0, private_key_length, cert_chain_length;
php_grpc_int root_certs_length = 0;
php_grpc_int private_key_length;
php_grpc_int cert_chain_length;
/* "s!ss" == 1 nullable string, 2 strings */
/* TODO: support multiple key cert pairs. */
@ -120,17 +113,23 @@ PHP_METHOD(ServerCredentials, createSsl) {
grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex(
pem_root_certs, &pem_key_cert_pair, 1,
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, NULL);
zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
zval *creds_object;
PHP_GRPC_MAKE_STD_ZVAL(creds_object);
creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
static zend_function_entry server_credentials_methods[] = {
PHP_ME(ServerCredentials, createSsl, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
PHP_ME(ServerCredentials, createSsl, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
void grpc_init_server_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\ServerCredentials", server_credentials_methods);
ce.create_object = create_wrapped_grpc_server_credentials;
grpc_ce_server_credentials = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_server_credentials,
server_credentials_ce_handlers);
}

@ -51,11 +51,27 @@ extern zend_class_entry *grpc_ce_server_credentials;
/* Wrapper struct for grpc_server_credentials that can be associated with a PHP
* object */
typedef struct wrapped_grpc_server_credentials {
zend_object std;
PHP_GRPC_WRAP_OBJECT_START(wrapped_grpc_server_credentials)
grpc_server_credentials *wrapped;
} wrapped_grpc_server_credentials;
PHP_GRPC_WRAP_OBJECT_END(wrapped_grpc_server_credentials)
#if PHP_MAJOR_VERSION < 7
#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv) \
(wrapped_grpc_server_credentials *)zend_object_store_get_object(zv TSRMLS_CC)
#else
static inline wrapped_grpc_server_credentials
*wrapped_grpc_server_credentials_from_obj(zend_object *obj) {
return (wrapped_grpc_server_credentials*)(
(char*)(obj) - XtOffsetOf(wrapped_grpc_server_credentials, std));
}
#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv) \
wrapped_grpc_server_credentials_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the Server_Credentials PHP class */
void grpc_init_server_credentials(TSRMLS_D);

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

Loading…
Cancel
Save