• 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 #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