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