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