aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/images/load_balancing_design.pngbin0 -> 40354 bytes
-rw-r--r--doc/load-balancing.md75
-rw-r--r--gRPC-Core.podspec24
-rw-r--r--include/grpc++/impl/codegen/async_unary_call.h2
-rw-r--r--include/grpc++/impl/codegen/config_protobuf.h4
-rw-r--r--include/grpc/impl/codegen/compression_types.h17
-rw-r--r--include/grpc/impl/codegen/grpc_types.h38
-rw-r--r--src/core/ext/client_config/channel_connectivity.c2
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c30
-rw-r--r--src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m394
-rw-r--r--src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist24
-rw-r--r--src/objective-c/tests/Podfile12
-rw-r--r--src/objective-c/tests/Tests.xcodeproj/project.pbxproj168
-rw-r--r--src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme99
-rw-r--r--src/php/ext/grpc/call.c692
-rw-r--r--src/php/ext/grpc/call.h36
-rw-r--r--src/php/ext/grpc/call_credentials.c103
-rwxr-xr-xsrc/php/ext/grpc/call_credentials.h23
-rw-r--r--src/php/ext/grpc/channel.c194
-rwxr-xr-xsrc/php/ext/grpc/channel.h23
-rw-r--r--src/php/ext/grpc/channel_credentials.c92
-rwxr-xr-xsrc/php/ext/grpc/channel_credentials.h23
-rw-r--r--src/php/ext/grpc/php_grpc.c54
-rw-r--r--src/php/ext/grpc/php_grpc.h4
-rw-r--r--src/php/ext/grpc/server.c136
-rwxr-xr-xsrc/php/ext/grpc/server.h20
-rw-r--r--src/php/ext/grpc/server_credentials.c67
-rwxr-xr-xsrc/php/ext/grpc/server_credentials.h20
-rw-r--r--src/php/ext/grpc/timeval.c144
-rwxr-xr-xsrc/php/ext/grpc/timeval.h23
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/BaseStub.php4
-rw-r--r--src/php/lib/Grpc/BidiStreamingCall.php1
-rw-r--r--src/php/lib/Grpc/ClientStreamingCall.php1
-rw-r--r--src/php/lib/Grpc/ServerStreamingCall.php1
-rw-r--r--src/php/lib/Grpc/UnaryCall.php1
-rw-r--r--src/php/tests/unit_tests/CallCredentialsTest.php3
-rw-r--r--[-rwxr-xr-x]src/php/tests/unit_tests/CallTest.php49
-rw-r--r--src/php/tests/unit_tests/ChannelCredentialsTest.php25
-rw-r--r--src/php/tests/unit_tests/ChannelTest.php107
-rw-r--r--[-rwxr-xr-x]src/php/tests/unit_tests/EndToEndTest.php3
-rw-r--r--[-rwxr-xr-x]src/php/tests/unit_tests/SecureEndToEndTest.php0
-rw-r--r--src/php/tests/unit_tests/ServerTest.php85
-rw-r--r--[-rwxr-xr-x]src/php/tests/unit_tests/TimevalTest.php53
-rw-r--r--templates/gRPC-Core.podspec.template24
-rwxr-xr-xtools/gcp/stress_test/stress_test_utils.py2
-rwxr-xr-xtools/profiling/latency_profile/profile_analyzer.py28
46 files changed, 2576 insertions, 354 deletions
diff --git a/doc/images/load_balancing_design.png b/doc/images/load_balancing_design.png
new file mode 100644
index 0000000000..86183966fb
--- /dev/null
+++ b/doc/images/load_balancing_design.png
Binary files differ
diff --git a/doc/load-balancing.md b/doc/load-balancing.md
index 681be02a72..dfaa7a7f33 100644
--- a/doc/load-balancing.md
+++ b/doc/load-balancing.md
@@ -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.
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index e10e05387b..f7d8701735 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -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
@@ -759,4 +761,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
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index 47ac5bee92..05681e2242 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -65,7 +65,7 @@ class ClientAsyncResponseReader GRPC_FINAL
const W& request)
: context_(context),
call_(channel->CreateCall(method, context, cq)),
- collection_(new CallOpSetCollection) {
+ collection_(std::make_shared<CallOpSetCollection>()) {
collection_->init_buf_.SetCollection(collection_);
collection_->init_buf_.SendInitialMetadata(
context->send_initial_metadata_, context->initial_metadata_flags());
diff --git a/include/grpc++/impl/codegen/config_protobuf.h b/include/grpc++/impl/codegen/config_protobuf.h
index 4bee1bc422..318ba59683 100644
--- a/include/grpc++/impl/codegen/config_protobuf.h
+++ b/include/grpc++/impl/codegen/config_protobuf.h
@@ -49,7 +49,7 @@
#include <google/protobuf/descriptor.pb.h>
#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool
-#define GPRC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
+#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
@@ -75,7 +75,7 @@ typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool;
-typedef GPRC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
+typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
diff --git a/include/grpc/impl/codegen/compression_types.h b/include/grpc/impl/codegen/compression_types.h
index 9065d1edd0..3034182d4c 100644
--- a/include/grpc/impl/codegen/compression_types.h
+++ b/include/grpc/impl/codegen/compression_types.h
@@ -46,12 +46,27 @@ extern "C" {
#define GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY \
"grpc-internal-encoding-request"
-/** To be used in channel arguments */
+/** To be used in channel arguments.
+ *
+ * \addtogroup grpc_arg_keys
+ * \{ */
+/** Default compression algorithm for the channel.
+ * Its value is an int from the \a grpc_compression_algorithm enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \
"grpc.default_compression_algorithm"
+/** Default compression level for the channel.
+ * Its value is an int from the \a grpc_compression_level enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level"
+/** Compression algorithms supported by the channel.
+ * Its value is a bitset (an int). Bits correspond to algorithms in \a
+ * grpc_compression_algorithm. For example, its LSB corresponds to
+ * GRPC_COMPRESS_NONE, the next bit to GRPC_COMPRESS_DEFLATE, etc.
+ * Unset bits disable support for the algorithm. By default all algorithms are
+ * supported. It's not possible to disable GRPC_COMPRESS_NONE (the attempt will
+ * be ignored). */
#define GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET \
"grpc.compression_enabled_algorithms_bitset"
+/** \} */
/* The various compression algorithms supported by gRPC */
typedef enum {
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index c0ed139506..e5a82883be 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -106,58 +106,66 @@ typedef struct {
by grpc_arg; keys are strings to allow easy backwards-compatible extension
by arbitrary parties.
All evaluation is performed at channel creation time (i.e. the values in
- this structure need only live through the creation invocation). */
+ this structure need only live through the creation invocation).
+
+ See the description of the \ref grpc_arg_keys "available args" for more
+ details. */
typedef struct {
size_t num_args;
grpc_arg *args;
} grpc_channel_args;
-/* Channel argument keys: */
-/** Enable census for tracing and stats collection */
+/** \defgroup grpc_arg_keys
+ * Channel argument keys.
+ * \{
+ */
+/** If non-zero, enable census for tracing and stats collection. */
#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
-/** Enable load reporting */
+/** If non-zero, enable load reporting. */
#define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting"
/** Maximum number of concurrent incoming streams to allow on a http2
- connection */
+ connection. Int valued. */
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
-/** Maximum message length that the channel can receive */
+/** Maximum message length that the channel can receive. Int valued, bytes. */
#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
-/** Initial sequence number for http2 transports */
+/** Initial sequence number for http2 transports. Int valued. */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Amount to read ahead on individual streams. Defaults to 64kb, larger
values can help throughput on high-latency connections.
NOTE: at some point we'd like to auto-tune this, and this parameter
- will become a no-op. */
+ will become a no-op. Int valued, bytes. */
#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
-/** How much memory to use for hpack decoding */
+/** How much memory to use for hpack decoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
"grpc.http2.hpack_table_size.decoder"
-/** How much memory to use for hpack encoding */
+/** How much memory to use for hpack encoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
"grpc.http2.hpack_table_size.encoder"
-/** Default authority to pass if none specified on call construction */
+/** Default authority to pass if none specified on call construction. A string.
+ * */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
/** Primary user agent: goes at the start of the user-agent metadata
- sent on each request */
+ sent on each request. A string. */
#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
/** Secondary user agent: goes at the end of the user-agent metadata
- sent on each request */
+ sent on each request. A string. */
#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
/** The maximum time between subsequent connection attempts, in ms */
#define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
/* The caller of the secure_channel_create functions may override the target
name used for SSL host name checking using this channel argument which is of
- type GRPC_ARG_STRING. This *should* be used for testing only.
+ type \a GRPC_ARG_STRING. This *should* be used for testing only.
If this argument is not specified, the name used for SSL host name checking
will be the target parameter (assuming that the secure channel is an SSL
channel). If this parameter is specified and the underlying is not an SSL
channel, it will just be ignored. */
#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
-/* Maximum metadata size */
+/* Maximum metadata size, in bytes. */
#define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
+/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
diff --git a/src/core/ext/client_config/channel_connectivity.c b/src/core/ext/client_config/channel_connectivity.c
index c1220e3a8c..ce3c13a4ee 100644
--- a/src/core/ext/client_config/channel_connectivity.c
+++ b/src/core/ext/client_config/channel_connectivity.c
@@ -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;
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index 4b593f4b2c..16a5e3083e 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -844,6 +844,11 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
*worker_hdl = &worker;
grpc_error *error = GRPC_ERROR_NONE;
+ /* Avoid malloc for small number of elements. */
+ enum { inline_elements = 96 };
+ struct pollfd pollfd_space[inline_elements];
+ struct grpc_fd_watcher watcher_space[inline_elements];
+
/* pollset->mu already held */
int added_worker = 0;
int locked = 1;
@@ -899,15 +904,23 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
int r;
size_t i, fd_count;
nfds_t pfd_count;
- /* TODO(ctiller): inline some elements to avoid an allocation */
grpc_fd_watcher *watchers;
struct pollfd *pfds;
timeout = poll_deadline_to_millis_timeout(deadline, now);
- /* TODO(ctiller): perform just one malloc here if we exceed the inline
- * case */
- pfds = gpr_malloc(sizeof(*pfds) * (pollset->fd_count + 2));
- watchers = gpr_malloc(sizeof(*watchers) * (pollset->fd_count + 2));
+
+ if (pollset->fd_count + 2 <= inline_elements) {
+ pfds = pollfd_space;
+ watchers = watcher_space;
+ } else {
+ /* Allocate one buffer to hold both pfds and watchers arrays */
+ const size_t pfd_size = sizeof(*pfds) * (pollset->fd_count + 2);
+ const size_t watch_size = sizeof(*watchers) * (pollset->fd_count + 2);
+ void *buf = gpr_malloc(pfd_size + watch_size);
+ pfds = buf;
+ watchers = (void *)((char *)buf + pfd_size);
+ }
+
fd_count = 0;
pfd_count = 2;
pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
@@ -974,8 +987,11 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
}
- gpr_free(pfds);
- gpr_free(watchers);
+ if (pfds != pollfd_space) {
+ /* pfds and watchers are in the same memory block pointed to by pfds */
+ gpr_free(pfds);
+ }
+
GPR_TIMER_END("maybe_work_and_unlock", 0);
locked = 0;
} else {
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
new file mode 100644
index 0000000000..58abb492ce
--- /dev/null
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
@@ -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
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist b/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
new file mode 100644
index 0000000000..fbeeb96ba6
--- /dev/null
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
@@ -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>
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 17b9740d52..db11208a1b 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -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
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index f9389a4977..2c80b08d03 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -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 = (
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
new file mode 100644
index 0000000000..a1da2e0c97
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
@@ -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>
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 2cd45f10dc..bd1eccb01b 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -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
}
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 36c5f2d272..9fc52d7820 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -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);
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index ec0e6b9181..70aaffb848 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -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
}
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
index d2f6a92449..e05e14698b 100755
--- a/src/php/ext/grpc/call_credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -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;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 8d94c59683..6737e340f9 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -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
}
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index cc5823ee7f..ea5efeaf86 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -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_ */
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index b76fb105f3..16ba0368eb 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -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
}
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
index d89984ce60..44071b10f1 100755
--- a/src/php/ext/grpc/channel_credentials.h
+++ b/src/php/ext/grpc/channel_credentials.h
@@ -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);
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 449ba3cd47..5edfa2da7d 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -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
- */
diff --git a/src/php/ext/grpc/php_grpc.h b/src/php/ext/grpc/php_grpc.h
index 1d4834c50f..bd7ee75a6f 100644
--- a/src/php/ext/grpc/php_grpc.h
+++ b/src/php/ext/grpc/php_grpc.h
@@ -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)
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index c13e7cd1f9..50fb2d0cf9 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -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
}
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index 022257f37c..a7df456a11 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -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);
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 505da10a28..296632d5bd 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -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
}
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index 7101d65000..d37fafc0dc 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -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);
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 5e242162a8..8dc997c2dd 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -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) {}
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index 7456eb6d58..d4eb2facde 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -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_ */
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index df3fe85d44..2fec1bd9cc 100755..100644
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -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 {
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index 95e51c5088..c2fdb94b86 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -113,6 +113,7 @@ class BidiStreamingCall extends AbstractCall
]);
$this->trailing_metadata = $status_event->status->metadata;
+
return $status_event->status;
}
}
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 315a406735..4050f7ed06 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -88,6 +88,7 @@ class ClientStreamingCall extends AbstractCall
$status = $event->status;
$this->trailing_metadata = $status->metadata;
+
return [$this->deserializeResponse($event->message), $status];
}
}
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index 53599fe4ae..ba89d9f972 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -92,6 +92,7 @@ class ServerStreamingCall extends AbstractCall
]);
$this->trailing_metadata = $status_event->status->metadata;
+
return $status_event->status;
}
}
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index b114b771b8..a71b05dc93 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -77,6 +77,7 @@ class UnaryCall extends AbstractCall
$status = $event->status;
$this->trailing_metadata = $status->metadata;
+
return [$this->deserializeResponse($event->message), $status];
}
}
diff --git a/src/php/tests/unit_tests/CallCredentialsTest.php b/src/php/tests/unit_tests/CallCredentialsTest.php
index 5fec06cd13..1994c8afe5 100644
--- a/src/php/tests/unit_tests/CallCredentialsTest.php
+++ b/src/php/tests/unit_tests/CallCredentialsTest.php
@@ -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));
}
/**
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index fa026f0935..d736f51546 100755..100644
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -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([]);
+ }
}
diff --git a/src/php/tests/unit_tests/ChannelCredentialsTest.php b/src/php/tests/unit_tests/ChannelCredentialsTest.php
index 56c1d8f006..e822929ccd 100644
--- a/src/php/tests/unit_tests/ChannelCredentialsTest.php
+++ b/src/php/tests/unit_tests/ChannelCredentialsTest.php
@@ -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);
- }
}
diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php
index a1f9053c39..4b35b1a28c 100644
--- a/src/php/tests/unit_tests/ChannelTest.php
+++ b/src/php/tests/unit_tests/ChannelTest.php
@@ -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');
+ }
}
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 2b09f9d112..09364580c0 100755..100644
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -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()
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index c388ee5031..c388ee5031 100755..100644
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
diff --git a/src/php/tests/unit_tests/ServerTest.php b/src/php/tests/unit_tests/ServerTest.php
index 76aaa06970..f2346ab113 100644
--- a/src/php/tests/unit_tests/ServerTest.php
+++ b/src/php/tests/unit_tests/ServerTest.php
@@ -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');
}
}
diff --git a/src/php/tests/unit_tests/TimevalTest.php b/src/php/tests/unit_tests/TimevalTest.php
index a3dbce079f..2d19f64c79 100755..100644
--- a/src/php/tests/unit_tests/TimevalTest.php
+++ b/src/php/tests/unit_tests/TimevalTest.php
@@ -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);
}
}
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index aefe6e965c..9eeee22271 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -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
diff --git a/tools/gcp/stress_test/stress_test_utils.py b/tools/gcp/stress_test/stress_test_utils.py
index b821fc8fcc..be50af3184 100755
--- a/tools/gcp/stress_test/stress_test_utils.py
+++ b/tools/gcp/stress_test/stress_test_utils.py
@@ -121,7 +121,7 @@ class BigQueryHelper:
if not page['jobComplete']:
print('TIMEOUT ERROR: The query %s timed out. Current timeout value is'
' %d msec. Returning False (i.e assuming there are no failures)'
- ) % (query, timeoout_msec)
+ ) % (query, timeout_msec)
return False
num_failures = int(page['totalRows'])
diff --git a/tools/profiling/latency_profile/profile_analyzer.py b/tools/profiling/latency_profile/profile_analyzer.py
index dad0712d40..48b8e9b950 100755
--- a/tools/profiling/latency_profile/profile_analyzer.py
+++ b/tools/profiling/latency_profile/profile_analyzer.py
@@ -43,6 +43,7 @@ TIME_FROM_SCOPE_START = object()
TIME_TO_SCOPE_END = object()
TIME_FROM_STACK_START = object()
TIME_TO_STACK_END = object()
+TIME_FROM_LAST_IMPORTANT = object()
argp = argparse.ArgumentParser(description='Process output of basic_prof builds')
@@ -78,10 +79,14 @@ class ScopeBuilder(object):
self.call_stack_builder.lines.append(line_item)
def finish(self, line):
- assert line['tag'] == self.top_line.tag, 'expected %s, got %s; thread=%s; t0=%f t1=%f' % (self.top_line.tag, line['tag'], line['thd'], self.top_line.start_time, line['t'])
+ assert line['tag'] == self.top_line.tag, (
+ 'expected %s, got %s; thread=%s; t0=%f t1=%f' %
+ (self.top_line.tag, line['tag'], line['thd'], self.top_line.start_time,
+ line['t']))
final_time_stamp = line['t']
assert self.top_line.end_time is None
self.top_line.end_time = final_time_stamp
+ self.top_line.important = self.top_line.important or line['imp']
assert SELF_TIME not in self.top_line.times
self.top_line.times[SELF_TIME] = final_time_stamp - self.top_line.start_time
for line in self.call_stack_builder.lines[self.first_child_pos:]:
@@ -101,9 +106,14 @@ class CallStackBuilder(object):
start_time = self.lines[0].start_time
end_time = self.lines[0].end_time
self.signature = self.signature.hexdigest()
+ last_important = start_time
for line in self.lines:
line.times[TIME_FROM_STACK_START] = line.start_time - start_time
line.times[TIME_TO_STACK_END] = end_time - line.end_time
+ line.times[TIME_FROM_LAST_IMPORTANT] = line.start_time - last_important
+ if line.important:
+ last_important = line.end_time
+ last_important = end_time
def add(self, line):
line_type = line['type']
@@ -113,7 +123,9 @@ class CallStackBuilder(object):
self.stk.append(ScopeBuilder(self, line))
return False
elif line_type == '}':
- assert self.stk, 'expected non-empty stack for closing %s; thread=%s; t=%f' % (line['tag'], line['thd'], line['t'])
+ assert self.stk, (
+ 'expected non-empty stack for closing %s; thread=%s; t=%f' %
+ (line['tag'], line['thd'], line['t']))
self.stk.pop().finish(line)
if not self.stk:
self.finish()
@@ -216,9 +228,16 @@ def time_format(idx):
return ''
return ent
+BANNER = {
+ 'simple': 'Count: %(count)d',
+ 'html': '<h1>Count: %(count)d</h1>'
+}
+
FORMAT = [
('TAG', lambda line: '..'*line.indent + tidy_tag(line.tag)),
('LOC', lambda line: '%s:%d' % (line.filename[line.filename.rfind('/')+1:], line.fileline)),
+ ('IMP', lambda line: '*' if line.important else ''),
+ ('FROM_IMP', time_format(TIME_FROM_LAST_IMPORTANT)),
('FROM_STACK_START', time_format(TIME_FROM_STACK_START)),
('SELF', time_format(SELF_TIME)),
('TO_STACK_END', time_format(TIME_TO_STACK_END)),
@@ -227,11 +246,6 @@ FORMAT = [
('TO_SCOPE_END', time_format(TIME_TO_SCOPE_END)),
]
-BANNER = {
- 'simple': 'Count: %(count)d',
- 'html': '<h1>Count: %(count)d</h1>'
-}
-
if args.fmt == 'html':
print '<html>'
print '<head>'