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