1*cc02d7e2SAndroid Build Coastguard Worker /*
2*cc02d7e2SAndroid Build Coastguard Worker *
3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2015 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker *
5*cc02d7e2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker *
9*cc02d7e2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker *
11*cc02d7e2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker * limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker *
17*cc02d7e2SAndroid Build Coastguard Worker */
18*cc02d7e2SAndroid Build Coastguard Worker
19*cc02d7e2SAndroid Build Coastguard Worker /**
20*cc02d7e2SAndroid Build Coastguard Worker * class Server
21*cc02d7e2SAndroid Build Coastguard Worker * @see https://github.com/grpc/grpc/tree/master/src/php/ext/grpc/server.c
22*cc02d7e2SAndroid Build Coastguard Worker */
23*cc02d7e2SAndroid Build Coastguard Worker
24*cc02d7e2SAndroid Build Coastguard Worker #include "server.h"
25*cc02d7e2SAndroid Build Coastguard Worker
26*cc02d7e2SAndroid Build Coastguard Worker #include <ext/spl/spl_exceptions.h>
27*cc02d7e2SAndroid Build Coastguard Worker #include <zend_exceptions.h>
28*cc02d7e2SAndroid Build Coastguard Worker
29*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/grpc_security.h>
30*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/slice.h>
31*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/support/alloc.h>
32*cc02d7e2SAndroid Build Coastguard Worker
33*cc02d7e2SAndroid Build Coastguard Worker #include "call.h"
34*cc02d7e2SAndroid Build Coastguard Worker #include "completion_queue.h"
35*cc02d7e2SAndroid Build Coastguard Worker #include "channel.h"
36*cc02d7e2SAndroid Build Coastguard Worker #include "server_credentials.h"
37*cc02d7e2SAndroid Build Coastguard Worker #include "timeval.h"
38*cc02d7e2SAndroid Build Coastguard Worker
39*cc02d7e2SAndroid Build Coastguard Worker zend_class_entry *grpc_ce_server;
40*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_DECLARE_OBJECT_HANDLER(server_ce_handlers)
41*cc02d7e2SAndroid Build Coastguard Worker
42*cc02d7e2SAndroid Build Coastguard Worker /* Frees and destroys an instance of wrapped_grpc_server */
43*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server)
44*cc02d7e2SAndroid Build Coastguard Worker if (p->wrapped != NULL) {
45*cc02d7e2SAndroid Build Coastguard Worker grpc_server_shutdown_and_notify(p->wrapped, completion_queue, NULL);
46*cc02d7e2SAndroid Build Coastguard Worker grpc_server_cancel_all_calls(p->wrapped);
47*cc02d7e2SAndroid Build Coastguard Worker grpc_completion_queue_pluck(completion_queue, NULL,
48*cc02d7e2SAndroid Build Coastguard Worker gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
49*cc02d7e2SAndroid Build Coastguard Worker grpc_server_destroy(p->wrapped);
50*cc02d7e2SAndroid Build Coastguard Worker }
PHP_GRPC_FREE_WRAPPED_FUNC_END()51*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_FREE_WRAPPED_FUNC_END()
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard Worker /* Initializes an instance of wrapped_grpc_call to be associated with an
54*cc02d7e2SAndroid Build Coastguard Worker * object of a class specified by class_type */
55*cc02d7e2SAndroid Build Coastguard Worker php_grpc_zend_object create_wrapped_grpc_server(zend_class_entry *class_type
56*cc02d7e2SAndroid Build Coastguard Worker TSRMLS_DC) {
57*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server);
58*cc02d7e2SAndroid Build Coastguard Worker zend_object_std_init(&intern->std, class_type TSRMLS_CC);
59*cc02d7e2SAndroid Build Coastguard Worker object_properties_init(&intern->std, class_type);
60*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server, server_ce_handlers);
61*cc02d7e2SAndroid Build Coastguard Worker }
62*cc02d7e2SAndroid Build Coastguard Worker
63*cc02d7e2SAndroid Build Coastguard Worker /**
64*cc02d7e2SAndroid Build Coastguard Worker * Constructs a new instance of the Server class
65*cc02d7e2SAndroid Build Coastguard Worker * @param array $args_array The arguments to pass to the server (optional)
66*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Server,__construct)67*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Server, __construct) {
68*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server *server =
69*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server, getThis());
70*cc02d7e2SAndroid Build Coastguard Worker zval *args_array = NULL;
71*cc02d7e2SAndroid Build Coastguard Worker grpc_channel_args args;
72*cc02d7e2SAndroid Build Coastguard Worker
73*cc02d7e2SAndroid Build Coastguard Worker /* "|a" == 1 optional array */
74*cc02d7e2SAndroid Build Coastguard Worker if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) ==
75*cc02d7e2SAndroid Build Coastguard Worker FAILURE) {
76*cc02d7e2SAndroid Build Coastguard Worker zend_throw_exception(spl_ce_InvalidArgumentException,
77*cc02d7e2SAndroid Build Coastguard Worker "Server expects an array", 1 TSRMLS_CC);
78*cc02d7e2SAndroid Build Coastguard Worker return;
79*cc02d7e2SAndroid Build Coastguard Worker }
80*cc02d7e2SAndroid Build Coastguard Worker if (args_array == NULL) {
81*cc02d7e2SAndroid Build Coastguard Worker server->wrapped = grpc_server_create(NULL, NULL);
82*cc02d7e2SAndroid Build Coastguard Worker } else {
83*cc02d7e2SAndroid Build Coastguard Worker if (php_grpc_read_args_array(args_array, &args TSRMLS_CC) == FAILURE) {
84*cc02d7e2SAndroid Build Coastguard Worker efree(args.args);
85*cc02d7e2SAndroid Build Coastguard Worker return;
86*cc02d7e2SAndroid Build Coastguard Worker }
87*cc02d7e2SAndroid Build Coastguard Worker server->wrapped = grpc_server_create(&args, NULL);
88*cc02d7e2SAndroid Build Coastguard Worker efree(args.args);
89*cc02d7e2SAndroid Build Coastguard Worker }
90*cc02d7e2SAndroid Build Coastguard Worker grpc_server_register_completion_queue(server->wrapped, completion_queue,
91*cc02d7e2SAndroid Build Coastguard Worker NULL);
92*cc02d7e2SAndroid Build Coastguard Worker }
93*cc02d7e2SAndroid Build Coastguard Worker
94*cc02d7e2SAndroid Build Coastguard Worker /**
95*cc02d7e2SAndroid Build Coastguard Worker * Request a call on a server. Creates a single GRPC_SERVER_RPC_NEW event.
96*cc02d7e2SAndroid Build Coastguard Worker * @return void
97*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Server,requestCall)98*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Server, requestCall) {
99*cc02d7e2SAndroid Build Coastguard Worker grpc_call_error error_code;
100*cc02d7e2SAndroid Build Coastguard Worker grpc_call *call;
101*cc02d7e2SAndroid Build Coastguard Worker grpc_call_details details;
102*cc02d7e2SAndroid Build Coastguard Worker grpc_metadata_array metadata;
103*cc02d7e2SAndroid Build Coastguard Worker grpc_event event;
104*cc02d7e2SAndroid Build Coastguard Worker
105*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server *server =
106*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server, getThis());
107*cc02d7e2SAndroid Build Coastguard Worker zval *result;
108*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_MAKE_STD_ZVAL(result);
109*cc02d7e2SAndroid Build Coastguard Worker object_init(result);
110*cc02d7e2SAndroid Build Coastguard Worker
111*cc02d7e2SAndroid Build Coastguard Worker grpc_call_details_init(&details);
112*cc02d7e2SAndroid Build Coastguard Worker grpc_metadata_array_init(&metadata);
113*cc02d7e2SAndroid Build Coastguard Worker error_code =
114*cc02d7e2SAndroid Build Coastguard Worker grpc_server_request_call(server->wrapped, &call, &details, &metadata,
115*cc02d7e2SAndroid Build Coastguard Worker completion_queue, completion_queue, NULL);
116*cc02d7e2SAndroid Build Coastguard Worker if (error_code != GRPC_CALL_OK) {
117*cc02d7e2SAndroid Build Coastguard Worker zend_throw_exception(spl_ce_LogicException, "request_call failed",
118*cc02d7e2SAndroid Build Coastguard Worker (long)error_code TSRMLS_CC);
119*cc02d7e2SAndroid Build Coastguard Worker goto cleanup;
120*cc02d7e2SAndroid Build Coastguard Worker }
121*cc02d7e2SAndroid Build Coastguard Worker event = grpc_completion_queue_pluck(completion_queue, NULL,
122*cc02d7e2SAndroid Build Coastguard Worker gpr_inf_future(GPR_CLOCK_REALTIME),
123*cc02d7e2SAndroid Build Coastguard Worker NULL);
124*cc02d7e2SAndroid Build Coastguard Worker if (!event.success) {
125*cc02d7e2SAndroid Build Coastguard Worker zend_throw_exception(spl_ce_LogicException,
126*cc02d7e2SAndroid Build Coastguard Worker "Failed to request a call for some reason",
127*cc02d7e2SAndroid Build Coastguard Worker 1 TSRMLS_CC);
128*cc02d7e2SAndroid Build Coastguard Worker goto cleanup;
129*cc02d7e2SAndroid Build Coastguard Worker }
130*cc02d7e2SAndroid Build Coastguard Worker char *method_text = grpc_slice_to_c_string(details.method);
131*cc02d7e2SAndroid Build Coastguard Worker char *host_text = grpc_slice_to_c_string(details.host);
132*cc02d7e2SAndroid Build Coastguard Worker php_grpc_add_property_string(result, "method", method_text, true);
133*cc02d7e2SAndroid Build Coastguard Worker php_grpc_add_property_string(result, "host", host_text, true);
134*cc02d7e2SAndroid Build Coastguard Worker gpr_free(method_text);
135*cc02d7e2SAndroid Build Coastguard Worker gpr_free(host_text);
136*cc02d7e2SAndroid Build Coastguard Worker php_grpc_add_property_zval(result, "call",
137*cc02d7e2SAndroid Build Coastguard Worker grpc_php_wrap_call(call, true TSRMLS_CC));
138*cc02d7e2SAndroid Build Coastguard Worker php_grpc_add_property_zval(result, "absolute_deadline",
139*cc02d7e2SAndroid Build Coastguard Worker grpc_php_wrap_timeval(details.deadline TSRMLS_CC));
140*cc02d7e2SAndroid Build Coastguard Worker php_grpc_add_property_zval(result, "metadata",
141*cc02d7e2SAndroid Build Coastguard Worker grpc_parse_metadata_array(&metadata TSRMLS_CC));
142*cc02d7e2SAndroid Build Coastguard Worker
143*cc02d7e2SAndroid Build Coastguard Worker cleanup:
144*cc02d7e2SAndroid Build Coastguard Worker grpc_call_details_destroy(&details);
145*cc02d7e2SAndroid Build Coastguard Worker grpc_metadata_array_destroy(&metadata);
146*cc02d7e2SAndroid Build Coastguard Worker RETURN_DESTROY_ZVAL(result);
147*cc02d7e2SAndroid Build Coastguard Worker }
148*cc02d7e2SAndroid Build Coastguard Worker
149*cc02d7e2SAndroid Build Coastguard Worker /**
150*cc02d7e2SAndroid Build Coastguard Worker * Add a http2 over tcp listener.
151*cc02d7e2SAndroid Build Coastguard Worker * @param string $addr The address to add
152*cc02d7e2SAndroid Build Coastguard Worker * @return int Port on success, 0 on failure
153*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Server,addHttp2Port)154*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Server, addHttp2Port) {
155*cc02d7e2SAndroid Build Coastguard Worker const char *addr;
156*cc02d7e2SAndroid Build Coastguard Worker php_grpc_int addr_len;
157*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server *server =
158*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server, getThis());
159*cc02d7e2SAndroid Build Coastguard Worker
160*cc02d7e2SAndroid Build Coastguard Worker /* "s" == 1 string */
161*cc02d7e2SAndroid Build Coastguard Worker if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len)
162*cc02d7e2SAndroid Build Coastguard Worker == FAILURE) {
163*cc02d7e2SAndroid Build Coastguard Worker zend_throw_exception(spl_ce_InvalidArgumentException,
164*cc02d7e2SAndroid Build Coastguard Worker "add_http2_port expects a string", 1 TSRMLS_CC);
165*cc02d7e2SAndroid Build Coastguard Worker return;
166*cc02d7e2SAndroid Build Coastguard Worker }
167*cc02d7e2SAndroid Build Coastguard Worker grpc_server_credentials *creds = grpc_insecure_server_credentials_create();
168*cc02d7e2SAndroid Build Coastguard Worker int result = grpc_server_add_http2_port(server->wrapped, addr, creds);
169*cc02d7e2SAndroid Build Coastguard Worker grpc_server_credentials_release(creds);
170*cc02d7e2SAndroid Build Coastguard Worker RETURN_LONG(result);
171*cc02d7e2SAndroid Build Coastguard Worker }
172*cc02d7e2SAndroid Build Coastguard Worker
173*cc02d7e2SAndroid Build Coastguard Worker /**
174*cc02d7e2SAndroid Build Coastguard Worker * Add a secure http2 over tcp listener.
175*cc02d7e2SAndroid Build Coastguard Worker * @param string $addr The address to add
176*cc02d7e2SAndroid Build Coastguard Worker * @param ServerCredentials The ServerCredentials object
177*cc02d7e2SAndroid Build Coastguard Worker * @return int Port on success, 0 on failure
178*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Server,addSecureHttp2Port)179*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Server, addSecureHttp2Port) {
180*cc02d7e2SAndroid Build Coastguard Worker const char *addr;
181*cc02d7e2SAndroid Build Coastguard Worker php_grpc_int addr_len;
182*cc02d7e2SAndroid Build Coastguard Worker zval *creds_obj;
183*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server *server =
184*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server, getThis());
185*cc02d7e2SAndroid Build Coastguard Worker
186*cc02d7e2SAndroid Build Coastguard Worker /* "sO" == 1 string, 1 object */
187*cc02d7e2SAndroid Build Coastguard Worker if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
188*cc02d7e2SAndroid Build Coastguard Worker &creds_obj, grpc_ce_server_credentials) ==
189*cc02d7e2SAndroid Build Coastguard Worker FAILURE) {
190*cc02d7e2SAndroid Build Coastguard Worker zend_throw_exception(spl_ce_InvalidArgumentException,
191*cc02d7e2SAndroid Build Coastguard Worker "add_http2_port expects a string and a "
192*cc02d7e2SAndroid Build Coastguard Worker "ServerCredentials", 1 TSRMLS_CC);
193*cc02d7e2SAndroid Build Coastguard Worker return;
194*cc02d7e2SAndroid Build Coastguard Worker }
195*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server_credentials *creds =
196*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server_credentials, creds_obj);
197*cc02d7e2SAndroid Build Coastguard Worker RETURN_LONG(grpc_server_add_http2_port(server->wrapped, addr,
198*cc02d7e2SAndroid Build Coastguard Worker creds->wrapped));
199*cc02d7e2SAndroid Build Coastguard Worker }
200*cc02d7e2SAndroid Build Coastguard Worker
201*cc02d7e2SAndroid Build Coastguard Worker /**
202*cc02d7e2SAndroid Build Coastguard Worker * Start a server - tells all listeners to start listening
203*cc02d7e2SAndroid Build Coastguard Worker * @return void
204*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Server,start)205*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Server, start) {
206*cc02d7e2SAndroid Build Coastguard Worker wrapped_grpc_server *server =
207*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_server, getThis());
208*cc02d7e2SAndroid Build Coastguard Worker grpc_server_start(server->wrapped);
209*cc02d7e2SAndroid Build Coastguard Worker }
210*cc02d7e2SAndroid Build Coastguard Worker
211*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 0)
212*cc02d7e2SAndroid Build Coastguard Worker ZEND_ARG_INFO(0, args)
213*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
214*cc02d7e2SAndroid Build Coastguard Worker
215*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_requestCall, 0, 0, 0)
216*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
217*cc02d7e2SAndroid Build Coastguard Worker
218*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_addHttp2Port, 0, 0, 1)
219*cc02d7e2SAndroid Build Coastguard Worker ZEND_ARG_INFO(0, addr)
220*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
221*cc02d7e2SAndroid Build Coastguard Worker
222*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_addSecureHttp2Port, 0, 0, 2)
223*cc02d7e2SAndroid Build Coastguard Worker ZEND_ARG_INFO(0, addr)
224*cc02d7e2SAndroid Build Coastguard Worker ZEND_ARG_INFO(0, server_creds)
225*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
226*cc02d7e2SAndroid Build Coastguard Worker
227*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_start, 0, 0, 0)
228*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
229*cc02d7e2SAndroid Build Coastguard Worker
230*cc02d7e2SAndroid Build Coastguard Worker static zend_function_entry server_methods[] = {
231*cc02d7e2SAndroid Build Coastguard Worker PHP_ME(Server, __construct, arginfo_construct,
232*cc02d7e2SAndroid Build Coastguard Worker ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
233*cc02d7e2SAndroid Build Coastguard Worker PHP_ME(Server, requestCall, arginfo_requestCall,
234*cc02d7e2SAndroid Build Coastguard Worker ZEND_ACC_PUBLIC)
235*cc02d7e2SAndroid Build Coastguard Worker PHP_ME(Server, addHttp2Port, arginfo_addHttp2Port,
236*cc02d7e2SAndroid Build Coastguard Worker ZEND_ACC_PUBLIC)
237*cc02d7e2SAndroid Build Coastguard Worker PHP_ME(Server, addSecureHttp2Port, arginfo_addSecureHttp2Port,
238*cc02d7e2SAndroid Build Coastguard Worker ZEND_ACC_PUBLIC)
239*cc02d7e2SAndroid Build Coastguard Worker PHP_ME(Server, start, arginfo_start,
240*cc02d7e2SAndroid Build Coastguard Worker ZEND_ACC_PUBLIC)
241*cc02d7e2SAndroid Build Coastguard Worker PHP_FE_END
242*cc02d7e2SAndroid Build Coastguard Worker };
243*cc02d7e2SAndroid Build Coastguard Worker
grpc_init_server(TSRMLS_D)244*cc02d7e2SAndroid Build Coastguard Worker void grpc_init_server(TSRMLS_D) {
245*cc02d7e2SAndroid Build Coastguard Worker zend_class_entry ce;
246*cc02d7e2SAndroid Build Coastguard Worker INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods);
247*cc02d7e2SAndroid Build Coastguard Worker ce.create_object = create_wrapped_grpc_server;
248*cc02d7e2SAndroid Build Coastguard Worker grpc_ce_server = zend_register_internal_class(&ce TSRMLS_CC);
249*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_INIT_HANDLER(wrapped_grpc_server, server_ce_handlers);
250*cc02d7e2SAndroid Build Coastguard Worker }
251