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