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