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