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