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 "php_grpc.h"
20
21 #include "call.h"
22 #include "channel.h"
23 #include "server.h"
24 #include "timeval.h"
25 #include "version.h"
26 #include "channel_credentials.h"
27 #include "call_credentials.h"
28 #include "server_credentials.h"
29 #include "completion_queue.h"
30 #include <inttypes.h>
31 #include <grpc/credentials.h>
32 #include <grpc/grpc_security.h>
33 #include <grpc/support/alloc.h>
34 #include <grpc/support/log.h>
35 #include <grpc/support/string_util.h>
36 #include <grpc/support/time.h>
37 #include <ext/spl/spl_exceptions.h>
38 #include <zend_exceptions.h>
39
40 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
41 #include <pthread.h>
42 #endif
43
44 ZEND_DECLARE_MODULE_GLOBALS(grpc)
45 static PHP_GINIT_FUNCTION(grpc);
46 HashTable grpc_persistent_list;
47 HashTable grpc_target_upper_bound_map;
48 /* {{{ grpc_functions[]
49 *
50 * Every user visible function must have an entry in grpc_functions[].
51 */
52 const zend_function_entry grpc_functions[] = {
53 PHP_FE_END /* Must be the last line in grpc_functions[] */
54 };
55 /* }}} */
56
57 ZEND_DECLARE_MODULE_GLOBALS(grpc);
58
59 /* {{{ grpc_module_entry
60 */
61 zend_module_entry grpc_module_entry = {
62 STANDARD_MODULE_HEADER,
63 "grpc",
64 grpc_functions,
65 PHP_MINIT(grpc),
66 PHP_MSHUTDOWN(grpc),
67 PHP_RINIT(grpc),
68 NULL,
69 PHP_MINFO(grpc),
70 PHP_GRPC_VERSION,
71 PHP_MODULE_GLOBALS(grpc),
72 PHP_GINIT(grpc),
73 NULL,
74 NULL,
75 STANDARD_MODULE_PROPERTIES_EX};
76 /* }}} */
77
78 #ifdef COMPILE_DL_GRPC
79 ZEND_GET_MODULE(grpc)
80 #endif
81
82 /* {{{ PHP_INI
83 */
PHP_INI_BEGIN()84 PHP_INI_BEGIN()
85 STD_PHP_INI_ENTRY("grpc.enable_fork_support", "0", PHP_INI_SYSTEM, OnUpdateBool,
86 enable_fork_support, zend_grpc_globals, grpc_globals)
87 STD_PHP_INI_ENTRY("grpc.poll_strategy", NULL, PHP_INI_SYSTEM, OnUpdateString,
88 poll_strategy, zend_grpc_globals, grpc_globals)
89 STD_PHP_INI_ENTRY("grpc.grpc_verbosity", NULL, PHP_INI_SYSTEM, OnUpdateString,
90 grpc_verbosity, zend_grpc_globals, grpc_globals)
91 STD_PHP_INI_ENTRY("grpc.grpc_trace", NULL, PHP_INI_SYSTEM, OnUpdateString,
92 grpc_trace, zend_grpc_globals, grpc_globals)
93 PHP_INI_END()
94 /* }}} */
95
96 /* {{{ php_grpc_init_globals
97 */
98 /* Uncomment this function if you have INI entries
99 static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
100 {
101 grpc_globals->global_value = 0;
102 grpc_globals->global_string = NULL;
103 }
104 */
105 /* }}} */
106
107 void create_new_channel(
108 wrapped_grpc_channel *channel,
109 char *target,
110 grpc_channel_args args,
111 wrapped_grpc_channel_credentials *creds) {
112 if (creds == NULL) {
113 grpc_channel_credentials *insecure_creds = grpc_insecure_credentials_create();
114 channel->wrapper->wrapped = grpc_channel_create(target, insecure_creds, &args);
115 grpc_channel_credentials_release(insecure_creds);
116 } else {
117 channel->wrapper->wrapped =
118 grpc_channel_create(target, creds->wrapped, &args);
119 }
120 }
121
acquire_persistent_locks()122 void acquire_persistent_locks() {
123 zval *data;
124 PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
125 php_grpc_zend_resource *rsrc =
126 (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
127 if (rsrc == NULL) {
128 break;
129 }
130 channel_persistent_le_t* le = rsrc->ptr;
131
132 gpr_mu_lock(&le->channel->mu);
133 PHP_GRPC_HASH_FOREACH_END()
134 }
135
release_persistent_locks()136 void release_persistent_locks() {
137 zval *data;
138 PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
139 php_grpc_zend_resource *rsrc =
140 (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
141 if (rsrc == NULL) {
142 break;
143 }
144 channel_persistent_le_t* le = rsrc->ptr;
145
146 gpr_mu_unlock(&le->channel->mu);
147 PHP_GRPC_HASH_FOREACH_END()
148 }
149
destroy_grpc_channels()150 void destroy_grpc_channels() {
151 zval *data;
152 PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
153 php_grpc_zend_resource *rsrc =
154 (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
155 if (rsrc == NULL) {
156 break;
157 }
158 channel_persistent_le_t* le = rsrc->ptr;
159
160 wrapped_grpc_channel wrapped_channel;
161 wrapped_channel.wrapper = le->channel;
162 grpc_channel_wrapper *channel = wrapped_channel.wrapper;
163 grpc_channel_destroy(channel->wrapped);
164 channel->wrapped = NULL;
165 PHP_GRPC_HASH_FOREACH_END()
166 }
167
prefork()168 void prefork() {
169 acquire_persistent_locks();
170 }
171
172 // Clean all channels in the persistent list
173 // Called at post fork
php_grpc_clean_persistent_list(TSRMLS_D)174 void php_grpc_clean_persistent_list(TSRMLS_D) {
175 zend_hash_clean(&grpc_persistent_list);
176 zend_hash_clean(&grpc_target_upper_bound_map);
177 }
178
postfork_child()179 void postfork_child() {
180 TSRMLS_FETCH();
181
182 // loop through persistent list and destroy all underlying grpc_channel objs
183 destroy_grpc_channels();
184
185 release_persistent_locks();
186
187 // clean all channels in the persistent list
188 php_grpc_clean_persistent_list(TSRMLS_C);
189
190 // clear completion queue
191 grpc_php_shutdown_completion_queue(TSRMLS_C);
192
193 // clean-up grpc_core
194 grpc_shutdown();
195 if (grpc_is_initialized() > 0) {
196 zend_throw_exception(spl_ce_UnexpectedValueException,
197 "Oops, failed to shutdown gRPC Core after fork()",
198 1 TSRMLS_CC);
199 }
200
201 // restart grpc_core
202 grpc_init();
203 grpc_php_init_completion_queue(TSRMLS_C);
204 }
205
postfork_parent()206 void postfork_parent() {
207 release_persistent_locks();
208 }
209
register_fork_handlers()210 void register_fork_handlers() {
211 if (getenv("GRPC_ENABLE_FORK_SUPPORT")) {
212 #ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
213 pthread_atfork(&prefork, &postfork_parent, &postfork_child);
214 #endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
215 }
216 }
217
apply_ini_settings(TSRMLS_D)218 void apply_ini_settings(TSRMLS_D) {
219 if (GRPC_G(enable_fork_support)) {
220 char *enable_str = malloc(sizeof("GRPC_ENABLE_FORK_SUPPORT=1"));
221 strcpy(enable_str, "GRPC_ENABLE_FORK_SUPPORT=1");
222 putenv(enable_str);
223 }
224
225 if (GRPC_G(poll_strategy)) {
226 char *poll_str = malloc(sizeof("GRPC_POLL_STRATEGY=") +
227 strlen(GRPC_G(poll_strategy)));
228 strcpy(poll_str, "GRPC_POLL_STRATEGY=");
229 strcat(poll_str, GRPC_G(poll_strategy));
230 putenv(poll_str);
231 }
232
233 if (GRPC_G(grpc_verbosity)) {
234 char *verbosity_str = malloc(sizeof("GRPC_VERBOSITY=") +
235 strlen(GRPC_G(grpc_verbosity)));
236 strcpy(verbosity_str, "GRPC_VERBOSITY=");
237 strcat(verbosity_str, GRPC_G(grpc_verbosity));
238 putenv(verbosity_str);
239 }
240
241 if (GRPC_G(grpc_trace)) {
242 char *trace_str = malloc(sizeof("GRPC_TRACE=") +
243 strlen(GRPC_G(grpc_trace)));
244 strcpy(trace_str, "GRPC_TRACE=");
245 strcat(trace_str, GRPC_G(grpc_trace));
246 putenv(trace_str);
247 }
248 }
249
250
251 /* {{{ PHP_MINIT_FUNCTION
252 */
PHP_MINIT_FUNCTION(grpc)253 PHP_MINIT_FUNCTION(grpc) {
254 REGISTER_INI_ENTRIES();
255
256 /* Register call error constants */
257 /** everything went ok */
258 REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK,
259 CONST_CS | CONST_PERSISTENT);
260 /** something failed, we don't know what */
261 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR,
262 CONST_CS | CONST_PERSISTENT);
263 /** this method is not available on the server */
264 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER",
265 GRPC_CALL_ERROR_NOT_ON_SERVER,
266 CONST_CS | CONST_PERSISTENT);
267 /** this method is not available on the client */
268 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT",
269 GRPC_CALL_ERROR_NOT_ON_CLIENT,
270 CONST_CS | CONST_PERSISTENT);
271 /** this method must be called before invoke */
272 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED",
273 GRPC_CALL_ERROR_ALREADY_INVOKED,
274 CONST_CS | CONST_PERSISTENT);
275 /** this method must be called after invoke */
276 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED",
277 GRPC_CALL_ERROR_NOT_INVOKED,
278 CONST_CS | CONST_PERSISTENT);
279 /** this call is already finished
280 (writes_done or write_status has already been called) */
281 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED",
282 GRPC_CALL_ERROR_ALREADY_FINISHED,
283 CONST_CS | CONST_PERSISTENT);
284 /** there is already an outstanding read/write operation on the call */
285 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS",
286 GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
287 CONST_CS | CONST_PERSISTENT);
288 /** the flags value was illegal for this call */
289 REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
290 GRPC_CALL_ERROR_INVALID_FLAGS,
291 CONST_CS | CONST_PERSISTENT);
292
293 /* Register flag constants */
294 /** Hint that the write may be buffered and need not go out on the wire
295 immediately. GRPC is free to buffer the message until the next non-buffered
296 write, or until writes_done, but it need not buffer completely or at all. */
297 REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
298 CONST_CS | CONST_PERSISTENT);
299 /** Force compression to be disabled for a particular write
300 (start_write/add_metadata). Illegal on invoke/accept. */
301 REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
302 CONST_CS | CONST_PERSISTENT);
303
304 /* Register status constants */
305 /** Not an error; returned on success */
306 REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK,
307 CONST_CS | CONST_PERSISTENT);
308 /** The operation was cancelled (typically by the caller). */
309 REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
310 CONST_CS | CONST_PERSISTENT);
311 /** Unknown error. An example of where this error may be returned is
312 if a Status value received from another address space belongs to
313 an error-space that is not known in this address space. Also
314 errors raised by APIs that do not return enough error information
315 may be converted to this error. */
316 REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", GRPC_STATUS_UNKNOWN,
317 CONST_CS | CONST_PERSISTENT);
318 /** Client specified an invalid argument. Note that this differs
319 from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
320 that are problematic regardless of the state of the system
321 (e.g., a malformed file name). */
322 REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
323 GRPC_STATUS_INVALID_ARGUMENT,
324 CONST_CS | CONST_PERSISTENT);
325 /** Deadline expired before operation could complete. For operations
326 that change the state of the system, this error may be returned
327 even if the operation has completed successfully. For example, a
328 successful response from a server could have been delayed long
329 enough for the deadline to expire. */
330 REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
331 GRPC_STATUS_DEADLINE_EXCEEDED,
332 CONST_CS | CONST_PERSISTENT);
333 /** Some requested entity (e.g., file or directory) was not found. */
334 REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND", GRPC_STATUS_NOT_FOUND,
335 CONST_CS | CONST_PERSISTENT);
336 /** Some entity that we attempted to create (e.g., file or directory)
337 already exists. */
338 REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS",
339 GRPC_STATUS_ALREADY_EXISTS,
340 CONST_CS | CONST_PERSISTENT);
341 /** The caller does not have permission to execute the specified
342 operation. PERMISSION_DENIED must not be used for rejections
343 caused by exhausting some resource (use RESOURCE_EXHAUSTED
344 instead for those errors). PERMISSION_DENIED must not be
345 used if the caller can not be identified (use UNAUTHENTICATED
346 instead for those errors). */
347 REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED",
348 GRPC_STATUS_PERMISSION_DENIED,
349 CONST_CS | CONST_PERSISTENT);
350 /** The request does not have valid authentication credentials for the
351 operation. */
352 REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED",
353 GRPC_STATUS_UNAUTHENTICATED,
354 CONST_CS | CONST_PERSISTENT);
355 /** Some resource has been exhausted, perhaps a per-user quota, or
356 perhaps the entire file system is out of space. */
357 REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED",
358 GRPC_STATUS_RESOURCE_EXHAUSTED,
359 CONST_CS | CONST_PERSISTENT);
360 /** Operation was rejected because the system is not in a state
361 required for the operation's execution. For example, directory
362 to be deleted may be non-empty, an rmdir operation is applied to
363 a non-directory, etc.
364
365 A litmus test that may help a service implementor in deciding
366 between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
367 (a) Use UNAVAILABLE if the client can retry just the failing call.
368 (b) Use ABORTED if the client should retry at a higher-level
369 (e.g., restarting a read-modify-write sequence).
370 (c) Use FAILED_PRECONDITION if the client should not retry until
371 the system state has been explicitly fixed. E.g., if an "rmdir"
372 fails because the directory is non-empty, FAILED_PRECONDITION
373 should be returned since the client should not retry unless
374 they have first fixed up the directory by deleting files from it.
375 (d) Use FAILED_PRECONDITION if the client performs conditional
376 REST Get/Update/Delete on a resource and the resource on the
377 server does not match the condition. E.g., conflicting
378 read-modify-write on the same resource. */
379 REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION",
380 GRPC_STATUS_FAILED_PRECONDITION,
381 CONST_CS | CONST_PERSISTENT);
382 /** The operation was aborted, typically due to a concurrency issue
383 like sequencer check failures, transaction aborts, etc.
384
385 See litmus test above for deciding between FAILED_PRECONDITION,
386 ABORTED, and UNAVAILABLE. */
387 REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED,
388 CONST_CS | CONST_PERSISTENT);
389 /** Operation was attempted past the valid range. E.g., seeking or
390 reading past end of file.
391
392 Unlike INVALID_ARGUMENT, this error indicates a problem that may
393 be fixed if the system state changes. For example, a 32-bit file
394 system will generate INVALID_ARGUMENT if asked to read at an
395 offset that is not in the range [0,2^32-1], but it will generate
396 OUT_OF_RANGE if asked to read from an offset past the current
397 file size.
398
399 There is a fair bit of overlap between FAILED_PRECONDITION and
400 OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific
401 error) when it applies so that callers who are iterating through
402 a space can easily look for an OUT_OF_RANGE error to detect when
403 they are done. */
404 REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE",
405 GRPC_STATUS_OUT_OF_RANGE,
406 CONST_CS | CONST_PERSISTENT);
407 /** Operation is not implemented or not supported/enabled in this service. */
408 REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
409 GRPC_STATUS_UNIMPLEMENTED,
410 CONST_CS | CONST_PERSISTENT);
411 /** Internal errors. Means some invariants expected by underlying
412 system has been broken. If you see one of these errors,
413 something is very broken. */
414 REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL", GRPC_STATUS_INTERNAL,
415 CONST_CS | CONST_PERSISTENT);
416 /** The service is currently unavailable. This is a most likely a
417 transient condition and may be corrected by retrying with
418 a backoff. Note that it is not always safe to retry non-idempotent
419 operations.
420
421 WARNING: Although data MIGHT not have been transmitted when this
422 status occurs, there is NOT A GUARANTEE that the server has not seen
423 anything. So in general it is unsafe to retry on this status code
424 if the call is non-idempotent.
425
426 See litmus test above for deciding between FAILED_PRECONDITION,
427 ABORTED, and UNAVAILABLE. */
428 REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE", GRPC_STATUS_UNAVAILABLE,
429 CONST_CS | CONST_PERSISTENT);
430 /** Unrecoverable data loss or corruption. */
431 REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
432 CONST_CS | CONST_PERSISTENT);
433
434 /* Register op type constants */
435 /** Send initial metadata: one and only one instance MUST be sent for each
436 call, unless the call was cancelled - in which case this can be skipped.
437 This op completes after all bytes of metadata have been accepted by
438 outgoing flow control. */
439 REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
440 GRPC_OP_SEND_INITIAL_METADATA,
441 CONST_CS | CONST_PERSISTENT);
442 /** Send a message: 0 or more of these operations can occur for each call.
443 This op completes after all bytes for the message have been accepted by
444 outgoing flow control. */
445 REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
446 GRPC_OP_SEND_MESSAGE,
447 CONST_CS | CONST_PERSISTENT);
448 /** Send a close from the client: one and only one instance MUST be sent from
449 the client, unless the call was cancelled - in which case this can be
450 skipped. This op completes after all bytes for the call
451 (including the close) have passed outgoing flow control. */
452 REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
453 GRPC_OP_SEND_CLOSE_FROM_CLIENT,
454 CONST_CS | CONST_PERSISTENT);
455 /** Send status from the server: one and only one instance MUST be sent from
456 the server unless the call was cancelled - in which case this can be
457 skipped. This op completes after all bytes for the call
458 (including the status) have passed outgoing flow control. */
459 REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
460 GRPC_OP_SEND_STATUS_FROM_SERVER,
461 CONST_CS | CONST_PERSISTENT);
462 /** Receive initial metadata: one and only one MUST be made on the client,
463 must not be made on the server.
464 This op completes after all initial metadata has been read from the
465 peer. */
466 REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
467 GRPC_OP_RECV_INITIAL_METADATA,
468 CONST_CS | CONST_PERSISTENT);
469 /** Receive a message: 0 or more of these operations can occur for each call.
470 This op completes after all bytes of the received message have been
471 read, or after a half-close has been received on this call. */
472 REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
473 GRPC_OP_RECV_MESSAGE,
474 CONST_CS | CONST_PERSISTENT);
475 /** Receive status on the client: one and only one must be made on the client.
476 This operation always succeeds, meaning ops paired with this operation
477 will also appear to succeed, even though they may not have. In that case
478 the status will indicate some failure.
479 This op completes after all activity on the call has completed. */
480 REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
481 GRPC_OP_RECV_STATUS_ON_CLIENT,
482 CONST_CS | CONST_PERSISTENT);
483 /** Receive close on the server: one and only one must be made on the
484 server. This op completes after the close has been received by the
485 server. This operation always succeeds, meaning ops paired with
486 this operation will also appear to succeed, even though they may not
487 have. */
488 REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
489 GRPC_OP_RECV_CLOSE_ON_SERVER,
490 CONST_CS | CONST_PERSISTENT);
491
492 /* Register connectivity state constants */
493 /** channel is idle */
494 REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
495 GRPC_CHANNEL_IDLE,
496 CONST_CS | CONST_PERSISTENT);
497 /** channel is connecting */
498 REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
499 GRPC_CHANNEL_CONNECTING,
500 CONST_CS | CONST_PERSISTENT);
501 /** channel is ready for work */
502 REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
503 GRPC_CHANNEL_READY,
504 CONST_CS | CONST_PERSISTENT);
505 /** channel has seen a failure but expects to recover */
506 REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
507 GRPC_CHANNEL_TRANSIENT_FAILURE,
508 CONST_CS | CONST_PERSISTENT);
509 /** channel has seen a failure that it cannot recover from */
510 REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_FATAL_FAILURE",
511 GRPC_CHANNEL_SHUTDOWN,
512 CONST_CS | CONST_PERSISTENT);
513
514 /** grpc version string */
515 REGISTER_STRING_CONSTANT("Grpc\\VERSION", PHP_GRPC_VERSION,
516 CONST_CS | CONST_PERSISTENT);
517
518 grpc_init_call(TSRMLS_C);
519 GRPC_STARTUP(channel);
520 grpc_init_server(TSRMLS_C);
521 grpc_init_timeval(TSRMLS_C);
522 grpc_init_channel_credentials(TSRMLS_C);
523 grpc_init_call_credentials(TSRMLS_C);
524 grpc_init_server_credentials(TSRMLS_C);
525 return SUCCESS;
526 }
527 /* }}} */
528
529 /* {{{ PHP_MSHUTDOWN_FUNCTION
530 */
PHP_MSHUTDOWN_FUNCTION(grpc)531 PHP_MSHUTDOWN_FUNCTION(grpc) {
532 UNREGISTER_INI_ENTRIES();
533 // WARNING: This function IS being called by PHP when the extension
534 // is unloaded but the logs were somehow suppressed.
535 if (GRPC_G(initialized)) {
536 zend_hash_clean(&grpc_persistent_list);
537 zend_hash_destroy(&grpc_persistent_list);
538 zend_hash_clean(&grpc_target_upper_bound_map);
539 zend_hash_destroy(&grpc_target_upper_bound_map);
540 grpc_shutdown_timeval(TSRMLS_C);
541 grpc_php_shutdown_completion_queue(TSRMLS_C);
542 grpc_shutdown();
543 GRPC_G(initialized) = 0;
544 }
545 return SUCCESS;
546 }
547 /* }}} */
548
549 /* {{{ PHP_MINFO_FUNCTION
550 */
PHP_MINFO_FUNCTION(grpc)551 PHP_MINFO_FUNCTION(grpc) {
552 php_info_print_table_start();
553 php_info_print_table_row(2, "grpc support", "enabled");
554 php_info_print_table_row(2, "grpc module version", PHP_GRPC_VERSION);
555 php_info_print_table_end();
556 DISPLAY_INI_ENTRIES();
557 }
558 /* }}} */
559
560 /* {{{ PHP_RINIT_FUNCTION
561 */
PHP_RINIT_FUNCTION(grpc)562 PHP_RINIT_FUNCTION(grpc) {
563 if (!GRPC_G(initialized)) {
564 apply_ini_settings(TSRMLS_C);
565 grpc_init();
566 register_fork_handlers();
567 grpc_php_init_completion_queue(TSRMLS_C);
568 GRPC_G(initialized) = 1;
569 }
570 return SUCCESS;
571 }
572 /* }}} */
573
574 /* {{{ PHP_GINIT_FUNCTION
575 */
PHP_GINIT_FUNCTION(grpc)576 static PHP_GINIT_FUNCTION(grpc) {
577 grpc_globals->initialized = 0;
578 grpc_globals->enable_fork_support = 0;
579 grpc_globals->poll_strategy = NULL;
580 grpc_globals->grpc_verbosity = NULL;
581 grpc_globals->grpc_trace = NULL;
582 }
583 /* }}} */
584
585 /* The previous line is meant for vim and emacs, so it can correctly fold and
586 unfold functions in source code. See the corresponding marks just before
587 function definition, where the functions purpose is also documented. Please
588 follow this convention for the convenience of others editing your code.
589 */
590