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