From bb7d088ed2ea79bdad2917b7be86bad622d1f790 Mon Sep 17 00:00:00 2001 From: Vizerai Date: Mon, 23 Oct 2017 12:06:29 -0700 Subject: Cleaning up census code. --- grpc.def | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'grpc.def') diff --git a/grpc.def b/grpc.def index 558be60c3c..4fc521f406 100644 --- a/grpc.def +++ b/grpc.def @@ -1,32 +1,4 @@ EXPORTS - census_initialize - census_shutdown - census_supported - census_enabled - census_context_create - census_context_destroy - census_context_get_status - census_context_initialize_iterator - census_context_next_tag - census_context_get_tag - census_context_encode - census_context_decode - census_trace_mask - census_set_trace_mask - census_start_rpc_op_timestamp - census_start_client_rpc_op - census_set_rpc_client_peer - census_start_server_rpc_op - census_start_op - census_end_op - census_trace_print - census_trace_scan_start - census_get_trace_record - census_trace_scan_end - census_define_resource - census_delete_resource - census_resource_id - census_record_values grpc_compression_algorithm_parse grpc_compression_algorithm_name grpc_stream_compression_algorithm_name -- cgit v1.2.3 From 42bd87e376913939850bfa78a3c7f96ce83af11e Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Fri, 20 Oct 2017 10:32:30 -0700 Subject: Adds gRPC Experimental CQ DoThenAsyncNext lambda API --- grpc.def | 2 + include/grpc++/impl/codegen/completion_queue.h | 39 +++++++++ include/grpc/grpc.h | 17 ++++ src/core/lib/surface/completion_queue.cc | 116 ++++++++++++++++++------- src/core/lib/surface/completion_queue.h | 3 + src/core/lib/surface/init.cc | 1 + src/cpp/common/completion_queue_cc.cc | 25 ++++++ src/ruby/ext/grpc/rb_grpc_imports.generated.c | 4 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 6 ++ test/core/surface/completion_queue_test.c | 76 ++++++++++++++++ test/cpp/end2end/async_end2end_test.cc | 111 ++++++++++++++++++++++- test/cpp/qps/client.h | 44 ++++------ test/cpp/qps/client_async.cc | 48 ++++++---- test/cpp/qps/client_sync.cc | 39 ++++++--- test/cpp/qps/server_async.cc | 31 ++++--- 15 files changed, 466 insertions(+), 96 deletions(-) (limited to 'grpc.def') diff --git a/grpc.def b/grpc.def index 558be60c3c..e4281f3ab6 100644 --- a/grpc.def +++ b/grpc.def @@ -54,6 +54,8 @@ EXPORTS grpc_completion_queue_pluck grpc_completion_queue_shutdown grpc_completion_queue_destroy + grpc_completion_queue_thread_local_cache_init + grpc_completion_queue_thread_local_cache_flush grpc_alarm_create grpc_alarm_set grpc_alarm_cancel diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h index ca757e2a9c..e2c0c29dca 100644 --- a/include/grpc++/impl/codegen/completion_queue.h +++ b/include/grpc++/impl/codegen/completion_queue.h @@ -109,6 +109,30 @@ class CompletionQueue : private GrpcLibraryCodegen { TIMEOUT ///< deadline was reached. }; + /// EXPERIMENTAL + /// First executes \a F, then reads from the queue, blocking up to + /// \a deadline (or the queue's shutdown). + /// Both \a tag and \a ok are updated upon success (if an event is available + /// within the \a deadline). A \a tag points to an arbitrary location usually + /// employed to uniquely identify an event. + /// + /// \param F[in] Function to execute before calling AsyncNext on this queue. + /// \param tag[out] Upon sucess, updated to point to the event's tag. + /// \param ok[out] Upon sucess, true if read a regular event, false otherwise. + /// \param deadline[in] How long to block in wait for an event. + /// + /// \return The type of event read. + template + NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) { + CompletionQueueTLSCache cache = CompletionQueueTLSCache(this); + f(); + if (cache.Flush(tag, ok)) { + return GOT_EVENT; + } else { + return AsyncNext(tag, ok, deadline); + } + } + /// Read from the queue, blocking up to \a deadline (or the queue's shutdown). /// Both \a tag and \a ok are updated upon success (if an event is available /// within the \a deadline). A \a tag points to an arbitrary location usually @@ -213,6 +237,21 @@ class CompletionQueue : private GrpcLibraryCodegen { const InputMessage& request, OutputMessage* result); + /// EXPERIMENTAL + /// Creates a Thread Local cache to store the first event + /// On this completion queue queued from this thread. Once + /// initialized, it must be flushed on the same thread. + class CompletionQueueTLSCache { + public: + CompletionQueueTLSCache(CompletionQueue* cq); + ~CompletionQueueTLSCache(); + bool Flush(void** tag, bool* ok); + + private: + CompletionQueue* cq_; + bool flushed_; + }; + NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); /// Wraps \a grpc_completion_queue_pluck. diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 1de289fba4..6df3b8086e 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -143,6 +143,23 @@ GRPCAPI void grpc_completion_queue_shutdown(grpc_completion_queue *cq); drained and no threads are executing grpc_completion_queue_next */ GRPCAPI void grpc_completion_queue_destroy(grpc_completion_queue *cq); +/*********** EXPERIMENTAL API ************/ +/** Initializes a thread local cache for \a cq. + * grpc_flush_cq_tls_cache() MUST be called on the same thread, + * with the same cq. + */ +GRPCAPI void grpc_completion_queue_thread_local_cache_init( + grpc_completion_queue *cq); + +/*********** EXPERIMENTAL API ************/ +/** Flushes the thread local cache for \a cq. + * Returns 1 if there was contents in the cache. If there was an event + * in \a cq tls cache, its tag is placed in tag, and ok is set to the + * event success. + */ +GRPCAPI int grpc_completion_queue_thread_local_cache_flush( + grpc_completion_queue *cq, void **tag, int *ok); + /** Create a completion queue alarm instance */ GRPCAPI grpc_alarm *grpc_alarm_create(void *reserved); diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc index 21664f03c8..5009f786e6 100644 --- a/src/core/lib/surface/completion_queue.cc +++ b/src/core/lib/surface/completion_queue.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include "src/core/lib/debug/stats.h" #include "src/core/lib/iomgr/pollset.h" @@ -48,6 +49,14 @@ grpc_tracer_flag grpc_trace_cq_refcount = GRPC_TRACER_INITIALIZER(false, "cq_refcount"); #endif +// Specifies a cq thread local cache. +// The first event that occurs on a thread +// with a cq cache will go into that cache, and +// will only be returned on the thread that initialized the cache. +// NOTE: Only one event will ever be cached. +GPR_TLS_DECL(g_cached_event); +GPR_TLS_DECL(g_cached_cq); + typedef struct { grpc_pollset_worker **worker; void *tag; @@ -345,6 +354,46 @@ grpc_tracer_flag grpc_cq_event_timeout_trace = static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cq, grpc_error *error); +void grpc_cq_global_init() { + gpr_tls_init(&g_cached_event); + gpr_tls_init(&g_cached_cq); +} + +void grpc_completion_queue_thread_local_cache_init(grpc_completion_queue *cq) { + if ((grpc_completion_queue *)gpr_tls_get(&g_cached_cq) == nullptr) { + gpr_tls_set(&g_cached_event, (intptr_t)0); + gpr_tls_set(&g_cached_cq, (intptr_t)cq); + } +} + +int grpc_completion_queue_thread_local_cache_flush(grpc_completion_queue *cq, + void **tag, int *ok) { + grpc_cq_completion *storage = + (grpc_cq_completion *)gpr_tls_get(&g_cached_event); + int ret = 0; + if (storage != NULL && + (grpc_completion_queue *)gpr_tls_get(&g_cached_cq) == cq) { + *tag = storage->tag; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + storage->done(&exec_ctx, storage->done_arg, storage); + *ok = (storage->next & (uintptr_t)(1)) == 1; + ret = 1; + cq_next_data *cqd = (cq_next_data *)DATA_FROM_CQ(cq); + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_mu_lock(cq->mu); + cq_finish_shutdown_next(&exec_ctx, cq); + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "shutting_down"); + } + grpc_exec_ctx_finish(&exec_ctx); + } + gpr_tls_set(&g_cached_event, (intptr_t)0); + gpr_tls_set(&g_cached_cq, (intptr_t)0); + + return ret; +} + static void cq_event_queue_init(grpc_cq_event_queue *q) { gpr_mpscq_init(&q->queue); q->queue_lock = GPR_SPINLOCK_INITIALIZER; @@ -617,7 +666,6 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } } - cq_next_data *cqd = (cq_next_data *)DATA_FROM_CQ(cq); int is_success = (error == GRPC_ERROR_NONE); @@ -628,44 +676,50 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, cq_check_tag(cq, tag, true); /* Used in debug builds only */ - /* Add the completion to the queue */ - bool is_first = cq_event_queue_push(&cqd->queue, storage); - gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); - - /* Since we do not hold the cq lock here, it is important to do an 'acquire' - load here (instead of a 'no_barrier' load) to match with the release store - (done via gpr_atm_full_fetch_add(pending_events, -1)) in cq_shutdown_next - */ - bool will_definitely_shutdown = gpr_atm_acq_load(&cqd->pending_events) == 1; - - if (!will_definitely_shutdown) { - /* Only kick if this is the first item queued */ - if (is_first) { - gpr_mu_lock(cq->mu); - grpc_error *kick_error = - cq->poller_vtable->kick(exec_ctx, POLLSET_FROM_CQ(cq), NULL); - gpr_mu_unlock(cq->mu); + if ((grpc_completion_queue *)gpr_tls_get(&g_cached_cq) == cq && + (grpc_cq_completion *)gpr_tls_get(&g_cached_event) == nullptr) { + gpr_tls_set(&g_cached_event, (intptr_t)storage); + } else { + /* Add the completion to the queue */ + bool is_first = cq_event_queue_push(&cqd->queue, storage); + gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); + + /* Since we do not hold the cq lock here, it is important to do an 'acquire' + load here (instead of a 'no_barrier' load) to match with the release + store + (done via gpr_atm_full_fetch_add(pending_events, -1)) in cq_shutdown_next + */ + bool will_definitely_shutdown = gpr_atm_acq_load(&cqd->pending_events) == 1; + + if (!will_definitely_shutdown) { + /* Only kick if this is the first item queued */ + if (is_first) { + gpr_mu_lock(cq->mu); + grpc_error *kick_error = + cq->poller_vtable->kick(exec_ctx, POLLSET_FROM_CQ(cq), NULL); + gpr_mu_unlock(cq->mu); - if (kick_error != GRPC_ERROR_NONE) { - const char *msg = grpc_error_string(kick_error); - gpr_log(GPR_ERROR, "Kick failed: %s", msg); - GRPC_ERROR_UNREF(kick_error); + if (kick_error != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(kick_error); + gpr_log(GPR_ERROR, "Kick failed: %s", msg); + GRPC_ERROR_UNREF(kick_error); + } } - } - if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) { + GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_mu_lock(cq->mu); + cq_finish_shutdown_next(exec_ctx, cq); + gpr_mu_unlock(cq->mu); + GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); + } + } else { GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); + gpr_atm_rel_store(&cqd->pending_events, 0); gpr_mu_lock(cq->mu); cq_finish_shutdown_next(exec_ctx, cq); gpr_mu_unlock(cq->mu); GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); } - } else { - GRPC_CQ_INTERNAL_REF(cq, "shutting_down"); - gpr_atm_rel_store(&cqd->pending_events, 0); - gpr_mu_lock(cq->mu); - cq_finish_shutdown_next(exec_ctx, cq); - gpr_mu_unlock(cq->mu); - GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down"); } GPR_TIMER_END("cq_end_op_for_next", 0); diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h index 69d144bd95..c02bc5da07 100644 --- a/src/core/lib/surface/completion_queue.h +++ b/src/core/lib/surface/completion_queue.h @@ -70,6 +70,9 @@ void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc); #define GRPC_CQ_INTERNAL_UNREF(ec, cc, reason) grpc_cq_internal_unref(ec, cc) #endif +/* Initializes global variables used by completion queues */ +void grpc_cq_global_init(); + /* Flag that an operation is beginning: the completion channel will not finish shutdown until a corrensponding grpc_cq_end_* call is made. \a tag is currently used only in debug builds. Return true on success, and diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index b089da2c54..058e88f804 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -64,6 +64,7 @@ static void do_basic_init(void) { gpr_log_verbosity_init(); gpr_mu_init(&g_init_mu); grpc_register_built_in_plugins(); + grpc_cq_global_init(); g_initializations = 0; } diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc index f34b0f3d58..4a2e2be688 100644 --- a/src/cpp/common/completion_queue_cc.cc +++ b/src/cpp/common/completion_queue_cc.cc @@ -71,4 +71,29 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( } } +CompletionQueue::CompletionQueueTLSCache::CompletionQueueTLSCache( + CompletionQueue* cq) + : cq_(cq), flushed_(false) { + grpc_completion_queue_thread_local_cache_init(cq_->cq_); +} + +CompletionQueue::CompletionQueueTLSCache::~CompletionQueueTLSCache() { + GPR_ASSERT(flushed_); +} + +bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) { + int res = 0; + void* res_tag; + flushed_ = true; + if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag, + &res)) { + auto cq_tag = static_cast(res_tag); + *ok = res == 1; + if (cq_tag->FinalizeResult(tag, ok)) { + return true; + } + } + return false; +} + } // namespace grpc diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 70831494fa..cd1bd98abc 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -77,6 +77,8 @@ grpc_completion_queue_next_type grpc_completion_queue_next_import; grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import; grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import; grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import; +grpc_completion_queue_thread_local_cache_init_type grpc_completion_queue_thread_local_cache_init_import; +grpc_completion_queue_thread_local_cache_flush_type grpc_completion_queue_thread_local_cache_flush_import; grpc_alarm_create_type grpc_alarm_create_import; grpc_alarm_set_type grpc_alarm_set_import; grpc_alarm_cancel_type grpc_alarm_cancel_import; @@ -385,6 +387,8 @@ void grpc_rb_load_imports(HMODULE library) { grpc_completion_queue_pluck_import = (grpc_completion_queue_pluck_type) GetProcAddress(library, "grpc_completion_queue_pluck"); grpc_completion_queue_shutdown_import = (grpc_completion_queue_shutdown_type) GetProcAddress(library, "grpc_completion_queue_shutdown"); grpc_completion_queue_destroy_import = (grpc_completion_queue_destroy_type) GetProcAddress(library, "grpc_completion_queue_destroy"); + grpc_completion_queue_thread_local_cache_init_import = (grpc_completion_queue_thread_local_cache_init_type) GetProcAddress(library, "grpc_completion_queue_thread_local_cache_init"); + grpc_completion_queue_thread_local_cache_flush_import = (grpc_completion_queue_thread_local_cache_flush_type) GetProcAddress(library, "grpc_completion_queue_thread_local_cache_flush"); grpc_alarm_create_import = (grpc_alarm_create_type) GetProcAddress(library, "grpc_alarm_create"); grpc_alarm_set_import = (grpc_alarm_set_type) GetProcAddress(library, "grpc_alarm_set"); grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 868772cfc8..c7e78b70dc 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -212,6 +212,12 @@ extern grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import typedef void(*grpc_completion_queue_destroy_type)(grpc_completion_queue *cq); extern grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import; #define grpc_completion_queue_destroy grpc_completion_queue_destroy_import +typedef void(*grpc_completion_queue_thread_local_cache_init_type)(grpc_completion_queue *cq); +extern grpc_completion_queue_thread_local_cache_init_type grpc_completion_queue_thread_local_cache_init_import; +#define grpc_completion_queue_thread_local_cache_init grpc_completion_queue_thread_local_cache_init_import +typedef int(*grpc_completion_queue_thread_local_cache_flush_type)(grpc_completion_queue *cq, void **tag, int *ok); +extern grpc_completion_queue_thread_local_cache_flush_type grpc_completion_queue_thread_local_cache_flush_import; +#define grpc_completion_queue_thread_local_cache_flush grpc_completion_queue_thread_local_cache_flush_import typedef grpc_alarm *(*grpc_alarm_create_type)(void *reserved); extern grpc_alarm_create_type grpc_alarm_create_import; #define grpc_alarm_create grpc_alarm_create_import diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c index e6372a379c..e4e4c9f1b2 100644 --- a/test/core/surface/completion_queue_test.c +++ b/test/core/surface/completion_queue_test.c @@ -158,6 +158,80 @@ static void test_cq_end_op(void) { } } +static void test_cq_tls_cache_full(void) { + grpc_event ev; + grpc_completion_queue *cc; + grpc_cq_completion completion; + grpc_cq_polling_type polling_types[] = { + GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING}; + grpc_completion_queue_attributes attr; + grpc_exec_ctx init_exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_exec_ctx exec_ctx; + void *tag = create_test_tag(); + void *res_tag; + int ok; + + LOG_TEST("test_cq_tls_cache_full"); + + attr.version = 1; + attr.cq_completion_type = GRPC_CQ_NEXT; + for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) { + exec_ctx = init_exec_ctx; // Reset exec_ctx + attr.cq_polling_type = polling_types[i]; + cc = grpc_completion_queue_create( + grpc_completion_queue_factory_lookup(&attr), &attr, NULL); + + grpc_completion_queue_thread_local_cache_init(cc); + GPR_ASSERT(grpc_cq_begin_op(cc, tag)); + grpc_cq_end_op(&exec_ctx, cc, tag, GRPC_ERROR_NONE, + do_nothing_end_completion, NULL, &completion); + + ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL); + GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT); + + GPR_ASSERT( + grpc_completion_queue_thread_local_cache_flush(cc, &res_tag, &ok) == 1); + GPR_ASSERT(res_tag == tag); + GPR_ASSERT(ok); + + ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL); + GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT); + + shutdown_and_destroy(cc); + grpc_exec_ctx_finish(&exec_ctx); + } +} + +static void test_cq_tls_cache_empty(void) { + grpc_completion_queue *cc; + grpc_cq_polling_type polling_types[] = { + GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING}; + grpc_completion_queue_attributes attr; + grpc_exec_ctx init_exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_exec_ctx exec_ctx; + void *res_tag; + int ok; + + LOG_TEST("test_cq_tls_cache_empty"); + + attr.version = 1; + attr.cq_completion_type = GRPC_CQ_NEXT; + for (size_t i = 0; i < GPR_ARRAY_SIZE(polling_types); i++) { + exec_ctx = init_exec_ctx; // Reset exec_ctx + attr.cq_polling_type = polling_types[i]; + cc = grpc_completion_queue_create( + grpc_completion_queue_factory_lookup(&attr), &attr, NULL); + + GPR_ASSERT( + grpc_completion_queue_thread_local_cache_flush(cc, &res_tag, &ok) == 0); + grpc_completion_queue_thread_local_cache_init(cc); + GPR_ASSERT( + grpc_completion_queue_thread_local_cache_flush(cc, &res_tag, &ok) == 0); + shutdown_and_destroy(cc); + grpc_exec_ctx_finish(&exec_ctx); + } +} + static void test_shutdown_then_next_polling(void) { grpc_cq_polling_type polling_types[] = { GRPC_CQ_DEFAULT_POLLING, GRPC_CQ_NON_LISTENING, GRPC_CQ_NON_POLLING}; @@ -300,6 +374,8 @@ int main(int argc, char **argv) { test_cq_end_op(); test_pluck(); test_pluck_after_shutdown(); + test_cq_tls_cache_full(); + test_cq_tls_cache_empty(); grpc_shutdown(); return 0; } diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 2a33e8ae11..b7634d0438 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -99,7 +99,7 @@ class PollingOverrider { class Verifier { public: - explicit Verifier(bool spin) : spin_(spin) {} + explicit Verifier(bool spin) : spin_(spin), lambda_run_(false) {} // Expect sets the expected ok value for a specific tag Verifier& Expect(int i, bool expect_ok) { return ExpectUnless(i, expect_ok, false); @@ -142,6 +142,18 @@ class Verifier { return detag(got_tag); } + template + CompletionQueue::NextStatus DoOnceThenAsyncNext( + CompletionQueue* cq, void** got_tag, bool* ok, T deadline, + std::function lambda) { + if (lambda_run_) { + return cq->AsyncNext(got_tag, ok, deadline); + } else { + lambda_run_ = true; + return cq->DoThenAsyncNext(lambda, got_tag, ok, deadline); + } + } + // Verify keeps calling Next until all currently set // expected tags are complete void Verify(CompletionQueue* cq) { Verify(cq, false); } @@ -154,6 +166,7 @@ class Verifier { Next(cq, ignore_ok); } } + // This version of Verify stops after a certain deadline void Verify(CompletionQueue* cq, std::chrono::system_clock::time_point deadline) { @@ -193,6 +206,47 @@ class Verifier { } } + // This version of Verify stops after a certain deadline, and uses the + // DoThenAsyncNext API + // to call the lambda + void Verify(CompletionQueue* cq, + std::chrono::system_clock::time_point deadline, + std::function lambda) { + if (expectations_.empty()) { + bool ok; + void* got_tag; + if (spin_) { + while (std::chrono::system_clock::now() < deadline) { + EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda), + CompletionQueue::TIMEOUT); + } + } else { + EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda), + CompletionQueue::TIMEOUT); + } + } else { + while (!expectations_.empty()) { + bool ok; + void* got_tag; + if (spin_) { + for (;;) { + GPR_ASSERT(std::chrono::system_clock::now() < deadline); + auto r = DoOnceThenAsyncNext( + cq, &got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME), lambda); + if (r == CompletionQueue::TIMEOUT) continue; + if (r == CompletionQueue::GOT_EVENT) break; + gpr_log(GPR_ERROR, "unexpected result from AsyncNext"); + abort(); + } + } else { + EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda), + CompletionQueue::GOT_EVENT); + } + GotTag(got_tag, ok, false); + } + } + } + private: void GotTag(void* got_tag, bool ok, bool ignore_ok) { auto it = expectations_.find(got_tag); @@ -226,6 +280,7 @@ class Verifier { std::map expectations_; std::map maybe_expectations_; bool spin_; + bool lambda_run_; }; bool plugin_has_sync_methods(std::unique_ptr& plugin) { @@ -490,6 +545,60 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) { EXPECT_TRUE(recv_status.ok()); } +// Test a simple RPC using the async version of Next +TEST_P(AsyncEnd2endTest, DoThenAsyncNextRpc) { + ResetStub(); + + EchoRequest send_request; + EchoRequest recv_request; + EchoResponse send_response; + EchoResponse recv_response; + Status recv_status; + + ClientContext cli_ctx; + ServerContext srv_ctx; + grpc::ServerAsyncResponseWriter response_writer(&srv_ctx); + + send_request.set_message(GetParam().message_content); + std::unique_ptr> response_reader( + stub_->AsyncEcho(&cli_ctx, send_request, cq_.get())); + + std::chrono::system_clock::time_point time_now( + std::chrono::system_clock::now()); + std::chrono::system_clock::time_point time_limit( + std::chrono::system_clock::now() + std::chrono::seconds(10)); + Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now); + Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now); + + auto resp_writer_ptr = &response_writer; + auto lambda_2 = [&, this, resp_writer_ptr]() { + gpr_log(GPR_ERROR, "CALLED"); + service_->RequestEcho(&srv_ctx, &recv_request, resp_writer_ptr, cq_.get(), + cq_.get(), tag(2)); + }; + + Verifier(GetParam().disable_blocking) + .Expect(2, true) + .Verify(cq_.get(), time_limit, lambda_2); + EXPECT_EQ(send_request.message(), recv_request.message()); + + auto recv_resp_ptr = &recv_response; + auto status_ptr = &recv_status; + send_response.set_message(recv_request.message()); + auto lambda_3 = [&, this, resp_writer_ptr, send_response]() { + resp_writer_ptr->Finish(send_response, Status::OK, tag(3)); + }; + response_reader->Finish(recv_resp_ptr, status_ptr, tag(4)); + Verifier(GetParam().disable_blocking) + .Expect(3, true) + .Expect(4, true) + .Verify(cq_.get(), std::chrono::system_clock::time_point::max(), + lambda_3); + + EXPECT_EQ(send_response.message(), recv_response.message()); + EXPECT_TRUE(recv_status.ok()); +} + // Two pings and a final pong. TEST_P(AsyncEnd2endTest, SimpleClientStreaming) { ResetStub(); diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h index abf755b393..9888c762f2 100644 --- a/test/cpp/qps/client.h +++ b/test/cpp/qps/client.h @@ -226,8 +226,6 @@ class Client { } virtual void DestroyMultithreading() = 0; - virtual void InitThreadFunc(size_t thread_idx) = 0; - virtual bool ThreadFunc(HistogramEntry* histogram, size_t thread_idx) = 0; void SetupLoadTest(const ClientConfig& config, size_t num_threads) { // Set up the load distribution based on the number of threads @@ -275,7 +273,6 @@ class Client { : std::bind(&Client::NextIssueTime, this, thread_idx); } - private: class Thread { public: Thread(Client* client, size_t idx) @@ -295,6 +292,16 @@ class Client { MergeStatusHistogram(statuses_, s); } + void UpdateHistogram(HistogramEntry* entry) { + std::lock_guard g(mu_); + if (entry->value_used()) { + histogram_.Add(entry->value()); + } + if (entry->status_used()) { + statuses_[entry->status()]++; + } + } + private: Thread(const Thread&); Thread& operator=(const Thread&); @@ -310,29 +317,8 @@ class Client { wait_loop++; } - client_->InitThreadFunc(idx_); - - for (;;) { - // run the loop body - HistogramEntry entry; - const bool thread_still_ok = client_->ThreadFunc(&entry, idx_); - // lock, update histogram if needed and see if we're done - std::lock_guard g(mu_); - if (entry.value_used()) { - histogram_.Add(entry.value()); - } - if (entry.status_used()) { - statuses_[entry.status()]++; - } - if (!thread_still_ok) { - gpr_log(GPR_ERROR, "Finishing client thread due to RPC error"); - } - if (!thread_still_ok || - static_cast(gpr_atm_acq_load(&client_->thread_pool_done_))) { - client_->CompleteThread(); - return; - } - } + client_->ThreadFunc(idx_, this); + client_->CompleteThread(); } std::mutex mu_; @@ -343,6 +329,12 @@ class Client { std::thread impl_; }; + bool ThreadCompleted() { + return static_cast(gpr_atm_acq_load(&thread_pool_done_)); + } + + virtual void ThreadFunc(size_t thread_idx, Client::Thread* t) = 0; + std::vector> threads_; std::unique_ptr timer_; diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index 9ed4e0b355..b5c7208664 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -236,33 +236,47 @@ class AsyncClient : public ClientImpl { this->EndThreads(); // this needed for resolution } - void InitThreadFunc(size_t thread_idx) override final {} - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override final { + void ThreadFunc(size_t thread_idx, Client::Thread* t) override final { void* got_tag; bool ok; - if (cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { + HistogramEntry entry; + HistogramEntry* entry_ptr = &entry; + if (!cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { + return; + } + ClientRpcContext* ctx; + std::mutex* shutdown_mu = &shutdown_state_[thread_idx]->mutex; + do { + t->UpdateHistogram(entry_ptr); // Got a regular event, so process it - ClientRpcContext* ctx = ClientRpcContext::detag(got_tag); + ctx = ClientRpcContext::detag(got_tag); // Proceed while holding a lock to make sure that // this thread isn't supposed to shut down - std::lock_guard l(shutdown_state_[thread_idx]->mutex); + shutdown_mu->lock(); if (shutdown_state_[thread_idx]->shutdown) { ctx->TryCancel(); delete ctx; - return true; - } - if (!ctx->RunNextState(ok, entry)) { - // The RPC and callback are done, so clone the ctx - // and kickstart the new one - ctx->StartNewClone(cli_cqs_[cq_[thread_idx]].get()); - delete ctx; + while (cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { + ctx = ClientRpcContext::detag(got_tag); + ctx->TryCancel(); + delete ctx; + } + shutdown_mu->unlock(); + return; } - return true; - } else { - // queue is shutting down, so we must be done - return true; - } + } while (cli_cqs_[cq_[thread_idx]]->DoThenAsyncNext( + [&, ctx, ok, entry_ptr, shutdown_mu]() { + bool next_ok = ok; + if (!ctx->RunNextState(next_ok, entry_ptr)) { + // The RPC and callback are done, so clone the ctx + // and kickstart the new one + ctx->StartNewClone(cli_cqs_[cq_[thread_idx]].get()); + delete ctx; + } + shutdown_mu->unlock(); + }, + &got_tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME))); } std::vector> cli_cqs_; diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index 94554a46b2..9f20b148eb 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -62,6 +62,25 @@ class SynchronousClient virtual ~SynchronousClient(){}; + virtual void InitThreadFuncImpl(size_t thread_idx) = 0; + virtual bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) = 0; + + void ThreadFunc(size_t thread_idx, Thread* t) override { + InitThreadFuncImpl(thread_idx); + for (;;) { + // run the loop body + HistogramEntry entry; + const bool thread_still_ok = ThreadFuncImpl(&entry, thread_idx); + t->UpdateHistogram(&entry); + if (!thread_still_ok) { + gpr_log(GPR_ERROR, "Finishing client thread due to RPC error"); + } + if (!thread_still_ok || ThreadCompleted()) { + return; + } + } + } + protected: // WaitToIssue returns false if we realize that we need to break out bool WaitToIssue(int thread_idx) { @@ -103,9 +122,9 @@ class SynchronousUnaryClient final : public SynchronousClient { } ~SynchronousUnaryClient() {} - void InitThreadFunc(size_t thread_idx) override {} + void InitThreadFuncImpl(size_t thread_idx) override {} - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override { + bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override { if (!WaitToIssue(thread_idx)) { return true; } @@ -192,13 +211,13 @@ class SynchronousStreamingPingPongClient final } } - void InitThreadFunc(size_t thread_idx) override { + void InitThreadFuncImpl(size_t thread_idx) override { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]); messages_issued_[thread_idx] = 0; } - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override { + bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override { if (!WaitToIssue(thread_idx)) { return true; } @@ -246,14 +265,14 @@ class SynchronousStreamingFromClientClient final } } - void InitThreadFunc(size_t thread_idx) override { + void InitThreadFuncImpl(size_t thread_idx) override { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); stream_[thread_idx] = stub->StreamingFromClient(&context_[thread_idx], &responses_[thread_idx]); last_issue_[thread_idx] = UsageTimer::Now(); } - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override { + bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override { // Figure out how to make histogram sensible if this is rate-paced if (!WaitToIssue(thread_idx)) { return true; @@ -282,13 +301,13 @@ class SynchronousStreamingFromServerClient final public: SynchronousStreamingFromServerClient(const ClientConfig& config) : SynchronousStreamingClient(config), last_recv_(num_threads_) {} - void InitThreadFunc(size_t thread_idx) override { + void InitThreadFuncImpl(size_t thread_idx) override { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); stream_[thread_idx] = stub->StreamingFromServer(&context_[thread_idx], request_); last_recv_[thread_idx] = UsageTimer::Now(); } - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override { + bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override { GPR_TIMER_SCOPE("SynchronousStreamingFromServerClient::ThreadFunc", 0); if (stream_[thread_idx]->Read(&responses_[thread_idx])) { double now = UsageTimer::Now(); @@ -328,11 +347,11 @@ class SynchronousStreamingBothWaysClient final } } - void InitThreadFunc(size_t thread_idx) override { + void InitThreadFuncImpl(size_t thread_idx) override { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); stream_[thread_idx] = stub->StreamingBothWays(&context_[thread_idx]); } - bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) override { + bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override { // TODO (vjpai): Do this return true; } diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 4a82f98199..c1097cb8ee 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -194,23 +194,32 @@ class AsyncQpsServerTest final : public grpc::testing::Server { // Wait until work is available or we are shutting down bool ok; void *got_tag; - while (srv_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { - ServerRpcContext *ctx = detag(got_tag); + if (!srv_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { + return; + } + ServerRpcContext *ctx; + std::mutex *mu_ptr; + do { + ctx = detag(got_tag); // The tag is a pointer to an RPC context to invoke // Proceed while holding a lock to make sure that // this thread isn't supposed to shut down - std::lock_guard l(shutdown_state_[thread_idx]->mutex); + mu_ptr = &shutdown_state_[thread_idx]->mutex; + mu_ptr->lock(); if (shutdown_state_[thread_idx]->shutdown) { + mu_ptr->unlock(); return; } - std::lock_guard l2(*ctx); - const bool still_going = ctx->RunNextState(ok); - // if this RPC context is done, refresh it - if (!still_going) { - ctx->Reset(); - } - } - return; + } while (srv_cqs_[cq_[thread_idx]]->DoThenAsyncNext( + [&, ctx, ok, mu_ptr]() { + ctx->lock(); + if (!ctx->RunNextState(ok)) { + ctx->Reset(); + } + ctx->unlock(); + mu_ptr->unlock(); + }, + &got_tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME))); } class ServerRpcContext { -- cgit v1.2.3 From c1d354d7f2621f467e2f37f36498c20e132c3a72 Mon Sep 17 00:00:00 2001 From: Justin Burke Date: Tue, 19 Sep 2017 15:06:01 -0700 Subject: Support SSL server certificate reloading. --- grpc.def | 6 + include/grpc/grpc_security.h | 74 +++++- include/grpc/grpc_security_constants.h | 7 + .../security/credentials/ssl/ssl_credentials.cc | 156 ++++++++++++- .../lib/security/credentials/ssl/ssl_credentials.h | 12 + .../lib/security/transport/security_connector.cc | 251 +++++++++++++++------ .../lib/security/transport/security_connector.h | 4 +- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 12 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 18 ++ 9 files changed, 456 insertions(+), 84 deletions(-) (limited to 'grpc.def') diff --git a/grpc.def b/grpc.def index e4281f3ab6..eea12bdda5 100644 --- a/grpc.def +++ b/grpc.def @@ -132,8 +132,14 @@ EXPORTS grpc_metadata_credentials_create_from_plugin grpc_secure_channel_create grpc_server_credentials_release + grpc_ssl_server_certificate_config_create + grpc_ssl_server_certificate_config_destroy grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_ex + grpc_ssl_server_credentials_create_options_using_config + grpc_ssl_server_credentials_create_options_using_config_fetcher + grpc_ssl_server_credentials_options_destroy + grpc_ssl_server_credentials_create_with_options grpc_server_add_secure_http2_port grpc_call_set_credentials grpc_server_credentials_set_auth_metadata_processor diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 95b1447935..758aaf5b6c 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -316,6 +316,43 @@ typedef struct grpc_server_credentials grpc_server_credentials; */ GRPCAPI void grpc_server_credentials_release(grpc_server_credentials *creds); +/** Server certificate config object holds the server's public certificates and + associated private keys, as well as any CA certificates needed for client + certificate validation (if applicable). Create using + grpc_ssl_server_certificate_config_create(). */ +typedef struct grpc_ssl_server_certificate_config + grpc_ssl_server_certificate_config; + +/** Creates a grpc_ssl_server_certificate_config object. + - pem_roots_cert is the NULL-terminated string containing the PEM encoding of + the client root certificates. This parameter may be NULL if the server does + not want the client to be authenticated with SSL. + - pem_key_cert_pairs is an array private key / certificate chains of the + server. This parameter cannot be NULL. + - num_key_cert_pairs indicates the number of items in the private_key_files + and cert_chain_files parameters. It must be at least 1. + - It is the caller's responsibility to free this object via + grpc_ssl_server_certificate_config_destroy(). */ +GRPCAPI grpc_ssl_server_certificate_config * +grpc_ssl_server_certificate_config_create( + const char *pem_root_certs, + const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs); + +/** Destroys a grpc_ssl_server_certificate_config object. */ +GRPCAPI void grpc_ssl_server_certificate_config_destroy( + grpc_ssl_server_certificate_config *config); + +/** Callback to retrieve updated SSL server certificates, private keys, and + trusted CAs (for client authentication). + - user_data parameter, if not NULL, contains opaque data to be used by the + callback. + - Use grpc_ssl_server_certificate_config_create to create the config. + - The caller assumes ownership of the config. */ +typedef grpc_ssl_certificate_config_reload_status ( + *grpc_ssl_server_certificate_config_callback)( + void *user_data, grpc_ssl_server_certificate_config **config); + /** Deprecated in favor of grpc_ssl_server_credentials_create_ex. Creates an SSL server_credentials object. - pem_roots_cert is the NULL-terminated string containing the PEM encoding of @@ -332,7 +369,8 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved); -/** Same as grpc_ssl_server_credentials_create method except uses +/** Deprecated in favor of grpc_ssl_server_credentials_create_with_options. + Same as grpc_ssl_server_credentials_create method except uses grpc_ssl_client_certificate_request_type enum to support more ways to authenticate client cerificates.*/ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( @@ -341,6 +379,40 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved); +typedef struct grpc_ssl_server_credentials_options + grpc_ssl_server_credentials_options; + +/** Creates an options object using a certificate config. Use this method when + the certificates and keys of the SSL server will not change during the + server's lifetime. + - Takes ownership of the certificate_config parameter. */ +GRPCAPI grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config *certificate_config); + +/** Creates an options object using a certificate config fetcher. Use this + method to reload the certificates and keys of the SSL server without + interrupting the operation of the server. Initial certificate config will be + fetched during server initialization. + - user_data parameter, if not NULL, contains opaque data which will be passed + to the fetcher (see definition of + grpc_ssl_server_certificate_config_callback). */ +GRPCAPI grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config_fetcher( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config_callback cb, void *user_data); + +/** Destroys a grpc_ssl_server_credentials_options object. */ +GRPCAPI void grpc_ssl_server_credentials_options_destroy( + grpc_ssl_server_credentials_options *options); + +/** Creates an SSL server_credentials object using the provided options struct. + - Takes ownership of the options parameter. */ +GRPCAPI grpc_server_credentials * +grpc_ssl_server_credentials_create_with_options( + grpc_ssl_server_credentials_options *options); + /** --- Server-side secure ports. --- */ /** Add a HTTP2 over an encrypted link over tcp listener. diff --git a/include/grpc/grpc_security_constants.h b/include/grpc/grpc_security_constants.h index fde300dfb1..60e167eb88 100644 --- a/include/grpc/grpc_security_constants.h +++ b/include/grpc/grpc_security_constants.h @@ -48,6 +48,13 @@ typedef enum { GRPC_SSL_ROOTS_OVERRIDE_FAIL } grpc_ssl_roots_override_result; +/** Callback results for dynamically loading a SSL certificate config. */ +typedef enum { + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED, + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW, + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL +} grpc_ssl_certificate_config_reload_status; + typedef enum { /** Server does not request client certificate. A client can present a self signed or signed certificates if it wishes to do so and they would be diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/src/core/lib/security/credentials/ssl/ssl_credentials.cc index 8e47aebedb..2085e2b8e7 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.cc +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.cc @@ -119,6 +119,12 @@ grpc_channel_credentials *grpc_ssl_credentials_create( // SSL Server Credentials. // +struct grpc_ssl_server_credentials_options { + grpc_ssl_client_certificate_request_type client_certificate_request; + grpc_ssl_server_certificate_config *certificate_config; + grpc_ssl_server_certificate_config_fetcher *certificate_config_fetcher; +}; + static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; @@ -130,9 +136,7 @@ static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, static grpc_security_status ssl_server_create_security_connector( grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, grpc_server_security_connector **sc) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return grpc_ssl_server_security_connector_create(exec_ctx, creds, &c->config, - sc); + return grpc_ssl_server_security_connector_create(exec_ctx, creds, sc); } static grpc_server_credentials_vtable ssl_server_vtable = { @@ -170,6 +174,86 @@ static void ssl_build_server_config( config->num_key_cert_pairs = num_key_cert_pairs; } +grpc_ssl_server_certificate_config *grpc_ssl_server_certificate_config_create( + const char *pem_root_certs, + const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs) { + grpc_ssl_server_certificate_config *config = + (grpc_ssl_server_certificate_config *)gpr_zalloc( + sizeof(grpc_ssl_server_certificate_config)); + if (pem_root_certs != NULL) { + config->pem_root_certs = gpr_strdup(pem_root_certs); + } + if (num_key_cert_pairs > 0) { + GPR_ASSERT(pem_key_cert_pairs != NULL); + config->pem_key_cert_pairs = (grpc_ssl_pem_key_cert_pair *)gpr_zalloc( + num_key_cert_pairs * sizeof(grpc_ssl_pem_key_cert_pair)); + } + config->num_key_cert_pairs = num_key_cert_pairs; + for (size_t i = 0; i < num_key_cert_pairs; i++) { + GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); + GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); + config->pem_key_cert_pairs[i].cert_chain = + gpr_strdup(pem_key_cert_pairs[i].cert_chain); + config->pem_key_cert_pairs[i].private_key = + gpr_strdup(pem_key_cert_pairs[i].private_key); + } + return config; +} + +void grpc_ssl_server_certificate_config_destroy( + grpc_ssl_server_certificate_config *config) { + if (config == NULL) return; + for (size_t i = 0; i < config->num_key_cert_pairs; i++) { + gpr_free((void *)config->pem_key_cert_pairs[i].private_key); + gpr_free((void *)config->pem_key_cert_pairs[i].cert_chain); + } + gpr_free(config->pem_key_cert_pairs); + gpr_free(config->pem_root_certs); + gpr_free(config); +} + +grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config *config) { + grpc_ssl_server_credentials_options *options = NULL; + if (config == NULL) { + gpr_log(GPR_ERROR, "Certificate config must not be NULL."); + goto done; + } + options = (grpc_ssl_server_credentials_options *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials_options)); + options->client_certificate_request = client_certificate_request; + options->certificate_config = config; +done: + return options; +} + +grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config_fetcher( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config_callback cb, void *user_data) { + if (cb == NULL) { + gpr_log(GPR_ERROR, "Invalid certificate config callback parameter."); + return NULL; + } + + grpc_ssl_server_certificate_config_fetcher *fetcher = + (grpc_ssl_server_certificate_config_fetcher *)gpr_zalloc( + sizeof(grpc_ssl_server_certificate_config_fetcher)); + fetcher->cb = cb; + fetcher->user_data = user_data; + + grpc_ssl_server_credentials_options *options = + (grpc_ssl_server_credentials_options *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials_options)); + options->client_certificate_request = client_certificate_request; + options->certificate_config_fetcher = fetcher; + + return options; +} + grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved) { @@ -186,8 +270,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( size_t num_key_cert_pairs, grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)gpr_zalloc( - sizeof(grpc_ssl_server_credentials)); GRPC_API_TRACE( "grpc_ssl_server_credentials_create_ex(" "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, " @@ -195,11 +277,67 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( 5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs, client_certificate_request, reserved)); GPR_ASSERT(reserved == NULL); + + grpc_ssl_server_certificate_config *cert_config = + grpc_ssl_server_certificate_config_create( + pem_root_certs, pem_key_cert_pairs, num_key_cert_pairs); + grpc_ssl_server_credentials_options *options = + grpc_ssl_server_credentials_create_options_using_config( + client_certificate_request, cert_config); + + return grpc_ssl_server_credentials_create_with_options(options); +} + +grpc_server_credentials *grpc_ssl_server_credentials_create_with_options( + grpc_ssl_server_credentials_options *options) { + grpc_server_credentials *retval = NULL; + grpc_ssl_server_credentials *c = NULL; + + if (options == NULL) { + gpr_log(GPR_ERROR, + "Invalid options trying to create SSL server credentials."); + goto done; + } + + if (options->certificate_config == NULL && + options->certificate_config_fetcher == NULL) { + gpr_log(GPR_ERROR, + "SSL server credentials options must specify either " + "certificate config or fetcher."); + goto done; + } else if (options->certificate_config_fetcher != NULL && + options->certificate_config_fetcher->cb == NULL) { + gpr_log(GPR_ERROR, "Certificate config fetcher callback must not be NULL."); + goto done; + } + + c = (grpc_ssl_server_credentials *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials)); c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &ssl_server_vtable; - ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, - num_key_cert_pairs, client_certificate_request, - &c->config); - return &c->base; + + if (options->certificate_config_fetcher != NULL) { + c->config.client_certificate_request = options->client_certificate_request; + c->certificate_config_fetcher = *options->certificate_config_fetcher; + } else { + ssl_build_server_config(options->certificate_config->pem_root_certs, + options->certificate_config->pem_key_cert_pairs, + options->certificate_config->num_key_cert_pairs, + options->client_certificate_request, &c->config); + } + + retval = &c->base; + +done: + grpc_ssl_server_credentials_options_destroy(options); + return retval; +} + +void grpc_ssl_server_credentials_options_destroy( + grpc_ssl_server_credentials_options *o) { + if (o == NULL) return; + gpr_free(o->certificate_config_fetcher); + grpc_ssl_server_certificate_config_destroy(o->certificate_config); + gpr_free(o); } diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h index 42e425d9f1..5542484aae 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.h +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h @@ -29,9 +29,21 @@ typedef struct { grpc_ssl_config config; } grpc_ssl_credentials; +struct grpc_ssl_server_certificate_config { + grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs; + size_t num_key_cert_pairs; + char *pem_root_certs; +}; + +typedef struct { + grpc_ssl_server_certificate_config_callback cb; + void *user_data; +} grpc_ssl_server_certificate_config_fetcher; + typedef struct { grpc_server_credentials base; grpc_ssl_server_config config; + grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher; } grpc_ssl_server_credentials; tsi_ssl_pem_key_cert_pair *grpc_convert_grpc_to_tsi_cert_pairs( diff --git a/src/core/lib/security/transport/security_connector.cc b/src/core/lib/security/transport/security_connector.cc index b050be2129..06160d0caa 100644 --- a/src/core/lib/security/transport/security_connector.cc +++ b/src/core/lib/security/transport/security_connector.cc @@ -34,6 +34,7 @@ #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/fake/fake_credentials.h" +#include "src/core/lib/security/credentials/ssl/ssl_credentials.h" #include "src/core/lib/security/transport/lb_targets_info.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/security_handshaker.h" @@ -277,6 +278,30 @@ grpc_security_connector *grpc_security_connector_find_in_args( return NULL; } +static tsi_client_certificate_request_type +get_tsi_client_certificate_request_type( + grpc_ssl_client_certificate_request_type grpc_request_type) { + switch (grpc_request_type) { + case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: + return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; + + case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; + + case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: + return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; + + case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; + + case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: + return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; + + default: + return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; + } +} + /* -- Fake implementation. -- */ typedef struct { @@ -533,6 +558,15 @@ typedef struct { tsi_ssl_server_handshaker_factory *server_handshaker_factory; } grpc_ssl_server_security_connector; +static bool server_connector_has_cert_config_fetcher( + grpc_ssl_server_security_connector *c) { + GPR_ASSERT(c != NULL); + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)c->base.server_creds; + GPR_ASSERT(server_creds != NULL); + return server_creds->certificate_config_fetcher.cb != NULL; +} + static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = @@ -573,7 +607,6 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, tsi_result_to_string(result)); return; } - // Create handshakers. grpc_handshake_manager_add( handshake_mgr, @@ -581,12 +614,102 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } +static const char **fill_alpn_protocol_strings(size_t *num_alpn_protocols) { + GPR_ASSERT(num_alpn_protocols != NULL); + *num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + const char **alpn_protocol_strings = + (const char **)gpr_malloc(sizeof(const char *) * (*num_alpn_protocols)); + for (size_t i = 0; i < *num_alpn_protocols; i++) { + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); + } + return alpn_protocol_strings; +} + +/* Attempts to replace the server_handshaker_factory with a new factory using + * the provided grpc_ssl_server_certificate_config. Should new factory creation + * fail, the existing factory will not be replaced. Returns true on success (new + * factory created). */ +static bool try_replace_server_handshaker_factory( + grpc_ssl_server_security_connector *sc, + const grpc_ssl_server_certificate_config *config) { + if (config == NULL) { + gpr_log(GPR_ERROR, + "Server certificate config callback returned invalid (NULL) " + "config."); + return false; + } + gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config); + + size_t num_alpn_protocols = 0; + const char **alpn_protocol_strings = + fill_alpn_protocol_strings(&num_alpn_protocols); + tsi_ssl_pem_key_cert_pair *cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( + config->pem_key_cert_pairs, config->num_key_cert_pairs); + tsi_ssl_server_handshaker_factory *new_handshaker_factory = NULL; + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)sc->base.server_creds; + tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( + cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, + get_tsi_client_certificate_request_type( + server_creds->config.client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, + &new_handshaker_factory); + gpr_free(cert_pairs); + gpr_free((void *)alpn_protocol_strings); + + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + return false; + } + tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory); + sc->server_handshaker_factory = new_handshaker_factory; + return true; +} + +/* Attempts to fetch the server certificate config if a callback is available. + * Current certificate config will continue to be used if the callback returns + * an error. Returns true if new credentials were sucessfully loaded. */ +static bool try_fetch_ssl_server_credentials( + grpc_ssl_server_security_connector *sc) { + grpc_ssl_server_certificate_config *certificate_config = NULL; + bool status; + + GPR_ASSERT(sc != NULL); + if (!server_connector_has_cert_config_fetcher(sc)) return false; + + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)sc->base.server_creds; + grpc_ssl_certificate_config_reload_status cb_result = + server_creds->certificate_config_fetcher.cb( + server_creds->certificate_config_fetcher.user_data, + &certificate_config); + if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { + gpr_log(GPR_DEBUG, "No change in SSL server credentials."); + status = false; + } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { + status = try_replace_server_handshaker_factory(sc, certificate_config); + } else { + // Log error, continue using previously-loaded credentials. + gpr_log(GPR_ERROR, + "Failed fetching new server credentials, continuing to " + "use previously-loaded credentials."); + status = false; + } + + if (certificate_config != NULL) { + grpc_ssl_server_certificate_config_destroy(certificate_config); + } + return status; +} + static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; // Instantiate TSI handshaker. + try_fetch_ssl_server_credentials(c); tsi_handshaker *tsi_hs = NULL; tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( c->server_handshaker_factory, &tsi_hs); @@ -595,7 +718,6 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, tsi_result_to_string(result)); return; } - // Create handshakers. grpc_handshake_manager_add( handshake_mgr, @@ -857,31 +979,6 @@ grpc_slice grpc_get_default_ssl_roots_for_testing(void) { return compute_default_pem_root_certs_once(); } -static tsi_client_certificate_request_type -get_tsi_client_certificate_request_type( - grpc_ssl_client_certificate_request_type grpc_request_type) { - switch (grpc_request_type) { - case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: - return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; - - case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; - - case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: - return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; - - case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; - - case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: - return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; - - default: - // Is this a sane default - return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; - } -} - const char *grpc_get_default_ssl_roots(void) { /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in loading all the roots once for the lifetime of the process. */ @@ -897,18 +994,14 @@ grpc_security_status grpc_ssl_channel_security_connector_create( grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + size_t num_alpn_protocols = 0; const char **alpn_protocol_strings = - (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); + fill_alpn_protocol_strings(&num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; - size_t i; const char *pem_root_certs; char *port; bool has_key_cert_pair; - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); - } if (config == NULL || target_name == NULL) { gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); @@ -965,50 +1058,64 @@ error: return GRPC_SECURITY_ERROR; } +static grpc_ssl_server_security_connector * +grpc_ssl_server_security_connector_initialize( + grpc_server_credentials *server_creds) { + grpc_ssl_server_security_connector *c = + (grpc_ssl_server_security_connector *)gpr_zalloc( + sizeof(grpc_ssl_server_security_connector)); + gpr_ref_init(&c->base.base.refcount, 1); + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; + c->base.base.vtable = &ssl_server_vtable; + c->base.add_handshakers = ssl_server_add_handshakers; + c->base.server_creds = grpc_server_credentials_ref(server_creds); + return c; +} + grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, - const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const char **alpn_protocol_strings = - (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *gsc, + grpc_server_security_connector **sc) { tsi_result result = TSI_OK; - grpc_ssl_server_security_connector *c; - size_t i; + grpc_ssl_server_credentials *server_credentials = + (grpc_ssl_server_credentials *)gsc; + grpc_security_status retval = GRPC_SECURITY_OK; - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); - } + GPR_ASSERT(server_credentials != NULL); + GPR_ASSERT(sc != NULL); - if (config == NULL || config->num_key_cert_pairs == 0) { - gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); - goto error; + grpc_ssl_server_security_connector *c = + grpc_ssl_server_security_connector_initialize(gsc); + if (server_connector_has_cert_config_fetcher(c)) { + // Load initial credentials from certificate_config_fetcher: + if (!try_fetch_ssl_server_credentials(c)) { + gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher."); + retval = GRPC_SECURITY_ERROR; + } + } else { + size_t num_alpn_protocols = 0; + const char **alpn_protocol_strings = + fill_alpn_protocol_strings(&num_alpn_protocols); + result = tsi_create_ssl_server_handshaker_factory_ex( + server_credentials->config.pem_key_cert_pairs, + server_credentials->config.num_key_cert_pairs, + server_credentials->config.pem_root_certs, + get_tsi_client_certificate_request_type( + server_credentials->config.client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, + (uint16_t)num_alpn_protocols, &c->server_handshaker_factory); + gpr_free((void *)alpn_protocol_strings); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + retval = GRPC_SECURITY_ERROR; + } } - c = (grpc_ssl_server_security_connector *)gpr_zalloc( - sizeof(grpc_ssl_server_security_connector)); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.base.vtable = &ssl_server_vtable; - c->base.server_creds = grpc_server_credentials_ref(server_creds); - result = tsi_create_ssl_server_handshaker_factory_ex( - config->pem_key_cert_pairs, config->num_key_cert_pairs, - config->pem_root_certs, get_tsi_client_certificate_request_type( - config->client_certificate_request), - ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, - &c->server_handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - ssl_server_destroy(exec_ctx, &c->base.base); - *sc = NULL; - goto error; + if (retval == GRPC_SECURITY_OK) { + *sc = &c->base; + } else { + if (c != NULL) ssl_server_destroy(exec_ctx, &c->base.base); + if (sc != NULL) *sc = NULL; } - c->base.add_handshakers = ssl_server_add_handshakers; - *sc = &c->base; - gpr_free((void *)alpn_protocol_strings); - return GRPC_SECURITY_OK; - -error: - gpr_free((void *)alpn_protocol_strings); - return GRPC_SECURITY_ERROR; + return retval; } diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index 8287151f44..54a563bb2c 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -248,8 +248,8 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, - const grpc_ssl_server_config *config, grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_credentials, + grpc_server_security_connector **sc); /* Util. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index cd1bd98abc..843e05ab66 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -155,8 +155,14 @@ grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_impor grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import; grpc_secure_channel_create_type grpc_secure_channel_create_import; grpc_server_credentials_release_type grpc_server_credentials_release_import; +grpc_ssl_server_certificate_config_create_type grpc_ssl_server_certificate_config_create_import; +grpc_ssl_server_certificate_config_destroy_type grpc_ssl_server_certificate_config_destroy_import; grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import; grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import; +grpc_ssl_server_credentials_create_options_using_config_type grpc_ssl_server_credentials_create_options_using_config_import; +grpc_ssl_server_credentials_create_options_using_config_fetcher_type grpc_ssl_server_credentials_create_options_using_config_fetcher_import; +grpc_ssl_server_credentials_options_destroy_type grpc_ssl_server_credentials_options_destroy_import; +grpc_ssl_server_credentials_create_with_options_type grpc_ssl_server_credentials_create_with_options_import; grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import; grpc_call_set_credentials_type grpc_call_set_credentials_import; grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import; @@ -465,8 +471,14 @@ void grpc_rb_load_imports(HMODULE library) { grpc_metadata_credentials_create_from_plugin_import = (grpc_metadata_credentials_create_from_plugin_type) GetProcAddress(library, "grpc_metadata_credentials_create_from_plugin"); grpc_secure_channel_create_import = (grpc_secure_channel_create_type) GetProcAddress(library, "grpc_secure_channel_create"); grpc_server_credentials_release_import = (grpc_server_credentials_release_type) GetProcAddress(library, "grpc_server_credentials_release"); + grpc_ssl_server_certificate_config_create_import = (grpc_ssl_server_certificate_config_create_type) GetProcAddress(library, "grpc_ssl_server_certificate_config_create"); + grpc_ssl_server_certificate_config_destroy_import = (grpc_ssl_server_certificate_config_destroy_type) GetProcAddress(library, "grpc_ssl_server_certificate_config_destroy"); grpc_ssl_server_credentials_create_import = (grpc_ssl_server_credentials_create_type) GetProcAddress(library, "grpc_ssl_server_credentials_create"); grpc_ssl_server_credentials_create_ex_import = (grpc_ssl_server_credentials_create_ex_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_ex"); + grpc_ssl_server_credentials_create_options_using_config_import = (grpc_ssl_server_credentials_create_options_using_config_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_options_using_config"); + grpc_ssl_server_credentials_create_options_using_config_fetcher_import = (grpc_ssl_server_credentials_create_options_using_config_fetcher_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_options_using_config_fetcher"); + grpc_ssl_server_credentials_options_destroy_import = (grpc_ssl_server_credentials_options_destroy_type) GetProcAddress(library, "grpc_ssl_server_credentials_options_destroy"); + grpc_ssl_server_credentials_create_with_options_import = (grpc_ssl_server_credentials_create_with_options_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_with_options"); grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port"); grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials"); grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index c7e78b70dc..998eef800e 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -446,12 +446,30 @@ extern grpc_secure_channel_create_type grpc_secure_channel_create_import; typedef void(*grpc_server_credentials_release_type)(grpc_server_credentials *creds); extern grpc_server_credentials_release_type grpc_server_credentials_release_import; #define grpc_server_credentials_release grpc_server_credentials_release_import +typedef grpc_ssl_server_certificate_config *(*grpc_ssl_server_certificate_config_create_type)(const char *pem_root_certs, const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs); +extern grpc_ssl_server_certificate_config_create_type grpc_ssl_server_certificate_config_create_import; +#define grpc_ssl_server_certificate_config_create grpc_ssl_server_certificate_config_create_import +typedef void(*grpc_ssl_server_certificate_config_destroy_type)(grpc_ssl_server_certificate_config *config); +extern grpc_ssl_server_certificate_config_destroy_type grpc_ssl_server_certificate_config_destroy_import; +#define grpc_ssl_server_certificate_config_destroy grpc_ssl_server_certificate_config_destroy_import typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved); extern grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import; #define grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_import typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_ex_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved); extern grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import; #define grpc_ssl_server_credentials_create_ex grpc_ssl_server_credentials_create_ex_import +typedef grpc_ssl_server_credentials_options *(*grpc_ssl_server_credentials_create_options_using_config_type)(grpc_ssl_client_certificate_request_type client_certificate_request, grpc_ssl_server_certificate_config *certificate_config); +extern grpc_ssl_server_credentials_create_options_using_config_type grpc_ssl_server_credentials_create_options_using_config_import; +#define grpc_ssl_server_credentials_create_options_using_config grpc_ssl_server_credentials_create_options_using_config_import +typedef grpc_ssl_server_credentials_options *(*grpc_ssl_server_credentials_create_options_using_config_fetcher_type)(grpc_ssl_client_certificate_request_type client_certificate_request, grpc_ssl_server_certificate_config_callback cb, void *user_data); +extern grpc_ssl_server_credentials_create_options_using_config_fetcher_type grpc_ssl_server_credentials_create_options_using_config_fetcher_import; +#define grpc_ssl_server_credentials_create_options_using_config_fetcher grpc_ssl_server_credentials_create_options_using_config_fetcher_import +typedef void(*grpc_ssl_server_credentials_options_destroy_type)(grpc_ssl_server_credentials_options *options); +extern grpc_ssl_server_credentials_options_destroy_type grpc_ssl_server_credentials_options_destroy_import; +#define grpc_ssl_server_credentials_options_destroy grpc_ssl_server_credentials_options_destroy_import +typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_with_options_type)(grpc_ssl_server_credentials_options *options); +extern grpc_ssl_server_credentials_create_with_options_type grpc_ssl_server_credentials_create_with_options_import; +#define grpc_ssl_server_credentials_create_with_options grpc_ssl_server_credentials_create_with_options_import typedef int(*grpc_server_add_secure_http2_port_type)(grpc_server *server, const char *addr, grpc_server_credentials *creds); extern grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import; #define grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port_import -- cgit v1.2.3 From 2f921a3f9727859d36c77c8af61c84877e73e880 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Thu, 2 Nov 2017 16:59:19 -0700 Subject: Remove grpc_slice_buf_cmp and change public_headers_must_be_c89 to print the addresses of public api functions to check if they can be linked to --- grpc.def | 1 - include/grpc/slice.h | 1 - src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 - src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 - .../surface/public_headers_must_be_c89.c.template | 16 +- test/core/surface/public_headers_must_be_c89.c | 583 ++++++++++++++++++++- 6 files changed, 597 insertions(+), 9 deletions(-) (limited to 'grpc.def') diff --git a/grpc.def b/grpc.def index 710be52a3b..07c0b3e928 100644 --- a/grpc.def +++ b/grpc.def @@ -149,7 +149,6 @@ EXPORTS grpc_slice_eq grpc_slice_cmp grpc_slice_str_cmp - grpc_slice_buf_cmp grpc_slice_buf_start_eq grpc_slice_rchr grpc_slice_chr diff --git a/include/grpc/slice.h b/include/grpc/slice.h index 3f3cff1408..2203e3887b 100644 --- a/include/grpc/slice.h +++ b/include/grpc/slice.h @@ -137,7 +137,6 @@ GPRAPI int grpc_slice_eq(grpc_slice a, grpc_slice b); versions of the API. */ GPRAPI int grpc_slice_cmp(grpc_slice a, grpc_slice b); GPRAPI int grpc_slice_str_cmp(grpc_slice a, const char *b); -GPRAPI int grpc_slice_buf_cmp(grpc_slice a, const void *b, size_t blen); /** return non-zero if the first blen bytes of a are equal to b */ GPRAPI int grpc_slice_buf_start_eq(grpc_slice a, const void *b, size_t blen); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 128e912e23..648d515003 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -172,7 +172,6 @@ grpc_slice_default_eq_impl_type grpc_slice_default_eq_impl_import; grpc_slice_eq_type grpc_slice_eq_import; grpc_slice_cmp_type grpc_slice_cmp_import; grpc_slice_str_cmp_type grpc_slice_str_cmp_import; -grpc_slice_buf_cmp_type grpc_slice_buf_cmp_import; grpc_slice_buf_start_eq_type grpc_slice_buf_start_eq_import; grpc_slice_rchr_type grpc_slice_rchr_import; grpc_slice_chr_type grpc_slice_chr_import; @@ -460,7 +459,6 @@ void grpc_rb_load_imports(HMODULE library) { grpc_slice_eq_import = (grpc_slice_eq_type) GetProcAddress(library, "grpc_slice_eq"); grpc_slice_cmp_import = (grpc_slice_cmp_type) GetProcAddress(library, "grpc_slice_cmp"); grpc_slice_str_cmp_import = (grpc_slice_str_cmp_type) GetProcAddress(library, "grpc_slice_str_cmp"); - grpc_slice_buf_cmp_import = (grpc_slice_buf_cmp_type) GetProcAddress(library, "grpc_slice_buf_cmp"); grpc_slice_buf_start_eq_import = (grpc_slice_buf_start_eq_type) GetProcAddress(library, "grpc_slice_buf_start_eq"); grpc_slice_rchr_import = (grpc_slice_rchr_type) GetProcAddress(library, "grpc_slice_rchr"); grpc_slice_chr_import = (grpc_slice_chr_type) GetProcAddress(library, "grpc_slice_chr"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index b9b82e5e23..4f2383e982 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -496,9 +496,6 @@ extern grpc_slice_cmp_type grpc_slice_cmp_import; typedef int(*grpc_slice_str_cmp_type)(grpc_slice a, const char *b); extern grpc_slice_str_cmp_type grpc_slice_str_cmp_import; #define grpc_slice_str_cmp grpc_slice_str_cmp_import -typedef int(*grpc_slice_buf_cmp_type)(grpc_slice a, const void *b, size_t blen); -extern grpc_slice_buf_cmp_type grpc_slice_buf_cmp_import; -#define grpc_slice_buf_cmp grpc_slice_buf_cmp_import typedef int(*grpc_slice_buf_start_eq_type)(grpc_slice a, const void *b, size_t blen); extern grpc_slice_buf_start_eq_type grpc_slice_buf_start_eq_import; #define grpc_slice_buf_start_eq grpc_slice_buf_start_eq_import diff --git a/templates/test/core/surface/public_headers_must_be_c89.c.template b/templates/test/core/surface/public_headers_must_be_c89.c.template index dcaa59bb30..d6a1a8ceff 100644 --- a/templates/test/core/surface/public_headers_must_be_c89.c.template +++ b/templates/test/core/surface/public_headers_must_be_c89.c.template @@ -35,9 +35,23 @@ assert(hdr[0:len(pfx)] == pfx) hdrs.add(hdr[len(pfx):]) hdrs = sorted(list(hdrs)) + fns = list() + for api in c_apis: + if is_platform_header(api.header): + continue + fns.append(api.name) %>\ % for hdr in hdrs: #include <${hdr}> % endfor - int main(int argc, char **argv) { return 0; } + #include + + int main(int argc, char **argv) { + if(argc == 12345678) { + % for fn in fns: + printf("%lx", (unsigned long) ${fn});; + % endfor + } + return 0; + } diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index d36d116afb..280b6c423c 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -63,4 +63,585 @@ #include #include -int main(int argc, char **argv) { return 0; } +#include + +int main(int argc, char **argv) { + if (argc == 12345678) { + printf("%lx", (unsigned long)grpc_compression_algorithm_parse); + ; + printf("%lx", (unsigned long)grpc_compression_algorithm_name); + ; + printf("%lx", (unsigned long)grpc_stream_compression_algorithm_name); + ; + printf("%lx", (unsigned long)grpc_compression_algorithm_for_level); + ; + printf("%lx", (unsigned long)grpc_stream_compression_algorithm_for_level); + ; + printf("%lx", (unsigned long)grpc_compression_options_init); + ; + printf("%lx", (unsigned long)grpc_compression_options_enable_algorithm); + ; + printf("%lx", (unsigned long)grpc_compression_options_disable_algorithm); + ; + printf("%lx", (unsigned long)grpc_compression_options_is_algorithm_enabled); + ; + printf( + "%lx", + (unsigned long) + grpc_compression_options_is_stream_compression_algorithm_enabled); + ; + printf("%lx", (unsigned long)grpc_metadata_array_init); + ; + printf("%lx", (unsigned long)grpc_metadata_array_destroy); + ; + printf("%lx", (unsigned long)grpc_call_details_init); + ; + printf("%lx", (unsigned long)grpc_call_details_destroy); + ; + printf("%lx", (unsigned long)grpc_register_plugin); + ; + printf("%lx", (unsigned long)grpc_init); + ; + printf("%lx", (unsigned long)grpc_shutdown); + ; + printf("%lx", (unsigned long)grpc_version_string); + ; + printf("%lx", (unsigned long)grpc_g_stands_for); + ; + printf("%lx", (unsigned long)grpc_completion_queue_factory_lookup); + ; + printf("%lx", (unsigned long)grpc_completion_queue_create_for_next); + ; + printf("%lx", (unsigned long)grpc_completion_queue_create_for_pluck); + ; + printf("%lx", (unsigned long)grpc_completion_queue_create); + ; + printf("%lx", (unsigned long)grpc_completion_queue_next); + ; + printf("%lx", (unsigned long)grpc_completion_queue_pluck); + ; + printf("%lx", (unsigned long)grpc_completion_queue_shutdown); + ; + printf("%lx", (unsigned long)grpc_completion_queue_destroy); + ; + printf("%lx", (unsigned long)grpc_completion_queue_thread_local_cache_init); + ; + printf("%lx", + (unsigned long)grpc_completion_queue_thread_local_cache_flush); + ; + printf("%lx", (unsigned long)grpc_alarm_create); + ; + printf("%lx", (unsigned long)grpc_alarm_set); + ; + printf("%lx", (unsigned long)grpc_alarm_cancel); + ; + printf("%lx", (unsigned long)grpc_alarm_destroy); + ; + printf("%lx", (unsigned long)grpc_channel_check_connectivity_state); + ; + printf("%lx", + (unsigned long)grpc_channel_num_external_connectivity_watchers); + ; + printf("%lx", (unsigned long)grpc_channel_watch_connectivity_state); + ; + printf("%lx", (unsigned long)grpc_channel_support_connectivity_watcher); + ; + printf("%lx", (unsigned long)grpc_channel_create_call); + ; + printf("%lx", (unsigned long)grpc_channel_ping); + ; + printf("%lx", (unsigned long)grpc_channel_register_call); + ; + printf("%lx", (unsigned long)grpc_channel_create_registered_call); + ; + printf("%lx", (unsigned long)grpc_call_arena_alloc); + ; + printf("%lx", (unsigned long)grpc_call_start_batch); + ; + printf("%lx", (unsigned long)grpc_call_get_peer); + ; + printf("%lx", (unsigned long)grpc_census_call_set_context); + ; + printf("%lx", (unsigned long)grpc_census_call_get_context); + ; + printf("%lx", (unsigned long)grpc_channel_get_target); + ; + printf("%lx", (unsigned long)grpc_channel_get_info); + ; + printf("%lx", (unsigned long)grpc_insecure_channel_create); + ; + printf("%lx", (unsigned long)grpc_lame_client_channel_create); + ; + printf("%lx", (unsigned long)grpc_channel_destroy); + ; + printf("%lx", (unsigned long)grpc_call_cancel); + ; + printf("%lx", (unsigned long)grpc_call_cancel_with_status); + ; + printf("%lx", (unsigned long)grpc_call_ref); + ; + printf("%lx", (unsigned long)grpc_call_unref); + ; + printf("%lx", (unsigned long)grpc_server_request_call); + ; + printf("%lx", (unsigned long)grpc_server_register_method); + ; + printf("%lx", (unsigned long)grpc_server_request_registered_call); + ; + printf("%lx", (unsigned long)grpc_server_create); + ; + printf("%lx", (unsigned long)grpc_server_register_completion_queue); + ; + printf("%lx", (unsigned long)grpc_server_add_insecure_http2_port); + ; + printf("%lx", (unsigned long)grpc_server_start); + ; + printf("%lx", (unsigned long)grpc_server_shutdown_and_notify); + ; + printf("%lx", (unsigned long)grpc_server_cancel_all_calls); + ; + printf("%lx", (unsigned long)grpc_server_destroy); + ; + printf("%lx", (unsigned long)grpc_tracer_set_enabled); + ; + printf("%lx", (unsigned long)grpc_header_key_is_legal); + ; + printf("%lx", (unsigned long)grpc_header_nonbin_value_is_legal); + ; + printf("%lx", (unsigned long)grpc_is_binary_header); + ; + printf("%lx", (unsigned long)grpc_call_error_to_string); + ; + printf("%lx", (unsigned long)grpc_resource_quota_create); + ; + printf("%lx", (unsigned long)grpc_resource_quota_ref); + ; + printf("%lx", (unsigned long)grpc_resource_quota_unref); + ; + printf("%lx", (unsigned long)grpc_resource_quota_resize); + ; + printf("%lx", (unsigned long)grpc_resource_quota_arg_vtable); + ; + printf("%lx", (unsigned long)grpc_auth_property_iterator_next); + ; + printf("%lx", (unsigned long)grpc_auth_context_property_iterator); + ; + printf("%lx", (unsigned long)grpc_auth_context_peer_identity); + ; + printf("%lx", (unsigned long)grpc_auth_context_find_properties_by_name); + ; + printf("%lx", (unsigned long)grpc_auth_context_peer_identity_property_name); + ; + printf("%lx", (unsigned long)grpc_auth_context_peer_is_authenticated); + ; + printf("%lx", (unsigned long)grpc_call_auth_context); + ; + printf("%lx", (unsigned long)grpc_auth_context_release); + ; + printf("%lx", (unsigned long)grpc_auth_context_add_property); + ; + printf("%lx", (unsigned long)grpc_auth_context_add_cstring_property); + ; + printf("%lx", + (unsigned long)grpc_auth_context_set_peer_identity_property_name); + ; + printf("%lx", (unsigned long)grpc_channel_credentials_release); + ; + printf("%lx", (unsigned long)grpc_google_default_credentials_create); + ; + printf("%lx", (unsigned long)grpc_set_ssl_roots_override_callback); + ; + printf("%lx", (unsigned long)grpc_ssl_credentials_create); + ; + printf("%lx", (unsigned long)grpc_call_credentials_release); + ; + printf("%lx", (unsigned long)grpc_composite_channel_credentials_create); + ; + printf("%lx", (unsigned long)grpc_composite_call_credentials_create); + ; + printf("%lx", (unsigned long)grpc_google_compute_engine_credentials_create); + ; + printf("%lx", (unsigned long)grpc_max_auth_token_lifetime); + ; + printf("%lx", + (unsigned long)grpc_service_account_jwt_access_credentials_create); + ; + printf("%lx", (unsigned long)grpc_google_refresh_token_credentials_create); + ; + printf("%lx", (unsigned long)grpc_access_token_credentials_create); + ; + printf("%lx", (unsigned long)grpc_google_iam_credentials_create); + ; + printf("%lx", (unsigned long)grpc_metadata_credentials_create_from_plugin); + ; + printf("%lx", (unsigned long)grpc_secure_channel_create); + ; + printf("%lx", (unsigned long)grpc_server_credentials_release); + ; + printf("%lx", (unsigned long)grpc_ssl_server_certificate_config_create); + ; + printf("%lx", (unsigned long)grpc_ssl_server_certificate_config_destroy); + ; + printf("%lx", (unsigned long)grpc_ssl_server_credentials_create); + ; + printf("%lx", (unsigned long)grpc_ssl_server_credentials_create_ex); + ; + printf( + "%lx", + (unsigned long)grpc_ssl_server_credentials_create_options_using_config); + ; + printf("%lx", + (unsigned long) + grpc_ssl_server_credentials_create_options_using_config_fetcher); + ; + printf("%lx", (unsigned long)grpc_ssl_server_credentials_options_destroy); + ; + printf("%lx", + (unsigned long)grpc_ssl_server_credentials_create_with_options); + ; + printf("%lx", (unsigned long)grpc_server_add_secure_http2_port); + ; + printf("%lx", (unsigned long)grpc_call_set_credentials); + ; + printf("%lx", + (unsigned long)grpc_server_credentials_set_auth_metadata_processor); + ; + printf("%lx", (unsigned long)grpc_raw_byte_buffer_create); + ; + printf("%lx", (unsigned long)grpc_raw_compressed_byte_buffer_create); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_copy); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_length); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_destroy); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_reader_init); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_reader_destroy); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_reader_next); + ; + printf("%lx", (unsigned long)grpc_byte_buffer_reader_readall); + ; + printf("%lx", (unsigned long)grpc_raw_byte_buffer_from_reader); + ; + printf("%lx", (unsigned long)grpc_slice_ref); + ; + printf("%lx", (unsigned long)grpc_slice_unref); + ; + printf("%lx", (unsigned long)grpc_slice_copy); + ; + printf("%lx", (unsigned long)grpc_slice_new); + ; + printf("%lx", (unsigned long)grpc_slice_new_with_user_data); + ; + printf("%lx", (unsigned long)grpc_slice_new_with_len); + ; + printf("%lx", (unsigned long)grpc_slice_malloc); + ; + printf("%lx", (unsigned long)grpc_slice_malloc_large); + ; + printf("%lx", (unsigned long)grpc_slice_intern); + ; + printf("%lx", (unsigned long)grpc_slice_from_copied_string); + ; + printf("%lx", (unsigned long)grpc_slice_from_copied_buffer); + ; + printf("%lx", (unsigned long)grpc_slice_from_static_string); + ; + printf("%lx", (unsigned long)grpc_slice_from_static_buffer); + ; + printf("%lx", (unsigned long)grpc_slice_sub); + ; + printf("%lx", (unsigned long)grpc_slice_sub_no_ref); + ; + printf("%lx", (unsigned long)grpc_slice_split_tail); + ; + printf("%lx", (unsigned long)grpc_slice_split_tail_maybe_ref); + ; + printf("%lx", (unsigned long)grpc_slice_split_head); + ; + printf("%lx", (unsigned long)grpc_empty_slice); + ; + printf("%lx", (unsigned long)grpc_slice_default_hash_impl); + ; + printf("%lx", (unsigned long)grpc_slice_default_eq_impl); + ; + printf("%lx", (unsigned long)grpc_slice_eq); + ; + printf("%lx", (unsigned long)grpc_slice_cmp); + ; + printf("%lx", (unsigned long)grpc_slice_str_cmp); + ; + printf("%lx", (unsigned long)grpc_slice_buf_start_eq); + ; + printf("%lx", (unsigned long)grpc_slice_rchr); + ; + printf("%lx", (unsigned long)grpc_slice_chr); + ; + printf("%lx", (unsigned long)grpc_slice_slice); + ; + printf("%lx", (unsigned long)grpc_slice_hash); + ; + printf("%lx", (unsigned long)grpc_slice_is_equivalent); + ; + printf("%lx", (unsigned long)grpc_slice_dup); + ; + printf("%lx", (unsigned long)grpc_slice_to_c_string); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_init); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_destroy); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_add); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_add_indexed); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_addn); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_tiny_add); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_pop); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_reset_and_unref); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_swap); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_move_into); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_trim_end); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_move_first); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_move_first_no_ref); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_move_first_into_buffer); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_take_first); + ; + printf("%lx", (unsigned long)grpc_slice_buffer_undo_take_first); + ; + printf("%lx", (unsigned long)gpr_malloc); + ; + printf("%lx", (unsigned long)gpr_zalloc); + ; + printf("%lx", (unsigned long)gpr_free); + ; + printf("%lx", (unsigned long)gpr_realloc); + ; + printf("%lx", (unsigned long)gpr_malloc_aligned); + ; + printf("%lx", (unsigned long)gpr_free_aligned); + ; + printf("%lx", (unsigned long)gpr_set_allocation_functions); + ; + printf("%lx", (unsigned long)gpr_get_allocation_functions); + ; + printf("%lx", (unsigned long)gpr_avl_create); + ; + printf("%lx", (unsigned long)gpr_avl_ref); + ; + printf("%lx", (unsigned long)gpr_avl_unref); + ; + printf("%lx", (unsigned long)gpr_avl_add); + ; + printf("%lx", (unsigned long)gpr_avl_remove); + ; + printf("%lx", (unsigned long)gpr_avl_get); + ; + printf("%lx", (unsigned long)gpr_avl_maybe_get); + ; + printf("%lx", (unsigned long)gpr_avl_is_empty); + ; + printf("%lx", (unsigned long)gpr_cmdline_create); + ; + printf("%lx", (unsigned long)gpr_cmdline_add_int); + ; + printf("%lx", (unsigned long)gpr_cmdline_add_flag); + ; + printf("%lx", (unsigned long)gpr_cmdline_add_string); + ; + printf("%lx", (unsigned long)gpr_cmdline_on_extra_arg); + ; + printf("%lx", (unsigned long)gpr_cmdline_set_survive_failure); + ; + printf("%lx", (unsigned long)gpr_cmdline_parse); + ; + printf("%lx", (unsigned long)gpr_cmdline_destroy); + ; + printf("%lx", (unsigned long)gpr_cmdline_usage_string); + ; + printf("%lx", (unsigned long)gpr_cpu_num_cores); + ; + printf("%lx", (unsigned long)gpr_cpu_current_cpu); + ; + printf("%lx", (unsigned long)gpr_histogram_create); + ; + printf("%lx", (unsigned long)gpr_histogram_destroy); + ; + printf("%lx", (unsigned long)gpr_histogram_add); + ; + printf("%lx", (unsigned long)gpr_histogram_merge); + ; + printf("%lx", (unsigned long)gpr_histogram_percentile); + ; + printf("%lx", (unsigned long)gpr_histogram_mean); + ; + printf("%lx", (unsigned long)gpr_histogram_stddev); + ; + printf("%lx", (unsigned long)gpr_histogram_variance); + ; + printf("%lx", (unsigned long)gpr_histogram_maximum); + ; + printf("%lx", (unsigned long)gpr_histogram_minimum); + ; + printf("%lx", (unsigned long)gpr_histogram_count); + ; + printf("%lx", (unsigned long)gpr_histogram_sum); + ; + printf("%lx", (unsigned long)gpr_histogram_sum_of_squares); + ; + printf("%lx", (unsigned long)gpr_histogram_get_contents); + ; + printf("%lx", (unsigned long)gpr_histogram_merge_contents); + ; + printf("%lx", (unsigned long)gpr_join_host_port); + ; + printf("%lx", (unsigned long)gpr_split_host_port); + ; + printf("%lx", (unsigned long)gpr_log_severity_string); + ; + printf("%lx", (unsigned long)gpr_log); + ; + printf("%lx", (unsigned long)gpr_log_message); + ; + printf("%lx", (unsigned long)gpr_set_log_verbosity); + ; + printf("%lx", (unsigned long)gpr_log_verbosity_init); + ; + printf("%lx", (unsigned long)gpr_set_log_function); + ; + printf("%lx", (unsigned long)gpr_strdup); + ; + printf("%lx", (unsigned long)gpr_asprintf); + ; + printf("%lx", (unsigned long)gpr_subprocess_binary_extension); + ; + printf("%lx", (unsigned long)gpr_subprocess_create); + ; + printf("%lx", (unsigned long)gpr_subprocess_destroy); + ; + printf("%lx", (unsigned long)gpr_subprocess_join); + ; + printf("%lx", (unsigned long)gpr_subprocess_interrupt); + ; + printf("%lx", (unsigned long)gpr_mu_init); + ; + printf("%lx", (unsigned long)gpr_mu_destroy); + ; + printf("%lx", (unsigned long)gpr_mu_lock); + ; + printf("%lx", (unsigned long)gpr_mu_unlock); + ; + printf("%lx", (unsigned long)gpr_mu_trylock); + ; + printf("%lx", (unsigned long)gpr_cv_init); + ; + printf("%lx", (unsigned long)gpr_cv_destroy); + ; + printf("%lx", (unsigned long)gpr_cv_wait); + ; + printf("%lx", (unsigned long)gpr_cv_signal); + ; + printf("%lx", (unsigned long)gpr_cv_broadcast); + ; + printf("%lx", (unsigned long)gpr_once_init); + ; + printf("%lx", (unsigned long)gpr_event_init); + ; + printf("%lx", (unsigned long)gpr_event_set); + ; + printf("%lx", (unsigned long)gpr_event_get); + ; + printf("%lx", (unsigned long)gpr_event_wait); + ; + printf("%lx", (unsigned long)gpr_ref_init); + ; + printf("%lx", (unsigned long)gpr_ref); + ; + printf("%lx", (unsigned long)gpr_ref_non_zero); + ; + printf("%lx", (unsigned long)gpr_refn); + ; + printf("%lx", (unsigned long)gpr_unref); + ; + printf("%lx", (unsigned long)gpr_ref_is_unique); + ; + printf("%lx", (unsigned long)gpr_stats_init); + ; + printf("%lx", (unsigned long)gpr_stats_inc); + ; + printf("%lx", (unsigned long)gpr_stats_read); + ; + printf("%lx", (unsigned long)gpr_thd_new); + ; + printf("%lx", (unsigned long)gpr_thd_options_default); + ; + printf("%lx", (unsigned long)gpr_thd_options_set_detached); + ; + printf("%lx", (unsigned long)gpr_thd_options_set_joinable); + ; + printf("%lx", (unsigned long)gpr_thd_options_is_detached); + ; + printf("%lx", (unsigned long)gpr_thd_options_is_joinable); + ; + printf("%lx", (unsigned long)gpr_thd_currentid); + ; + printf("%lx", (unsigned long)gpr_thd_join); + ; + printf("%lx", (unsigned long)gpr_time_0); + ; + printf("%lx", (unsigned long)gpr_inf_future); + ; + printf("%lx", (unsigned long)gpr_inf_past); + ; + printf("%lx", (unsigned long)gpr_time_init); + ; + printf("%lx", (unsigned long)gpr_now); + ; + printf("%lx", (unsigned long)gpr_convert_clock_type); + ; + printf("%lx", (unsigned long)gpr_time_cmp); + ; + printf("%lx", (unsigned long)gpr_time_max); + ; + printf("%lx", (unsigned long)gpr_time_min); + ; + printf("%lx", (unsigned long)gpr_time_add); + ; + printf("%lx", (unsigned long)gpr_time_sub); + ; + printf("%lx", (unsigned long)gpr_time_from_micros); + ; + printf("%lx", (unsigned long)gpr_time_from_nanos); + ; + printf("%lx", (unsigned long)gpr_time_from_millis); + ; + printf("%lx", (unsigned long)gpr_time_from_seconds); + ; + printf("%lx", (unsigned long)gpr_time_from_minutes); + ; + printf("%lx", (unsigned long)gpr_time_from_hours); + ; + printf("%lx", (unsigned long)gpr_time_to_millis); + ; + printf("%lx", (unsigned long)gpr_time_similar); + ; + printf("%lx", (unsigned long)gpr_sleep_until); + ; + printf("%lx", (unsigned long)gpr_timespec_to_micros); + ; + } + return 0; +} -- cgit v1.2.3