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