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