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