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_destroy(&grpc_persistent_list);
175     zend_hash_clean(&grpc_target_upper_bound_map);
176     zend_hash_destroy(&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 
custom_logger(gpr_log_func_args * args)250 static void custom_logger(gpr_log_func_args* args) {
251   TSRMLS_FETCH();
252 
253   const char* final_slash;
254   const char* display_file;
255   char* prefix;
256   char* final;
257   gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
258 
259   final_slash = strrchr(args->file, '/');
260   if (final_slash) {
261     display_file = final_slash + 1;
262   } else {
263     display_file = args->file;
264   }
265 
266   FILE *fp = fopen(GRPC_G(log_filename), "ab");
267   if (!fp) {
268     return;
269   }
270 
271   gpr_asprintf(&prefix, "%s%" PRId64 ".%09" PRId32 " %s:%d]",
272                gpr_log_severity_string(args->severity), now.tv_sec,
273                now.tv_nsec, display_file, args->line);
274 
275   gpr_asprintf(&final, "%-60s %s\n", prefix, args->message);
276 
277   fprintf(fp, "%s", final);
278   fclose(fp);
279   gpr_free(prefix);
280   gpr_free(final);
281 }
282 
283 /* {{{ PHP_MINIT_FUNCTION
284  */
PHP_MINIT_FUNCTION(grpc)285 PHP_MINIT_FUNCTION(grpc) {
286   REGISTER_INI_ENTRIES();
287 
288   /* Register call error constants */
289   /** everything went ok */
290   REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK,
291                          CONST_CS | CONST_PERSISTENT);
292   /** something failed, we don't know what */
293   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR,
294                          CONST_CS | CONST_PERSISTENT);
295   /** this method is not available on the server */
296   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER",
297                          GRPC_CALL_ERROR_NOT_ON_SERVER,
298                          CONST_CS | CONST_PERSISTENT);
299   /** this method is not available on the client */
300   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT",
301                          GRPC_CALL_ERROR_NOT_ON_CLIENT,
302                          CONST_CS | CONST_PERSISTENT);
303   /** this method must be called before invoke */
304   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED",
305                          GRPC_CALL_ERROR_ALREADY_INVOKED,
306                          CONST_CS | CONST_PERSISTENT);
307   /** this method must be called after invoke */
308   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED",
309                          GRPC_CALL_ERROR_NOT_INVOKED,
310                          CONST_CS | CONST_PERSISTENT);
311   /** this call is already finished
312       (writes_done or write_status has already been called) */
313   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED",
314                          GRPC_CALL_ERROR_ALREADY_FINISHED,
315                          CONST_CS | CONST_PERSISTENT);
316   /** there is already an outstanding read/write operation on the call */
317   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS",
318                          GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
319                          CONST_CS | CONST_PERSISTENT);
320   /** the flags value was illegal for this call */
321   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
322                          GRPC_CALL_ERROR_INVALID_FLAGS,
323                          CONST_CS | CONST_PERSISTENT);
324 
325   /* Register flag constants */
326   /** Hint that the write may be buffered and need not go out on the wire
327       immediately. GRPC is free to buffer the message until the next non-buffered
328       write, or until writes_done, but it need not buffer completely or at all. */
329   REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
330                          CONST_CS | CONST_PERSISTENT);
331   /** Force compression to be disabled for a particular write
332       (start_write/add_metadata). Illegal on invoke/accept. */
333   REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
334                          CONST_CS | CONST_PERSISTENT);
335 
336   /* Register status constants */
337   /** Not an error; returned on success */
338   REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK,
339                          CONST_CS | CONST_PERSISTENT);
340   /** The operation was cancelled (typically by the caller). */
341   REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
342                          CONST_CS | CONST_PERSISTENT);
343   /** Unknown error.  An example of where this error may be returned is
344       if a Status value received from another address space belongs to
345       an error-space that is not known in this address space.  Also
346       errors raised by APIs that do not return enough error information
347       may be converted to this error. */
348   REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", GRPC_STATUS_UNKNOWN,
349                          CONST_CS | CONST_PERSISTENT);
350   /** Client specified an invalid argument.  Note that this differs
351       from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
352       that are problematic regardless of the state of the system
353       (e.g., a malformed file name). */
354   REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
355                          GRPC_STATUS_INVALID_ARGUMENT,
356                          CONST_CS | CONST_PERSISTENT);
357   /** Deadline expired before operation could complete.  For operations
358       that change the state of the system, this error may be returned
359       even if the operation has completed successfully.  For example, a
360       successful response from a server could have been delayed long
361       enough for the deadline to expire. */
362   REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
363                          GRPC_STATUS_DEADLINE_EXCEEDED,
364                          CONST_CS | CONST_PERSISTENT);
365   /** Some requested entity (e.g., file or directory) was not found. */
366   REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND", GRPC_STATUS_NOT_FOUND,
367                          CONST_CS | CONST_PERSISTENT);
368   /** Some entity that we attempted to create (e.g., file or directory)
369       already exists. */
370   REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS",
371                          GRPC_STATUS_ALREADY_EXISTS,
372                          CONST_CS | CONST_PERSISTENT);
373   /** The caller does not have permission to execute the specified
374       operation.  PERMISSION_DENIED must not be used for rejections
375       caused by exhausting some resource (use RESOURCE_EXHAUSTED
376       instead for those errors).  PERMISSION_DENIED must not be
377       used if the caller can not be identified (use UNAUTHENTICATED
378       instead for those errors). */
379   REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED",
380                          GRPC_STATUS_PERMISSION_DENIED,
381                          CONST_CS | CONST_PERSISTENT);
382   /** The request does not have valid authentication credentials for the
383       operation. */
384   REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED",
385                          GRPC_STATUS_UNAUTHENTICATED,
386                          CONST_CS | CONST_PERSISTENT);
387   /** Some resource has been exhausted, perhaps a per-user quota, or
388       perhaps the entire file system is out of space. */
389   REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED",
390                          GRPC_STATUS_RESOURCE_EXHAUSTED,
391                          CONST_CS | CONST_PERSISTENT);
392   /** Operation was rejected because the system is not in a state
393       required for the operation's execution.  For example, directory
394       to be deleted may be non-empty, an rmdir operation is applied to
395       a non-directory, etc.
396 
397       A litmus test that may help a service implementor in deciding
398       between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
399        (a) Use UNAVAILABLE if the client can retry just the failing call.
400        (b) Use ABORTED if the client should retry at a higher-level
401            (e.g., restarting a read-modify-write sequence).
402        (c) Use FAILED_PRECONDITION if the client should not retry until
403            the system state has been explicitly fixed.  E.g., if an "rmdir"
404            fails because the directory is non-empty, FAILED_PRECONDITION
405            should be returned since the client should not retry unless
406            they have first fixed up the directory by deleting files from it.
407        (d) Use FAILED_PRECONDITION if the client performs conditional
408            REST Get/Update/Delete on a resource and the resource on the
409            server does not match the condition. E.g., conflicting
410            read-modify-write on the same resource. */
411   REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION",
412                          GRPC_STATUS_FAILED_PRECONDITION,
413                          CONST_CS | CONST_PERSISTENT);
414   /** The operation was aborted, typically due to a concurrency issue
415       like sequencer check failures, transaction aborts, etc.
416 
417       See litmus test above for deciding between FAILED_PRECONDITION,
418       ABORTED, and UNAVAILABLE. */
419   REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED,
420                          CONST_CS | CONST_PERSISTENT);
421   /** Operation was attempted past the valid range.  E.g., seeking or
422       reading past end of file.
423 
424       Unlike INVALID_ARGUMENT, this error indicates a problem that may
425       be fixed if the system state changes. For example, a 32-bit file
426       system will generate INVALID_ARGUMENT if asked to read at an
427       offset that is not in the range [0,2^32-1], but it will generate
428       OUT_OF_RANGE if asked to read from an offset past the current
429       file size.
430 
431       There is a fair bit of overlap between FAILED_PRECONDITION and
432       OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
433       error) when it applies so that callers who are iterating through
434       a space can easily look for an OUT_OF_RANGE error to detect when
435       they are done. */
436   REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE",
437                          GRPC_STATUS_OUT_OF_RANGE,
438                          CONST_CS | CONST_PERSISTENT);
439   /** Operation is not implemented or not supported/enabled in this service. */
440   REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
441                          GRPC_STATUS_UNIMPLEMENTED,
442                          CONST_CS | CONST_PERSISTENT);
443   /** Internal errors.  Means some invariants expected by underlying
444       system has been broken.  If you see one of these errors,
445       something is very broken. */
446   REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL", GRPC_STATUS_INTERNAL,
447                          CONST_CS | CONST_PERSISTENT);
448   /** The service is currently unavailable.  This is a most likely a
449       transient condition and may be corrected by retrying with
450       a backoff. Note that it is not always safe to retry non-idempotent
451       operations.
452 
453       WARNING: Although data MIGHT not have been transmitted when this
454       status occurs, there is NOT A GUARANTEE that the server has not seen
455       anything. So in general it is unsafe to retry on this status code
456       if the call is non-idempotent.
457 
458       See litmus test above for deciding between FAILED_PRECONDITION,
459       ABORTED, and UNAVAILABLE. */
460   REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE", GRPC_STATUS_UNAVAILABLE,
461                          CONST_CS | CONST_PERSISTENT);
462   /** Unrecoverable data loss or corruption. */
463   REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
464                          CONST_CS | CONST_PERSISTENT);
465 
466   /* Register op type constants */
467   /** Send initial metadata: one and only one instance MUST be sent for each
468       call, unless the call was cancelled - in which case this can be skipped.
469       This op completes after all bytes of metadata have been accepted by
470       outgoing flow control. */
471   REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
472                          GRPC_OP_SEND_INITIAL_METADATA,
473                          CONST_CS | CONST_PERSISTENT);
474   /** Send a message: 0 or more of these operations can occur for each call.
475       This op completes after all bytes for the message have been accepted by
476       outgoing flow control. */
477   REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
478                          GRPC_OP_SEND_MESSAGE,
479                          CONST_CS | CONST_PERSISTENT);
480   /** Send a close from the client: one and only one instance MUST be sent from
481       the client, unless the call was cancelled - in which case this can be
482       skipped. This op completes after all bytes for the call
483       (including the close) have passed outgoing flow control. */
484   REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
485                          GRPC_OP_SEND_CLOSE_FROM_CLIENT,
486                          CONST_CS | CONST_PERSISTENT);
487   /** Send status from the server: one and only one instance MUST be sent from
488       the server unless the call was cancelled - in which case this can be
489       skipped. This op completes after all bytes for the call
490       (including the status) have passed outgoing flow control. */
491   REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
492                          GRPC_OP_SEND_STATUS_FROM_SERVER,
493                          CONST_CS | CONST_PERSISTENT);
494   /** Receive initial metadata: one and only one MUST be made on the client,
495       must not be made on the server.
496       This op completes after all initial metadata has been read from the
497       peer. */
498   REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
499                          GRPC_OP_RECV_INITIAL_METADATA,
500                          CONST_CS | CONST_PERSISTENT);
501   /** Receive a message: 0 or more of these operations can occur for each call.
502       This op completes after all bytes of the received message have been
503       read, or after a half-close has been received on this call. */
504   REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
505                          GRPC_OP_RECV_MESSAGE,
506                          CONST_CS | CONST_PERSISTENT);
507   /** Receive status on the client: one and only one must be made on the client.
508       This operation always succeeds, meaning ops paired with this operation
509       will also appear to succeed, even though they may not have. In that case
510       the status will indicate some failure.
511       This op completes after all activity on the call has completed. */
512   REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
513                          GRPC_OP_RECV_STATUS_ON_CLIENT,
514                          CONST_CS | CONST_PERSISTENT);
515   /** Receive close on the server: one and only one must be made on the
516       server. This op completes after the close has been received by the
517       server. This operation always succeeds, meaning ops paired with
518       this operation will also appear to succeed, even though they may not
519       have. */
520   REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
521                          GRPC_OP_RECV_CLOSE_ON_SERVER,
522                          CONST_CS | CONST_PERSISTENT);
523 
524   /* Register connectivity state constants */
525   /** channel is idle */
526   REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
527                          GRPC_CHANNEL_IDLE,
528                          CONST_CS | CONST_PERSISTENT);
529   /** channel is connecting */
530   REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
531                          GRPC_CHANNEL_CONNECTING,
532                          CONST_CS | CONST_PERSISTENT);
533   /** channel is ready for work */
534   REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
535                          GRPC_CHANNEL_READY,
536                          CONST_CS | CONST_PERSISTENT);
537   /** channel has seen a failure but expects to recover */
538   REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
539                          GRPC_CHANNEL_TRANSIENT_FAILURE,
540                          CONST_CS | CONST_PERSISTENT);
541   /** channel has seen a failure that it cannot recover from */
542   REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_FATAL_FAILURE",
543                          GRPC_CHANNEL_SHUTDOWN,
544                          CONST_CS | CONST_PERSISTENT);
545 
546   grpc_init_call(TSRMLS_C);
547   GRPC_STARTUP(channel);
548   grpc_init_server(TSRMLS_C);
549   grpc_init_timeval(TSRMLS_C);
550   grpc_init_channel_credentials(TSRMLS_C);
551   grpc_init_call_credentials(TSRMLS_C);
552   grpc_init_server_credentials(TSRMLS_C);
553   return SUCCESS;
554 }
555 /* }}} */
556 
557 /* {{{ PHP_MSHUTDOWN_FUNCTION
558  */
PHP_MSHUTDOWN_FUNCTION(grpc)559 PHP_MSHUTDOWN_FUNCTION(grpc) {
560   UNREGISTER_INI_ENTRIES();
561   // WARNING: This function IS being called by PHP when the extension
562   // is unloaded but the logs were somehow suppressed.
563   if (GRPC_G(initialized)) {
564     zend_hash_clean(&grpc_persistent_list);
565     zend_hash_destroy(&grpc_persistent_list);
566     zend_hash_clean(&grpc_target_upper_bound_map);
567     zend_hash_destroy(&grpc_target_upper_bound_map);
568     grpc_shutdown_timeval(TSRMLS_C);
569     grpc_php_shutdown_completion_queue(TSRMLS_C);
570     grpc_shutdown();
571     GRPC_G(initialized) = 0;
572   }
573   return SUCCESS;
574 }
575 /* }}} */
576 
577 /* {{{ PHP_MINFO_FUNCTION
578  */
PHP_MINFO_FUNCTION(grpc)579 PHP_MINFO_FUNCTION(grpc) {
580   php_info_print_table_start();
581   php_info_print_table_row(2, "grpc support", "enabled");
582   php_info_print_table_row(2, "grpc module version", PHP_GRPC_VERSION);
583   php_info_print_table_end();
584   DISPLAY_INI_ENTRIES();
585 }
586 /* }}} */
587 
588 /* {{{ PHP_RINIT_FUNCTION
589  */
PHP_RINIT_FUNCTION(grpc)590 PHP_RINIT_FUNCTION(grpc) {
591   if (!GRPC_G(initialized)) {
592     apply_ini_settings(TSRMLS_C);
593     if (GRPC_G(log_filename)) {
594       gpr_set_log_function(custom_logger);
595     }
596     grpc_init();
597     register_fork_handlers();
598     grpc_php_init_completion_queue(TSRMLS_C);
599     GRPC_G(initialized) = 1;
600   }
601   return SUCCESS;
602 }
603 /* }}} */
604 
605 /* {{{ PHP_GINIT_FUNCTION
606  */
PHP_GINIT_FUNCTION(grpc)607 static PHP_GINIT_FUNCTION(grpc) {
608   grpc_globals->initialized = 0;
609   grpc_globals->enable_fork_support = 0;
610   grpc_globals->poll_strategy = NULL;
611   grpc_globals->grpc_verbosity = NULL;
612   grpc_globals->grpc_trace = NULL;
613   grpc_globals->log_filename = NULL;
614 }
615 /* }}} */
616 
617 /* The previous line is meant for vim and emacs, so it can correctly fold and
618    unfold functions in source code. See the corresponding marks just before
619    function definition, where the functions purpose is also documented. Please
620    follow this convention for the convenience of others editing your code.
621 */
622