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