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

pull/7395/head
Mark D. Roth 8 years ago
commit 3b17e44eb3
  1. BIN
      doc/images/load_balancing_design.png
  2. 75
      doc/load-balancing.md
  3. 24
      gRPC-Core.podspec
  4. 2
      src/core/ext/client_config/channel_connectivity.c
  5. 394
      src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
  6. 24
      src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
  7. 12
      src/objective-c/tests/Podfile
  8. 168
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  9. 99
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
  10. 692
      src/php/ext/grpc/call.c
  11. 36
      src/php/ext/grpc/call.h
  12. 103
      src/php/ext/grpc/call_credentials.c
  13. 23
      src/php/ext/grpc/call_credentials.h
  14. 194
      src/php/ext/grpc/channel.c
  15. 23
      src/php/ext/grpc/channel.h
  16. 92
      src/php/ext/grpc/channel_credentials.c
  17. 23
      src/php/ext/grpc/channel_credentials.h
  18. 54
      src/php/ext/grpc/php_grpc.c
  19. 4
      src/php/ext/grpc/php_grpc.h
  20. 136
      src/php/ext/grpc/server.c
  21. 20
      src/php/ext/grpc/server.h
  22. 67
      src/php/ext/grpc/server_credentials.c
  23. 20
      src/php/ext/grpc/server_credentials.h
  24. 144
      src/php/ext/grpc/timeval.c
  25. 23
      src/php/ext/grpc/timeval.h
  26. 4
      src/php/lib/Grpc/BaseStub.php
  27. 1
      src/php/lib/Grpc/BidiStreamingCall.php
  28. 1
      src/php/lib/Grpc/ClientStreamingCall.php
  29. 1
      src/php/lib/Grpc/ServerStreamingCall.php
  30. 1
      src/php/lib/Grpc/UnaryCall.php
  31. 3
      src/php/tests/unit_tests/CallCredentialsTest.php
  32. 49
      src/php/tests/unit_tests/CallTest.php
  33. 25
      src/php/tests/unit_tests/ChannelCredentialsTest.php
  34. 107
      src/php/tests/unit_tests/ChannelTest.php
  35. 3
      src/php/tests/unit_tests/EndToEndTest.php
  36. 0
      src/php/tests/unit_tests/SecureEndToEndTest.php
  37. 85
      src/php/tests/unit_tests/ServerTest.php
  38. 53
      src/php/tests/unit_tests/TimevalTest.php
  39. 24
      templates/gRPC-Core.podspec.template

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@ -4,7 +4,7 @@ Load Balancing in gRPC
# Objective
To design a load balancing API between a gRPC client and a Load Balancer to
instruct the client how to send load to multiple backend servers.
instruct the client how to send load to multiple backend servers.
# Background
@ -19,7 +19,7 @@ have temporary copies of the RPC request and response. This model also increases
latency to the RPCs.
The proxy model was deemed inefficient when considering request heavy services
like storage.
like storage.
### Balancing-aware Client
@ -28,7 +28,7 @@ example, the client could contain many load balancing policies (Round Robin,
Random, etc) used to select servers from a list. In this model, a list of
servers would be either statically configured in the client, provided by the
name resolution system, an external load balancer, etc. In any case, the client
is responsible for choosing the preferred server from the list.
is responsible for choosing the preferred server from the list.
One of the drawbacks of this approach is writing and maintaining the load
balancing policies in multiple languages and/or versions of the clients. These
@ -53,14 +53,69 @@ unavailability or health issues. The load balancer will make any necessary
complex decisions and inform the client. The load balancer may communicate with
the backend servers to collect load and health information.
## Requirements
#### Simple API and client
The gRPC client load balancing code must be simple and portable. The client
should only contain simple algorithms (ie Round Robin) for server selection. For
complex algorithms, the client should rely on a load balancer to provide load
balancing configuration and the list of servers to which the client should send
requests. The balancer will update the server list as needed to balance the load
as well as handle server unavailability or health issues. The load balancer will
make any necessary complex decisions and inform the client. The load balancer
may communicate with the backend servers to collect load and health information.
#### Security
The load balancer may be separate from the actual server backends and a
compromise of the load balancer should only lead to a compromise of the
loadbalancing functionality. In other words, a compromised load balancer should
not be able to cause a client to trust a (potentially malicious) backend server
any more than in a comparable situation without loadbalancing.
# Proposed Architecture
The gRPC load balancing approach follows the third approach, by having an
external load balancer which provides simple clients with a list of servers.
The gRPC load balancing implements the external load balancing server approach:
an external load balancer provides simple clients with an up-to-date list of
servers.
![image](images/load_balancing_design.png)
1. On startup, the gRPC client issues a name resolution request for the service.
The name will resolve to one or more IP addresses to gRPC servers, a hint on
whether the IP address(es) point to a load balancer or not, and also return a
client config.
2. The gRPC client connects to a gRPC Server.
1. If the name resolution has hinted that the endpoint is a load balancer,
the client's gRPC LB policy will attempt to open a stream to the load
balancer service. The server may respond in only one of the following
ways.
1. `status::UNIMPLEMENTED`. There is no loadbalancing in use. The client
call will fail.
2. "I am a Load Balancer and here is the server list." (Goto Step 4.)
3. "Please contact Load Balancer X" (See Step 3.) The client will close
this connection and cancel the stream.
4. If the server fails to respond, the client will wait for some timeout
and then re-resolve the name (process to Step 1 above).
2. If the name resolution has not hinted that the endpoint is a load
balancer, the client connects directly to the service it wants to talk to.
3. The gRPC client's gRPC LB policy opens a separate connection to the Load
Balancer. If this fails, it will go back to step 1 and try another address.
1. During channel initialization to the Load Balancer, the client will
attempt to open a stream to the Load Balancer service.
2. The Load Balancer will return a server list to the gRPC client. If the
server list is empty, the call will wait until a non-empty one is
received. Optional: The Load Balancer will also open channels to the gRPC
servers if load reporting is needed.
4. The gRPC client will send RPCs to the gRPC servers contained in the server
list from the Load Balancer.
5. Optional: The gRPC servers may periodically report load to the Load Balancer.
## Client
When establishing a gRPC stream to the balancer, the client will send an initial
When establishing a gRPC _stream_ to the balancer, the client will send an initial
request to the load balancer (via a regular gRPC message). The load balancer
will respond with client config (including, for example, settings for flow
control, RPC deadlines, etc.) or a redirect to another load balancer. If the
@ -87,11 +142,3 @@ balancer in order to compute the next list of servers.
The gRPC Server is responsible for answering RPC requests and providing
responses to the client. The server will also report load to the load balancer
if a reporting stream was opened for this purpose.
### Security
The load balancer may be separate from the actual server backends and a
compromise of the load balancer should only lead to a compromise of the
loadbalancing functionality. In other words, a compromised load balancer should
not be able to cause a client to trust a (potentially malicious) backend server
any more than in a comparable situation without loadbalancing.

@ -101,6 +101,8 @@ Pod::Spec.new do |s|
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
}
s.default_subspecs = 'Interface', 'Implementation'
# Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
# sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't
# allow any header to be listed outside the `header_mappings_dir` (even though doing so works in
@ -762,4 +764,26 @@ Pod::Spec.new do |s|
'src/core/ext/census/mlog.h',
'src/core/ext/census/rpc_metric_id.h'
end
s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpc'
ss.source_files = 'include/grpc/grpc_cronet.h'
end
s.subspec 'Cronet-Tests' do |ss|
ss.header_mappings_dir = '.'
ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
'src/core/ext/transport/cronet/transport/cronet_transport.c',
'test/core/end2end/cq_verifier.{c,h}',
'test/core/end2end/end2end_tests.{c,h}',
'test/core/end2end/tests/*.{c,h}',
'test/core/end2end/data/*.{c,h}',
'test/core/util/test_config.{c,h}',
'test/core/util/port.h',
'test/core/util/port_posix.c',
'test/core/util/port_server_client.{c,h}'
ss.dependency 'CronetFramework'
end
end

@ -59,7 +59,7 @@ grpc_connectivity_state grpc_channel_check_connectivity_state(
}
gpr_log(GPR_ERROR,
"grpc_channel_check_connectivity_state called on something that is "
"not a (u)client channel, but '%s'",
"not a client channel, but '%s'",
client_channel_elem->filter->name);
grpc_exec_ctx_finish(&exec_ctx);
return GRPC_CHANNEL_SHUTDOWN;

@ -0,0 +1,394 @@
/*
*
* 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.
*
*/
/*
* This test file is derived from fixture h2_ssl.c in core end2end test
* (test/core/end2end/fixture/h2_ssl.c). The structure of the fixture is
* preserved as much as possible
*
* This fixture creates a server full stack using chttp2 and a client
* full stack using Cronet. End-to-end tests are run against this
* configuration
*
*/
#import <XCTest/XCTest.h>
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/support/tmpfile.h"
#include "test/core/end2end/data/ssl_test_data.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include <grpc/grpc_cronet.h>
#import <Cronet/Cronet.h>
typedef struct fullstack_secure_fixture_data {
char *localaddr;
} fullstack_secure_fixture_data;
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
grpc_channel_args *client_args, grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
int port = grpc_pick_unused_port_or_die();
fullstack_secure_fixture_data *ffd =
gpr_malloc(sizeof(fullstack_secure_fixture_data));
memset(&f, 0, sizeof(f));
gpr_join_host_port(&ffd->localaddr, "localhost", port);
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create(NULL);
return f;
}
static void process_auth_failure(void *state, grpc_auth_context *ctx,
const grpc_metadata *md, size_t md_count,
grpc_process_auth_metadata_done_cb cb,
void *user_data) {
GPR_ASSERT(state == NULL);
cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
}
static void cronet_init_client_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
cronet_engine *cronetEngine) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
f->client =
grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr, client_args, NULL);
GPR_ASSERT(f->client != NULL);
}
static void chttp2_init_server_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
grpc_server_credentials *server_creds) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
if (f->server) {
grpc_server_destroy(f->server);
}
f->server = grpc_server_create(server_args, NULL);
grpc_server_register_completion_queue(f->server, f->cq, NULL);
GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
server_creds));
grpc_server_credentials_release(server_creds);
grpc_server_start(f->server);
}
static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
gpr_free(ffd->localaddr);
gpr_free(ffd);
}
static void cronet_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.fr"}};
grpc_channel_args *new_client_args =
grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
[Cronet setHttp2Enabled:YES];
[Cronet start];
cronet_engine *cronetEngine = [Cronet getGlobalEngine];
cronet_init_client_secure_fullstack(f, new_client_args, cronetEngine);
grpc_channel_args_destroy(new_client_args);
}
static int fail_server_auth_check(grpc_channel_args *server_args) {
size_t i;
if (server_args == NULL) return 0;
for (i = 0; i < server_args->num_args; i++) {
if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) ==
0) {
return 1;
}
}
return 0;
}
static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL);
if (fail_server_auth_check(server_args)) {
grpc_auth_metadata_processor processor = {process_auth_failure, NULL, NULL};
grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor);
}
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
}
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/simple_ssl_fullstack",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS,
chttp2_create_fixture_secure_fullstack,
cronet_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},
};
static char *roots_filename;
@interface CoreCronetEnd2EndTests : XCTestCase
@end
@implementation CoreCronetEnd2EndTests
// The setUp() function is run before the test cases run and only run once
+ (void)setUp {
[super setUp];
FILE *roots_file;
size_t roots_size = strlen(test_root_cert);
char *argv[] = {"CoreCronetEnd2EndTests"};
grpc_test_init(1, argv);
grpc_end2end_tests_pre_init();
/* Set the SSL roots env var. */
roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
GPR_ASSERT(roots_filename != NULL);
GPR_ASSERT(roots_file != NULL);
GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
fclose(roots_file);
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
grpc_init();
}
// The tearDown() function is run after all test cases finish running
+ (void)tearDown {
grpc_shutdown();
/* Cleanup. */
remove(roots_filename);
gpr_free(roots_filename);
[super tearDown];
}
- (void)testIndividualCase:(char*)test_case {
char *argv[] = {"h2_ssl", test_case};
for (int i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
grpc_end2end_tests(sizeof(argv) / sizeof(argv[0]), argv, configs[i]);
}
}
// TODO(mxyan): Use NSStringFromSelector(_cmd) to acquire test name from the
// test case method name, so that bodies of test cases can stay identical
- (void)testBadHostname {
[self testIndividualCase:"bad_hostname"];
}
- (void)testBinaryMetadata {
[self testIndividualCase:"binary_metadata"];
}
- (void)testCallCreds {
[self testIndividualCase:"call_creds"];
}
- (void)testCancelAfterAccept {
[self testIndividualCase:"cancel_after_accept"];
}
- (void)testCancelAfterClientDone {
[self testIndividualCase:"cancel_after_client_done"];
}
- (void)testCancelAfterInvoke {
[self testIndividualCase:"cancel_after_invoke"];
}
- (void)testCancelBeforeInvoke {
[self testIndividualCase:"cancel_before_invoke"];
}
- (void)testCancelInAVacuum {
[self testIndividualCase:"cancel_in_a_vacuum"];
}
- (void)testCancelWithStatus {
[self testIndividualCase:"cancel_with_status"];
}
- (void)testCompressedPayload {
[self testIndividualCase:"compressed_payload"];
}
- (void)testConnectivity {
[self testIndividualCase:"connectivity"];
}
- (void)testDefaultHost {
[self testIndividualCase:"default_host"];
}
- (void)testDisappearingServer {
[self testIndividualCase:"disappearing_server"];
}
- (void)testEmptyBatch {
[self testIndividualCase:"empty_batch"];
}
- (void)testFilterCausesClose {
[self testIndividualCase:"filter_causes_close"];
}
- (void)testGracefulServerShutdown {
[self testIndividualCase:"graceful_server_shutdown"];
}
- (void)testHighInitialSeqno {
[self testIndividualCase:"high_initial_seqno"];
}
- (void)testHpackSize {
[self testIndividualCase:"hpack_size"];
}
- (void)testIdempotentRequest {
[self testIndividualCase:"idempotent_request"];
}
- (void)testInvokeLargeRequest {
[self testIndividualCase:"invoke_large_request"];
}
- (void)testLargeMetadata {
[self testIndividualCase:"large_metadata"];
}
- (void)testMaxConcurrentStreams {
[self testIndividualCase:"max_concurrent_streams"];
}
- (void)testMaxMessageLength {
[self testIndividualCase:"max_message_length"];
}
- (void)testNegativeDeadline {
[self testIndividualCase:"negative_deadline"];
}
- (void)testNetworkStatusChange {
[self testIndividualCase:"network_status_change"];
}
- (void)testNoOp {
[self testIndividualCase:"no_op"];
}
- (void)testPayload {
[self testIndividualCase:"payload"];
}
- (void)testPing {
[self testIndividualCase:"ping"];
}
- (void)testPingPongStreaming {
[self testIndividualCase:"ping_pong_streaming"];
}
- (void)testRegisteredCall {
[self testIndividualCase:"registered_call"];
}
- (void)testRequestWithFlags {
[self testIndividualCase:"request_with_flags"];
}
- (void)testRequestWithPayload {
[self testIndividualCase:"request_with_payload"];
}
- (void)testServerFinishesRequest {
[self testIndividualCase:"server_finishes_request"];
}
- (void)testShutdownFinishesCalls {
[self testIndividualCase:"shutdown_finishes_calls"];
}
- (void)testShutdownFinishesTags {
[self testIndividualCase:"shutdown_finishes_tags"];
}
- (void)testSimpleDelayedRequest {
[self testIndividualCase:"simple_delayed_request"];
}
- (void)testSimpleMetadata {
[self testIndividualCase:"simple_metadata"];
}
- (void)testSimpleRequest {
[self testIndividualCase:"simple_request"];
}
- (void)testStreamingErrorResponse {
[self testIndividualCase:"streaming_error_response"];
}
- (void)testTrailingMetadata {
[self testIndividualCase:"trailing_metadata"];
}
@end

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

@ -22,17 +22,23 @@ GRPC_LOCAL_SRC = '../../..'
pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC
pod 'RemoteTest', :path => "RemoteTestClient"
end
end
target 'CoreCronetEnd2EndTests' do
pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core/Cronet-Tests', :path => GRPC_LOCAL_SRC
end
# gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
# pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
# and before they are installed in the user project.
@ -69,7 +75,7 @@ post_install do |installer|
target.build_configurations.each do |config|
config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES'
end
if target.name == 'gRPC-Core'
if target.name == 'gRPC-Core' or target.name == 'gRPC-Core.default-Cronet-Interface-Cronet-Tests'
target.build_configurations.each do |config|
# TODO(zyc): Remove this setting after the issue is resolved
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void

@ -12,6 +12,9 @@
20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */; };
5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */; };
5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */; };
6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; };
@ -38,6 +41,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 635697C61B14FC11007A7283;
remoteInfo = Tests;
};
63423F4B1B150A5F006CF63C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
@ -91,12 +101,16 @@
060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = "<group>"; };
07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.debug.xcconfig"; sourceTree = "<group>"; };
20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.release.xcconfig"; sourceTree = "<group>"; };
4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.release.xcconfig"; sourceTree = "<group>"; };
51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.release.xcconfig"; sourceTree = "<group>"; };
553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.debug.xcconfig"; sourceTree = "<group>"; };
5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreCronetEnd2EndTests.m; sourceTree = "<group>"; };
6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = "<group>"; };
63423F441B150A5F006CF63C /* AllTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AllTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
63423F501B151B77006CF63C /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
@ -123,11 +137,21 @@
E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.debug.xcconfig"; sourceTree = "<group>"; };
E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = "<group>"; };
E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = "<group>"; };
FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartext.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */,
60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
63423F411B150A5F006CF63C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -194,6 +218,7 @@
DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */,
A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */,
20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */,
FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -215,15 +240,26 @@
3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */,
060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */,
E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */,
0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */,
4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
isa = PBXGroup;
children = (
5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */,
);
path = CoreCronetEnd2EndTests;
sourceTree = "<group>";
};
635697BE1B14FC11007A7283 = {
isa = PBXGroup;
children = (
635697C91B14FC11007A7283 /* Tests */,
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */,
5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
635697C81B14FC11007A7283 /* Products */,
51E4650F34F854F41FF053B3 /* Pods */,
136D535E19727099B941D7B1 /* Frameworks */,
@ -239,6 +275,7 @@
63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */,
63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */,
63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */,
5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -270,6 +307,27 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */;
buildPhases = (
F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */,
5E8A5DA01D3840B4000F8BC4 /* Sources */,
5E8A5DA11D3840B4000F8BC4 /* Frameworks */,
5E8A5DA21D3840B4000F8BC4 /* Resources */,
E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */,
6DFE9E77CAB5760196D79E0F /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */,
);
name = CoreCronetEnd2EndTests;
productName = CoreCronetEnd2EndTests;
productReference = 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
63423F431B150A5F006CF63C /* AllTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */;
@ -403,6 +461,9 @@
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
5E8A5DA31D3840B4000F8BC4 = {
CreatedOnToolsVersion = 7.3.1;
};
63423F431B150A5F006CF63C = {
CreatedOnToolsVersion = 6.3.1;
};
@ -441,11 +502,19 @@
63DC84221BE15267000708E8 /* InteropTestsRemote */,
63DC84331BE15294000708E8 /* InteropTestsLocalSSL */,
63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */,
5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
5E8A5DA21D3840B4000F8BC4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
63423F421B150A5F006CF63C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -561,6 +630,21 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh\"\n";
showEnvVarsInLog = 0;
};
6DFE9E77CAB5760196D79E0F /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
7418AC7B3844B29E48D24FC7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -741,9 +825,47 @@
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5E8A5DA01D3840B4000F8BC4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
63423F401B150A5F006CF63C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -804,6 +926,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 635697C61B14FC11007A7283 /* Tests */;
targetProxy = 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */;
};
63423F4C1B150A5F006CF63C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 635697C61B14FC11007A7283 /* Tests */;
@ -832,6 +959,38 @@
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
5E8A5DAC1D3840B4000F8BC4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
};
name = Debug;
};
5E8A5DAD1D3840B4000F8BC4 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
};
name = Release;
};
63423F4E1B150A5F006CF63C /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */;
@ -1071,6 +1230,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5E8A5DAC1D3840B4000F8BC4 /* Debug */,
5E8A5DAD1D3840B4000F8BC4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (

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

@ -59,12 +59,15 @@
zend_class_entry *grpc_ce_call;
#if PHP_MAJOR_VERSION < 7
/* 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);
}
zend_object_std_dtor(&call->std TSRMLS_CC);
efree(call);
}
@ -203,6 +206,131 @@ bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
return true;
}
#else
static zend_object_handlers call_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_call */
static void free_wrapped_grpc_call(zend_object *object) {
wrapped_grpc_call *call = wrapped_grpc_call_from_obj(object);
if (call->owned && call->wrapped != NULL) {
grpc_call_destroy(call->wrapped);
}
zend_object_std_dtor(&call->std);
}
/* Initializes an instance of wrapped_grpc_call to be associated with an
* object of a class specified by class_type */
zend_object *create_wrapped_grpc_call(zend_class_entry *class_type) {
wrapped_grpc_call *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_call) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &call_ce_handlers;
return &intern->std;
}
/* 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 */
void grpc_php_wrap_call(grpc_call *wrapped, bool owned, 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;
}
/* Creates and returns a PHP array object with the data in a
* grpc_metadata_array. Returns NULL on failure */
void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
zval *array) {
int count = metadata_array->count;
grpc_metadata *elements = metadata_array->metadata;
int i;
zval *data;
HashTable *array_hash;
zval inner_array;
char *str_key;
char *str_val;
size_t key_len;
array_init(array);
array_hash = HASH_OF(array);
grpc_metadata *elem;
for (i = 0; i < count; i++) {
elem = &elements[i];
key_len = strlen(elem->key);
str_key = ecalloc(key_len + 1, sizeof(char));
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 ((data = zend_hash_str_find(array_hash, str_key, key_len)) != NULL) {
if (Z_TYPE_P(data) != IS_ARRAY) {
zend_throw_exception(zend_exception_get_default(),
"Metadata hash somehow contains wrong types.",
1);
efree(str_key);
efree(str_val);
return;
}
add_next_index_stringl(data, str_val, elem->value_length);
} else {
array_init(&inner_array);
add_next_index_stringl(&inner_array, str_val, elem->value_length);
add_assoc_zval(array, str_key, &inner_array);
}
}
}
/* 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;
HashTable *inner_array_hash;
zend_string *key;
if (Z_TYPE_P(array) != IS_ARRAY) {
return false;
}
grpc_metadata_array_init(metadata);
array_hash = HASH_OF(array);
ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
if (key == NULL) {
return false;
}
if (Z_TYPE_P(inner_array) != IS_ARRAY) {
return false;
}
inner_array_hash = HASH_OF(inner_array);
metadata->capacity += zend_hash_num_elements(inner_array_hash);
}
ZEND_HASH_FOREACH_END();
metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
if (key == NULL) {
return false;
}
inner_array_hash = HASH_OF(inner_array);
ZEND_HASH_FOREACH_VAL(inner_array_hash, value) {
if (Z_TYPE_P(value) != IS_STRING) {
return false;
}
metadata->metadata[metadata->count].key = ZSTR_VAL(key);
metadata->metadata[metadata->count].value = Z_STRVAL_P(value);
metadata->metadata[metadata->count].value_length = Z_STRLEN_P(value);
metadata->count += 1;
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
return true;
}
#endif
/**
* Constructs a new instance of the Call class.
* @param Channel $channel The channel to associate the call with. Must not be
@ -211,30 +339,38 @@ 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;
zval *deadline_obj;
char *host_override = NULL;
#if PHP_MAJOR_VERSION < 7
int method_len;
int host_override_len = 0;
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
size_t method_len;
size_t host_override_len = 0;
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
#endif
/* "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;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(
channel_obj TSRMLS_CC);
#else
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(channel_obj);
#endif
if (channel->wrapped == NULL) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Call cannot be constructed from a closed Channel",
@ -242,12 +378,17 @@ PHP_METHOD(Call, __construct) {
return;
}
add_property_zval(getThis(), "channel", channel_obj);
#if PHP_MAJOR_VERSION < 7
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);
#else
wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
#endif
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 +398,40 @@ PHP_METHOD(Call, __construct) {
* @return object Object with results of all actions
*/
PHP_METHOD(Call, startBatch) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
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;
zval *result;
zval *recv_status;
MAKE_STD_ZVAL(result);
object_init(result);
#else
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
zval *value;
zval *inner_value;
zval *message_value;
zval *message_flags;
zend_string *key;
zend_ulong index;
zval recv_status;
object_init(return_value);
#endif
grpc_op ops[8];
size_t op_num = 0;
zval *array;
HashTable *array_hash;
HashTable *status_hash;
HashTable *message_hash;
grpc_metadata_array metadata;
grpc_metadata_array trailing_metadata;
grpc_metadata_array recv_metadata;
@ -283,17 +442,16 @@ 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,6 +459,9 @@ PHP_METHOD(Call, startBatch) {
"start_batch expects an array", 1 TSRMLS_CC);
goto cleanup;
}
#if PHP_MAJOR_VERSION < 7
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,
@ -313,124 +474,250 @@ PHP_METHOD(Call, startBatch) {
goto cleanup;
}
switch(index) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!create_metadata_array(*value, &metadata)) {
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) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected an array for send message",
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,
"Bad metadata value given", 1 TSRMLS_CC);
goto cleanup;
"Expected an int for message flags",
1 TSRMLS_CC);
}
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) {
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) {
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_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,
"Expected an array for send message",
"Bad trailing metadata value given",
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;
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;
}
if (zend_hash_find(message_hash, "message", sizeof("message"),
(void **)&message_value) != SUCCESS ||
Z_TYPE_PP(message_value) != IS_STRING) {
ops[op_num].data.send_status_from_server.status =
Z_LVAL_PP(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Integer status code is required",
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,
"Expected a string for send message",
"Status details must be a string",
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;
ops[op_num].data.send_status_from_server.status_details =
Z_STRVAL_PP(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"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++;
}
#else
array_hash = HASH_OF(array);
ZEND_HASH_FOREACH_KEY_VAL(array_hash, index, key, value) {
if (key) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"batch keys must be integers", 1);
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);
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);
goto cleanup;
}
message_hash = HASH_OF(value);
if ((message_flags =
zend_hash_str_find(message_hash, "flags",
sizeof("flags") - 1)) != NULL) {
if (Z_TYPE_P(message_flags) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected an int for message flags", 1);
}
ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
}
if ((message_value = zend_hash_str_find(message_hash, "message",
sizeof("message") - 1))
== NULL || Z_TYPE_P(message_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected a string for send message", 1);
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 = HASH_OF(value);
if ((inner_value = zend_hash_str_find(status_hash, "metadata",
sizeof("metadata") - 1))
!= NULL) {
if (!create_metadata_array(inner_value, &trailing_metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad trailing metadata value given", 1);
goto cleanup;
}
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 ((inner_value = zend_hash_str_find(status_hash, "code",
sizeof("code") - 1)) != NULL) {
if (Z_TYPE_P(inner_value) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Integer status code is required",
1 TSRMLS_CC);
"Status code must be an integer", 1);
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);
goto cleanup;
}
if ((inner_value = zend_hash_str_find(status_hash, "details",
sizeof("details") - 1)) != NULL) {
if (Z_TYPE_P(inner_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"String status details is required",
1 TSRMLS_CC);
"Status details must be a string", 1);
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);
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);
goto cleanup;
}
ops[op_num].op = (grpc_op_type)index;
ops[op_num].flags = 0;
ops[op_num].reserved = NULL;
op_num++;
}
ZEND_HASH_FOREACH_END();
#endif
error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
NULL);
if (error != GRPC_CALL_OK) {
@ -441,52 +728,98 @@ PHP_METHOD(Call, startBatch) {
}
grpc_completion_queue_pluck(completion_queue, call->wrapped,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
#if PHP_MAJOR_VERSION < 7
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:
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;
}
}
#else
for (int i = 0; i < op_num; i++) {
switch(ops[i].op) {
case GRPC_OP_SEND_INITIAL_METADATA:
add_property_bool(return_value, "send_metadata", true);
break;
case GRPC_OP_SEND_MESSAGE:
add_property_bool(return_value, "send_message", true);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
add_property_bool(return_value, "send_close", true);
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
add_property_bool(return_value, "send_status", true);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
grpc_parse_metadata_array(&recv_metadata, array);
add_property_zval(return_value, "metadata", array);
break;
case GRPC_OP_RECV_MESSAGE:
byte_buffer_to_string(message, &message_str, &message_len);
if (message_str == NULL) {
add_property_null(return_value, "message");
} else {
add_property_stringl(return_value, "message", message_str,
message_len);
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
object_init(&recv_status);
grpc_parse_metadata_array(&recv_trailing_metadata, array);
add_property_zval(&recv_status, "metadata", array);
add_property_long(&recv_status, "code", status);
add_property_string(&recv_status, "details", status_details);
add_property_zval(return_value, "status", &recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(return_value, "cancelled", cancelled);
break;
default:
break;
}
}
#endif
cleanup:
grpc_metadata_array_destroy(&metadata);
grpc_metadata_array_destroy(&trailing_metadata);
@ -503,7 +836,11 @@ cleanup:
grpc_byte_buffer_destroy(message);
}
}
#if PHP_MAJOR_VERSION < 7
RETURN_DESTROY_ZVAL(result);
#else
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -511,9 +848,14 @@ cleanup:
* @return string The URI of the endpoint
*/
PHP_METHOD(Call, getPeer) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
#else
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
RETURN_STRING(grpc_call_get_peer(call->wrapped));
#endif
}
/**
@ -521,8 +863,12 @@ PHP_METHOD(Call, getPeer) {
* has not already ended with another status.
*/
PHP_METHOD(Call, cancel) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
#endif
grpc_call_cancel(call->wrapped, NULL);
}
@ -543,12 +889,17 @@ PHP_METHOD(Call, setCredentials) {
return;
}
#if PHP_MAJOR_VERSION < 7
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);
#else
wrapped_grpc_call_credentials *creds =
Z_WRAPPED_GRPC_CALL_CREDS_P(creds_obj);
wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
#endif
grpc_call_error error = GRPC_CALL_ERROR;
error = grpc_call_set_credentials(call->wrapped, creds->wrapped);
@ -556,16 +907,23 @@ 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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&call_ce_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
call_ce_handlers.offset = XtOffsetOf(wrapped_grpc_call, std);
call_ce_handlers.free_obj = free_wrapped_grpc_call;
#endif
}

@ -48,17 +48,15 @@
/* Class entry for the Call PHP class */
extern zend_class_entry *grpc_ce_call;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_call that can be associated with a PHP object */
typedef struct wrapped_grpc_call {
zend_object std;
bool owned;
grpc_call *wrapped;
} wrapped_grpc_call;
/* Initializes the Call PHP class */
void grpc_init_call(TSRMLS_D);
/* Creates a Call object that wraps the given grpc_call struct */
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
@ -66,6 +64,36 @@ zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
* call metadata */
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC);
#else
/* Wrapper struct for grpc_call that can be associated with a PHP object */
typedef struct wrapped_grpc_call {
bool owned;
grpc_call *wrapped;
zend_object std;
} wrapped_grpc_call;
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)))
/* Creates a Call object that wraps the given grpc_call struct */
void grpc_php_wrap_call(grpc_call *wrapped, bool owned, zval *call_object);
/* Creates and returns a PHP associative array of metadata from a C array of
* call metadata */
void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
zval *array);
#endif /* PHP_MAJOR_VERSION */
/* 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);

@ -53,6 +53,8 @@
zend_class_entry *grpc_ce_call_credentials;
#if PHP_MAJOR_VERSION < 7
/* 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 =
@ -60,6 +62,7 @@ void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
if (creds->wrapped != NULL) {
grpc_call_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std TSRMLS_CC);
efree(creds);
}
@ -94,6 +97,43 @@ zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped TSRMLS_DC) {
return credentials_object;
}
#else
static zend_object_handlers call_credentials_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_call_credentials */
static void free_wrapped_grpc_call_credentials(zend_object *object) {
wrapped_grpc_call_credentials *creds =
wrapped_grpc_call_creds_from_obj(object);
if (creds->wrapped != NULL) {
grpc_call_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std);
}
/* Initializes an instance of wrapped_grpc_call_credentials to be
* associated with an object of a class specified by class_type */
zend_object *create_wrapped_grpc_call_credentials(zend_class_entry
*class_type) {
wrapped_grpc_call_credentials *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_call_credentials) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &call_credentials_ce_handlers;
return &intern->std;
}
void grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped,
zval *credentials_object) {
object_init_ex(credentials_object, grpc_ce_call_credentials);
wrapped_grpc_call_credentials *credentials =
Z_WRAPPED_GRPC_CALL_CREDS_P(credentials_object);
credentials->wrapped = wrapped;
}
#endif
/**
* Create composite credentials from two existing credentials.
* @param CallCredentials cred1 The first credential
@ -113,6 +153,7 @@ PHP_METHOD(CallCredentials, createComposite) {
1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_call_credentials *cred1 =
(wrapped_grpc_call_credentials *)zend_object_store_get_object(
cred1_obj TSRMLS_CC);
@ -124,6 +165,17 @@ PHP_METHOD(CallCredentials, createComposite) {
NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
wrapped_grpc_call_credentials *cred1 =
Z_WRAPPED_GRPC_CALL_CREDS_P(cred1_obj);
wrapped_grpc_call_credentials *cred2 =
Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
grpc_call_credentials *creds =
grpc_composite_call_credentials_create(cred1->wrapped,
cred2->wrapped, NULL);
grpc_php_wrap_call_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -141,13 +193,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,10 +214,15 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
plugin.state = (void *)state;
plugin.type = "";
grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
plugin, NULL);
grpc_call_credentials *creds =
grpc_metadata_credentials_create_from_plugin(plugin, NULL);
#if PHP_MAJOR_VERSION < 7
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
grpc_php_wrap_call_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/* Callback function for plugin creds API */
@ -181,6 +235,7 @@ 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 */
#if PHP_MAJOR_VERSION < 7
zval **params[1];
zval *arg;
zval *retval;
@ -192,21 +247,41 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
state->fci->param_count = 1;
state->fci->params = params;
state->fci->retval_ptr_ptr = &retval;
#else
zval arg;
zval retval;
object_init(&arg);
add_property_string(&arg, "service_url", context.service_url);
add_property_string(&arg, "method_name", context.method_name);
state->fci->param_count = 1;
state->fci->params = &arg;
state->fci->retval = &retval;
#endif
/* call the user callback function */
zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
if (Z_TYPE_P(retval) != IS_ARRAY) {
#else
if (Z_TYPE_P(&retval) != IS_ARRAY) {
#endif
zend_throw_exception(spl_ce_InvalidArgumentException,
"plugin callback must return metadata array",
1 TSRMLS_CC);
return;
}
grpc_metadata_array metadata;
#if PHP_MAJOR_VERSION < 7
if (!create_metadata_array(retval, &metadata)) {
#else
if (!create_metadata_array(&retval, &metadata)) {
#endif
zend_throw_exception(spl_ce_InvalidArgumentException,
"invalid metadata", 1 TSRMLS_CC);
grpc_metadata_array_destroy(&metadata);
return;
}
/* TODO: handle error */
@ -229,11 +304,21 @@ 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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&call_credentials_ce_handlers,
zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
call_credentials_ce_handlers.offset =
XtOffsetOf(wrapped_grpc_call_credentials, std);
call_credentials_ce_handlers.free_obj =
free_wrapped_grpc_call_credentials;
#endif
}

@ -49,14 +49,37 @@
/* Class entry for the CallCredentials PHP class */
extern zend_class_entry *grpc_ce_call_credentials;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_call_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_call_credentials {
zend_object std;
grpc_call_credentials *wrapped;
} wrapped_grpc_call_credentials;
#else
/* Wrapper struct for grpc_call_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_call_credentials {
grpc_call_credentials *wrapped;
zend_object std;
} wrapped_grpc_call_credentials;
static inline wrapped_grpc_call_credentials
*wrapped_grpc_call_creds_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_creds_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Struct to hold callback function for plugin creds API */
typedef struct plugin_state {
zend_fcall_info *fci;

@ -57,12 +57,15 @@
zend_class_entry *grpc_ce_channel;
#if PHP_MAJOR_VERSION < 7
/* 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);
}
zend_object_std_dtor(&channel->std TSRMLS_CC);
efree(channel);
}
@ -83,7 +86,8 @@ zend_object_value create_wrapped_grpc_channel(zend_class_entry *class_type
return retval;
}
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;
@ -107,23 +111,88 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_D
}
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;
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++;
}
}
#else
static zend_object_handlers channel_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_channel */
static void free_wrapped_grpc_channel(zend_object *object) {
wrapped_grpc_channel *channel = wrapped_grpc_channel_from_obj(object);
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
}
zend_object_std_dtor(&channel->std);
}
/* Initializes an instance of wrapped_grpc_channel to be associated with an
* object of a class specified by class_type */
zend_object *create_wrapped_grpc_channel(zend_class_entry *class_type) {
wrapped_grpc_channel *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_channel) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &channel_ce_handlers;
return &intern->std;
}
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) {
HashTable *array_hash;
int args_index;
zval *data;
zend_string *key;
array_hash = HASH_OF(args_array);
if (!array_hash) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"array_hash is NULL", 1);
return;
}
args->num_args = zend_hash_num_elements(array_hash);
args->args = ecalloc(args->num_args, sizeof(grpc_arg));
args_index = 0;
ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, data) {
if (key == NULL) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"args keys must be strings", 1);
}
args->args[args_index].key = ZSTR_VAL(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);
return;
}
args_index++;
} ZEND_HASH_FOREACH_END();
}
#endif
/**
* Construct an instance of the Channel class. If the $args array contains a
* "credentials" key mapping to a ChannelCredentials object, a secure channel
@ -132,16 +201,23 @@ 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) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(
getThis() TSRMLS_CC);
char *target;
zval **creds_obj = NULL;
int target_length;
#else
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
zval *creds_obj = NULL;
size_t target_length;
#endif
char *target;
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) {
@ -149,6 +225,7 @@ PHP_METHOD(Channel, __construct) {
"Channel expects a string and an array", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
array_hash = Z_ARRVAL_P(args_array);
if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
(void **)&creds_obj) == SUCCESS) {
@ -167,6 +244,24 @@ PHP_METHOD(Channel, __construct) {
zend_hash_del(array_hash, "credentials", 12);
}
}
#else
array_hash = HASH_OF(args_array);
if ((creds_obj = zend_hash_str_find(array_hash, "credentials",
sizeof("credentials") - 1)) != NULL) {
if (Z_TYPE_P(creds_obj) == IS_NULL) {
creds = NULL;
zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
} else if (Z_OBJ_P(creds_obj)->ce != grpc_ce_channel_credentials) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"credentials must be a ChannelCredentials object",
1);
return;
} else {
creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
}
}
#endif
php_grpc_read_args_array(args_array, &args TSRMLS_CC);
if (creds == NULL) {
channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
@ -182,9 +277,14 @@ PHP_METHOD(Channel, __construct) {
* @return string The URI of the endpoint
*/
PHP_METHOD(Channel, getTarget) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
#else
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
RETURN_STRING(grpc_channel_get_target(channel->wrapped));
#endif
}
/**
@ -193,12 +293,17 @@ PHP_METHOD(Channel, getTarget) {
* @return long The grpc connectivity state
*/
PHP_METHOD(Channel, getConnectivityState) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
bool try_to_connect;
#else
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
#endif
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,10 +320,16 @@ PHP_METHOD(Channel, getConnectivityState) {
* before deadline
*/
PHP_METHOD(Channel, watchConnectivityState) {
#if PHP_MAJOR_VERSION < 7
long last_state;
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
long last_state;
#else
zend_long last_state;
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
#endif
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) {
@ -228,15 +339,20 @@ PHP_METHOD(Channel, watchConnectivityState) {
return;
}
#if PHP_MAJOR_VERSION < 7
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);
#else
wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
#endif
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 +360,12 @@ PHP_METHOD(Channel, watchConnectivityState) {
* Close the channel
*/
PHP_METHOD(Channel, close) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel *channel =
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
(wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
#endif
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
channel->wrapped = NULL;
@ -253,16 +373,24 @@ 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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&channel_ce_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
channel_ce_handlers.offset =
XtOffsetOf(wrapped_grpc_channel, std);
channel_ce_handlers.free_obj = free_wrapped_grpc_channel;
#endif
}

@ -48,17 +48,38 @@
/* Class entry for the PHP Channel class */
extern zend_class_entry *grpc_ce_channel;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_channel that can be associated with a PHP object */
typedef struct wrapped_grpc_channel {
zend_object std;
grpc_channel *wrapped;
} wrapped_grpc_channel;
#else
/* Wrapper struct for grpc_channel that can be associated with a PHP object */
typedef struct wrapped_grpc_channel {
grpc_channel *wrapped;
zend_object std;
} wrapped_grpc_channel;
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,6 @@
#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_channel_credentials;
static char *default_pem_root_certs = NULL;
static grpc_ssl_roots_override_result get_ssl_roots_override(
@ -64,6 +63,8 @@ static grpc_ssl_roots_override_result get_ssl_roots_override(
return GRPC_SSL_ROOTS_OVERRIDE_OK;
}
#if PHP_MAJOR_VERSION < 7
/* 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 =
@ -71,6 +72,7 @@ void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
if (creds->wrapped != NULL) {
grpc_channel_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std TSRMLS_CC);
efree(creds);
}
@ -94,7 +96,8 @@ zend_object_value create_wrapped_grpc_channel_credentials(
return retval;
}
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);
object_init_ex(credentials_object, grpc_ce_channel_credentials);
@ -105,6 +108,43 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
return credentials_object;
}
#else
static zend_object_handlers channel_credentials_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
static void free_wrapped_grpc_channel_credentials(zend_object *object) {
wrapped_grpc_channel_credentials *creds =
wrapped_grpc_channel_creds_from_obj(object);
if (creds->wrapped != NULL) {
grpc_channel_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std);
}
/* Initializes an instance of wrapped_grpc_channel_credentials to be
* associated with an object of a class specified by class_type */
zend_object *create_wrapped_grpc_channel_credentials(zend_class_entry
*class_type) {
wrapped_grpc_channel_credentials *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_channel_credentials) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &channel_credentials_ce_handlers;
return &intern->std;
}
void grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped,
zval *credentials_object) {
object_init_ex(credentials_object, grpc_ce_channel_credentials);
wrapped_grpc_channel_credentials *credentials =
Z_WRAPPED_GRPC_CHANNEL_CREDS_P(credentials_object);
credentials->wrapped = wrapped;
}
#endif
/**
* Set default roots pem.
* @param string pem_roots PEM encoding of the server root certificates
@ -112,7 +152,13 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
*/
PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
char *pem_roots;
#if PHP_MAJOR_VERSION < 7
int pem_roots_length;
#else
size_t pem_roots_length;
#endif
/* "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,8 +175,13 @@ PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
*/
PHP_METHOD(ChannelCredentials, createDefault) {
grpc_channel_credentials *creds = grpc_google_default_credentials_create();
#if PHP_MAJOR_VERSION < 7
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
grpc_php_wrap_channel_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -146,11 +197,15 @@ PHP_METHOD(ChannelCredentials, createSsl) {
char *pem_root_certs = NULL;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
#if PHP_MAJOR_VERSION < 7
int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
#else
size_t root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
#endif
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,8 +219,13 @@ 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);
#if PHP_MAJOR_VERSION < 7
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
grpc_php_wrap_channel_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -178,7 +238,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) {
@ -186,6 +246,7 @@ PHP_METHOD(ChannelCredentials, createComposite) {
"createComposite expects 2 Credentials", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_channel_credentials *cred1 =
(wrapped_grpc_channel_credentials *)zend_object_store_get_object(
cred1_obj TSRMLS_CC);
@ -197,6 +258,17 @@ PHP_METHOD(ChannelCredentials, createComposite) {
NULL);
zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
wrapped_grpc_channel_credentials *cred1 =
Z_WRAPPED_GRPC_CHANNEL_CREDS_P(cred1_obj);
wrapped_grpc_call_credentials *cred2 =
Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
grpc_channel_credentials *creds =
grpc_composite_channel_credentials_create(cred1->wrapped,
cred2->wrapped, NULL);
grpc_php_wrap_channel_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -218,7 +290,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 +300,13 @@ 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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&channel_credentials_ce_handlers,
zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
channel_credentials_ce_handlers.offset =
XtOffsetOf(wrapped_grpc_channel_credentials, std);
channel_credentials_ce_handlers.free_obj =
free_wrapped_grpc_channel_credentials;
#endif
}

@ -49,14 +49,37 @@
/* Class entry for the ChannelCredentials PHP class */
extern zend_class_entry *grpc_ce_channel_credentials;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_channel_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_channel_credentials {
zend_object std;
grpc_channel_credentials *wrapped;
} wrapped_grpc_channel_credentials;
#else
/* Wrapper struct for grpc_channel_credentials that can be associated
* with a PHP object */
typedef struct wrapped_grpc_channel_credentials {
grpc_channel_credentials *wrapped;
zend_object std;
} wrapped_grpc_channel_credentials;
static inline wrapped_grpc_channel_credentials
*wrapped_grpc_channel_creds_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_creds_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the ChannelCredentials PHP class */
void grpc_init_channel_credentials(TSRMLS_D);

@ -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
*/

@ -72,8 +72,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)

@ -58,6 +58,8 @@
zend_class_entry *grpc_ce_server;
#if PHP_MAJOR_VERSION < 7
/* 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;
@ -68,6 +70,7 @@ void free_wrapped_grpc_server(void *object TSRMLS_DC) {
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
grpc_server_destroy(server->wrapped);
}
zend_object_std_dtor(&server->std TSRMLS_CC);
efree(server);
}
@ -90,15 +93,51 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
return retval;
}
#else
static zend_object_handlers server_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_server */
static void free_wrapped_grpc_server(zend_object *object) {
wrapped_grpc_server *server = wrapped_grpc_server_from_obj(object);
if (server->wrapped != NULL) {
grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
grpc_server_cancel_all_calls(server->wrapped);
grpc_completion_queue_pluck(completion_queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
grpc_server_destroy(server->wrapped);
}
zend_object_std_dtor(&server->std);
}
/* Initializes an instance of wrapped_grpc_call to be associated with an object
* of a class specified by class_type */
zend_object *create_wrapped_grpc_server(zend_class_entry *class_type) {
wrapped_grpc_server *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_server) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &server_ce_handlers;
return &intern->std;
}
#endif
/**
* Constructs a new instance of the Server class
* @param array $args The arguments to pass to the server (optional)
*/
PHP_METHOD(Server, __construct) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
#endif
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 +149,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 +167,22 @@ 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;
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *result;
MAKE_STD_ZVAL(result);
object_init(result);
#else
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
object_init(return_value);
#endif
grpc_call_details_init(&details);
grpc_metadata_array_init(&metadata);
error_code =
@ -146,23 +194,48 @@ 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;
}
#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));
add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata
TSRMLS_CC));
cleanup:
grpc_call_details_destroy(&details);
grpc_metadata_array_destroy(&metadata);
RETURN_DESTROY_ZVAL(result);
#else
zval zv_call;
zval zv_timeval;
zval zv_md;
grpc_php_wrap_call(call, true, &zv_call);
grpc_php_wrap_timeval(details.deadline, &zv_timeval);
grpc_parse_metadata_array(&metadata, &zv_md);
add_property_zval(return_value, "call", &zv_call);
add_property_string(return_value, "method", details.method);
add_property_string(return_value, "host", details.host);
add_property_zval(return_value, "absolute_deadline", &zv_timeval);
add_property_zval(return_value, "metadata", &zv_md);
cleanup:
grpc_call_details_destroy(&details);
grpc_metadata_array_destroy(&metadata);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -171,13 +244,19 @@ 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;
#if PHP_MAJOR_VERSION < 7
int addr_len;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
size_t addr_len;
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
#endif
/* "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 +265,17 @@ 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;
zval *creds_obj;
#if PHP_MAJOR_VERSION < 7
int addr_len;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
size_t addr_len;
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
#endif
/* "sO" == 1 string, 1 object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
&creds_obj, grpc_ce_server_credentials) ==
@ -200,9 +285,14 @@ PHP_METHOD(Server, addSecureHttp2Port) {
"add_http2_port expects a string and a ServerCredentials", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_server_credentials *creds =
(wrapped_grpc_server_credentials *)zend_object_store_get_object(
creds_obj TSRMLS_CC);
#else
wrapped_grpc_server_credentials *creds =
Z_WRAPPED_GRPC_SERVER_CREDS_P(creds_obj);
#endif
RETURN_LONG(grpc_server_add_secure_http2_port(server->wrapped, addr,
creds->wrapped));
}
@ -212,21 +302,33 @@ PHP_METHOD(Server, addSecureHttp2Port) {
* @return Void
*/
PHP_METHOD(Server, start) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
#endif
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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&server_ce_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
server_ce_handlers.offset = XtOffsetOf(wrapped_grpc_server, std);
server_ce_handlers.free_obj = free_wrapped_grpc_server;
#endif
}

@ -48,13 +48,33 @@
/* Class entry for the Server PHP class */
extern zend_class_entry *grpc_ce_server;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_server that can be associated with a PHP object */
typedef struct wrapped_grpc_server {
zend_object std;
grpc_server *wrapped;
} wrapped_grpc_server;
#else
/* Wrapper struct for grpc_server that can be associated with a PHP object */
typedef struct wrapped_grpc_server {
grpc_server *wrapped;
zend_object std;
} wrapped_grpc_server;
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);

@ -51,6 +51,8 @@
zend_class_entry *grpc_ce_server_credentials;
#if PHP_MAJOR_VERSION < 7
/* 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 =
@ -58,6 +60,7 @@ void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
if (creds->wrapped != NULL) {
grpc_server_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std TSRMLS_CC);
efree(creds);
}
@ -81,7 +84,8 @@ zend_object_value create_wrapped_grpc_server_credentials(
return retval;
}
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);
object_init_ex(server_credentials_object, grpc_ce_server_credentials);
@ -92,6 +96,43 @@ zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped TSRMLS_D
return server_credentials_object;
}
#else
static zend_object_handlers server_credentials_ce_handlers;
/* Frees and destroys an instace of wrapped_grpc_server_credentials */
static void free_wrapped_grpc_server_credentials(zend_object *object) {
wrapped_grpc_server_credentials *creds =
wrapped_grpc_server_creds_from_obj(object);
if (creds->wrapped != NULL) {
grpc_server_credentials_release(creds->wrapped);
}
zend_object_std_dtor(&creds->std);
}
/* Initializes an instace of wrapped_grpc_server_credentials to be associated
* with an object of a class specified by class_type */
zend_object *create_wrapped_grpc_server_credentials(zend_class_entry
*class_type) {
wrapped_grpc_server_credentials *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_server_credentials) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &server_credentials_ce_handlers;
return &intern->std;
}
void grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped,
zval *server_credentials_object) {
object_init_ex(server_credentials_object, grpc_ce_server_credentials);
wrapped_grpc_server_credentials *server_credentials =
Z_WRAPPED_GRPC_SERVER_CREDS_P(server_credentials_object);
server_credentials->wrapped = wrapped;
}
#endif
/**
* Create SSL credentials.
* @param string pem_root_certs PEM encoding of the server root certificates
@ -103,7 +144,11 @@ PHP_METHOD(ServerCredentials, createSsl) {
char *pem_root_certs = 0;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
#if PHP_MAJOR_VERSION < 7
int root_certs_length = 0, private_key_length, cert_chain_length;
#else
size_t root_certs_length = 0, private_key_length, cert_chain_length;
#endif
/* "s!ss" == 1 nullable string, 2 strings */
/* TODO: support multiple key cert pairs. */
@ -120,17 +165,33 @@ 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);
#if PHP_MAJOR_VERSION < 7
zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
#else
grpc_php_wrap_server_credentials(creds, return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
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);
#if PHP_MAJOR_VERSION >= 7
memcpy(&server_credentials_ce_handlers,
zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
server_credentials_ce_handlers.offset =
XtOffsetOf(wrapped_grpc_server_credentials, std);
server_credentials_ce_handlers.free_obj =
free_wrapped_grpc_server_credentials;
#endif
}

@ -49,14 +49,34 @@
/* Class entry for the Server_Credentials PHP class */
extern zend_class_entry *grpc_ce_server_credentials;
#if PHP_MAJOR_VERSION < 7
/* Wrapper struct for grpc_server_credentials that can be associated with a PHP
* object */
typedef struct wrapped_grpc_server_credentials {
zend_object std;
grpc_server_credentials *wrapped;
} wrapped_grpc_server_credentials;
#else
typedef struct wrapped_grpc_server_credentials {
grpc_server_credentials *wrapped;
zend_object std;
} wrapped_grpc_server_credentials;
static inline wrapped_grpc_server_credentials
*wrapped_grpc_server_creds_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_creds_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initializes the Server_Credentials PHP class */
void grpc_init_server_credentials(TSRMLS_D);

@ -52,8 +52,14 @@
zend_class_entry *grpc_ce_timeval;
#if PHP_MAJOR_VERSION < 7
/* Frees and destroys an instance of wrapped_grpc_call */
void free_wrapped_grpc_timeval(void *object TSRMLS_DC) { efree(object); }
void free_wrapped_grpc_timeval(void *object TSRMLS_DC) {
wrapped_grpc_timeval *timeval = (wrapped_grpc_timeval *)object;
zend_object_std_dtor(&timeval->std TSRMLS_CC);
efree(timeval);
}
/* Initializes an instance of wrapped_grpc_timeval to be associated with an
* object of a class specified by class_type */
@ -83,14 +89,50 @@ zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC) {
return timeval_object;
}
#else
static zend_object_handlers timeval_ce_handlers;
/* Frees and destroys an instance of wrapped_grpc_call */
static void free_wrapped_grpc_timeval(zend_object *object) {
wrapped_grpc_timeval *timeval = wrapped_grpc_timeval_from_obj(object);
zend_object_std_dtor(&timeval->std);
}
/* Initializes an instance of wrapped_grpc_timeval to be associated with an
* object of a class specified by class_type */
zend_object *create_wrapped_grpc_timeval(zend_class_entry *class_type) {
wrapped_grpc_timeval *intern;
intern = ecalloc(1, sizeof(wrapped_grpc_timeval) +
zend_object_properties_size(class_type));
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
intern->std.handlers = &timeval_ce_handlers;
return &intern->std;
}
void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object) {
object_init_ex(timeval_object, grpc_ce_timeval);
wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(timeval_object);
memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
}
#endif
/**
* Constructs a new instance of the Timeval class
* @param long $usec The number of microseconds in the interval
*/
PHP_METHOD(Timeval, __construct) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *timeval =
(wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
long microseconds;
#else
wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
zend_long microseconds;
#endif
/* "l" == 1 long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &microseconds) ==
FAILURE) {
@ -110,6 +152,7 @@ PHP_METHOD(Timeval, __construct) {
*/
PHP_METHOD(Timeval, add) {
zval *other_obj;
/* "O" == 1 Object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
grpc_ce_timeval) == FAILURE) {
@ -117,13 +160,23 @@ PHP_METHOD(Timeval, add) {
"add expects a Timeval", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *self =
(wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_timeval *other =
(wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
zval *sum =
grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped) TSRMLS_CC);
grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
TSRMLS_CC);
RETURN_DESTROY_ZVAL(sum);
#else
wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped),
return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -134,6 +187,7 @@ PHP_METHOD(Timeval, add) {
*/
PHP_METHOD(Timeval, subtract) {
zval *other_obj;
/* "O" == 1 Object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
grpc_ce_timeval) == FAILURE) {
@ -141,13 +195,22 @@ PHP_METHOD(Timeval, subtract) {
"subtract expects a Timeval", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *self =
(wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_timeval *other =
(wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
zval *diff =
grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped) TSRMLS_CC);
grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
TSRMLS_CC);
RETURN_DESTROY_ZVAL(diff);
#else
wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped),
return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -158,7 +221,9 @@ PHP_METHOD(Timeval, subtract) {
* @return long
*/
PHP_METHOD(Timeval, compare) {
zval *a_obj, *b_obj;
zval *a_obj;
zval *b_obj;
/* "OO" == 2 Objects */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &a_obj,
grpc_ce_timeval, &b_obj,
@ -167,10 +232,15 @@ PHP_METHOD(Timeval, compare) {
"compare expects two Timevals", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *a =
(wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
wrapped_grpc_timeval *b =
(wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
#else
wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
#endif
long result = gpr_time_cmp(a->wrapped, b->wrapped);
RETURN_LONG(result);
}
@ -183,7 +253,10 @@ PHP_METHOD(Timeval, compare) {
* @return bool True if $a and $b are within $threshold, False otherwise
*/
PHP_METHOD(Timeval, similar) {
zval *a_obj, *b_obj, *thresh_obj;
zval *a_obj;
zval *b_obj;
zval *thresh_obj;
/* "OOO" == 3 Objects */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OOO", &a_obj,
grpc_ce_timeval, &b_obj, grpc_ce_timeval,
@ -192,6 +265,7 @@ PHP_METHOD(Timeval, similar) {
"compare expects three Timevals", 1 TSRMLS_CC);
return;
}
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *a =
(wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
wrapped_grpc_timeval *b =
@ -199,6 +273,11 @@ PHP_METHOD(Timeval, similar) {
wrapped_grpc_timeval *thresh =
(wrapped_grpc_timeval *)zend_object_store_get_object(
thresh_obj TSRMLS_CC);
#else
wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
wrapped_grpc_timeval *thresh = Z_WRAPPED_GRPC_TIMEVAL_P(thresh_obj);
#endif
int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped);
RETURN_BOOL(result);
}
@ -208,8 +287,13 @@ PHP_METHOD(Timeval, similar) {
* @return Timeval The current time
*/
PHP_METHOD(Timeval, now) {
#if PHP_MAJOR_VERSION < 7
zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(now);
#else
grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME), return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -217,11 +301,18 @@ PHP_METHOD(Timeval, now) {
* @return Timeval Zero length time interval
*/
PHP_METHOD(Timeval, zero) {
#if PHP_MAJOR_VERSION < 7
zval *grpc_php_timeval_zero =
grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_ZVAL(grpc_php_timeval_zero,
false, /* Copy original before returning? */
true /* Destroy original before returning */);
#else
grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME), return_value);
RETURN_ZVAL(return_value,
false, /* Copy original before returning? */
true /* Destroy original before returning */);
#endif
}
/**
@ -229,9 +320,14 @@ PHP_METHOD(Timeval, zero) {
* @return Timeval Infinite future time value
*/
PHP_METHOD(Timeval, infFuture) {
#if PHP_MAJOR_VERSION < 7
zval *grpc_php_timeval_inf_future =
grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
#else
grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME), return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -239,9 +335,14 @@ PHP_METHOD(Timeval, infFuture) {
* @return Timeval Infinite past time value
*/
PHP_METHOD(Timeval, infPast) {
#if PHP_MAJOR_VERSION < 7
zval *grpc_php_timeval_inf_past =
grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
#else
grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME), return_value);
RETURN_DESTROY_ZVAL(return_value);
#endif
}
/**
@ -249,28 +350,41 @@ PHP_METHOD(Timeval, infPast) {
* @return void
*/
PHP_METHOD(Timeval, sleepUntil) {
#if PHP_MAJOR_VERSION < 7
wrapped_grpc_timeval *this =
(wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
#else
wrapped_grpc_timeval *this = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
#endif
gpr_sleep_until(this->wrapped);
}
static zend_function_entry timeval_methods[] = {
PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
void grpc_init_timeval(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods);
ce.create_object = create_wrapped_grpc_timeval;
grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 7
memcpy(&timeval_ce_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
timeval_ce_handlers.offset =
XtOffsetOf(wrapped_grpc_timeval, std);
timeval_ce_handlers.free_obj = free_wrapped_grpc_timeval;
#endif
}
void grpc_shutdown_timeval(TSRMLS_D) {}

@ -50,12 +50,31 @@
extern zend_class_entry *grpc_ce_timeval;
/* Wrapper struct for timeval that can be associated with a PHP object */
#if PHP_MAJOR_VERSION < 7
typedef struct wrapped_grpc_timeval {
zend_object std;
gpr_timespec wrapped;
} wrapped_grpc_timeval;
#else
typedef struct wrapped_grpc_timeval {
gpr_timespec wrapped;
zend_object std;
} wrapped_grpc_timeval;
static inline wrapped_grpc_timeval
*wrapped_grpc_timeval_from_obj(zend_object *obj) {
return (wrapped_grpc_timeval*)((char*)(obj) -
XtOffsetOf(wrapped_grpc_timeval, std));
}
#define Z_WRAPPED_GRPC_TIMEVAL_P(zv) \
wrapped_grpc_timeval_from_obj(Z_OBJ_P((zv)))
#endif /* PHP_MAJOR_VERSION */
/* Initialize the Timeval PHP class */
void grpc_init_timeval(TSRMLS_D);
@ -63,6 +82,10 @@ void grpc_init_timeval(TSRMLS_D);
void grpc_shutdown_timeval(TSRMLS_D);
/* Creates a Timeval object that wraps the given timeval struct */
#if PHP_MAJOR_VERSION < 7
zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC);
#else
void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object);
#endif /* PHP_MAJOR_VERSION */
#endif /* NET_GRPC_PHP_GRPC_TIMEVAL_H_ */

@ -84,8 +84,8 @@ class BaseStub
}
if ($channel) {
if (!is_a($channel, 'Channel')) {
throw new \Exception("The channel argument is not a".
"Channel object");
throw new \Exception('The channel argument is not a'.
'Channel object');
}
$this->channel = $channel;
} else {

@ -113,6 +113,7 @@ class BidiStreamingCall extends AbstractCall
]);
$this->trailing_metadata = $status_event->status->metadata;
return $status_event->status;
}
}

@ -88,6 +88,7 @@ class ClientStreamingCall extends AbstractCall
$status = $event->status;
$this->trailing_metadata = $status->metadata;
return [$this->deserializeResponse($event->message), $status];
}
}

@ -92,6 +92,7 @@ class ServerStreamingCall extends AbstractCall
]);
$this->trailing_metadata = $status_event->status->metadata;
return $status_event->status;
}
}

@ -77,6 +77,7 @@ class UnaryCall extends AbstractCall
$status = $event->status;
$this->trailing_metadata = $status->metadata;
return [$this->deserializeResponse($event->message), $status];
}
}

@ -148,7 +148,8 @@ class CallCredentialsTest extends PHPUnit_Framework_TestCase
$this->call_credentials,
$call_credentials2
);
$this->assertSame('Grpc\CallCredentials', get_class($call_credentials3));
$this->assertSame('Grpc\CallCredentials',
get_class($call_credentials3));
}
/**

@ -50,6 +50,18 @@ class CallTest extends PHPUnit_Framework_TestCase
Grpc\Timeval::infFuture());
}
public function tearDown()
{
unset($this->call);
unset($this->channel);
}
public function testConstructor()
{
$this->assertSame('Grpc\Call', get_class($this->call));
$this->assertObjectHasAttribute('channel', $this->call);
}
public function testAddEmptyMetadata()
{
$batch = [
@ -81,7 +93,8 @@ class CallTest extends PHPUnit_Framework_TestCase
{
$batch = [
Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
'key2' => ['value2', 'value3'], ],
'key2' => ['value2',
'value3'], ],
];
$result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
@ -118,4 +131,38 @@ class CallTest extends PHPUnit_Framework_TestCase
];
$result = $this->call->startBatch($batch);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidConstuctor()
{
$this->call = new Grpc\Call();
$this->assertNull($this->call);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidConstuctor2()
{
$this->call = new Grpc\Call('hi', 'hi', 'hi');
$this->assertNull($this->call);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidSetCredentials()
{
$this->call->setCredentials('hi');
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidSetCredentials2()
{
$this->call->setCredentials([]);
}
}

@ -42,10 +42,23 @@ class ChanellCredentialsTest extends PHPUnit_Framework_TestCase
{
}
public function testCreateDefault()
public function testCreateSslWith3Null()
{
$channel_credentials = Grpc\ChannelCredentials::createDefault();
$this->assertSame('Grpc\ChannelCredentials', get_class($channel_credentials));
$channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
null);
$this->assertNotNull($channel_credentials);
}
public function testCreateSslWith3NullString()
{
$channel_credentials = Grpc\ChannelCredentials::createSsl('', '', '');
$this->assertNotNull($channel_credentials);
}
public function testCreateInsecure()
{
$channel_credentials = Grpc\ChannelCredentials::createInsecure();
$this->assertNull($channel_credentials);
}
/**
@ -64,10 +77,4 @@ class ChanellCredentialsTest extends PHPUnit_Framework_TestCase
$channel_credentials = Grpc\ChannelCredentials::createComposite(
'something', 'something');
}
public function testCreateInsecure()
{
$channel_credentials = Grpc\ChannelCredentials::createInsecure();
$this->assertNull($channel_credentials);
}
}

@ -40,6 +40,7 @@ class ChannelTest extends PHPUnit_Framework_TestCase
public function tearDown()
{
unset($this->channel);
}
public function testInsecureCredentials()
@ -53,6 +54,82 @@ class ChannelTest extends PHPUnit_Framework_TestCase
$this->assertSame('Grpc\Channel', get_class($this->channel));
}
public function testGetConnectivityState()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$state = $this->channel->getConnectivityState();
$this->assertEquals(0, $state);
}
public function testGetConnectivityStateWithInt()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$state = $this->channel->getConnectivityState(123);
$this->assertEquals(0, $state);
}
public function testGetConnectivityStateWithString()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$state = $this->channel->getConnectivityState('hello');
$this->assertEquals(0, $state);
}
public function testGetConnectivityStateWithBool()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$state = $this->channel->getConnectivityState(true);
$this->assertEquals(0, $state);
}
public function testGetTarget()
{
$this->channel = new Grpc\Channel('localhost:8888',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$target = $this->channel->getTarget();
$this->assertTrue(is_string($target));
}
public function testWatchConnectivityState()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$time = new Grpc\Timeval(1000);
$state = $this->channel->watchConnectivityState(123, $time);
$this->assertTrue($state);
unset($time);
}
public function testClose()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$this->assertNotNull($this->channel);
$this->channel->close();
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidConstructorWithNull()
{
$this->channel = new Grpc\Channel();
$this->assertNull($this->channel);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidConstructorWith()
{
$this->channel = new Grpc\Channel('localhost', 'invalid');
$this->assertNull($this->channel);
}
/**
* @expectedException InvalidArgumentException
*/
@ -78,4 +155,34 @@ class ChannelTest extends PHPUnit_Framework_TestCase
]
);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidGetConnectivityStateWithArray()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$this->channel->getConnectivityState([]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidWatchConnectivityState()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$this->channel->watchConnectivityState([]);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidWatchConnectivityState2()
{
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$this->channel->watchConnectivityState(1, 'hi');
}
}

@ -521,7 +521,8 @@ class EndToEndTest extends PHPUnit_Framework_TestCase
public function testGetConnectivityState()
{
$this->assertTrue($this->channel->getConnectivityState() == Grpc\CHANNEL_IDLE);
$this->assertTrue($this->channel->getConnectivityState() ==
Grpc\CHANNEL_IDLE);
}
public function testWatchConnectivityStateFailed()

@ -36,10 +36,70 @@ class ServerTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$this->server = null;
}
public function tearDown()
{
unset($this->server);
}
public function testConstructorWithNull()
{
$this->server = new Grpc\Server();
$this->assertNotNull($this->server);
}
public function testConstructorWithNullArray()
{
$this->server = new Grpc\Server([]);
$this->assertNotNull($this->server);
}
public function testConstructorWithArray()
{
// key of array must be string
$this->server = new Grpc\Server(['ip' => '127.0.0.1',
'port' => '8080', ]);
$this->assertNotNull($this->server);
}
public function testRequestCall()
{
$this->server = new Grpc\Server();
$port = $this->server->addHttp2Port('0.0.0.0:8888');
$this->server->start();
$channel = new Grpc\Channel('localhost:8888',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$deadline = Grpc\Timeval::infFuture();
$call = new Grpc\Call($channel, 'dummy_method', $deadline);
$event = $call->startBatch([Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
]);
$c = $this->server->requestCall();
$this->assertObjectHasAttribute('call', $c);
$this->assertObjectHasAttribute('method', $c);
$this->assertSame('dummy_method', $c->method);
$this->assertObjectHasAttribute('host', $c);
$this->assertTrue(is_string($c->host));
$this->assertObjectHasAttribute('absolute_deadline', $c);
$this->assertObjectHasAttribute('metadata', $c);
unset($call);
unset($channel);
}
private function createSslObj()
{
$server_credentials = Grpc\ServerCredentials::createSsl(
null,
file_get_contents(dirname(__FILE__).'/../data/server1.key'),
file_get_contents(dirname(__FILE__).'/../data/server1.pem'));
return $server_credentials;
}
/**
@ -47,7 +107,8 @@ class ServerTest extends PHPUnit_Framework_TestCase
*/
public function testInvalidConstructor()
{
$server = new Grpc\Server('invalid_host');
$this->server = new Grpc\Server('invalid_host');
$this->assertNull($this->server);
}
/**
@ -56,7 +117,7 @@ class ServerTest extends PHPUnit_Framework_TestCase
public function testInvalidAddHttp2Port()
{
$this->server = new Grpc\Server([]);
$this->port = $this->server->addHttp2Port(['0.0.0.0:0']);
$port = $this->server->addHttp2Port(['0.0.0.0:0']);
}
/**
@ -65,6 +126,24 @@ class ServerTest extends PHPUnit_Framework_TestCase
public function testInvalidAddSecureHttp2Port()
{
$this->server = new Grpc\Server([]);
$this->port = $this->server->addSecureHttp2Port(['0.0.0.0:0']);
$port = $this->server->addSecureHttp2Port(['0.0.0.0:0']);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidAddSecureHttp2Port2()
{
$this->server = new Grpc\Server();
$port = $this->server->addSecureHttp2Port('0.0.0.0:0');
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidAddSecureHttp2Port3()
{
$this->server = new Grpc\Server();
$port = $this->server->addSecureHttp2Port('0.0.0.0:0', 'invalid');
}
}

@ -33,6 +33,57 @@
*/
class TimevalTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
}
public function tearDown()
{
unset($this->time);
}
public function testConstructorWithInt()
{
$this->time = new Grpc\Timeval(1234);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testConstructorWithNegative()
{
$this->time = new Grpc\Timeval(-123);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testConstructorWithZero()
{
$this->time = new Grpc\Timeval(0);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testConstructorWithOct()
{
$this->time = new Grpc\Timeval(0123);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testConstructorWithHex()
{
$this->time = new Grpc\Timeval(0x1A);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testConstructorWithFloat()
{
$this->time = new Grpc\Timeval(123.456);
$this->assertNotNull($this->time);
$this->assertSame('Grpc\Timeval', get_class($this->time));
}
public function testCompareSame()
{
$zero = Grpc\Timeval::zero();
@ -70,6 +121,7 @@ class TimevalTest extends PHPUnit_Framework_TestCase
public function testNowAndAdd()
{
$now = Grpc\Timeval::now();
$this->assertNotNull($now);
$delta = new Grpc\Timeval(1000);
$deadline = $now->add($delta);
$this->assertGreaterThan(0, Grpc\Timeval::compare($deadline, $now));
@ -154,5 +206,6 @@ class TimevalTest extends PHPUnit_Framework_TestCase
public function testSimilarInvalidParam()
{
$a = Grpc\Timeval::similar(1000, 1100, 1200);
$this->assertNull($delta);
}
}

@ -128,6 +128,8 @@
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
}
s.default_subspecs = 'Interface', 'Implementation'
# Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
# sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't
# allow any header to be listed outside the `header_mappings_dir` (even though doing so works in
@ -154,4 +156,26 @@
ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs), 30)}
end
s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpc'
ss.source_files = 'include/grpc/grpc_cronet.h'
end
s.subspec 'Cronet-Tests' do |ss|
ss.header_mappings_dir = '.'
ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
'src/core/ext/transport/cronet/transport/cronet_transport.c',
'test/core/end2end/cq_verifier.{c,h}',
'test/core/end2end/end2end_tests.{c,h}',
'test/core/end2end/tests/*.{c,h}',
'test/core/end2end/data/*.{c,h}',
'test/core/util/test_config.{c,h}',
'test/core/util/port.h',
'test/core/util/port_posix.c',
'test/core/util/port_server_client.{c,h}'
ss.dependency 'CronetFramework'
end
end

Loading…
Cancel
Save