create
This commit is contained in:
273
Pods/gRPC-C++/src/cpp/client/channel_cc.cc
generated
Normal file
273
Pods/gRPC-C++/src/cpp/client/channel_cc.cc
generated
Normal file
@@ -0,0 +1,273 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/connectivity_state.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/client_context.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set_interface.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
|
||||
#include "src/core/lib/iomgr/iomgr.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
Channel::Channel(
|
||||
const std::string& host, grpc_channel* channel,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators)
|
||||
: host_(host), c_channel_(channel) {
|
||||
interceptor_creators_ = std::move(interceptor_creators);
|
||||
}
|
||||
|
||||
Channel::~Channel() {
|
||||
grpc_channel_destroy(c_channel_);
|
||||
CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
|
||||
if (callback_cq != nullptr) {
|
||||
if (grpc_iomgr_run_in_background()) {
|
||||
// gRPC-core provides the backing needed for the preferred CQ type
|
||||
callback_cq->Shutdown();
|
||||
} else {
|
||||
CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline grpc_slice SliceFromArray(const char* arr, size_t len) {
|
||||
return grpc_slice_from_copied_buffer(arr, len);
|
||||
}
|
||||
|
||||
std::string GetChannelInfoField(grpc_channel* channel,
|
||||
grpc_channel_info* channel_info,
|
||||
char*** channel_info_field) {
|
||||
char* value = nullptr;
|
||||
memset(channel_info, 0, sizeof(*channel_info));
|
||||
*channel_info_field = &value;
|
||||
grpc_channel_get_info(channel, channel_info);
|
||||
if (value == nullptr) return "";
|
||||
std::string result = value;
|
||||
gpr_free(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string Channel::GetLoadBalancingPolicyName() const {
|
||||
grpc_channel_info channel_info;
|
||||
return GetChannelInfoField(c_channel_, &channel_info,
|
||||
&channel_info.lb_policy_name);
|
||||
}
|
||||
|
||||
std::string Channel::GetServiceConfigJSON() const {
|
||||
grpc_channel_info channel_info;
|
||||
return GetChannelInfoField(c_channel_, &channel_info,
|
||||
&channel_info.service_config_json);
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
void ChannelResetConnectionBackoff(Channel* channel) {
|
||||
grpc_channel_reset_connect_backoff(channel->c_channel_);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
grpc::internal::Call Channel::CreateCallInternal(
|
||||
const grpc::internal::RpcMethod& method, grpc::ClientContext* context,
|
||||
grpc::CompletionQueue* cq, size_t interceptor_pos) {
|
||||
const bool kRegistered = method.channel_tag() && context->authority().empty();
|
||||
grpc_call* c_call = nullptr;
|
||||
if (kRegistered) {
|
||||
c_call = grpc_channel_create_registered_call(
|
||||
c_channel_, context->propagate_from_call_,
|
||||
context->propagation_options_.c_bitmask(), cq->cq(),
|
||||
method.channel_tag(), context->raw_deadline(), nullptr);
|
||||
} else {
|
||||
const ::std::string* host_str = nullptr;
|
||||
if (!context->authority_.empty()) {
|
||||
host_str = &context->authority_;
|
||||
} else if (!host_.empty()) {
|
||||
host_str = &host_;
|
||||
}
|
||||
grpc_slice method_slice =
|
||||
SliceFromArray(method.name(), strlen(method.name()));
|
||||
grpc_slice host_slice;
|
||||
if (host_str != nullptr) {
|
||||
host_slice = grpc::SliceFromCopiedString(*host_str);
|
||||
}
|
||||
c_call = grpc_channel_create_call(
|
||||
c_channel_, context->propagate_from_call_,
|
||||
context->propagation_options_.c_bitmask(), cq->cq(), method_slice,
|
||||
host_str == nullptr ? nullptr : &host_slice, context->raw_deadline(),
|
||||
nullptr);
|
||||
grpc_slice_unref(method_slice);
|
||||
if (host_str != nullptr) {
|
||||
grpc_slice_unref(host_slice);
|
||||
}
|
||||
}
|
||||
grpc_census_call_set_context(c_call, context->census_context());
|
||||
|
||||
// ClientRpcInfo should be set before call because set_call also checks
|
||||
// whether the call has been cancelled, and if the call was cancelled, we
|
||||
// should notify the interceptors too.
|
||||
auto* info = context->set_client_rpc_info(
|
||||
method.name(), method.suffix_for_stats(), method.method_type(), this,
|
||||
interceptor_creators_, interceptor_pos);
|
||||
context->set_call(c_call, shared_from_this());
|
||||
|
||||
return grpc::internal::Call(c_call, this, cq, info);
|
||||
}
|
||||
|
||||
grpc::internal::Call Channel::CreateCall(
|
||||
const grpc::internal::RpcMethod& method, grpc::ClientContext* context,
|
||||
CompletionQueue* cq) {
|
||||
return CreateCallInternal(method, context, cq, 0);
|
||||
}
|
||||
|
||||
void Channel::PerformOpsOnCall(grpc::internal::CallOpSetInterface* ops,
|
||||
grpc::internal::Call* call) {
|
||||
ops->FillOps(
|
||||
call); // Make a copy of call. It's fine since Call just has pointers
|
||||
}
|
||||
|
||||
void* Channel::RegisterMethod(const char* method) {
|
||||
return grpc_channel_register_call(
|
||||
c_channel_, method, host_.empty() ? nullptr : host_.c_str(), nullptr);
|
||||
}
|
||||
|
||||
grpc_connectivity_state Channel::GetState(bool try_to_connect) {
|
||||
return grpc_channel_check_connectivity_state(c_channel_, try_to_connect);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TagSaver final : public grpc::internal::CompletionQueueTag {
|
||||
public:
|
||||
explicit TagSaver(void* tag) : tag_(tag) {}
|
||||
~TagSaver() override {}
|
||||
bool FinalizeResult(void** tag, bool* /*status*/) override {
|
||||
*tag = tag_;
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void* tag_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
|
||||
gpr_timespec deadline,
|
||||
grpc::CompletionQueue* cq, void* tag) {
|
||||
TagSaver* tag_saver = new TagSaver(tag);
|
||||
grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline,
|
||||
cq->cq(), tag_saver);
|
||||
}
|
||||
|
||||
bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
|
||||
gpr_timespec deadline) {
|
||||
grpc::CompletionQueue cq;
|
||||
bool ok = false;
|
||||
void* tag = nullptr;
|
||||
NotifyOnStateChangeImpl(last_observed, deadline, &cq, nullptr);
|
||||
cq.Next(&tag, &ok);
|
||||
GPR_ASSERT(tag == nullptr);
|
||||
return ok;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ShutdownCallback : public grpc_completion_queue_functor {
|
||||
public:
|
||||
ShutdownCallback() {
|
||||
functor_run = &ShutdownCallback::Run;
|
||||
// Set inlineable to true since this callback is trivial and thus does not
|
||||
// need to be run from the executor (triggering a thread hop). This should
|
||||
// only be used by internal callbacks like this and not by user application
|
||||
// code.
|
||||
inlineable = true;
|
||||
}
|
||||
// TakeCQ takes ownership of the cq into the shutdown callback
|
||||
// so that the shutdown callback will be responsible for destroying it
|
||||
void TakeCQ(grpc::CompletionQueue* cq) { cq_ = cq; }
|
||||
|
||||
// The Run function will get invoked by the completion queue library
|
||||
// when the shutdown is actually complete
|
||||
static void Run(grpc_completion_queue_functor* cb, int) {
|
||||
auto* callback = static_cast<ShutdownCallback*>(cb);
|
||||
delete callback->cq_;
|
||||
delete callback;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc::CompletionQueue* cq_ = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
::grpc::CompletionQueue* Channel::CallbackCQ() {
|
||||
// TODO(vjpai): Consider using a single global CQ for the default CQ
|
||||
// if there is no explicit per-channel CQ registered
|
||||
CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
|
||||
if (callback_cq != nullptr) {
|
||||
return callback_cq;
|
||||
}
|
||||
// The callback_cq_ wasn't already set, so grab a lock and set it up exactly
|
||||
// once for this channel.
|
||||
grpc::internal::MutexLock l(&mu_);
|
||||
callback_cq = callback_cq_.load(std::memory_order_relaxed);
|
||||
if (callback_cq == nullptr) {
|
||||
if (grpc_iomgr_run_in_background()) {
|
||||
// gRPC-core provides the backing needed for the preferred CQ type
|
||||
|
||||
auto* shutdown_callback = new ShutdownCallback;
|
||||
callback_cq = new grpc::CompletionQueue(grpc_completion_queue_attributes{
|
||||
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
|
||||
shutdown_callback});
|
||||
|
||||
// Transfer ownership of the new cq to its own shutdown callback
|
||||
shutdown_callback->TakeCQ(callback_cq);
|
||||
} else {
|
||||
// Otherwise we need to use the alternative CQ variant
|
||||
callback_cq = CompletionQueue::CallbackAlternativeCQ();
|
||||
}
|
||||
callback_cq_.store(callback_cq, std::memory_order_release);
|
||||
}
|
||||
return callback_cq;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
40
Pods/gRPC-C++/src/cpp/client/client_callback.cc
generated
Normal file
40
Pods/gRPC-C++/src/cpp/client/client_callback.cc
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpcpp/support/client_callback.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
#include "src/core/lib/iomgr/closure.h"
|
||||
#include "src/core/lib/iomgr/error.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/iomgr/executor.h"
|
||||
#include "src/core/lib/surface/call.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
bool ClientReactor::InternalTrailersOnly(const grpc_call* call) const {
|
||||
return grpc_call_is_trailers_only(call);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
189
Pods/gRPC-C++/src/cpp/client/client_context.cc
generated
Normal file
189
Pods/gRPC-C++/src/cpp/client/client_context.cc
generated
Normal file
@@ -0,0 +1,189 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
#include <grpc/compression.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/compression_types.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/client_context.h>
|
||||
#include <grpcpp/impl/interceptor_common.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
#include "src/core/lib/gprpp/crash.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class Channel;
|
||||
|
||||
class DefaultGlobalClientCallbacks final
|
||||
: public ClientContext::GlobalCallbacks {
|
||||
public:
|
||||
~DefaultGlobalClientCallbacks() override {}
|
||||
void DefaultConstructor(ClientContext* /*context*/) override {}
|
||||
void Destructor(ClientContext* /*context*/) override {}
|
||||
};
|
||||
|
||||
static DefaultGlobalClientCallbacks* g_default_client_callbacks =
|
||||
new DefaultGlobalClientCallbacks();
|
||||
static ClientContext::GlobalCallbacks* g_client_callbacks =
|
||||
g_default_client_callbacks;
|
||||
|
||||
ClientContext::ClientContext()
|
||||
: initial_metadata_received_(false),
|
||||
wait_for_ready_(false),
|
||||
wait_for_ready_explicitly_set_(false),
|
||||
call_(nullptr),
|
||||
call_canceled_(false),
|
||||
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
|
||||
census_context_(nullptr),
|
||||
propagate_from_call_(nullptr),
|
||||
compression_algorithm_(GRPC_COMPRESS_NONE),
|
||||
initial_metadata_corked_(false) {
|
||||
g_client_callbacks->DefaultConstructor(this);
|
||||
}
|
||||
|
||||
ClientContext::~ClientContext() {
|
||||
if (call_) {
|
||||
grpc_call_unref(call_);
|
||||
call_ = nullptr;
|
||||
}
|
||||
g_client_callbacks->Destructor(this);
|
||||
}
|
||||
|
||||
void ClientContext::set_credentials(
|
||||
const std::shared_ptr<CallCredentials>& creds) {
|
||||
creds_ = creds;
|
||||
// If call_ is set, we have already created the call, and set the call
|
||||
// credentials. This should only be done before we have started the batch
|
||||
// for sending initial metadata.
|
||||
if (creds_ != nullptr && call_ != nullptr) {
|
||||
if (!creds_->ApplyToCall(call_)) {
|
||||
SendCancelToInterceptors();
|
||||
grpc_call_cancel_with_status(call_, GRPC_STATUS_CANCELLED,
|
||||
"Failed to set credentials to rpc.",
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ClientContext> ClientContext::FromInternalServerContext(
|
||||
const grpc::ServerContextBase& context, PropagationOptions options) {
|
||||
std::unique_ptr<ClientContext> ctx(new ClientContext);
|
||||
ctx->propagate_from_call_ = context.call_.call;
|
||||
ctx->propagation_options_ = options;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
std::unique_ptr<ClientContext> ClientContext::FromServerContext(
|
||||
const grpc::ServerContextBase& server_context, PropagationOptions options) {
|
||||
return FromInternalServerContext(server_context, options);
|
||||
}
|
||||
|
||||
std::unique_ptr<ClientContext> ClientContext::FromCallbackServerContext(
|
||||
const grpc::CallbackServerContext& server_context,
|
||||
PropagationOptions options) {
|
||||
return FromInternalServerContext(server_context, options);
|
||||
}
|
||||
|
||||
void ClientContext::AddMetadata(const std::string& meta_key,
|
||||
const std::string& meta_value) {
|
||||
send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));
|
||||
}
|
||||
|
||||
void ClientContext::set_call(grpc_call* call,
|
||||
const std::shared_ptr<Channel>& channel) {
|
||||
internal::MutexLock lock(&mu_);
|
||||
GPR_ASSERT(call_ == nullptr);
|
||||
call_ = call;
|
||||
channel_ = channel;
|
||||
if (creds_ && !creds_->ApplyToCall(call_)) {
|
||||
// TODO(yashykt): should interceptors also see this status?
|
||||
SendCancelToInterceptors();
|
||||
grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
|
||||
"Failed to set credentials to rpc.", nullptr);
|
||||
}
|
||||
if (call_canceled_) {
|
||||
SendCancelToInterceptors();
|
||||
grpc_call_cancel(call_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::set_compression_algorithm(
|
||||
grpc_compression_algorithm algorithm) {
|
||||
compression_algorithm_ = algorithm;
|
||||
const char* algorithm_name = nullptr;
|
||||
if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
|
||||
grpc_core::Crash(absl::StrFormat(
|
||||
"Name for compression algorithm '%d' unknown.", algorithm));
|
||||
}
|
||||
GPR_ASSERT(algorithm_name != nullptr);
|
||||
AddMetadata(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY, algorithm_name);
|
||||
}
|
||||
|
||||
void ClientContext::TryCancel() {
|
||||
internal::MutexLock lock(&mu_);
|
||||
if (call_) {
|
||||
SendCancelToInterceptors();
|
||||
grpc_call_cancel(call_, nullptr);
|
||||
} else {
|
||||
call_canceled_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientContext::SendCancelToInterceptors() {
|
||||
internal::CancelInterceptorBatchMethods cancel_methods;
|
||||
for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) {
|
||||
rpc_info_.RunInterceptor(&cancel_methods, i);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ClientContext::peer() const {
|
||||
std::string peer;
|
||||
if (call_) {
|
||||
char* c_peer = grpc_call_get_peer(call_);
|
||||
peer = c_peer;
|
||||
gpr_free(c_peer);
|
||||
}
|
||||
return peer;
|
||||
}
|
||||
|
||||
void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
|
||||
GPR_ASSERT(g_client_callbacks == g_default_client_callbacks);
|
||||
GPR_ASSERT(client_callbacks != nullptr);
|
||||
GPR_ASSERT(client_callbacks != g_default_client_callbacks);
|
||||
g_client_callbacks = client_callbacks;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
47
Pods/gRPC-C++/src/cpp/client/client_interceptor.cc
generated
Normal file
47
Pods/gRPC-C++/src/cpp/client/client_interceptor.cc
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
#include "src/core/lib/gprpp/crash.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace internal {
|
||||
experimental::ClientInterceptorFactoryInterface*
|
||||
g_global_client_interceptor_factory = nullptr;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace experimental {
|
||||
void RegisterGlobalClientInterceptorFactory(
|
||||
ClientInterceptorFactoryInterface* factory) {
|
||||
if (internal::g_global_client_interceptor_factory != nullptr) {
|
||||
grpc_core::Crash(
|
||||
"It is illegal to call RegisterGlobalClientInterceptorFactory "
|
||||
"multiple times.");
|
||||
}
|
||||
internal::g_global_client_interceptor_factory = factory;
|
||||
}
|
||||
|
||||
// For testing purposes only.
|
||||
void TestOnlyResetGlobalClientInterceptorFactory() {
|
||||
internal::g_global_client_interceptor_factory = nullptr;
|
||||
}
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
40
Pods/gRPC-C++/src/cpp/client/client_stats_interceptor.cc
generated
Normal file
40
Pods/gRPC-C++/src/cpp/client/client_stats_interceptor.cc
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
#include "src/core/lib/gprpp/crash.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
experimental::ClientInterceptorFactoryInterface*
|
||||
g_global_client_stats_interceptor_factory = nullptr;
|
||||
|
||||
void RegisterGlobalClientStatsInterceptorFactory(
|
||||
grpc::experimental::ClientInterceptorFactoryInterface* factory) {
|
||||
if (internal::g_global_client_stats_interceptor_factory != nullptr) {
|
||||
grpc_core::Crash(
|
||||
"It is illegal to call RegisterGlobalClientStatsInterceptorFactory "
|
||||
"multiple times.");
|
||||
}
|
||||
internal::g_global_client_interceptor_factory = factory;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
33
Pods/gRPC-C++/src/cpp/client/client_stats_interceptor.h
generated
Normal file
33
Pods/gRPC-C++/src/cpp/client/client_stats_interceptor.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_CLIENT_CLIENT_STATS_INTERCEPTOR_H
|
||||
#define GRPC_SRC_CPP_CLIENT_CLIENT_STATS_INTERCEPTOR_H
|
||||
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
void RegisterGlobalClientStatsInterceptorFactory(
|
||||
grpc::experimental::ClientInterceptorFactoryInterface* factory);
|
||||
|
||||
}
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_CLIENT_CLIENT_STATS_INTERCEPTOR_H
|
||||
92
Pods/gRPC-C++/src/cpp/client/create_channel.cc
generated
Normal file
92
Pods/gRPC-C++/src/cpp/client/create_channel.cc
generated
Normal file
@@ -0,0 +1,92 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/create_channel.h>
|
||||
#include <grpcpp/impl/grpc_library.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
|
||||
namespace grpc {
|
||||
std::shared_ptr<grpc::Channel> CreateChannel(
|
||||
const grpc::string& target,
|
||||
const std::shared_ptr<grpc::ChannelCredentials>& creds) {
|
||||
return CreateCustomChannel(target, creds, grpc::ChannelArguments());
|
||||
}
|
||||
|
||||
std::shared_ptr<grpc::Channel> CreateCustomChannel(
|
||||
const grpc::string& target,
|
||||
const std::shared_ptr<grpc::ChannelCredentials>& creds,
|
||||
const grpc::ChannelArguments& args) {
|
||||
grpc::internal::GrpcLibrary
|
||||
init_lib; // We need to call init in case of bad creds.
|
||||
return creds ? creds->CreateChannelImpl(target, args)
|
||||
: grpc::CreateChannelInternal(
|
||||
"",
|
||||
grpc_lame_client_channel_create(
|
||||
nullptr, GRPC_STATUS_INVALID_ARGUMENT,
|
||||
"Invalid credentials."),
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::
|
||||
ClientInterceptorFactoryInterface>>());
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
/// Create a new \em custom \a Channel pointing to \a target with \a
|
||||
/// interceptors being invoked per call.
|
||||
///
|
||||
/// \warning For advanced use and testing ONLY. Override default channel
|
||||
/// arguments only if necessary.
|
||||
///
|
||||
/// \param target The URI of the endpoint to connect to.
|
||||
/// \param creds Credentials to use for the created channel. If it does not
|
||||
/// hold an object or is invalid, a lame channel (one on which all operations
|
||||
/// fail) is returned.
|
||||
/// \param args Options for channel creation.
|
||||
std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
|
||||
const std::string& target,
|
||||
const std::shared_ptr<grpc::ChannelCredentials>& creds,
|
||||
const grpc::ChannelArguments& args,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) {
|
||||
grpc::internal::GrpcLibrary
|
||||
init_lib; // We need to call init in case of bad creds.
|
||||
return creds ? creds->CreateChannelWithInterceptors(
|
||||
target, args, std::move(interceptor_creators))
|
||||
: grpc::CreateChannelInternal(
|
||||
"",
|
||||
grpc_lame_client_channel_create(
|
||||
nullptr, GRPC_STATUS_INVALID_ARGUMENT,
|
||||
"Invalid credentials."),
|
||||
std::move(interceptor_creators));
|
||||
}
|
||||
} // namespace experimental
|
||||
|
||||
} // namespace grpc
|
||||
39
Pods/gRPC-C++/src/cpp/client/create_channel_internal.cc
generated
Normal file
39
Pods/gRPC-C++/src/cpp/client/create_channel_internal.cc
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpcpp/channel.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::shared_ptr<Channel> CreateChannelInternal(
|
||||
const std::string& host, grpc_channel* c_channel,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) {
|
||||
return std::shared_ptr<Channel>(
|
||||
new Channel(host, c_channel, std::move(interceptor_creators)));
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
40
Pods/gRPC-C++/src/cpp/client/create_channel_internal.h
generated
Normal file
40
Pods/gRPC-C++/src/cpp/client/create_channel_internal.h
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H
|
||||
#define GRPC_SRC_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::shared_ptr<Channel> CreateChannelInternal(
|
||||
const std::string& host, grpc_channel* c_channel,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators);
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_CLIENT_CREATE_CHANNEL_INTERNAL_H
|
||||
89
Pods/gRPC-C++/src/cpp/client/create_channel_posix.cc
generated
Normal file
89
Pods/gRPC-C++/src/cpp/client/create_channel_posix.cc
generated
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_posix.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/impl/grpc_library.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class ChannelArguments;
|
||||
|
||||
#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
|
||||
|
||||
std::shared_ptr<Channel> CreateInsecureChannelFromFd(const std::string& target,
|
||||
int fd) {
|
||||
internal::GrpcLibrary init_lib;
|
||||
grpc_channel_credentials* creds = grpc_insecure_credentials_create();
|
||||
auto channel = CreateChannelInternal(
|
||||
"", grpc_channel_create_from_fd(target.c_str(), fd, creds, nullptr),
|
||||
std::vector<
|
||||
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
|
||||
grpc_channel_credentials_release(creds);
|
||||
return channel;
|
||||
}
|
||||
|
||||
std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
|
||||
const std::string& target, int fd, const grpc::ChannelArguments& args) {
|
||||
internal::GrpcLibrary init_lib;
|
||||
grpc_channel_args channel_args;
|
||||
args.SetChannelArgs(&channel_args);
|
||||
grpc_channel_credentials* creds = grpc_insecure_credentials_create();
|
||||
auto channel = CreateChannelInternal(
|
||||
"", grpc_channel_create_from_fd(target.c_str(), fd, creds, &channel_args),
|
||||
std::vector<
|
||||
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
|
||||
grpc_channel_credentials_release(creds);
|
||||
// Channel also initializes gRPC, so we can decrement the init ref count here.
|
||||
return channel;
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
std::shared_ptr<Channel> CreateCustomInsecureChannelWithInterceptorsFromFd(
|
||||
const std::string& target, int fd, const ChannelArguments& args,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) {
|
||||
internal::GrpcLibrary init_lib;
|
||||
grpc_channel_args channel_args;
|
||||
args.SetChannelArgs(&channel_args);
|
||||
grpc_channel_credentials* creds = grpc_insecure_credentials_create();
|
||||
auto channel = CreateChannelInternal(
|
||||
"", grpc_channel_create_from_fd(target.c_str(), fd, creds, &channel_args),
|
||||
std::move(interceptor_creators));
|
||||
grpc_channel_credentials_release(creds);
|
||||
return channel;
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
|
||||
|
||||
} // namespace grpc
|
||||
72
Pods/gRPC-C++/src/cpp/client/insecure_credentials.cc
generated
Normal file
72
Pods/gRPC-C++/src/cpp/client/insecure_credentials.cc
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace {
|
||||
class InsecureChannelCredentialsImpl final : public ChannelCredentials {
|
||||
public:
|
||||
std::shared_ptr<Channel> CreateChannelImpl(
|
||||
const std::string& target, const ChannelArguments& args) override {
|
||||
return CreateChannelWithInterceptors(
|
||||
target, args,
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::ClientInterceptorFactoryInterface>>());
|
||||
}
|
||||
|
||||
std::shared_ptr<Channel> CreateChannelWithInterceptors(
|
||||
const std::string& target, const ChannelArguments& args,
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) override {
|
||||
grpc_channel_args channel_args;
|
||||
args.SetChannelArgs(&channel_args);
|
||||
grpc_channel_credentials* creds = grpc_insecure_credentials_create();
|
||||
std::shared_ptr<Channel> channel = grpc::CreateChannelInternal(
|
||||
"", grpc_channel_create(target.c_str(), creds, &channel_args),
|
||||
std::move(interceptor_creators));
|
||||
grpc_channel_credentials_release(creds);
|
||||
return channel;
|
||||
}
|
||||
|
||||
SecureChannelCredentials* AsSecureCredentials() override { return nullptr; }
|
||||
|
||||
private:
|
||||
bool IsInsecure() const override { return true; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<ChannelCredentials> InsecureChannelCredentials() {
|
||||
return std::shared_ptr<ChannelCredentials>(
|
||||
new InsecureChannelCredentialsImpl());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
519
Pods/gRPC-C++/src/cpp/client/secure_credentials.cc
generated
Normal file
519
Pods/gRPC-C++/src/cpp/client/secure_credentials.cc
generated
Normal file
@@ -0,0 +1,519 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/client/secure_credentials.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
#include <grpc/event_engine/event_engine.h>
|
||||
#include <grpc/grpc_security_constants.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/support/json.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/impl/grpc_library.h>
|
||||
#include <grpcpp/security/tls_credentials_options.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/config.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
#include "src/core/lib/event_engine/default_event_engine.h"
|
||||
#include "src/core/lib/gprpp/env.h"
|
||||
#include "src/core/lib/gprpp/load_file.h"
|
||||
#include "src/core/lib/gprpp/status_helper.h"
|
||||
#include "src/core/lib/iomgr/error.h"
|
||||
#include "src/core/lib/json/json.h"
|
||||
#include "src/core/lib/json/json_reader.h"
|
||||
#include "src/core/lib/security/util/json_util.h"
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
#include "src/cpp/common/secure_auth_context.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
SecureChannelCredentials::SecureChannelCredentials(
|
||||
grpc_channel_credentials* c_creds)
|
||||
: c_creds_(c_creds) {}
|
||||
|
||||
std::shared_ptr<Channel> SecureChannelCredentials::CreateChannelImpl(
|
||||
const std::string& target, const ChannelArguments& args) {
|
||||
return CreateChannelWithInterceptors(
|
||||
target, args,
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::ClientInterceptorFactoryInterface>>());
|
||||
}
|
||||
|
||||
std::shared_ptr<Channel>
|
||||
SecureChannelCredentials::CreateChannelWithInterceptors(
|
||||
const std::string& target, const ChannelArguments& args,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) {
|
||||
grpc_channel_args channel_args;
|
||||
args.SetChannelArgs(&channel_args);
|
||||
return grpc::CreateChannelInternal(
|
||||
args.GetSslTargetNameOverride(),
|
||||
grpc_channel_create(target.c_str(), c_creds_, &channel_args),
|
||||
std::move(interceptor_creators));
|
||||
}
|
||||
|
||||
SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
|
||||
: c_creds_(c_creds) {}
|
||||
|
||||
bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
|
||||
return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
std::shared_ptr<ChannelCredentials> WrapChannelCredentials(
|
||||
grpc_channel_credentials* creds) {
|
||||
return creds == nullptr ? nullptr
|
||||
: std::shared_ptr<ChannelCredentials>(
|
||||
new SecureChannelCredentials(creds));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace {
|
||||
|
||||
std::shared_ptr<CallCredentials> WrapCallCredentials(
|
||||
grpc_call_credentials* creds) {
|
||||
return creds == nullptr ? nullptr
|
||||
: std::shared_ptr<CallCredentials>(
|
||||
new SecureCallCredentials(creds));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return internal::WrapChannelCredentials(
|
||||
grpc_google_default_credentials_create(nullptr));
|
||||
}
|
||||
|
||||
std::shared_ptr<CallCredentials> ExternalAccountCredentials(
|
||||
const grpc::string& json_string, const std::vector<grpc::string>& scopes) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return WrapCallCredentials(grpc_external_account_credentials_create(
|
||||
json_string.c_str(), absl::StrJoin(scopes, ",").c_str()));
|
||||
}
|
||||
|
||||
// Builds SSL Credentials given SSL specific options
|
||||
std::shared_ptr<ChannelCredentials> SslCredentials(
|
||||
const SslCredentialsOptions& options) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
|
||||
options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
|
||||
|
||||
grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
|
||||
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
|
||||
options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr,
|
||||
nullptr);
|
||||
return internal::WrapChannelCredentials(c_creds);
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
namespace {
|
||||
|
||||
void ClearStsCredentialsOptions(StsCredentialsOptions* options) {
|
||||
if (options == nullptr) return;
|
||||
options->token_exchange_service_uri.clear();
|
||||
options->resource.clear();
|
||||
options->audience.clear();
|
||||
options->scope.clear();
|
||||
options->requested_token_type.clear();
|
||||
options->subject_token_path.clear();
|
||||
options->subject_token_type.clear();
|
||||
options->actor_token_path.clear();
|
||||
options->actor_token_type.clear();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Builds STS credentials options from JSON.
|
||||
grpc::Status StsCredentialsOptionsFromJson(const std::string& json_string,
|
||||
StsCredentialsOptions* options) {
|
||||
if (options == nullptr) {
|
||||
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
|
||||
"options cannot be nullptr.");
|
||||
}
|
||||
ClearStsCredentialsOptions(options);
|
||||
auto json = grpc_core::JsonParse(json_string.c_str());
|
||||
if (!json.ok() || json->type() != grpc_core::Json::Type::kObject) {
|
||||
return grpc::Status(
|
||||
grpc::StatusCode::INVALID_ARGUMENT,
|
||||
absl::StrCat("Invalid json: ", json.status().ToString()));
|
||||
}
|
||||
|
||||
// Required fields.
|
||||
const char* value = grpc_json_get_string_property(
|
||||
*json, "token_exchange_service_uri", nullptr);
|
||||
if (value == nullptr) {
|
||||
ClearStsCredentialsOptions(options);
|
||||
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
|
||||
"token_exchange_service_uri must be specified.");
|
||||
}
|
||||
options->token_exchange_service_uri.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "subject_token_path", nullptr);
|
||||
if (value == nullptr) {
|
||||
ClearStsCredentialsOptions(options);
|
||||
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
|
||||
"subject_token_path must be specified.");
|
||||
}
|
||||
options->subject_token_path.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "subject_token_type", nullptr);
|
||||
if (value == nullptr) {
|
||||
ClearStsCredentialsOptions(options);
|
||||
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
|
||||
"subject_token_type must be specified.");
|
||||
}
|
||||
options->subject_token_type.assign(value);
|
||||
|
||||
// Optional fields.
|
||||
value = grpc_json_get_string_property(*json, "resource", nullptr);
|
||||
if (value != nullptr) options->resource.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "audience", nullptr);
|
||||
if (value != nullptr) options->audience.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "scope", nullptr);
|
||||
if (value != nullptr) options->scope.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "requested_token_type", nullptr);
|
||||
if (value != nullptr) options->requested_token_type.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "actor_token_path", nullptr);
|
||||
if (value != nullptr) options->actor_token_path.assign(value);
|
||||
value = grpc_json_get_string_property(*json, "actor_token_type", nullptr);
|
||||
if (value != nullptr) options->actor_token_type.assign(value);
|
||||
|
||||
return grpc::Status();
|
||||
}
|
||||
|
||||
// Builds STS credentials Options from the $STS_CREDENTIALS env var.
|
||||
grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options) {
|
||||
if (options == nullptr) {
|
||||
return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
|
||||
"options cannot be nullptr.");
|
||||
}
|
||||
ClearStsCredentialsOptions(options);
|
||||
auto sts_creds_path = grpc_core::GetEnv("STS_CREDENTIALS");
|
||||
if (!sts_creds_path.has_value()) {
|
||||
return grpc::Status(grpc::StatusCode::NOT_FOUND,
|
||||
"STS_CREDENTIALS environment variable not set.");
|
||||
}
|
||||
auto json_slice =
|
||||
grpc_core::LoadFile(*sts_creds_path, /*add_null_terminator=*/true);
|
||||
if (!json_slice.ok()) {
|
||||
return grpc::Status(grpc::StatusCode::NOT_FOUND,
|
||||
json_slice.status().ToString());
|
||||
}
|
||||
return StsCredentialsOptionsFromJson(json_slice->as_string_view().data(),
|
||||
options);
|
||||
}
|
||||
|
||||
// C++ to Core STS Credentials options.
|
||||
grpc_sts_credentials_options StsCredentialsCppToCoreOptions(
|
||||
const StsCredentialsOptions& options) {
|
||||
grpc_sts_credentials_options opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.token_exchange_service_uri = options.token_exchange_service_uri.c_str();
|
||||
opts.resource = options.resource.c_str();
|
||||
opts.audience = options.audience.c_str();
|
||||
opts.scope = options.scope.c_str();
|
||||
opts.requested_token_type = options.requested_token_type.c_str();
|
||||
opts.subject_token_path = options.subject_token_path.c_str();
|
||||
opts.subject_token_type = options.subject_token_type.c_str();
|
||||
opts.actor_token_path = options.actor_token_path.c_str();
|
||||
opts.actor_token_type = options.actor_token_type.c_str();
|
||||
return opts;
|
||||
}
|
||||
|
||||
// Builds STS credentials.
|
||||
std::shared_ptr<CallCredentials> StsCredentials(
|
||||
const StsCredentialsOptions& options) {
|
||||
auto opts = StsCredentialsCppToCoreOptions(options);
|
||||
return WrapCallCredentials(grpc_sts_credentials_create(&opts, nullptr));
|
||||
}
|
||||
|
||||
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
|
||||
std::unique_ptr<MetadataCredentialsPlugin> plugin,
|
||||
grpc_security_level min_security_level) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
const char* type = plugin->GetType();
|
||||
grpc::MetadataCredentialsPluginWrapper* wrapper =
|
||||
new grpc::MetadataCredentialsPluginWrapper(std::move(plugin));
|
||||
grpc_metadata_credentials_plugin c_plugin = {
|
||||
grpc::MetadataCredentialsPluginWrapper::GetMetadata,
|
||||
grpc::MetadataCredentialsPluginWrapper::DebugString,
|
||||
grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
|
||||
return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
|
||||
c_plugin, min_security_level, nullptr));
|
||||
}
|
||||
|
||||
// Builds ALTS Credentials given ALTS specific options
|
||||
std::shared_ptr<ChannelCredentials> AltsCredentials(
|
||||
const AltsCredentialsOptions& options) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
grpc_alts_credentials_options* c_options =
|
||||
grpc_alts_credentials_client_options_create();
|
||||
for (const auto& service_account : options.target_service_accounts) {
|
||||
grpc_alts_credentials_client_options_add_target_service_account(
|
||||
c_options, service_account.c_str());
|
||||
}
|
||||
grpc_channel_credentials* c_creds = grpc_alts_credentials_create(c_options);
|
||||
grpc_alts_credentials_options_destroy(c_options);
|
||||
return internal::WrapChannelCredentials(c_creds);
|
||||
}
|
||||
|
||||
// Builds Local Credentials
|
||||
std::shared_ptr<ChannelCredentials> LocalCredentials(
|
||||
grpc_local_connect_type type) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return internal::WrapChannelCredentials(grpc_local_credentials_create(type));
|
||||
}
|
||||
|
||||
// Builds TLS Credentials given TLS options.
|
||||
std::shared_ptr<ChannelCredentials> TlsCredentials(
|
||||
const TlsChannelCredentialsOptions& options) {
|
||||
return internal::WrapChannelCredentials(
|
||||
grpc_tls_credentials_create(options.c_credentials_options()));
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
// Builds credentials for use when running in GCE
|
||||
std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return WrapCallCredentials(
|
||||
grpc_google_compute_engine_credentials_create(nullptr));
|
||||
}
|
||||
|
||||
// Builds JWT credentials.
|
||||
std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
|
||||
const std::string& json_key, long token_lifetime_seconds) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
if (token_lifetime_seconds <= 0) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Trying to create JWTCredentials with non-positive lifetime");
|
||||
return WrapCallCredentials(nullptr);
|
||||
}
|
||||
gpr_timespec lifetime =
|
||||
gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
|
||||
return WrapCallCredentials(grpc_service_account_jwt_access_credentials_create(
|
||||
json_key.c_str(), lifetime, nullptr));
|
||||
}
|
||||
|
||||
// Builds refresh token credentials.
|
||||
std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
|
||||
const std::string& json_refresh_token) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return WrapCallCredentials(grpc_google_refresh_token_credentials_create(
|
||||
json_refresh_token.c_str(), nullptr));
|
||||
}
|
||||
|
||||
// Builds access token credentials.
|
||||
std::shared_ptr<CallCredentials> AccessTokenCredentials(
|
||||
const std::string& access_token) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return WrapCallCredentials(
|
||||
grpc_access_token_credentials_create(access_token.c_str(), nullptr));
|
||||
}
|
||||
|
||||
// Builds IAM credentials.
|
||||
std::shared_ptr<CallCredentials> GoogleIAMCredentials(
|
||||
const std::string& authorization_token,
|
||||
const std::string& authority_selector) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
return WrapCallCredentials(grpc_google_iam_credentials_create(
|
||||
authorization_token.c_str(), authority_selector.c_str(), nullptr));
|
||||
}
|
||||
|
||||
// Combines one channel credentials and one call credentials into a channel
|
||||
// composite credentials.
|
||||
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
|
||||
const std::shared_ptr<ChannelCredentials>& channel_creds,
|
||||
const std::shared_ptr<CallCredentials>& call_creds) {
|
||||
// Note that we are not saving shared_ptrs to the two credentials passed in
|
||||
// here. This is OK because the underlying C objects (i.e., channel_creds and
|
||||
// call_creds) into grpc_composite_credentials_create will see their refcounts
|
||||
// incremented.
|
||||
SecureChannelCredentials* s_channel_creds =
|
||||
channel_creds->AsSecureCredentials();
|
||||
SecureCallCredentials* s_call_creds = call_creds->AsSecureCredentials();
|
||||
if (s_channel_creds && s_call_creds) {
|
||||
return internal::WrapChannelCredentials(
|
||||
grpc_composite_channel_credentials_create(
|
||||
s_channel_creds->GetRawCreds(), s_call_creds->GetRawCreds(),
|
||||
nullptr));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CallCredentials> CompositeCallCredentials(
|
||||
const std::shared_ptr<CallCredentials>& creds1,
|
||||
const std::shared_ptr<CallCredentials>& creds2) {
|
||||
SecureCallCredentials* s_creds1 = creds1->AsSecureCredentials();
|
||||
SecureCallCredentials* s_creds2 = creds2->AsSecureCredentials();
|
||||
if (s_creds1 != nullptr && s_creds2 != nullptr) {
|
||||
return WrapCallCredentials(grpc_composite_call_credentials_create(
|
||||
s_creds1->GetRawCreds(), s_creds2->GetRawCreds(), nullptr));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
|
||||
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
|
||||
grpc::internal::GrpcLibrary init; // To call grpc_init().
|
||||
const char* type = plugin->GetType();
|
||||
grpc::MetadataCredentialsPluginWrapper* wrapper =
|
||||
new grpc::MetadataCredentialsPluginWrapper(std::move(plugin));
|
||||
grpc_metadata_credentials_plugin c_plugin = {
|
||||
grpc::MetadataCredentialsPluginWrapper::GetMetadata,
|
||||
grpc::MetadataCredentialsPluginWrapper::DebugString,
|
||||
grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
|
||||
return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
|
||||
c_plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr));
|
||||
}
|
||||
|
||||
char* MetadataCredentialsPluginWrapper::DebugString(void* wrapper) {
|
||||
GPR_ASSERT(wrapper);
|
||||
MetadataCredentialsPluginWrapper* w =
|
||||
static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
|
||||
return gpr_strdup(w->plugin_->DebugString().c_str());
|
||||
}
|
||||
|
||||
void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
|
||||
if (wrapper == nullptr) return;
|
||||
grpc_event_engine::experimental::GetDefaultEventEngine()->Run([wrapper] {
|
||||
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
delete static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
|
||||
});
|
||||
}
|
||||
|
||||
int MetadataCredentialsPluginWrapper::GetMetadata(
|
||||
void* wrapper, grpc_auth_metadata_context context,
|
||||
grpc_credentials_plugin_metadata_cb cb, void* user_data,
|
||||
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
|
||||
size_t* num_creds_md, grpc_status_code* status,
|
||||
const char** error_details) {
|
||||
GPR_ASSERT(wrapper);
|
||||
MetadataCredentialsPluginWrapper* w =
|
||||
static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
|
||||
if (!w->plugin_) {
|
||||
*num_creds_md = 0;
|
||||
*status = GRPC_STATUS_OK;
|
||||
*error_details = nullptr;
|
||||
return 1;
|
||||
}
|
||||
if (w->plugin_->IsBlocking()) {
|
||||
// The internals of context may be destroyed if GetMetadata is cancelled.
|
||||
// Make a copy for InvokePlugin.
|
||||
grpc_auth_metadata_context context_copy = grpc_auth_metadata_context();
|
||||
grpc_auth_metadata_context_copy(&context, &context_copy);
|
||||
// Asynchronous return.
|
||||
w->thread_pool_->Add([w, context_copy, cb, user_data]() mutable {
|
||||
w->MetadataCredentialsPluginWrapper::InvokePlugin(
|
||||
context_copy, cb, user_data, nullptr, nullptr, nullptr, nullptr);
|
||||
grpc_auth_metadata_context_reset(&context_copy);
|
||||
});
|
||||
return 0;
|
||||
} else {
|
||||
// Synchronous return.
|
||||
w->InvokePlugin(context, cb, user_data, creds_md, num_creds_md, status,
|
||||
error_details);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void UnrefMetadata(const std::vector<grpc_metadata>& md) {
|
||||
for (const auto& metadatum : md) {
|
||||
grpc_slice_unref(metadatum.key);
|
||||
grpc_slice_unref(metadatum.value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void MetadataCredentialsPluginWrapper::InvokePlugin(
|
||||
grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
|
||||
void* user_data, grpc_metadata creds_md[4], size_t* num_creds_md,
|
||||
grpc_status_code* status_code, const char** error_details) {
|
||||
std::multimap<std::string, std::string> metadata;
|
||||
|
||||
// const_cast is safe since the SecureAuthContext only inc/dec the refcount
|
||||
// and the object is passed as a const ref to plugin_->GetMetadata.
|
||||
SecureAuthContext cpp_channel_auth_context(
|
||||
const_cast<grpc_auth_context*>(context.channel_auth_context));
|
||||
|
||||
Status status = plugin_->GetMetadata(context.service_url, context.method_name,
|
||||
cpp_channel_auth_context, &metadata);
|
||||
std::vector<grpc_metadata> md;
|
||||
for (auto& metadatum : metadata) {
|
||||
grpc_metadata md_entry;
|
||||
md_entry.key = SliceFromCopiedString(metadatum.first);
|
||||
md_entry.value = SliceFromCopiedString(metadatum.second);
|
||||
md.push_back(md_entry);
|
||||
}
|
||||
if (creds_md != nullptr) {
|
||||
// Synchronous return.
|
||||
if (md.size() > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
|
||||
*num_creds_md = 0;
|
||||
*status_code = GRPC_STATUS_INTERNAL;
|
||||
*error_details = gpr_strdup(
|
||||
"blocking plugin credentials returned too many metadata keys");
|
||||
UnrefMetadata(md);
|
||||
} else {
|
||||
for (const auto& elem : md) {
|
||||
creds_md[*num_creds_md].key = elem.key;
|
||||
creds_md[*num_creds_md].value = elem.value;
|
||||
++(*num_creds_md);
|
||||
}
|
||||
*status_code = static_cast<grpc_status_code>(status.error_code());
|
||||
*error_details =
|
||||
status.ok() ? nullptr : gpr_strdup(status.error_message().c_str());
|
||||
}
|
||||
} else {
|
||||
// Asynchronous return.
|
||||
cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
|
||||
static_cast<grpc_status_code>(status.error_code()),
|
||||
status.error_message().c_str());
|
||||
UnrefMetadata(md);
|
||||
}
|
||||
}
|
||||
|
||||
MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
|
||||
std::unique_ptr<MetadataCredentialsPlugin> plugin)
|
||||
: plugin_(std::move(plugin)) {
|
||||
if (plugin_->IsBlocking()) {
|
||||
thread_pool_.reset(CreateDefaultThreadPool());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
134
Pods/gRPC-C++/src/cpp/client/secure_credentials.h
generated
Normal file
134
Pods/gRPC-C++/src/cpp/client/secure_credentials.h
generated
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_CLIENT_SECURE_CREDENTIALS_H
|
||||
#define GRPC_SRC_CPP_CLIENT_SECURE_CREDENTIALS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/impl/grpc_library.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
// TODO(yashykt): We shouldn't be including "src/core" headers.
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/security/credentials/credentials.h"
|
||||
#include "src/cpp/server/thread_pool_interface.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class Channel;
|
||||
|
||||
class SecureChannelCredentials final : public ChannelCredentials {
|
||||
public:
|
||||
explicit SecureChannelCredentials(grpc_channel_credentials* c_creds);
|
||||
~SecureChannelCredentials() override {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
if (c_creds_ != nullptr) c_creds_->Unref();
|
||||
}
|
||||
grpc_channel_credentials* GetRawCreds() { return c_creds_; }
|
||||
|
||||
std::shared_ptr<Channel> CreateChannelImpl(
|
||||
const std::string& target, const ChannelArguments& args) override;
|
||||
|
||||
SecureChannelCredentials* AsSecureCredentials() override { return this; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Channel> CreateChannelWithInterceptors(
|
||||
const std::string& target, const ChannelArguments& args,
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) override;
|
||||
grpc_channel_credentials* const c_creds_;
|
||||
};
|
||||
|
||||
class SecureCallCredentials final : public CallCredentials {
|
||||
public:
|
||||
explicit SecureCallCredentials(grpc_call_credentials* c_creds);
|
||||
~SecureCallCredentials() override {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
if (c_creds_ != nullptr) c_creds_->Unref();
|
||||
}
|
||||
grpc_call_credentials* GetRawCreds() { return c_creds_; }
|
||||
|
||||
bool ApplyToCall(grpc_call* call) override;
|
||||
SecureCallCredentials* AsSecureCredentials() override { return this; }
|
||||
std::string DebugString() override {
|
||||
return absl::StrCat("SecureCallCredentials{",
|
||||
std::string(c_creds_->debug_string()), "}");
|
||||
}
|
||||
|
||||
private:
|
||||
grpc_call_credentials* const c_creds_;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
std::shared_ptr<ChannelCredentials> WrapChannelCredentials(
|
||||
grpc_channel_credentials* creds);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace experimental {
|
||||
|
||||
// Transforms C++ STS Credentials options to core options. The pointers of the
|
||||
// resulting core options point to the memory held by the C++ options so C++
|
||||
// options need to be kept alive until after the core credentials creation.
|
||||
grpc_sts_credentials_options StsCredentialsCppToCoreOptions(
|
||||
const StsCredentialsOptions& options);
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
class MetadataCredentialsPluginWrapper final : private internal::GrpcLibrary {
|
||||
public:
|
||||
static void Destroy(void* wrapper);
|
||||
static int GetMetadata(
|
||||
void* wrapper, grpc_auth_metadata_context context,
|
||||
grpc_credentials_plugin_metadata_cb cb, void* user_data,
|
||||
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
|
||||
size_t* num_creds_md, grpc_status_code* status,
|
||||
const char** error_details);
|
||||
static char* DebugString(void* wrapper);
|
||||
|
||||
explicit MetadataCredentialsPluginWrapper(
|
||||
std::unique_ptr<MetadataCredentialsPlugin> plugin);
|
||||
|
||||
private:
|
||||
void InvokePlugin(
|
||||
grpc_auth_metadata_context context,
|
||||
grpc_credentials_plugin_metadata_cb cb, void* user_data,
|
||||
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
|
||||
size_t* num_creds_md, grpc_status_code* status_code,
|
||||
const char** error_details);
|
||||
std::unique_ptr<ThreadPoolInterface> thread_pool_;
|
||||
std::unique_ptr<MetadataCredentialsPlugin> plugin_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_CLIENT_SECURE_CREDENTIALS_H
|
||||
54
Pods/gRPC-C++/src/cpp/client/xds_credentials.cc
generated
Normal file
54
Pods/gRPC-C++/src/cpp/client/xds_credentials.cc
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2020 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/credentials.h>
|
||||
|
||||
#include "src/cpp/client/secure_credentials.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::shared_ptr<ChannelCredentials> XdsCredentials(
|
||||
const std::shared_ptr<ChannelCredentials>& fallback_creds) {
|
||||
GPR_ASSERT(fallback_creds != nullptr);
|
||||
if (fallback_creds->IsInsecure()) {
|
||||
grpc_channel_credentials* insecure_creds =
|
||||
grpc_insecure_credentials_create();
|
||||
auto xds_creds = internal::WrapChannelCredentials(
|
||||
grpc_xds_credentials_create(insecure_creds));
|
||||
grpc_channel_credentials_release(insecure_creds);
|
||||
return xds_creds;
|
||||
} else {
|
||||
return internal::WrapChannelCredentials(grpc_xds_credentials_create(
|
||||
fallback_creds->AsSecureCredentials()->GetRawCreds()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
std::shared_ptr<ChannelCredentials> XdsCredentials(
|
||||
const std::shared_ptr<ChannelCredentials>& fallback_creds) {
|
||||
return grpc::XdsCredentials(fallback_creds);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
180
Pods/gRPC-C++/src/cpp/common/alarm.cc
generated
Normal file
180
Pods/gRPC-C++/src/cpp/common/alarm.cc
generated
Normal file
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// Copyright 2018 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <grpc/event_engine/event_engine.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/sync.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/alarm.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
|
||||
#include "src/core/lib/event_engine/default_event_engine.h"
|
||||
#include "src/core/lib/gprpp/time.h"
|
||||
#include "src/core/lib/iomgr/error.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/surface/completion_queue.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
using grpc_event_engine::experimental::EventEngine;
|
||||
} // namespace
|
||||
|
||||
class AlarmImpl : public grpc::internal::CompletionQueueTag {
|
||||
public:
|
||||
AlarmImpl()
|
||||
: event_engine_(grpc_event_engine::experimental::GetDefaultEventEngine()),
|
||||
cq_(nullptr),
|
||||
tag_(nullptr) {
|
||||
gpr_ref_init(&refs_, 1);
|
||||
}
|
||||
~AlarmImpl() override {}
|
||||
bool FinalizeResult(void** tag, bool* /*status*/) override {
|
||||
*tag = tag_;
|
||||
Unref();
|
||||
return true;
|
||||
}
|
||||
void Set(grpc::CompletionQueue* cq, gpr_timespec deadline, void* tag) {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
GRPC_CQ_INTERNAL_REF(cq->cq(), "alarm");
|
||||
cq_ = cq->cq();
|
||||
tag_ = tag;
|
||||
GPR_ASSERT(grpc_cq_begin_op(cq_, this));
|
||||
Ref();
|
||||
GPR_ASSERT(cq_armed_.exchange(true) == false);
|
||||
GPR_ASSERT(!callback_armed_.load());
|
||||
cq_timer_handle_ = event_engine_->RunAfter(
|
||||
grpc_core::Timestamp::FromTimespecRoundUp(deadline) -
|
||||
grpc_core::ExecCtx::Get()->Now(),
|
||||
[this] { OnCQAlarm(absl::OkStatus()); });
|
||||
}
|
||||
void Set(gpr_timespec deadline, std::function<void(bool)> f) {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
// Don't use any CQ at all. Instead just use the timer to fire the function
|
||||
callback_ = std::move(f);
|
||||
Ref();
|
||||
GPR_ASSERT(callback_armed_.exchange(true) == false);
|
||||
GPR_ASSERT(!cq_armed_.load());
|
||||
callback_timer_handle_ = event_engine_->RunAfter(
|
||||
grpc_core::Timestamp::FromTimespecRoundUp(deadline) -
|
||||
grpc_core::ExecCtx::Get()->Now(),
|
||||
[this] { OnCallbackAlarm(true); });
|
||||
}
|
||||
void Cancel() {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
if (callback_armed_.load() &&
|
||||
event_engine_->Cancel(callback_timer_handle_)) {
|
||||
event_engine_->Run([this] { OnCallbackAlarm(/*is_ok=*/false); });
|
||||
}
|
||||
if (cq_armed_.load() && event_engine_->Cancel(cq_timer_handle_)) {
|
||||
event_engine_->Run(
|
||||
[this] { OnCQAlarm(absl::CancelledError("cancelled")); });
|
||||
}
|
||||
}
|
||||
void Destroy() {
|
||||
Cancel();
|
||||
Unref();
|
||||
}
|
||||
|
||||
private:
|
||||
void OnCQAlarm(grpc_error_handle error) {
|
||||
cq_armed_.store(false);
|
||||
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
// Preserve the cq and reset the cq_ so that the alarm
|
||||
// can be reset when the alarm tag is delivered.
|
||||
grpc_completion_queue* cq = cq_;
|
||||
cq_ = nullptr;
|
||||
grpc_cq_end_op(
|
||||
cq, this, error,
|
||||
[](void* /*arg*/, grpc_cq_completion* /*completion*/) {}, nullptr,
|
||||
&completion_);
|
||||
GRPC_CQ_INTERNAL_UNREF(cq, "alarm");
|
||||
}
|
||||
|
||||
void OnCallbackAlarm(bool is_ok) {
|
||||
callback_armed_.store(false);
|
||||
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
callback_(is_ok);
|
||||
Unref();
|
||||
}
|
||||
|
||||
void Ref() { gpr_ref(&refs_); }
|
||||
void Unref() {
|
||||
if (gpr_unref(&refs_)) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_;
|
||||
std::atomic<bool> cq_armed_{false};
|
||||
EventEngine::TaskHandle cq_timer_handle_ = EventEngine::TaskHandle::kInvalid;
|
||||
std::atomic<bool> callback_armed_{false};
|
||||
EventEngine::TaskHandle callback_timer_handle_ =
|
||||
EventEngine::TaskHandle::kInvalid;
|
||||
gpr_refcount refs_;
|
||||
grpc_cq_completion completion_;
|
||||
// completion queue where events about this alarm will be posted
|
||||
grpc_completion_queue* cq_;
|
||||
void* tag_;
|
||||
std::function<void(bool)> callback_;
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
Alarm::Alarm() : alarm_(new internal::AlarmImpl()) {}
|
||||
|
||||
void Alarm::SetInternal(grpc::CompletionQueue* cq, gpr_timespec deadline,
|
||||
void* tag) {
|
||||
// Note that we know that alarm_ is actually an internal::AlarmImpl
|
||||
// but we declared it as the base pointer to avoid a forward declaration
|
||||
// or exposing core data structures in the C++ public headers.
|
||||
// Thus it is safe to use a static_cast to the subclass here, and the
|
||||
// C++ style guide allows us to do so in this case
|
||||
static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag);
|
||||
}
|
||||
|
||||
void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) {
|
||||
// Note that we know that alarm_ is actually an internal::AlarmImpl
|
||||
// but we declared it as the base pointer to avoid a forward declaration
|
||||
// or exposing core data structures in the C++ public headers.
|
||||
// Thus it is safe to use a static_cast to the subclass here, and the
|
||||
// C++ style guide allows us to do so in this case
|
||||
static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f));
|
||||
}
|
||||
|
||||
Alarm::~Alarm() {
|
||||
if (alarm_ != nullptr) {
|
||||
static_cast<internal::AlarmImpl*>(alarm_)->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void Alarm::Cancel() { static_cast<internal::AlarmImpl*>(alarm_)->Cancel(); }
|
||||
} // namespace grpc
|
||||
72
Pods/gRPC-C++/src/cpp/common/auth_property_iterator.cc
generated
Normal file
72
Pods/gRPC-C++/src/cpp/common/auth_property_iterator.cc
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/security/auth_context.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
AuthPropertyIterator::AuthPropertyIterator()
|
||||
: property_(nullptr), ctx_(nullptr), index_(0), name_(nullptr) {}
|
||||
|
||||
AuthPropertyIterator::AuthPropertyIterator(
|
||||
const grpc_auth_property* property, const grpc_auth_property_iterator* iter)
|
||||
: property_(property),
|
||||
ctx_(iter->ctx),
|
||||
index_(iter->index),
|
||||
name_(iter->name) {}
|
||||
|
||||
AuthPropertyIterator::~AuthPropertyIterator() {}
|
||||
|
||||
AuthPropertyIterator& AuthPropertyIterator::operator++() {
|
||||
grpc_auth_property_iterator iter = {ctx_, index_, name_};
|
||||
property_ = grpc_auth_property_iterator_next(&iter);
|
||||
ctx_ = iter.ctx;
|
||||
index_ = iter.index;
|
||||
name_ = iter.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AuthPropertyIterator AuthPropertyIterator::operator++(int) {
|
||||
AuthPropertyIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool AuthPropertyIterator::operator==(const AuthPropertyIterator& rhs) const {
|
||||
if (property_ == nullptr || rhs.property_ == nullptr) {
|
||||
return property_ == rhs.property_;
|
||||
} else {
|
||||
return index_ == rhs.index_;
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
AuthProperty AuthPropertyIterator::operator*() {
|
||||
return std::pair<grpc::string_ref, grpc::string_ref>(
|
||||
property_->name,
|
||||
grpc::string_ref(property_->value, property_->value_length));
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
220
Pods/gRPC-C++/src/cpp/common/channel_arguments.cc
generated
Normal file
220
Pods/gRPC-C++/src/cpp/common/channel_arguments.cc
generated
Normal file
@@ -0,0 +1,220 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/impl/channel_arg_names.h>
|
||||
#include <grpc/impl/compression_types.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#include <grpcpp/resource_quota.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/iomgr/socket_mutator.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
ChannelArguments::ChannelArguments() {
|
||||
// This will be ignored if used on the server side.
|
||||
SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + grpc::Version());
|
||||
}
|
||||
|
||||
ChannelArguments::ChannelArguments(const ChannelArguments& other)
|
||||
: strings_(other.strings_) {
|
||||
args_.reserve(other.args_.size());
|
||||
auto list_it_dst = strings_.begin();
|
||||
auto list_it_src = other.strings_.begin();
|
||||
for (const auto& a : other.args_) {
|
||||
grpc_arg ap;
|
||||
ap.type = a.type;
|
||||
GPR_ASSERT(list_it_src->c_str() == a.key);
|
||||
ap.key = const_cast<char*>(list_it_dst->c_str());
|
||||
++list_it_src;
|
||||
++list_it_dst;
|
||||
switch (a.type) {
|
||||
case GRPC_ARG_INTEGER:
|
||||
ap.value.integer = a.value.integer;
|
||||
break;
|
||||
case GRPC_ARG_STRING:
|
||||
GPR_ASSERT(list_it_src->c_str() == a.value.string);
|
||||
ap.value.string = const_cast<char*>(list_it_dst->c_str());
|
||||
++list_it_src;
|
||||
++list_it_dst;
|
||||
break;
|
||||
case GRPC_ARG_POINTER:
|
||||
ap.value.pointer = a.value.pointer;
|
||||
ap.value.pointer.p = a.value.pointer.vtable->copy(ap.value.pointer.p);
|
||||
break;
|
||||
}
|
||||
args_.push_back(ap);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelArguments::~ChannelArguments() {
|
||||
for (auto& arg : args_) {
|
||||
if (arg.type == GRPC_ARG_POINTER) {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
arg.value.pointer.vtable->destroy(arg.value.pointer.p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelArguments::Swap(ChannelArguments& other) {
|
||||
args_.swap(other.args_);
|
||||
strings_.swap(other.strings_);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetCompressionAlgorithm(
|
||||
grpc_compression_algorithm algorithm) {
|
||||
SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, algorithm);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetGrpclbFallbackTimeout(int fallback_timeout) {
|
||||
SetInt(GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS, fallback_timeout);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetSocketMutator(grpc_socket_mutator* mutator) {
|
||||
if (!mutator) {
|
||||
return;
|
||||
}
|
||||
grpc_arg mutator_arg = grpc_socket_mutator_to_arg(mutator);
|
||||
bool replaced = false;
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
for (auto& arg : args_) {
|
||||
if (arg.type == mutator_arg.type &&
|
||||
std::string(arg.key) == std::string(mutator_arg.key)) {
|
||||
GPR_ASSERT(!replaced);
|
||||
arg.value.pointer.vtable->destroy(arg.value.pointer.p);
|
||||
arg.value.pointer = mutator_arg.value.pointer;
|
||||
replaced = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replaced) {
|
||||
strings_.push_back(std::string(mutator_arg.key));
|
||||
args_.push_back(mutator_arg);
|
||||
args_.back().key = const_cast<char*>(strings_.back().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: a second call to this will add in front the result of the first call.
|
||||
// An example is calling this on a copy of ChannelArguments which already has a
|
||||
// prefix. The user can build up a prefix string by calling this multiple times,
|
||||
// each with more significant identifier.
|
||||
void ChannelArguments::SetUserAgentPrefix(
|
||||
const std::string& user_agent_prefix) {
|
||||
if (user_agent_prefix.empty()) {
|
||||
return;
|
||||
}
|
||||
bool replaced = false;
|
||||
auto strings_it = strings_.begin();
|
||||
for (auto& arg : args_) {
|
||||
++strings_it;
|
||||
if (arg.type == GRPC_ARG_STRING) {
|
||||
if (std::string(arg.key) == GRPC_ARG_PRIMARY_USER_AGENT_STRING) {
|
||||
GPR_ASSERT(arg.value.string == strings_it->c_str());
|
||||
*(strings_it) = user_agent_prefix + " " + arg.value.string;
|
||||
arg.value.string = const_cast<char*>(strings_it->c_str());
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
++strings_it;
|
||||
}
|
||||
}
|
||||
if (!replaced) {
|
||||
SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelArguments::SetResourceQuota(
|
||||
const grpc::ResourceQuota& resource_quota) {
|
||||
SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA,
|
||||
resource_quota.c_resource_quota(),
|
||||
grpc_resource_quota_arg_vtable());
|
||||
}
|
||||
|
||||
void ChannelArguments::SetMaxReceiveMessageSize(int size) {
|
||||
SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, size);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetMaxSendMessageSize(int size) {
|
||||
SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, size);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetLoadBalancingPolicyName(
|
||||
const std::string& lb_policy_name) {
|
||||
SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetServiceConfigJSON(
|
||||
const std::string& service_config_json) {
|
||||
SetString(GRPC_ARG_SERVICE_CONFIG, service_config_json);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetInt(const std::string& key, int value) {
|
||||
grpc_arg arg;
|
||||
arg.type = GRPC_ARG_INTEGER;
|
||||
strings_.push_back(key);
|
||||
arg.key = const_cast<char*>(strings_.back().c_str());
|
||||
arg.value.integer = value;
|
||||
|
||||
args_.push_back(arg);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetPointer(const std::string& key, void* value) {
|
||||
static const grpc_arg_pointer_vtable vtable = {
|
||||
&PointerVtableMembers::Copy, &PointerVtableMembers::Destroy,
|
||||
&PointerVtableMembers::Compare};
|
||||
SetPointerWithVtable(key, value, &vtable);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetPointerWithVtable(
|
||||
const std::string& key, void* value,
|
||||
const grpc_arg_pointer_vtable* vtable) {
|
||||
grpc_arg arg;
|
||||
arg.type = GRPC_ARG_POINTER;
|
||||
strings_.push_back(key);
|
||||
arg.key = const_cast<char*>(strings_.back().c_str());
|
||||
arg.value.pointer.p = vtable->copy(value);
|
||||
arg.value.pointer.vtable = vtable;
|
||||
args_.push_back(arg);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetString(const std::string& key,
|
||||
const std::string& value) {
|
||||
grpc_arg arg;
|
||||
arg.type = GRPC_ARG_STRING;
|
||||
strings_.push_back(key);
|
||||
arg.key = const_cast<char*>(strings_.back().c_str());
|
||||
strings_.push_back(value);
|
||||
arg.value.string = const_cast<char*>(strings_.back().c_str());
|
||||
|
||||
args_.push_back(arg);
|
||||
}
|
||||
|
||||
void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const {
|
||||
channel_args->num_args = args_.size();
|
||||
if (channel_args->num_args > 0) {
|
||||
channel_args->args = const_cast<grpc_arg*>(&args_[0]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
206
Pods/gRPC-C++/src/cpp/common/completion_queue_cc.cc
generated
Normal file
206
Pods/gRPC-C++/src/cpp/common/completion_queue_cc.cc
generated
Normal file
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/cpu.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/sync.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
#include <grpcpp/impl/grpc_library.h>
|
||||
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/gprpp/thd.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace {
|
||||
|
||||
gpr_once g_once_init_callback_alternative = GPR_ONCE_INIT;
|
||||
grpc_core::Mutex* g_callback_alternative_mu;
|
||||
|
||||
// Implement a ref-counted callback CQ for global use in the alternative
|
||||
// implementation so that its threads are only created once. Do this using
|
||||
// explicit ref-counts and raw pointers rather than a shared-ptr since that
|
||||
// has a non-trivial destructor and thus can't be used for global variables.
|
||||
struct CallbackAlternativeCQ {
|
||||
int refs ABSL_GUARDED_BY(g_callback_alternative_mu) = 0;
|
||||
CompletionQueue* cq ABSL_GUARDED_BY(g_callback_alternative_mu);
|
||||
std::vector<grpc_core::Thread>* nexting_threads
|
||||
ABSL_GUARDED_BY(g_callback_alternative_mu);
|
||||
|
||||
CompletionQueue* Ref() {
|
||||
grpc_core::MutexLock lock(&*g_callback_alternative_mu);
|
||||
refs++;
|
||||
if (refs == 1) {
|
||||
cq = new CompletionQueue;
|
||||
int num_nexting_threads =
|
||||
grpc_core::Clamp(gpr_cpu_num_cores() / 2, 2u, 16u);
|
||||
nexting_threads = new std::vector<grpc_core::Thread>;
|
||||
for (int i = 0; i < num_nexting_threads; i++) {
|
||||
nexting_threads->emplace_back(
|
||||
"nexting_thread",
|
||||
[](void* arg) {
|
||||
grpc_completion_queue* cq =
|
||||
static_cast<CompletionQueue*>(arg)->cq();
|
||||
while (true) {
|
||||
// Use the raw Core next function rather than the C++ Next since
|
||||
// Next incorporates FinalizeResult and we actually want that
|
||||
// called from the callback functor itself.
|
||||
// TODO(vjpai): Migrate below to next without a timeout or idle
|
||||
// phase. That's currently starving out some other polling,
|
||||
// though.
|
||||
auto ev = grpc_completion_queue_next(
|
||||
cq,
|
||||
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
|
||||
gpr_time_from_millis(1000, GPR_TIMESPAN)),
|
||||
nullptr);
|
||||
if (ev.type == GRPC_QUEUE_SHUTDOWN) {
|
||||
return;
|
||||
}
|
||||
if (ev.type == GRPC_QUEUE_TIMEOUT) {
|
||||
gpr_sleep_until(
|
||||
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
|
||||
gpr_time_from_millis(100, GPR_TIMESPAN)));
|
||||
continue;
|
||||
}
|
||||
GPR_DEBUG_ASSERT(ev.type == GRPC_OP_COMPLETE);
|
||||
// We can always execute the callback inline rather than
|
||||
// pushing it to another Executor thread because this
|
||||
// thread is definitely running on a background thread, does not
|
||||
// hold any application locks before executing the callback,
|
||||
// and cannot be entered recursively.
|
||||
auto* functor =
|
||||
static_cast<grpc_completion_queue_functor*>(ev.tag);
|
||||
functor->functor_run(functor, ev.success);
|
||||
}
|
||||
},
|
||||
cq);
|
||||
}
|
||||
for (auto& th : *nexting_threads) {
|
||||
th.Start();
|
||||
}
|
||||
}
|
||||
return cq;
|
||||
}
|
||||
|
||||
void Unref() {
|
||||
grpc_core::MutexLock lock(g_callback_alternative_mu);
|
||||
refs--;
|
||||
if (refs == 0) {
|
||||
cq->Shutdown();
|
||||
for (auto& th : *nexting_threads) {
|
||||
th.Join();
|
||||
}
|
||||
delete nexting_threads;
|
||||
delete cq;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CallbackAlternativeCQ g_callback_alternative_cq;
|
||||
|
||||
} // namespace
|
||||
|
||||
// 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
|
||||
// i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
|
||||
// a 'grpc_completion_queue' instance (which is being passed as the input to
|
||||
// this constructor), one must have already called grpc_init().
|
||||
CompletionQueue::CompletionQueue(grpc_completion_queue* take)
|
||||
: GrpcLibrary(false), cq_(take) {
|
||||
InitialAvalanching();
|
||||
}
|
||||
|
||||
void CompletionQueue::Shutdown() {
|
||||
#ifndef NDEBUG
|
||||
if (!ServerListEmpty()) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"CompletionQueue shutdown being shutdown before its server.");
|
||||
}
|
||||
#endif
|
||||
CompleteAvalanching();
|
||||
}
|
||||
|
||||
CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
|
||||
void** tag, bool* ok, gpr_timespec deadline) {
|
||||
for (;;) {
|
||||
auto ev = grpc_completion_queue_next(cq_, deadline, nullptr);
|
||||
switch (ev.type) {
|
||||
case GRPC_QUEUE_TIMEOUT:
|
||||
return TIMEOUT;
|
||||
case GRPC_QUEUE_SHUTDOWN:
|
||||
return SHUTDOWN;
|
||||
case GRPC_OP_COMPLETE:
|
||||
auto core_cq_tag =
|
||||
static_cast<grpc::internal::CompletionQueueTag*>(ev.tag);
|
||||
*ok = ev.success != 0;
|
||||
*tag = core_cq_tag;
|
||||
if (core_cq_tag->FinalizeResult(tag, ok)) {
|
||||
return GOT_EVENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 core_cq_tag =
|
||||
static_cast<grpc::internal::CompletionQueueTag*>(res_tag);
|
||||
*ok = res == 1;
|
||||
if (core_cq_tag->FinalizeResult(tag, ok)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CompletionQueue* CompletionQueue::CallbackAlternativeCQ() {
|
||||
gpr_once_init(&g_once_init_callback_alternative,
|
||||
[] { g_callback_alternative_mu = new grpc_core::Mutex(); });
|
||||
return g_callback_alternative_cq.Ref();
|
||||
}
|
||||
|
||||
void CompletionQueue::ReleaseCallbackAlternativeCQ(CompletionQueue* cq)
|
||||
ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
(void)cq;
|
||||
// This accesses g_callback_alternative_cq without acquiring the mutex
|
||||
// but it's considered safe because it just reads the pointer address.
|
||||
GPR_DEBUG_ASSERT(cq == g_callback_alternative_cq.cq);
|
||||
g_callback_alternative_cq.Unref();
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
44
Pods/gRPC-C++/src/cpp/common/resource_quota_cc.cc
generated
Normal file
44
Pods/gRPC-C++/src/cpp/common/resource_quota_cc.cc
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpcpp/resource_quota.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
ResourceQuota::ResourceQuota() : impl_(grpc_resource_quota_create(nullptr)) {}
|
||||
|
||||
ResourceQuota::ResourceQuota(const std::string& name)
|
||||
: impl_(grpc_resource_quota_create(name.c_str())) {}
|
||||
|
||||
ResourceQuota::~ResourceQuota() { grpc_resource_quota_unref(impl_); }
|
||||
|
||||
ResourceQuota& ResourceQuota::Resize(size_t new_size) {
|
||||
grpc_resource_quota_resize(impl_, new_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceQuota& ResourceQuota::SetMaxThreads(int new_max_threads) {
|
||||
grpc_resource_quota_set_max_threads(impl_, new_max_threads);
|
||||
return *this;
|
||||
}
|
||||
} // namespace grpc
|
||||
21
Pods/gRPC-C++/src/cpp/common/rpc_method.cc
generated
Normal file
21
Pods/gRPC-C++/src/cpp/common/rpc_method.cc
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
|
||||
namespace grpc {} // namespace grpc
|
||||
99
Pods/gRPC-C++/src/cpp/common/secure_auth_context.cc
generated
Normal file
99
Pods/gRPC-C++/src/cpp/common/secure_auth_context.cc
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/common/secure_auth_context.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::vector<grpc::string_ref> SecureAuthContext::GetPeerIdentity() const {
|
||||
if (ctx_ == nullptr) {
|
||||
return std::vector<grpc::string_ref>();
|
||||
}
|
||||
grpc_auth_property_iterator iter =
|
||||
grpc_auth_context_peer_identity(ctx_.get());
|
||||
std::vector<grpc::string_ref> identity;
|
||||
const grpc_auth_property* property = nullptr;
|
||||
while ((property = grpc_auth_property_iterator_next(&iter))) {
|
||||
identity.push_back(
|
||||
grpc::string_ref(property->value, property->value_length));
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
|
||||
std::string SecureAuthContext::GetPeerIdentityPropertyName() const {
|
||||
if (ctx_ == nullptr) {
|
||||
return "";
|
||||
}
|
||||
const char* name = grpc_auth_context_peer_identity_property_name(ctx_.get());
|
||||
return name == nullptr ? "" : name;
|
||||
}
|
||||
|
||||
std::vector<grpc::string_ref> SecureAuthContext::FindPropertyValues(
|
||||
const std::string& name) const {
|
||||
if (ctx_ == nullptr) {
|
||||
return std::vector<grpc::string_ref>();
|
||||
}
|
||||
grpc_auth_property_iterator iter =
|
||||
grpc_auth_context_find_properties_by_name(ctx_.get(), name.c_str());
|
||||
const grpc_auth_property* property = nullptr;
|
||||
std::vector<grpc::string_ref> values;
|
||||
while ((property = grpc_auth_property_iterator_next(&iter))) {
|
||||
values.push_back(grpc::string_ref(property->value, property->value_length));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
AuthPropertyIterator SecureAuthContext::begin() const {
|
||||
if (ctx_ != nullptr) {
|
||||
grpc_auth_property_iterator iter =
|
||||
grpc_auth_context_property_iterator(ctx_.get());
|
||||
const grpc_auth_property* property =
|
||||
grpc_auth_property_iterator_next(&iter);
|
||||
return AuthPropertyIterator(property, &iter);
|
||||
} else {
|
||||
return end();
|
||||
}
|
||||
}
|
||||
|
||||
AuthPropertyIterator SecureAuthContext::end() const {
|
||||
return AuthPropertyIterator();
|
||||
}
|
||||
|
||||
void SecureAuthContext::AddProperty(const std::string& key,
|
||||
const grpc::string_ref& value) {
|
||||
if (ctx_ == nullptr) return;
|
||||
grpc_auth_context_add_property(ctx_.get(), key.c_str(), value.data(),
|
||||
value.size());
|
||||
}
|
||||
|
||||
bool SecureAuthContext::SetPeerIdentityPropertyName(const std::string& name) {
|
||||
if (ctx_ == nullptr) return false;
|
||||
return grpc_auth_context_set_peer_identity_property_name(ctx_.get(),
|
||||
name.c_str()) != 0;
|
||||
}
|
||||
|
||||
bool SecureAuthContext::IsPeerAuthenticated() const {
|
||||
if (ctx_ == nullptr) return false;
|
||||
return grpc_auth_context_peer_is_authenticated(ctx_.get()) != 0;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
65
Pods/gRPC-C++/src/cpp/common/secure_auth_context.h
generated
Normal file
65
Pods/gRPC-C++/src/cpp/common/secure_auth_context.h
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_COMMON_SECURE_AUTH_CONTEXT_H
|
||||
#define GRPC_SRC_CPP_COMMON_SECURE_AUTH_CONTEXT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/security/auth_context.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/security/context/security_context.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class SecureAuthContext final : public AuthContext {
|
||||
public:
|
||||
explicit SecureAuthContext(grpc_auth_context* ctx)
|
||||
: ctx_(ctx != nullptr ? ctx->Ref() : nullptr) {}
|
||||
|
||||
~SecureAuthContext() override = default;
|
||||
|
||||
bool IsPeerAuthenticated() const override;
|
||||
|
||||
std::vector<grpc::string_ref> GetPeerIdentity() const override;
|
||||
|
||||
std::string GetPeerIdentityPropertyName() const override;
|
||||
|
||||
std::vector<grpc::string_ref> FindPropertyValues(
|
||||
const std::string& name) const override;
|
||||
|
||||
AuthPropertyIterator begin() const override;
|
||||
|
||||
AuthPropertyIterator end() const override;
|
||||
|
||||
void AddProperty(const std::string& key,
|
||||
const grpc::string_ref& value) override;
|
||||
|
||||
bool SetPeerIdentityPropertyName(const std::string& name) override;
|
||||
|
||||
private:
|
||||
grpc_core::RefCountedPtr<grpc_auth_context> ctx_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_COMMON_SECURE_AUTH_CONTEXT_H
|
||||
41
Pods/gRPC-C++/src/cpp/common/secure_channel_arguments.cc
generated
Normal file
41
Pods/gRPC-C++/src/cpp/common/secure_channel_arguments.cc
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/channel_arg_names.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
void ChannelArguments::SetSslTargetNameOverride(const std::string& name) {
|
||||
SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name);
|
||||
}
|
||||
|
||||
std::string ChannelArguments::GetSslTargetNameOverride() const {
|
||||
for (unsigned int i = 0; i < args_.size(); i++) {
|
||||
if (std::string(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == args_[i].key) {
|
||||
return args_[i].value.string;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
38
Pods/gRPC-C++/src/cpp/common/secure_create_auth_context.cc
generated
Normal file
38
Pods/gRPC-C++/src/cpp/common/secure_create_auth_context.cc
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
#include <memory>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/security/auth_context.h>
|
||||
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/security/context/security_context.h"
|
||||
#include "src/cpp/common/secure_auth_context.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
|
||||
if (call == nullptr) {
|
||||
return std::shared_ptr<const AuthContext>();
|
||||
}
|
||||
grpc_core::RefCountedPtr<grpc_auth_context> ctx(grpc_call_auth_context(call));
|
||||
return std::make_shared<SecureAuthContext>(ctx.get());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
60
Pods/gRPC-C++/src/cpp/common/tls_certificate_provider.cc
generated
Normal file
60
Pods/gRPC-C++/src/cpp/common/tls_certificate_provider.cc
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Copyright 2020 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/tls_certificate_provider.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
|
||||
StaticDataCertificateProvider::StaticDataCertificateProvider(
|
||||
const std::string& root_certificate,
|
||||
const std::vector<IdentityKeyCertPair>& identity_key_cert_pairs) {
|
||||
GPR_ASSERT(!root_certificate.empty() || !identity_key_cert_pairs.empty());
|
||||
grpc_tls_identity_pairs* pairs_core = grpc_tls_identity_pairs_create();
|
||||
for (const IdentityKeyCertPair& pair : identity_key_cert_pairs) {
|
||||
grpc_tls_identity_pairs_add_pair(pairs_core, pair.private_key.c_str(),
|
||||
pair.certificate_chain.c_str());
|
||||
}
|
||||
c_provider_ = grpc_tls_certificate_provider_static_data_create(
|
||||
root_certificate.c_str(), pairs_core);
|
||||
GPR_ASSERT(c_provider_ != nullptr);
|
||||
};
|
||||
|
||||
StaticDataCertificateProvider::~StaticDataCertificateProvider() {
|
||||
grpc_tls_certificate_provider_release(c_provider_);
|
||||
};
|
||||
|
||||
FileWatcherCertificateProvider::FileWatcherCertificateProvider(
|
||||
const std::string& private_key_path,
|
||||
const std::string& identity_certificate_path,
|
||||
const std::string& root_cert_path, unsigned int refresh_interval_sec) {
|
||||
c_provider_ = grpc_tls_certificate_provider_file_watcher_create(
|
||||
private_key_path.c_str(), identity_certificate_path.c_str(),
|
||||
root_cert_path.c_str(), refresh_interval_sec);
|
||||
GPR_ASSERT(c_provider_ != nullptr);
|
||||
};
|
||||
|
||||
FileWatcherCertificateProvider::~FileWatcherCertificateProvider() {
|
||||
grpc_tls_certificate_provider_release(c_provider_);
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
260
Pods/gRPC-C++/src/cpp/common/tls_certificate_verifier.cc
generated
Normal file
260
Pods/gRPC-C++/src/cpp/common/tls_certificate_verifier.cc
generated
Normal file
@@ -0,0 +1,260 @@
|
||||
//
|
||||
// Copyright 2021 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/security/tls_certificate_verifier.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
|
||||
TlsCustomVerificationCheckRequest::TlsCustomVerificationCheckRequest(
|
||||
grpc_tls_custom_verification_check_request* request)
|
||||
: c_request_(request) {
|
||||
GPR_ASSERT(c_request_ != nullptr);
|
||||
}
|
||||
|
||||
grpc::string_ref TlsCustomVerificationCheckRequest::target_name() const {
|
||||
return c_request_->target_name != nullptr ? c_request_->target_name : "";
|
||||
}
|
||||
|
||||
grpc::string_ref TlsCustomVerificationCheckRequest::peer_cert() const {
|
||||
return c_request_->peer_info.peer_cert != nullptr
|
||||
? c_request_->peer_info.peer_cert
|
||||
: "";
|
||||
}
|
||||
|
||||
grpc::string_ref TlsCustomVerificationCheckRequest::peer_cert_full_chain()
|
||||
const {
|
||||
return c_request_->peer_info.peer_cert_full_chain != nullptr
|
||||
? c_request_->peer_info.peer_cert_full_chain
|
||||
: "";
|
||||
}
|
||||
|
||||
grpc::string_ref TlsCustomVerificationCheckRequest::common_name() const {
|
||||
return c_request_->peer_info.common_name != nullptr
|
||||
? c_request_->peer_info.common_name
|
||||
: "";
|
||||
}
|
||||
|
||||
grpc::string_ref TlsCustomVerificationCheckRequest::verified_root_cert_subject()
|
||||
const {
|
||||
return c_request_->peer_info.verified_root_cert_subject != nullptr
|
||||
? c_request_->peer_info.verified_root_cert_subject
|
||||
: "";
|
||||
}
|
||||
|
||||
std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::uri_names()
|
||||
const {
|
||||
std::vector<grpc::string_ref> uri_names;
|
||||
for (size_t i = 0; i < c_request_->peer_info.san_names.uri_names_size; ++i) {
|
||||
uri_names.emplace_back(c_request_->peer_info.san_names.uri_names[i]);
|
||||
}
|
||||
return uri_names;
|
||||
}
|
||||
|
||||
std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::dns_names()
|
||||
const {
|
||||
std::vector<grpc::string_ref> dns_names;
|
||||
for (size_t i = 0; i < c_request_->peer_info.san_names.dns_names_size; ++i) {
|
||||
dns_names.emplace_back(c_request_->peer_info.san_names.dns_names[i]);
|
||||
}
|
||||
return dns_names;
|
||||
}
|
||||
|
||||
std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::email_names()
|
||||
const {
|
||||
std::vector<grpc::string_ref> email_names;
|
||||
for (size_t i = 0; i < c_request_->peer_info.san_names.email_names_size;
|
||||
++i) {
|
||||
email_names.emplace_back(c_request_->peer_info.san_names.email_names[i]);
|
||||
}
|
||||
return email_names;
|
||||
}
|
||||
|
||||
std::vector<grpc::string_ref> TlsCustomVerificationCheckRequest::ip_names()
|
||||
const {
|
||||
std::vector<grpc::string_ref> ip_names;
|
||||
for (size_t i = 0; i < c_request_->peer_info.san_names.ip_names_size; ++i) {
|
||||
ip_names.emplace_back(c_request_->peer_info.san_names.ip_names[i]);
|
||||
}
|
||||
return ip_names;
|
||||
}
|
||||
|
||||
CertificateVerifier::CertificateVerifier(grpc_tls_certificate_verifier* v)
|
||||
: verifier_(v) {}
|
||||
|
||||
CertificateVerifier::~CertificateVerifier() {
|
||||
grpc_tls_certificate_verifier_release(verifier_);
|
||||
}
|
||||
|
||||
bool CertificateVerifier::Verify(TlsCustomVerificationCheckRequest* request,
|
||||
std::function<void(grpc::Status)> callback,
|
||||
grpc::Status* sync_status) {
|
||||
GPR_ASSERT(request != nullptr);
|
||||
GPR_ASSERT(request->c_request() != nullptr);
|
||||
{
|
||||
internal::MutexLock lock(&mu_);
|
||||
request_map_.emplace(request->c_request(), std::move(callback));
|
||||
}
|
||||
grpc_status_code status_code = GRPC_STATUS_OK;
|
||||
char* error_details = nullptr;
|
||||
bool is_done = grpc_tls_certificate_verifier_verify(
|
||||
verifier_, request->c_request(), &AsyncCheckDone, this, &status_code,
|
||||
&error_details);
|
||||
if (is_done) {
|
||||
if (status_code != GRPC_STATUS_OK) {
|
||||
*sync_status = grpc::Status(static_cast<grpc::StatusCode>(status_code),
|
||||
error_details);
|
||||
}
|
||||
internal::MutexLock lock(&mu_);
|
||||
request_map_.erase(request->c_request());
|
||||
}
|
||||
gpr_free(error_details);
|
||||
return is_done;
|
||||
}
|
||||
|
||||
void CertificateVerifier::Cancel(TlsCustomVerificationCheckRequest* request) {
|
||||
GPR_ASSERT(request != nullptr);
|
||||
GPR_ASSERT(request->c_request() != nullptr);
|
||||
grpc_tls_certificate_verifier_cancel(verifier_, request->c_request());
|
||||
}
|
||||
|
||||
void CertificateVerifier::AsyncCheckDone(
|
||||
grpc_tls_custom_verification_check_request* request, void* callback_arg,
|
||||
grpc_status_code status, const char* error_details) {
|
||||
auto* self = static_cast<CertificateVerifier*>(callback_arg);
|
||||
std::function<void(grpc::Status)> callback;
|
||||
{
|
||||
internal::MutexLock lock(&self->mu_);
|
||||
auto it = self->request_map_.find(request);
|
||||
if (it != self->request_map_.end()) {
|
||||
callback = std::move(it->second);
|
||||
self->request_map_.erase(it);
|
||||
}
|
||||
}
|
||||
if (callback != nullptr) {
|
||||
grpc::Status return_status;
|
||||
if (status != GRPC_STATUS_OK) {
|
||||
return_status =
|
||||
grpc::Status(static_cast<grpc::StatusCode>(status), error_details);
|
||||
}
|
||||
callback(return_status);
|
||||
}
|
||||
}
|
||||
|
||||
ExternalCertificateVerifier::ExternalCertificateVerifier() {
|
||||
base_ = new grpc_tls_certificate_verifier_external();
|
||||
base_->user_data = this;
|
||||
base_->verify = VerifyInCoreExternalVerifier;
|
||||
base_->cancel = CancelInCoreExternalVerifier;
|
||||
base_->destruct = DestructInCoreExternalVerifier;
|
||||
}
|
||||
|
||||
ExternalCertificateVerifier::~ExternalCertificateVerifier() { delete base_; }
|
||||
|
||||
int ExternalCertificateVerifier::VerifyInCoreExternalVerifier(
|
||||
void* user_data, grpc_tls_custom_verification_check_request* request,
|
||||
grpc_tls_on_custom_verification_check_done_cb callback, void* callback_arg,
|
||||
grpc_status_code* sync_status, char** sync_error_details) {
|
||||
auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
|
||||
TlsCustomVerificationCheckRequest* cpp_request = nullptr;
|
||||
{
|
||||
internal::MutexLock lock(&self->mu_);
|
||||
auto pair = self->request_map_.emplace(
|
||||
request, AsyncRequestState(callback, callback_arg, request));
|
||||
GPR_ASSERT(pair.second);
|
||||
cpp_request = &pair.first->second.cpp_request;
|
||||
}
|
||||
grpc::Status sync_current_verifier_status;
|
||||
bool is_done = self->Verify(
|
||||
cpp_request,
|
||||
[self, request](grpc::Status status) {
|
||||
grpc_tls_on_custom_verification_check_done_cb callback = nullptr;
|
||||
void* callback_arg = nullptr;
|
||||
{
|
||||
internal::MutexLock lock(&self->mu_);
|
||||
auto it = self->request_map_.find(request);
|
||||
if (it != self->request_map_.end()) {
|
||||
callback = it->second.callback;
|
||||
callback_arg = it->second.callback_arg;
|
||||
self->request_map_.erase(it);
|
||||
}
|
||||
}
|
||||
if (callback != nullptr) {
|
||||
callback(request, callback_arg,
|
||||
static_cast<grpc_status_code>(status.error_code()),
|
||||
status.error_message().c_str());
|
||||
}
|
||||
},
|
||||
&sync_current_verifier_status);
|
||||
if (is_done) {
|
||||
if (!sync_current_verifier_status.ok()) {
|
||||
*sync_status = static_cast<grpc_status_code>(
|
||||
sync_current_verifier_status.error_code());
|
||||
*sync_error_details =
|
||||
gpr_strdup(sync_current_verifier_status.error_message().c_str());
|
||||
}
|
||||
internal::MutexLock lock(&self->mu_);
|
||||
self->request_map_.erase(request);
|
||||
}
|
||||
return is_done;
|
||||
}
|
||||
|
||||
void ExternalCertificateVerifier::CancelInCoreExternalVerifier(
|
||||
void* user_data, grpc_tls_custom_verification_check_request* request) {
|
||||
auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
|
||||
TlsCustomVerificationCheckRequest* cpp_request = nullptr;
|
||||
{
|
||||
internal::MutexLock lock(&self->mu_);
|
||||
auto it = self->request_map_.find(request);
|
||||
if (it != self->request_map_.end()) {
|
||||
cpp_request = &it->second.cpp_request;
|
||||
}
|
||||
}
|
||||
if (cpp_request != nullptr) {
|
||||
self->Cancel(cpp_request);
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalCertificateVerifier::DestructInCoreExternalVerifier(
|
||||
void* user_data) {
|
||||
auto* self = static_cast<ExternalCertificateVerifier*>(user_data);
|
||||
delete self;
|
||||
}
|
||||
|
||||
NoOpCertificateVerifier::NoOpCertificateVerifier()
|
||||
: CertificateVerifier(grpc_tls_certificate_verifier_no_op_create()) {}
|
||||
|
||||
HostNameCertificateVerifier::HostNameCertificateVerifier()
|
||||
: CertificateVerifier(grpc_tls_certificate_verifier_host_name_create()) {}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
152
Pods/gRPC-C++/src/cpp/common/tls_credentials_options.cc
generated
Normal file
152
Pods/gRPC-C++/src/cpp/common/tls_credentials_options.cc
generated
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <grpc/grpc_crl_provider.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/grpc_security_constants.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/tls_certificate_provider.h>
|
||||
#include <grpcpp/security/tls_certificate_verifier.h>
|
||||
#include <grpcpp/security/tls_credentials_options.h>
|
||||
#include <grpcpp/security/tls_crl_provider.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
|
||||
TlsCredentialsOptions::TlsCredentialsOptions() {
|
||||
c_credentials_options_ = grpc_tls_credentials_options_create();
|
||||
}
|
||||
|
||||
TlsCredentialsOptions::~TlsCredentialsOptions() {
|
||||
grpc_tls_credentials_options_destroy(c_credentials_options_);
|
||||
}
|
||||
|
||||
TlsCredentialsOptions::TlsCredentialsOptions(
|
||||
const TlsCredentialsOptions& other) {
|
||||
c_credentials_options_ =
|
||||
grpc_tls_credentials_options_copy(other.c_credentials_options_);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_certificate_provider(
|
||||
std::shared_ptr<CertificateProviderInterface> certificate_provider) {
|
||||
certificate_provider_ = certificate_provider;
|
||||
if (certificate_provider_ != nullptr) {
|
||||
grpc_tls_credentials_options_set_certificate_provider(
|
||||
c_credentials_options_, certificate_provider_->c_provider());
|
||||
}
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_crl_provider(
|
||||
std::shared_ptr<CrlProvider> crl_provider) {
|
||||
grpc_tls_credentials_options_set_crl_provider(c_credentials_options_,
|
||||
crl_provider);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::watch_root_certs() {
|
||||
grpc_tls_credentials_options_watch_root_certs(c_credentials_options_);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_root_cert_name(
|
||||
const std::string& root_cert_name) {
|
||||
grpc_tls_credentials_options_set_root_cert_name(c_credentials_options_,
|
||||
root_cert_name.c_str());
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::watch_identity_key_cert_pairs() {
|
||||
grpc_tls_credentials_options_watch_identity_key_cert_pairs(
|
||||
c_credentials_options_);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_identity_cert_name(
|
||||
const std::string& identity_cert_name) {
|
||||
grpc_tls_credentials_options_set_identity_cert_name(
|
||||
c_credentials_options_, identity_cert_name.c_str());
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_crl_directory(const std::string& path) {
|
||||
grpc_tls_credentials_options_set_crl_directory(c_credentials_options_,
|
||||
path.c_str());
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_tls_session_key_log_file_path(
|
||||
const std::string& tls_session_key_log_file_path) {
|
||||
grpc_tls_credentials_options_set_tls_session_key_log_file_path(
|
||||
c_credentials_options_, tls_session_key_log_file_path.c_str());
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_certificate_verifier(
|
||||
std::shared_ptr<CertificateVerifier> certificate_verifier) {
|
||||
certificate_verifier_ = certificate_verifier;
|
||||
if (certificate_verifier_ != nullptr) {
|
||||
grpc_tls_credentials_options_set_certificate_verifier(
|
||||
c_credentials_options_, certificate_verifier_->c_verifier());
|
||||
}
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_min_tls_version(grpc_tls_version tls_version) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_min_tls_version(options, tls_version);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_max_tls_version(grpc_tls_version tls_version) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_max_tls_version(options, tls_version);
|
||||
}
|
||||
|
||||
grpc_tls_credentials_options* TlsCredentialsOptions::c_credentials_options()
|
||||
const {
|
||||
return grpc_tls_credentials_options_copy(c_credentials_options_);
|
||||
}
|
||||
|
||||
void TlsCredentialsOptions::set_check_call_host(bool check_call_host) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_check_call_host(options, check_call_host);
|
||||
}
|
||||
|
||||
void TlsChannelCredentialsOptions::set_verify_server_certs(
|
||||
bool verify_server_certs) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_verify_server_cert(options,
|
||||
verify_server_certs);
|
||||
}
|
||||
|
||||
void TlsServerCredentialsOptions::set_cert_request_type(
|
||||
grpc_ssl_client_certificate_request_type cert_request_type) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_cert_request_type(options,
|
||||
cert_request_type);
|
||||
}
|
||||
|
||||
void TlsServerCredentialsOptions::set_send_client_ca_list(
|
||||
bool send_client_ca_list) {
|
||||
grpc_tls_credentials_options* options = mutable_c_credentials_options();
|
||||
GPR_ASSERT(options != nullptr);
|
||||
grpc_tls_credentials_options_set_send_client_ca_list(options,
|
||||
send_client_ca_list);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
44
Pods/gRPC-C++/src/cpp/common/validate_service_config.cc
generated
Normal file
44
Pods/gRPC-C++/src/cpp/common/validate_service_config.cc
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpcpp/support/validate_service_config.h>
|
||||
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/service_config/service_config.h"
|
||||
#include "src/core/service_config/service_config_impl.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
std::string ValidateServiceConfigJSON(const std::string& service_config_json) {
|
||||
grpc_init();
|
||||
auto service_config = grpc_core::ServiceConfigImpl::Create(
|
||||
grpc_core::ChannelArgs(), service_config_json.c_str());
|
||||
std::string return_value;
|
||||
if (!service_config.ok()) return_value = service_config.status().ToString();
|
||||
grpc_shutdown();
|
||||
return return_value;
|
||||
}
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
25
Pods/gRPC-C++/src/cpp/common/version_cc.cc
generated
Normal file
25
Pods/gRPC-C++/src/cpp/common/version_cc.cc
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
|
||||
namespace grpc {
|
||||
std::string Version() { return GRPC_CPP_VERSION_STRING; }
|
||||
} // namespace grpc
|
||||
33
Pods/gRPC-C++/src/cpp/server/async_generic_service.cc
generated
Normal file
33
Pods/gRPC-C++/src/cpp/server/async_generic_service.cc
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/generic/async_generic_service.h>
|
||||
#include <grpcpp/server.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
void AsyncGenericService::RequestCall(
|
||||
GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer,
|
||||
grpc::CompletionQueue* call_cq,
|
||||
grpc::ServerCompletionQueue* notification_cq, void* tag) {
|
||||
server_->RequestAsyncGenericCall(ctx, reader_writer, call_cq, notification_cq,
|
||||
tag);
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
421
Pods/gRPC-C++/src/cpp/server/backend_metric_recorder.cc
generated
Normal file
421
Pods/gRPC-C++/src/cpp/server/backend_metric_recorder.cc
generated
Normal file
@@ -0,0 +1,421 @@
|
||||
//
|
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "src/cpp/server/backend_metric_recorder.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/ext/call_metric_recorder.h>
|
||||
#include <grpcpp/ext/server_metric_recorder.h>
|
||||
|
||||
#include "src/core/lib/debug/trace.h"
|
||||
#include "src/core/load_balancing/backend_metric_data.h"
|
||||
|
||||
using grpc_core::BackendMetricData;
|
||||
|
||||
namespace {
|
||||
// Utilization values with soft limits must be in [0, infy).
|
||||
bool IsUtilizationWithSoftLimitsValid(double util) { return util >= 0.0; }
|
||||
|
||||
// Other utilization values must be in [0, 1].
|
||||
bool IsUtilizationValid(double utilization) {
|
||||
return utilization >= 0.0 && utilization <= 1.0;
|
||||
}
|
||||
|
||||
// Rate values (qps and eps) must be in [0, infy).
|
||||
bool IsRateValid(double rate) { return rate >= 0.0; }
|
||||
|
||||
grpc_core::TraceFlag grpc_backend_metric_trace(false, "backend_metric");
|
||||
} // namespace
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
|
||||
std::unique_ptr<ServerMetricRecorder> ServerMetricRecorder::Create() {
|
||||
return std::unique_ptr<ServerMetricRecorder>(new ServerMetricRecorder());
|
||||
}
|
||||
|
||||
ServerMetricRecorder::ServerMetricRecorder()
|
||||
: metric_state_(std::make_shared<const BackendMetricDataState>()) {}
|
||||
|
||||
void ServerMetricRecorder::UpdateBackendMetricDataState(
|
||||
std::function<void(BackendMetricData*)> updater) {
|
||||
internal::MutexLock lock(&mu_);
|
||||
auto new_state = std::make_shared<BackendMetricDataState>(*metric_state_);
|
||||
updater(&new_state->data);
|
||||
++new_state->sequence_number;
|
||||
metric_state_ = std::move(new_state);
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetCpuUtilization(double value) {
|
||||
if (!IsUtilizationWithSoftLimitsValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] CPU utilization rejected: %f", this, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
UpdateBackendMetricDataState(
|
||||
[value](BackendMetricData* data) { data->cpu_utilization = value; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] CPU utilization set: %f", this, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetMemoryUtilization(double value) {
|
||||
if (!IsUtilizationValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Mem utilization rejected: %f", this, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
UpdateBackendMetricDataState(
|
||||
[value](BackendMetricData* data) { data->mem_utilization = value; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Mem utilization set: %f", this, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetApplicationUtilization(double value) {
|
||||
if (!IsUtilizationWithSoftLimitsValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Application utilization rejected: %f", this,
|
||||
value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
UpdateBackendMetricDataState([value](BackendMetricData* data) {
|
||||
data->application_utilization = value;
|
||||
});
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Application utilization set: %f", this, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetQps(double value) {
|
||||
if (!IsRateValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] QPS rejected: %f", this, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
UpdateBackendMetricDataState(
|
||||
[value](BackendMetricData* data) { data->qps = value; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] QPS set: %f", this, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetEps(double value) {
|
||||
if (!IsRateValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] EPS rejected: %f", this, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
UpdateBackendMetricDataState(
|
||||
[value](BackendMetricData* data) { data->eps = value; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] EPS set: %f", this, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetNamedUtilization(string_ref name, double value) {
|
||||
if (!IsUtilizationValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Named utilization rejected: %f name: %s", this,
|
||||
value, std::string(name.data(), name.size()).c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Named utilization set: %f name: %s", this, value,
|
||||
std::string(name.data(), name.size()).c_str());
|
||||
}
|
||||
UpdateBackendMetricDataState([name, value](BackendMetricData* data) {
|
||||
data->utilization[absl::string_view(name.data(), name.size())] = value;
|
||||
});
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::SetAllNamedUtilization(
|
||||
std::map<string_ref, double> named_utilization) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] All named utilization updated. size: %" PRIuPTR,
|
||||
this, named_utilization.size());
|
||||
}
|
||||
UpdateBackendMetricDataState(
|
||||
[utilization = std::move(named_utilization)](BackendMetricData* data) {
|
||||
data->utilization.clear();
|
||||
for (const auto& u : utilization) {
|
||||
data->utilization[absl::string_view(u.first.data(), u.first.size())] =
|
||||
u.second;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearCpuUtilization() {
|
||||
UpdateBackendMetricDataState(
|
||||
[](BackendMetricData* data) { data->cpu_utilization = -1; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] CPU utilization cleared.", this);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearMemoryUtilization() {
|
||||
UpdateBackendMetricDataState(
|
||||
[](BackendMetricData* data) { data->mem_utilization = -1; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Mem utilization cleared.", this);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearApplicationUtilization() {
|
||||
UpdateBackendMetricDataState(
|
||||
[](BackendMetricData* data) { data->application_utilization = -1; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Application utilization cleared.", this);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearQps() {
|
||||
UpdateBackendMetricDataState([](BackendMetricData* data) { data->qps = -1; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] QPS utilization cleared.", this);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearEps() {
|
||||
UpdateBackendMetricDataState([](BackendMetricData* data) { data->eps = -1; });
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] EPS utilization cleared.", this);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerMetricRecorder::ClearNamedUtilization(string_ref name) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Named utilization cleared. name: %s", this,
|
||||
std::string(name.data(), name.size()).c_str());
|
||||
}
|
||||
UpdateBackendMetricDataState([name](BackendMetricData* data) {
|
||||
data->utilization.erase(absl::string_view(name.data(), name.size()));
|
||||
});
|
||||
}
|
||||
|
||||
grpc_core::BackendMetricData ServerMetricRecorder::GetMetrics() const {
|
||||
auto result = GetMetricsIfChanged();
|
||||
return result->data;
|
||||
}
|
||||
|
||||
std::shared_ptr<const ServerMetricRecorder::BackendMetricDataState>
|
||||
ServerMetricRecorder::GetMetricsIfChanged() const {
|
||||
std::shared_ptr<const BackendMetricDataState> result;
|
||||
{
|
||||
internal::MutexLock lock(&mu_);
|
||||
result = metric_state_;
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
const auto& data = result->data;
|
||||
gpr_log(GPR_INFO,
|
||||
"[%p] GetMetrics() returned: seq:%" PRIu64
|
||||
" cpu:%f mem:%f app:%f qps:%f eps:%f utilization size: %" PRIuPTR,
|
||||
this, result->sequence_number, data.cpu_utilization,
|
||||
data.mem_utilization, data.application_utilization, data.qps,
|
||||
data.eps, data.utilization.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
experimental::CallMetricRecorder&
|
||||
BackendMetricState::RecordCpuUtilizationMetric(double value) {
|
||||
if (!IsUtilizationWithSoftLimitsValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] CPU utilization value rejected: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
cpu_utilization_.store(value, std::memory_order_relaxed);
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] CPU utilization recorded: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder&
|
||||
BackendMetricState::RecordMemoryUtilizationMetric(double value) {
|
||||
if (!IsUtilizationValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Mem utilization value rejected: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
mem_utilization_.store(value, std::memory_order_relaxed);
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Mem utilization recorded: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder&
|
||||
BackendMetricState::RecordApplicationUtilizationMetric(double value) {
|
||||
if (!IsUtilizationWithSoftLimitsValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Application utilization value rejected: %f", this,
|
||||
value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
application_utilization_.store(value, std::memory_order_relaxed);
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Application utilization recorded: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder& BackendMetricState::RecordQpsMetric(
|
||||
double value) {
|
||||
if (!IsRateValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] QPS value rejected: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
qps_.store(value, std::memory_order_relaxed);
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] QPS recorded: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder& BackendMetricState::RecordEpsMetric(
|
||||
double value) {
|
||||
if (!IsRateValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] EPS value rejected: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
eps_.store(value, std::memory_order_relaxed);
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] EPS recorded: %f", this, value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder& BackendMetricState::RecordUtilizationMetric(
|
||||
string_ref name, double value) {
|
||||
if (!IsUtilizationValid(value)) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Utilization value rejected: %s %f", this,
|
||||
std::string(name.data(), name.length()).c_str(), value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
internal::MutexLock lock(&mu_);
|
||||
absl::string_view name_sv(name.data(), name.length());
|
||||
utilization_[name_sv] = value;
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Utilization recorded: %s %f", this,
|
||||
std::string(name_sv).c_str(), value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder& BackendMetricState::RecordRequestCostMetric(
|
||||
string_ref name, double value) {
|
||||
internal::MutexLock lock(&mu_);
|
||||
absl::string_view name_sv(name.data(), name.length());
|
||||
request_cost_[name_sv] = value;
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Request cost recorded: %s %f", this,
|
||||
std::string(name_sv).c_str(), value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
experimental::CallMetricRecorder& BackendMetricState::RecordNamedMetric(
|
||||
string_ref name, double value) {
|
||||
internal::MutexLock lock(&mu_);
|
||||
absl::string_view name_sv(name.data(), name.length());
|
||||
named_metrics_[name_sv] = value;
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO, "[%p] Named metric recorded: %s %f", this,
|
||||
std::string(name_sv).c_str(), value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BackendMetricData BackendMetricState::GetBackendMetricData() {
|
||||
// Merge metrics from the ServerMetricRecorder first since metrics recorded
|
||||
// to CallMetricRecorder takes a higher precedence.
|
||||
BackendMetricData data;
|
||||
if (server_metric_recorder_ != nullptr) {
|
||||
data = server_metric_recorder_->GetMetrics();
|
||||
}
|
||||
// Only overwrite if the value is set i.e. in the valid range.
|
||||
const double cpu = cpu_utilization_.load(std::memory_order_relaxed);
|
||||
if (IsUtilizationWithSoftLimitsValid(cpu)) {
|
||||
data.cpu_utilization = cpu;
|
||||
}
|
||||
const double mem = mem_utilization_.load(std::memory_order_relaxed);
|
||||
if (IsUtilizationValid(mem)) {
|
||||
data.mem_utilization = mem;
|
||||
}
|
||||
const double app_util =
|
||||
application_utilization_.load(std::memory_order_relaxed);
|
||||
if (IsUtilizationWithSoftLimitsValid(app_util)) {
|
||||
data.application_utilization = app_util;
|
||||
}
|
||||
const double qps = qps_.load(std::memory_order_relaxed);
|
||||
if (IsRateValid(qps)) {
|
||||
data.qps = qps;
|
||||
}
|
||||
const double eps = eps_.load(std::memory_order_relaxed);
|
||||
if (IsRateValid(eps)) {
|
||||
data.eps = eps;
|
||||
}
|
||||
{
|
||||
internal::MutexLock lock(&mu_);
|
||||
for (const auto& u : utilization_) {
|
||||
data.utilization[u.first] = u.second;
|
||||
}
|
||||
for (const auto& r : request_cost_) {
|
||||
data.request_cost[r.first] = r.second;
|
||||
}
|
||||
for (const auto& r : named_metrics_) {
|
||||
data.named_metrics[r.first] = r.second;
|
||||
}
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
|
||||
gpr_log(GPR_INFO,
|
||||
"[%p] Backend metric data returned: cpu:%f mem:%f qps:%f eps:%f "
|
||||
"utilization size:%" PRIuPTR " request_cost size:%" PRIuPTR
|
||||
"named_metrics size:%" PRIuPTR,
|
||||
this, data.cpu_utilization, data.mem_utilization, data.qps,
|
||||
data.eps, data.utilization.size(), data.request_cost.size(),
|
||||
data.named_metrics.size());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
89
Pods/gRPC-C++/src/cpp/server/backend_metric_recorder.h
generated
Normal file
89
Pods/gRPC-C++/src/cpp/server/backend_metric_recorder.h
generated
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_BACKEND_METRIC_RECORDER_H
|
||||
#define GRPC_SRC_CPP_SERVER_BACKEND_METRIC_RECORDER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#include <grpcpp/ext/call_metric_recorder.h>
|
||||
#include <grpcpp/ext/server_metric_recorder.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
#include "src/core/ext/filters/backend_metrics/backend_metric_provider.h"
|
||||
#include "src/core/load_balancing/backend_metric_data.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace experimental {
|
||||
|
||||
// Backend metrics and an associated update sequence number.
|
||||
struct ServerMetricRecorder::BackendMetricDataState {
|
||||
grpc_core::BackendMetricData data;
|
||||
uint64_t sequence_number = 0;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
class BackendMetricState : public grpc_core::BackendMetricProvider,
|
||||
public experimental::CallMetricRecorder {
|
||||
public:
|
||||
// `server_metric_recorder` is optional. When set, GetBackendMetricData()
|
||||
// merges metrics from `server_metric_recorder` with metrics recorded to this.
|
||||
explicit BackendMetricState(
|
||||
experimental::ServerMetricRecorder* server_metric_recorder)
|
||||
: server_metric_recorder_(server_metric_recorder) {}
|
||||
experimental::CallMetricRecorder& RecordCpuUtilizationMetric(
|
||||
double value) override;
|
||||
experimental::CallMetricRecorder& RecordMemoryUtilizationMetric(
|
||||
double value) override;
|
||||
experimental::CallMetricRecorder& RecordApplicationUtilizationMetric(
|
||||
double value) override;
|
||||
experimental::CallMetricRecorder& RecordQpsMetric(double value) override;
|
||||
experimental::CallMetricRecorder& RecordEpsMetric(double value) override;
|
||||
experimental::CallMetricRecorder& RecordUtilizationMetric(
|
||||
string_ref name, double value) override;
|
||||
experimental::CallMetricRecorder& RecordRequestCostMetric(
|
||||
string_ref name, double value) override;
|
||||
experimental::CallMetricRecorder& RecordNamedMetric(string_ref name,
|
||||
double value) override;
|
||||
// This clears metrics currently recorded. Don't call twice.
|
||||
grpc_core::BackendMetricData GetBackendMetricData() override;
|
||||
|
||||
private:
|
||||
experimental::ServerMetricRecorder* server_metric_recorder_;
|
||||
std::atomic<double> cpu_utilization_{-1.0};
|
||||
std::atomic<double> mem_utilization_{-1.0};
|
||||
std::atomic<double> application_utilization_{-1.0};
|
||||
std::atomic<double> qps_{-1.0};
|
||||
std::atomic<double> eps_{-1.0};
|
||||
internal::Mutex mu_;
|
||||
std::map<absl::string_view, double> utilization_ ABSL_GUARDED_BY(mu_);
|
||||
std::map<absl::string_view, double> request_cost_ ABSL_GUARDED_BY(mu_);
|
||||
std::map<absl::string_view, double> named_metrics_ ABSL_GUARDED_BY(mu_);
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_BACKEND_METRIC_RECORDER_H
|
||||
93
Pods/gRPC-C++/src/cpp/server/channel_argument_option.cc
generated
Normal file
93
Pods/gRPC-C++/src/cpp/server/channel_argument_option.cc
generated
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2017 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <grpcpp/impl/channel_argument_option.h>
|
||||
#include <grpcpp/impl/server_builder_option.h>
|
||||
#include <grpcpp/impl/server_builder_plugin.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
|
||||
const std::string& name, const std::string& value) {
|
||||
class StringOption final : public ServerBuilderOption {
|
||||
public:
|
||||
StringOption(const std::string& name, const std::string& value)
|
||||
: name_(name), value_(value) {}
|
||||
|
||||
void UpdateArguments(ChannelArguments* args) override {
|
||||
args->SetString(name_, value_);
|
||||
}
|
||||
void UpdatePlugins(
|
||||
std::vector<std::unique_ptr<ServerBuilderPlugin>>* /*plugins*/)
|
||||
override {}
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
const std::string value_;
|
||||
};
|
||||
return std::unique_ptr<ServerBuilderOption>(new StringOption(name, value));
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
|
||||
const std::string& name, int value) {
|
||||
class IntOption final : public ServerBuilderOption {
|
||||
public:
|
||||
IntOption(const std::string& name, int value)
|
||||
: name_(name), value_(value) {}
|
||||
|
||||
void UpdateArguments(ChannelArguments* args) override {
|
||||
args->SetInt(name_, value_);
|
||||
}
|
||||
void UpdatePlugins(
|
||||
std::vector<std::unique_ptr<ServerBuilderPlugin>>* /*plugins*/)
|
||||
override {}
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
const int value_;
|
||||
};
|
||||
return std::unique_ptr<ServerBuilderOption>(new IntOption(name, value));
|
||||
}
|
||||
|
||||
std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
|
||||
const std::string& name, void* value) {
|
||||
class PointerOption final : public ServerBuilderOption {
|
||||
public:
|
||||
PointerOption(const std::string& name, void* value)
|
||||
: name_(name), value_(value) {}
|
||||
|
||||
void UpdateArguments(ChannelArguments* args) override {
|
||||
args->SetPointer(name_, value_);
|
||||
}
|
||||
void UpdatePlugins(
|
||||
std::vector<std::unique_ptr<ServerBuilderPlugin>>* /*plugins*/)
|
||||
override {}
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
void* value_;
|
||||
};
|
||||
return std::unique_ptr<ServerBuilderOption>(new PointerOption(name, value));
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
41
Pods/gRPC-C++/src/cpp/server/create_default_thread_pool.cc
generated
Normal file
41
Pods/gRPC-C++/src/cpp/server/create_default_thread_pool.cc
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/server/dynamic_thread_pool.h"
|
||||
#include "src/cpp/server/thread_pool_interface.h"
|
||||
|
||||
#ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL
|
||||
|
||||
namespace grpc {
|
||||
namespace {
|
||||
|
||||
ThreadPoolInterface* CreateDefaultThreadPoolImpl() {
|
||||
return new DynamicThreadPool();
|
||||
}
|
||||
|
||||
CreateThreadPoolFunc g_ctp_impl = CreateDefaultThreadPoolImpl;
|
||||
|
||||
} // namespace
|
||||
|
||||
ThreadPoolInterface* CreateDefaultThreadPool() { return g_ctp_impl(); }
|
||||
|
||||
void SetCreateThreadPool(CreateThreadPoolFunc func) { g_ctp_impl = func; }
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // !GRPC_CUSTOM_DEFAULT_THREAD_POOL
|
||||
45
Pods/gRPC-C++/src/cpp/server/dynamic_thread_pool.h
generated
Normal file
45
Pods/gRPC-C++/src/cpp/server/dynamic_thread_pool.h
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_DYNAMIC_THREAD_POOL_H
|
||||
#define GRPC_SRC_CPP_SERVER_DYNAMIC_THREAD_POOL_H
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <grpc/event_engine/event_engine.h>
|
||||
|
||||
#include "src/core/lib/event_engine/default_event_engine.h"
|
||||
#include "src/cpp/server/thread_pool_interface.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class DynamicThreadPool final : public ThreadPoolInterface {
|
||||
public:
|
||||
void Add(const std::function<void()>& callback) override {
|
||||
event_engine_->Run(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine_ =
|
||||
grpc_event_engine::experimental::GetDefaultEventEngine();
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_DYNAMIC_THREAD_POOL_H
|
||||
99
Pods/gRPC-C++/src/cpp/server/external_connection_acceptor_impl.cc
generated
Normal file
99
Pods/gRPC-C++/src/cpp/server/external_connection_acceptor_impl.cc
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/server/external_connection_acceptor_impl.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/server_builder.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
namespace {
|
||||
// The actual type to return to user. It co-owns the internal impl object with
|
||||
// the server.
|
||||
class AcceptorWrapper : public experimental::ExternalConnectionAcceptor {
|
||||
public:
|
||||
explicit AcceptorWrapper(std::shared_ptr<ExternalConnectionAcceptorImpl> impl)
|
||||
: impl_(std::move(impl)) {}
|
||||
void HandleNewConnection(NewConnectionParameters* p) override {
|
||||
impl_->HandleNewConnection(p);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ExternalConnectionAcceptorImpl> impl_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
ExternalConnectionAcceptorImpl::ExternalConnectionAcceptorImpl(
|
||||
const std::string& name,
|
||||
ServerBuilder::experimental_type::ExternalConnectionType type,
|
||||
std::shared_ptr<ServerCredentials> creds)
|
||||
: name_(name), creds_(std::move(creds)) {
|
||||
GPR_ASSERT(type ==
|
||||
ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD);
|
||||
}
|
||||
|
||||
std::unique_ptr<experimental::ExternalConnectionAcceptor>
|
||||
ExternalConnectionAcceptorImpl::GetAcceptor() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
GPR_ASSERT(!has_acceptor_);
|
||||
has_acceptor_ = true;
|
||||
return std::unique_ptr<experimental::ExternalConnectionAcceptor>(
|
||||
new AcceptorWrapper(shared_from_this()));
|
||||
}
|
||||
|
||||
void ExternalConnectionAcceptorImpl::HandleNewConnection(
|
||||
experimental::ExternalConnectionAcceptor::NewConnectionParameters* p) {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
if (shutdown_ || !started_) {
|
||||
// TODO(yangg) clean up.
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"NOT handling external connection with fd %d, started %d, shutdown %d",
|
||||
p->fd, started_, shutdown_);
|
||||
return;
|
||||
}
|
||||
if (handler_) {
|
||||
handler_->Handle(p->listener_fd, p->fd, p->read_buffer.c_buffer());
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalConnectionAcceptorImpl::Shutdown() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
shutdown_ = true;
|
||||
}
|
||||
|
||||
void ExternalConnectionAcceptorImpl::Start() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
GPR_ASSERT(!started_);
|
||||
GPR_ASSERT(has_acceptor_);
|
||||
GPR_ASSERT(!shutdown_);
|
||||
started_ = true;
|
||||
}
|
||||
|
||||
void ExternalConnectionAcceptorImpl::SetToChannelArgs(ChannelArguments* args) {
|
||||
args->SetPointer(name_, &handler_);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
71
Pods/gRPC-C++/src/cpp/server/external_connection_acceptor_impl.h
generated
Normal file
71
Pods/gRPC-C++/src/cpp/server/external_connection_acceptor_impl.h
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H
|
||||
#define GRPC_SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
#include <grpcpp/server_builder.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/iomgr/tcp_server.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
class ExternalConnectionAcceptorImpl
|
||||
: public std::enable_shared_from_this<ExternalConnectionAcceptorImpl> {
|
||||
public:
|
||||
ExternalConnectionAcceptorImpl(
|
||||
const std::string& name,
|
||||
ServerBuilder::experimental_type::ExternalConnectionType type,
|
||||
std::shared_ptr<ServerCredentials> creds);
|
||||
// Should only be called once.
|
||||
std::unique_ptr<experimental::ExternalConnectionAcceptor> GetAcceptor();
|
||||
|
||||
void HandleNewConnection(
|
||||
experimental::ExternalConnectionAcceptor::NewConnectionParameters* p);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void Start();
|
||||
|
||||
const char* name() { return name_.c_str(); }
|
||||
|
||||
ServerCredentials* GetCredentials() { return creds_.get(); }
|
||||
|
||||
void SetToChannelArgs(grpc::ChannelArguments* args);
|
||||
|
||||
private:
|
||||
const std::string name_;
|
||||
std::shared_ptr<ServerCredentials> creds_;
|
||||
grpc_core::TcpServerFdHandler* handler_ = nullptr; // not owned
|
||||
grpc_core::Mutex mu_;
|
||||
bool has_acceptor_ = false;
|
||||
bool started_ = false;
|
||||
bool shutdown_ = false;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H
|
||||
370
Pods/gRPC-C++/src/cpp/server/health/default_health_check_service.cc
generated
Normal file
370
Pods/gRPC-C++/src/cpp/server/health/default_health_check_service.cc
generated
Normal file
@@ -0,0 +1,370 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/server/health/default_health_check_service.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "upb/base/string_view.h"
|
||||
#include "upb/mem/arena.hpp"
|
||||
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
#include <grpcpp/impl/rpc_service_method.h>
|
||||
#include <grpcpp/impl/server_callback_handlers.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
|
||||
#include "src/proto/grpc/health/v1/health.upb.h"
|
||||
|
||||
#define MAX_SERVICE_NAME_LENGTH 200
|
||||
|
||||
namespace grpc {
|
||||
|
||||
//
|
||||
// DefaultHealthCheckService
|
||||
//
|
||||
|
||||
DefaultHealthCheckService::DefaultHealthCheckService() {
|
||||
services_map_[""].SetServingStatus(SERVING);
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::SetServingStatus(
|
||||
const std::string& service_name, bool serving) {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
if (shutdown_) {
|
||||
// Set to NOT_SERVING in case service_name is not in the map.
|
||||
serving = false;
|
||||
}
|
||||
services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING);
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::SetServingStatus(bool serving) {
|
||||
const ServingStatus status = serving ? SERVING : NOT_SERVING;
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
if (shutdown_) return;
|
||||
for (auto& p : services_map_) {
|
||||
ServiceData& service_data = p.second;
|
||||
service_data.SetServingStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::Shutdown() {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
if (shutdown_) return;
|
||||
shutdown_ = true;
|
||||
for (auto& p : services_map_) {
|
||||
ServiceData& service_data = p.second;
|
||||
service_data.SetServingStatus(NOT_SERVING);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultHealthCheckService::ServingStatus
|
||||
DefaultHealthCheckService::GetServingStatus(
|
||||
const std::string& service_name) const {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
auto it = services_map_.find(service_name);
|
||||
if (it == services_map_.end()) return NOT_FOUND;
|
||||
const ServiceData& service_data = it->second;
|
||||
return service_data.GetServingStatus();
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::RegisterWatch(
|
||||
const std::string& service_name,
|
||||
grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher) {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
ServiceData& service_data = services_map_[service_name];
|
||||
watcher->SendHealth(service_data.GetServingStatus());
|
||||
service_data.AddWatch(std::move(watcher));
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::UnregisterWatch(
|
||||
const std::string& service_name,
|
||||
HealthCheckServiceImpl::WatchReactor* watcher) {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
auto it = services_map_.find(service_name);
|
||||
if (it == services_map_.end()) return;
|
||||
ServiceData& service_data = it->second;
|
||||
service_data.RemoveWatch(watcher);
|
||||
if (service_data.Unused()) services_map_.erase(it);
|
||||
}
|
||||
|
||||
DefaultHealthCheckService::HealthCheckServiceImpl*
|
||||
DefaultHealthCheckService::GetHealthCheckService() {
|
||||
GPR_ASSERT(impl_ == nullptr);
|
||||
impl_ = std::make_unique<HealthCheckServiceImpl>(this);
|
||||
return impl_.get();
|
||||
}
|
||||
|
||||
//
|
||||
// DefaultHealthCheckService::ServiceData
|
||||
//
|
||||
|
||||
void DefaultHealthCheckService::ServiceData::SetServingStatus(
|
||||
ServingStatus status) {
|
||||
status_ = status;
|
||||
for (const auto& p : watchers_) {
|
||||
p.first->SendHealth(status);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::ServiceData::AddWatch(
|
||||
grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher) {
|
||||
watchers_[watcher.get()] = std::move(watcher);
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::ServiceData::RemoveWatch(
|
||||
HealthCheckServiceImpl::WatchReactor* watcher) {
|
||||
watchers_.erase(watcher);
|
||||
}
|
||||
|
||||
//
|
||||
// DefaultHealthCheckService::HealthCheckServiceImpl
|
||||
//
|
||||
|
||||
namespace {
|
||||
const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check";
|
||||
const char kHealthWatchMethodName[] = "/grpc.health.v1.Health/Watch";
|
||||
} // namespace
|
||||
|
||||
DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl(
|
||||
DefaultHealthCheckService* database)
|
||||
: database_(database) {
|
||||
// Add Check() method.
|
||||
AddMethod(new internal::RpcServiceMethod(
|
||||
kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, nullptr));
|
||||
MarkMethodCallback(
|
||||
0, new internal::CallbackUnaryHandler<ByteBuffer, ByteBuffer>(
|
||||
[database](CallbackServerContext* context,
|
||||
const ByteBuffer* request, ByteBuffer* response) {
|
||||
return HandleCheckRequest(database, context, request, response);
|
||||
}));
|
||||
// Add Watch() method.
|
||||
AddMethod(new internal::RpcServiceMethod(
|
||||
kHealthWatchMethodName, internal::RpcMethod::SERVER_STREAMING, nullptr));
|
||||
MarkMethodCallback(
|
||||
1, new internal::CallbackServerStreamingHandler<ByteBuffer, ByteBuffer>(
|
||||
[this](CallbackServerContext* /*ctx*/, const ByteBuffer* request) {
|
||||
return new WatchReactor(this, request);
|
||||
}));
|
||||
}
|
||||
|
||||
DefaultHealthCheckService::HealthCheckServiceImpl::~HealthCheckServiceImpl() {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
shutdown_ = true;
|
||||
while (num_watches_ > 0) {
|
||||
shutdown_condition_.Wait(&mu_);
|
||||
}
|
||||
}
|
||||
|
||||
ServerUnaryReactor*
|
||||
DefaultHealthCheckService::HealthCheckServiceImpl::HandleCheckRequest(
|
||||
DefaultHealthCheckService* database, CallbackServerContext* context,
|
||||
const ByteBuffer* request, ByteBuffer* response) {
|
||||
auto* reactor = context->DefaultReactor();
|
||||
std::string service_name;
|
||||
if (!DecodeRequest(*request, &service_name)) {
|
||||
reactor->Finish(
|
||||
Status(StatusCode::INVALID_ARGUMENT, "could not parse request"));
|
||||
return reactor;
|
||||
}
|
||||
ServingStatus serving_status = database->GetServingStatus(service_name);
|
||||
if (serving_status == NOT_FOUND) {
|
||||
reactor->Finish(Status(StatusCode::NOT_FOUND, "service name unknown"));
|
||||
return reactor;
|
||||
}
|
||||
if (!EncodeResponse(serving_status, response)) {
|
||||
reactor->Finish(Status(StatusCode::INTERNAL, "could not encode response"));
|
||||
return reactor;
|
||||
}
|
||||
reactor->Finish(Status::OK);
|
||||
return reactor;
|
||||
}
|
||||
|
||||
bool DefaultHealthCheckService::HealthCheckServiceImpl::DecodeRequest(
|
||||
const ByteBuffer& request, std::string* service_name) {
|
||||
Slice slice;
|
||||
if (!request.DumpToSingleSlice(&slice).ok()) return false;
|
||||
uint8_t* request_bytes = nullptr;
|
||||
size_t request_size = 0;
|
||||
request_bytes = const_cast<uint8_t*>(slice.begin());
|
||||
request_size = slice.size();
|
||||
upb::Arena arena;
|
||||
grpc_health_v1_HealthCheckRequest* request_struct =
|
||||
grpc_health_v1_HealthCheckRequest_parse(
|
||||
reinterpret_cast<char*>(request_bytes), request_size, arena.ptr());
|
||||
if (request_struct == nullptr) {
|
||||
return false;
|
||||
}
|
||||
upb_StringView service =
|
||||
grpc_health_v1_HealthCheckRequest_service(request_struct);
|
||||
if (service.size > MAX_SERVICE_NAME_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
service_name->assign(service.data, service.size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DefaultHealthCheckService::HealthCheckServiceImpl::EncodeResponse(
|
||||
ServingStatus status, ByteBuffer* response) {
|
||||
upb::Arena arena;
|
||||
grpc_health_v1_HealthCheckResponse* response_struct =
|
||||
grpc_health_v1_HealthCheckResponse_new(arena.ptr());
|
||||
grpc_health_v1_HealthCheckResponse_set_status(
|
||||
response_struct,
|
||||
status == NOT_FOUND ? grpc_health_v1_HealthCheckResponse_SERVICE_UNKNOWN
|
||||
: status == SERVING ? grpc_health_v1_HealthCheckResponse_SERVING
|
||||
: grpc_health_v1_HealthCheckResponse_NOT_SERVING);
|
||||
size_t buf_length;
|
||||
char* buf = grpc_health_v1_HealthCheckResponse_serialize(
|
||||
response_struct, arena.ptr(), &buf_length);
|
||||
if (buf == nullptr) {
|
||||
return false;
|
||||
}
|
||||
grpc_slice response_slice = grpc_slice_from_copied_buffer(buf, buf_length);
|
||||
Slice encoded_response(response_slice, Slice::STEAL_REF);
|
||||
ByteBuffer response_buffer(&encoded_response, 1);
|
||||
response->Swap(&response_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor
|
||||
//
|
||||
|
||||
DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::WatchReactor(
|
||||
HealthCheckServiceImpl* service, const ByteBuffer* request)
|
||||
: service_(service) {
|
||||
{
|
||||
grpc::internal::MutexLock lock(&service_->mu_);
|
||||
++service_->num_watches_;
|
||||
}
|
||||
bool success = DecodeRequest(*request, &service_name_);
|
||||
gpr_log(GPR_DEBUG, "[HCS %p] watcher %p \"%s\": watch call started", service_,
|
||||
this, service_name_.c_str());
|
||||
if (!success) {
|
||||
MaybeFinishLocked(Status(StatusCode::INTERNAL, "could not parse request"));
|
||||
return;
|
||||
}
|
||||
// Register the call for updates to the service.
|
||||
service_->database_->RegisterWatch(service_name_, Ref());
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::
|
||||
SendHealth(ServingStatus status) {
|
||||
gpr_log(GPR_DEBUG,
|
||||
"[HCS %p] watcher %p \"%s\": SendHealth() for ServingStatus %d",
|
||||
service_, this, service_name_.c_str(), status);
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
// If there's already a send in flight, cache the new status, and
|
||||
// we'll start a new send for it when the one in flight completes.
|
||||
if (write_pending_) {
|
||||
gpr_log(GPR_DEBUG, "[HCS %p] watcher %p \"%s\": queuing write", service_,
|
||||
this, service_name_.c_str());
|
||||
pending_status_ = status;
|
||||
return;
|
||||
}
|
||||
// Start a send.
|
||||
SendHealthLocked(status);
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::
|
||||
SendHealthLocked(ServingStatus status) {
|
||||
// Do nothing if Finish() has already been called.
|
||||
if (finish_called_) return;
|
||||
// Check if we're shutting down.
|
||||
{
|
||||
grpc::internal::MutexLock lock(&service_->mu_);
|
||||
if (service_->shutdown_) {
|
||||
MaybeFinishLocked(
|
||||
Status(StatusCode::CANCELLED, "not writing due to shutdown"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Send response.
|
||||
bool success = EncodeResponse(status, &response_);
|
||||
if (!success) {
|
||||
MaybeFinishLocked(
|
||||
Status(StatusCode::INTERNAL, "could not encode response"));
|
||||
return;
|
||||
}
|
||||
gpr_log(GPR_DEBUG,
|
||||
"[HCS %p] watcher %p \"%s\": starting write for ServingStatus %d",
|
||||
service_, this, service_name_.c_str(), status);
|
||||
write_pending_ = true;
|
||||
StartWrite(&response_);
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::
|
||||
OnWriteDone(bool ok) {
|
||||
gpr_log(GPR_DEBUG, "[HCS %p] watcher %p \"%s\": OnWriteDone(): ok=%d",
|
||||
service_, this, service_name_.c_str(), ok);
|
||||
response_.Clear();
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
if (!ok) {
|
||||
MaybeFinishLocked(Status(StatusCode::CANCELLED, "OnWriteDone() ok=false"));
|
||||
return;
|
||||
}
|
||||
write_pending_ = false;
|
||||
// If we got a new status since we started the last send, start a
|
||||
// new send for it.
|
||||
if (pending_status_ != NOT_FOUND) {
|
||||
auto status = pending_status_;
|
||||
pending_status_ = NOT_FOUND;
|
||||
SendHealthLocked(status);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::
|
||||
OnCancel() {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
MaybeFinishLocked(Status(StatusCode::UNKNOWN, "OnCancel()"));
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::OnDone() {
|
||||
gpr_log(GPR_DEBUG, "[HCS %p] watcher %p \"%s\": OnDone()", service_, this,
|
||||
service_name_.c_str());
|
||||
service_->database_->UnregisterWatch(service_name_, this);
|
||||
{
|
||||
grpc::internal::MutexLock lock(&service_->mu_);
|
||||
if (--service_->num_watches_ == 0 && service_->shutdown_) {
|
||||
service_->shutdown_condition_.Signal();
|
||||
}
|
||||
}
|
||||
// Free the initial ref from instantiation.
|
||||
Unref();
|
||||
}
|
||||
|
||||
void DefaultHealthCheckService::HealthCheckServiceImpl::WatchReactor::
|
||||
MaybeFinishLocked(Status status) {
|
||||
gpr_log(GPR_DEBUG,
|
||||
"[HCS %p] watcher %p \"%s\": MaybeFinishLocked() with code=%d msg=%s",
|
||||
service_, this, service_name_.c_str(), status.error_code(),
|
||||
status.error_message().c_str());
|
||||
if (!finish_called_) {
|
||||
gpr_log(GPR_DEBUG, "[HCS %p] watcher %p \"%s\": actually calling Finish()",
|
||||
service_, this, service_name_.c_str());
|
||||
finish_called_ = true;
|
||||
Finish(status);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
148
Pods/gRPC-C++/src/cpp/server/health/default_health_check_service.h
generated
Normal file
148
Pods/gRPC-C++/src/cpp/server/health/default_health_check_service.h
generated
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_HEALTH_DEFAULT_HEALTH_CHECK_SERVICE_H
|
||||
#define GRPC_SRC_CPP_SERVER_HEALTH_DEFAULT_HEALTH_CHECK_SERVICE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#include <grpcpp/health_check_service_interface.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/server_callback.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// Default implementation of HealthCheckServiceInterface. Server will create and
|
||||
// own it.
|
||||
class DefaultHealthCheckService final : public HealthCheckServiceInterface {
|
||||
public:
|
||||
enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
|
||||
|
||||
// The service impl to register with the server.
|
||||
class HealthCheckServiceImpl : public Service {
|
||||
public:
|
||||
// Reactor for handling Watch streams.
|
||||
class WatchReactor : public ServerWriteReactor<ByteBuffer>,
|
||||
public grpc_core::RefCounted<WatchReactor> {
|
||||
public:
|
||||
WatchReactor(HealthCheckServiceImpl* service, const ByteBuffer* request);
|
||||
|
||||
void SendHealth(ServingStatus status);
|
||||
|
||||
void OnWriteDone(bool ok) override;
|
||||
void OnCancel() override;
|
||||
void OnDone() override;
|
||||
|
||||
private:
|
||||
void SendHealthLocked(ServingStatus status)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
|
||||
|
||||
void MaybeFinishLocked(Status status) ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
|
||||
|
||||
HealthCheckServiceImpl* service_;
|
||||
std::string service_name_;
|
||||
ByteBuffer response_;
|
||||
|
||||
grpc::internal::Mutex mu_;
|
||||
bool write_pending_ ABSL_GUARDED_BY(mu_) = false;
|
||||
ServingStatus pending_status_ ABSL_GUARDED_BY(mu_) = NOT_FOUND;
|
||||
bool finish_called_ ABSL_GUARDED_BY(mu_) = false;
|
||||
};
|
||||
|
||||
explicit HealthCheckServiceImpl(DefaultHealthCheckService* database);
|
||||
|
||||
~HealthCheckServiceImpl() override;
|
||||
|
||||
private:
|
||||
// Request handler for Check method.
|
||||
static ServerUnaryReactor* HandleCheckRequest(
|
||||
DefaultHealthCheckService* database, CallbackServerContext* context,
|
||||
const ByteBuffer* request, ByteBuffer* response);
|
||||
|
||||
// Returns true on success.
|
||||
static bool DecodeRequest(const ByteBuffer& request,
|
||||
std::string* service_name);
|
||||
static bool EncodeResponse(ServingStatus status, ByteBuffer* response);
|
||||
|
||||
DefaultHealthCheckService* database_;
|
||||
|
||||
grpc::internal::Mutex mu_;
|
||||
grpc::internal::CondVar shutdown_condition_;
|
||||
bool shutdown_ ABSL_GUARDED_BY(mu_) = false;
|
||||
size_t num_watches_ ABSL_GUARDED_BY(mu_) = 0;
|
||||
};
|
||||
|
||||
DefaultHealthCheckService();
|
||||
|
||||
void SetServingStatus(const std::string& service_name, bool serving) override;
|
||||
void SetServingStatus(bool serving) override;
|
||||
|
||||
void Shutdown() override;
|
||||
|
||||
ServingStatus GetServingStatus(const std::string& service_name) const;
|
||||
|
||||
HealthCheckServiceImpl* GetHealthCheckService();
|
||||
|
||||
private:
|
||||
// Stores the current serving status of a service and any call
|
||||
// handlers registered for updates when the service's status changes.
|
||||
class ServiceData {
|
||||
public:
|
||||
void SetServingStatus(ServingStatus status);
|
||||
ServingStatus GetServingStatus() const { return status_; }
|
||||
void AddWatch(
|
||||
grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher);
|
||||
void RemoveWatch(HealthCheckServiceImpl::WatchReactor* watcher);
|
||||
bool Unused() const { return watchers_.empty() && status_ == NOT_FOUND; }
|
||||
|
||||
private:
|
||||
ServingStatus status_ = NOT_FOUND;
|
||||
std::map<HealthCheckServiceImpl::WatchReactor*,
|
||||
grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor>>
|
||||
watchers_;
|
||||
};
|
||||
|
||||
void RegisterWatch(
|
||||
const std::string& service_name,
|
||||
grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher);
|
||||
|
||||
void UnregisterWatch(const std::string& service_name,
|
||||
HealthCheckServiceImpl::WatchReactor* watcher);
|
||||
|
||||
mutable grpc::internal::Mutex mu_;
|
||||
bool shutdown_ ABSL_GUARDED_BY(&mu_) = false;
|
||||
std::map<std::string, ServiceData> services_map_ ABSL_GUARDED_BY(&mu_);
|
||||
std::unique_ptr<HealthCheckServiceImpl> impl_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_HEALTH_DEFAULT_HEALTH_CHECK_SERVICE_H
|
||||
34
Pods/gRPC-C++/src/cpp/server/health/health_check_service.cc
generated
Normal file
34
Pods/gRPC-C++/src/cpp/server/health/health_check_service.cc
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpcpp/health_check_service_interface.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace {
|
||||
bool g_grpc_default_health_check_service_enabled = false;
|
||||
} // namespace
|
||||
|
||||
bool DefaultHealthCheckServiceEnabled() {
|
||||
return g_grpc_default_health_check_service_enabled;
|
||||
}
|
||||
|
||||
void EnableDefaultHealthCheckService(bool enable) {
|
||||
g_grpc_default_health_check_service_enabled = enable;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
42
Pods/gRPC-C++/src/cpp/server/health/health_check_service_server_builder_option.cc
generated
Normal file
42
Pods/gRPC-C++/src/cpp/server/health/health_check_service_server_builder_option.cc
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpcpp/ext/health_check_service_server_builder_option.h>
|
||||
#include <grpcpp/health_check_service_interface.h>
|
||||
#include <grpcpp/impl/server_builder_plugin.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
HealthCheckServiceServerBuilderOption::HealthCheckServiceServerBuilderOption(
|
||||
std::unique_ptr<HealthCheckServiceInterface> hc)
|
||||
: hc_(std::move(hc)) {}
|
||||
// Hand over hc_ to the server.
|
||||
void HealthCheckServiceServerBuilderOption::UpdateArguments(
|
||||
ChannelArguments* args) {
|
||||
args->SetPointer(kHealthCheckServiceInterfaceArg, hc_.release());
|
||||
}
|
||||
|
||||
void HealthCheckServiceServerBuilderOption::UpdatePlugins(
|
||||
std::vector<std::unique_ptr<ServerBuilderPlugin>>* /*plugins*/) {}
|
||||
|
||||
} // namespace grpc
|
||||
55
Pods/gRPC-C++/src/cpp/server/insecure_server_credentials.cc
generated
Normal file
55
Pods/gRPC-C++/src/cpp/server/insecure_server_credentials.cc
generated
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/auth_metadata_processor.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
|
||||
namespace grpc {
|
||||
namespace {
|
||||
class InsecureServerCredentialsImpl final : public ServerCredentials {
|
||||
public:
|
||||
int AddPortToServer(const std::string& addr, grpc_server* server) override {
|
||||
grpc_server_credentials* server_creds =
|
||||
grpc_insecure_server_credentials_create();
|
||||
int result = grpc_server_add_http2_port(server, addr.c_str(), server_creds);
|
||||
grpc_server_credentials_release(server_creds);
|
||||
return result;
|
||||
}
|
||||
void SetAuthMetadataProcessor(
|
||||
const std::shared_ptr<grpc::AuthMetadataProcessor>& processor) override {
|
||||
(void)processor;
|
||||
GPR_ASSERT(0); // Should not be called on InsecureServerCredentials.
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsInsecure() const override { return true; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<ServerCredentials> InsecureServerCredentials() {
|
||||
return std::shared_ptr<ServerCredentials>(
|
||||
new InsecureServerCredentialsImpl());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
164
Pods/gRPC-C++/src/cpp/server/secure_server_credentials.cc
generated
Normal file
164
Pods/gRPC-C++/src/cpp/server/secure_server_credentials.cc
generated
Normal file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/server/secure_server_credentials.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc_security_constants.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpcpp/security/auth_metadata_processor.h>
|
||||
#include <grpcpp/security/tls_credentials_options.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
#include "src/cpp/common/secure_auth_context.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
void AuthMetadataProcessorAsyncWrapper::Destroy(void* wrapper) {
|
||||
auto* w = static_cast<AuthMetadataProcessorAsyncWrapper*>(wrapper);
|
||||
delete w;
|
||||
}
|
||||
|
||||
void AuthMetadataProcessorAsyncWrapper::Process(
|
||||
void* wrapper, grpc_auth_context* context, const grpc_metadata* md,
|
||||
size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) {
|
||||
auto* w = static_cast<AuthMetadataProcessorAsyncWrapper*>(wrapper);
|
||||
if (!w->processor_) {
|
||||
// Early exit.
|
||||
cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr);
|
||||
return;
|
||||
}
|
||||
if (w->processor_->IsBlocking()) {
|
||||
w->thread_pool_->Add([w, context, md, num_md, cb, user_data] {
|
||||
w->AuthMetadataProcessorAsyncWrapper::InvokeProcessor(context, md, num_md,
|
||||
cb, user_data);
|
||||
});
|
||||
} else {
|
||||
// invoke directly.
|
||||
w->InvokeProcessor(context, md, num_md, cb, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void AuthMetadataProcessorAsyncWrapper::InvokeProcessor(
|
||||
grpc_auth_context* context, const grpc_metadata* md, size_t num_md,
|
||||
grpc_process_auth_metadata_done_cb cb, void* user_data) {
|
||||
AuthMetadataProcessor::InputMetadata metadata;
|
||||
for (size_t i = 0; i < num_md; i++) {
|
||||
metadata.insert(std::make_pair(StringRefFromSlice(&md[i].key),
|
||||
StringRefFromSlice(&md[i].value)));
|
||||
}
|
||||
SecureAuthContext ctx(context);
|
||||
AuthMetadataProcessor::OutputMetadata consumed_metadata;
|
||||
AuthMetadataProcessor::OutputMetadata response_metadata;
|
||||
|
||||
Status status = processor_->Process(metadata, &ctx, &consumed_metadata,
|
||||
&response_metadata);
|
||||
|
||||
std::vector<grpc_metadata> consumed_md;
|
||||
for (const auto& consumed : consumed_metadata) {
|
||||
grpc_metadata md_entry;
|
||||
md_entry.key = SliceReferencingString(consumed.first);
|
||||
md_entry.value = SliceReferencingString(consumed.second);
|
||||
consumed_md.push_back(md_entry);
|
||||
}
|
||||
std::vector<grpc_metadata> response_md;
|
||||
for (const auto& response : response_metadata) {
|
||||
grpc_metadata md_entry;
|
||||
md_entry.key = SliceReferencingString(response.first);
|
||||
md_entry.value = SliceReferencingString(response.second);
|
||||
response_md.push_back(md_entry);
|
||||
}
|
||||
auto consumed_md_data = consumed_md.empty() ? nullptr : &consumed_md[0];
|
||||
auto response_md_data = response_md.empty() ? nullptr : &response_md[0];
|
||||
cb(user_data, consumed_md_data, consumed_md.size(), response_md_data,
|
||||
response_md.size(), static_cast<grpc_status_code>(status.error_code()),
|
||||
status.error_message().c_str());
|
||||
}
|
||||
|
||||
int SecureServerCredentials::AddPortToServer(const std::string& addr,
|
||||
grpc_server* server) {
|
||||
return grpc_server_add_http2_port(server, addr.c_str(), creds_);
|
||||
}
|
||||
|
||||
void SecureServerCredentials::SetAuthMetadataProcessor(
|
||||
const std::shared_ptr<grpc::AuthMetadataProcessor>& processor) {
|
||||
auto* wrapper = new grpc::AuthMetadataProcessorAsyncWrapper(processor);
|
||||
grpc_server_credentials_set_auth_metadata_processor(
|
||||
creds_, {grpc::AuthMetadataProcessorAsyncWrapper::Process,
|
||||
grpc::AuthMetadataProcessorAsyncWrapper::Destroy, wrapper});
|
||||
}
|
||||
|
||||
std::shared_ptr<ServerCredentials> SslServerCredentials(
|
||||
const grpc::SslServerCredentialsOptions& options) {
|
||||
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
|
||||
for (const auto& key_cert_pair : options.pem_key_cert_pairs) {
|
||||
grpc_ssl_pem_key_cert_pair p = {key_cert_pair.private_key.c_str(),
|
||||
key_cert_pair.cert_chain.c_str()};
|
||||
pem_key_cert_pairs.push_back(p);
|
||||
}
|
||||
grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create_ex(
|
||||
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
|
||||
pem_key_cert_pairs.empty() ? nullptr : &pem_key_cert_pairs[0],
|
||||
pem_key_cert_pairs.size(),
|
||||
options.force_client_auth
|
||||
? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
|
||||
: options.client_certificate_request,
|
||||
nullptr);
|
||||
return std::shared_ptr<ServerCredentials>(
|
||||
new SecureServerCredentials(c_creds));
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
std::shared_ptr<ServerCredentials> AltsServerCredentials(
|
||||
const AltsServerCredentialsOptions& /* options */) {
|
||||
grpc_alts_credentials_options* c_options =
|
||||
grpc_alts_credentials_server_options_create();
|
||||
grpc_server_credentials* c_creds =
|
||||
grpc_alts_server_credentials_create(c_options);
|
||||
grpc_alts_credentials_options_destroy(c_options);
|
||||
return std::shared_ptr<ServerCredentials>(
|
||||
new SecureServerCredentials(c_creds));
|
||||
}
|
||||
|
||||
std::shared_ptr<ServerCredentials> LocalServerCredentials(
|
||||
grpc_local_connect_type type) {
|
||||
return std::shared_ptr<ServerCredentials>(
|
||||
new SecureServerCredentials(grpc_local_server_credentials_create(type)));
|
||||
}
|
||||
|
||||
std::shared_ptr<ServerCredentials> TlsServerCredentials(
|
||||
const grpc::experimental::TlsServerCredentialsOptions& options) {
|
||||
grpc_server_credentials* c_creds =
|
||||
grpc_tls_server_credentials_create(options.c_credentials_options());
|
||||
if (c_creds == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::shared_ptr<ServerCredentials>(
|
||||
new SecureServerCredentials(c_creds));
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
86
Pods/gRPC-C++/src/cpp/server/secure_server_credentials.h
generated
Normal file
86
Pods/gRPC-C++/src/cpp/server/secure_server_credentials.h
generated
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
|
||||
#define GRPC_SRC_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/security/auth_metadata_processor.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
|
||||
#include "src/cpp/server/thread_pool_interface.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class SecureServerCredentials;
|
||||
|
||||
class AuthMetadataProcessorAsyncWrapper final {
|
||||
public:
|
||||
static void Destroy(void* wrapper);
|
||||
|
||||
static void Process(void* wrapper, grpc_auth_context* context,
|
||||
const grpc_metadata* md, size_t num_md,
|
||||
grpc_process_auth_metadata_done_cb cb, void* user_data);
|
||||
|
||||
explicit AuthMetadataProcessorAsyncWrapper(
|
||||
const std::shared_ptr<AuthMetadataProcessor>& processor)
|
||||
: processor_(processor) {
|
||||
if (processor && processor->IsBlocking()) {
|
||||
thread_pool_.reset(CreateDefaultThreadPool());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md,
|
||||
size_t num_md, grpc_process_auth_metadata_done_cb cb,
|
||||
void* user_data);
|
||||
std::unique_ptr<ThreadPoolInterface> thread_pool_;
|
||||
std::shared_ptr<AuthMetadataProcessor> processor_;
|
||||
};
|
||||
|
||||
class SecureServerCredentials final : public ServerCredentials {
|
||||
public:
|
||||
explicit SecureServerCredentials(grpc_server_credentials* creds)
|
||||
: creds_(creds) {}
|
||||
~SecureServerCredentials() override {
|
||||
grpc_server_credentials_release(creds_);
|
||||
}
|
||||
|
||||
int AddPortToServer(const std::string& addr, grpc_server* server) override;
|
||||
|
||||
void SetAuthMetadataProcessor(
|
||||
const std::shared_ptr<grpc::AuthMetadataProcessor>& processor) override;
|
||||
|
||||
grpc_server_credentials* c_creds() { return creds_; }
|
||||
|
||||
private:
|
||||
SecureServerCredentials* AsSecureServerCredentials() override { return this; }
|
||||
|
||||
grpc_server_credentials* creds_;
|
||||
std::unique_ptr<grpc::AuthMetadataProcessorAsyncWrapper> processor_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
|
||||
471
Pods/gRPC-C++/src/cpp/server/server_builder.cc
generated
Normal file
471
Pods/gRPC-C++/src/cpp/server/server_builder.cc
generated
Normal file
@@ -0,0 +1,471 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015-2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/channel_arg_names.h>
|
||||
#include <grpc/impl/compression_types.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/sync.h>
|
||||
#include <grpc/support/workaround_list.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/impl/server_builder_option.h>
|
||||
#include <grpcpp/impl/server_builder_plugin.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/resource_quota.h>
|
||||
#include <grpcpp/security/authorization_policy_provider.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
#include <grpcpp/server.h>
|
||||
#include <grpcpp/server_builder.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/server_interface.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/server_interceptor.h>
|
||||
|
||||
#include "src/core/lib/gpr/string.h"
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/cpp/server/external_connection_acceptor_impl.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
static std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>*
|
||||
g_plugin_factory_list;
|
||||
static gpr_once once_init_plugin_list = GPR_ONCE_INIT;
|
||||
|
||||
static void do_plugin_list_init(void) {
|
||||
g_plugin_factory_list =
|
||||
new std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>();
|
||||
}
|
||||
|
||||
ServerBuilder::ServerBuilder()
|
||||
: max_receive_message_size_(INT_MIN),
|
||||
max_send_message_size_(INT_MIN),
|
||||
sync_server_settings_(SyncServerSettings()),
|
||||
resource_quota_(nullptr) {
|
||||
gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
|
||||
for (const auto& value : *g_plugin_factory_list) {
|
||||
plugins_.emplace_back(value());
|
||||
}
|
||||
|
||||
// all compression algorithms enabled by default.
|
||||
enabled_compression_algorithms_bitset_ =
|
||||
(1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
|
||||
memset(&maybe_default_compression_level_, 0,
|
||||
sizeof(maybe_default_compression_level_));
|
||||
memset(&maybe_default_compression_algorithm_, 0,
|
||||
sizeof(maybe_default_compression_algorithm_));
|
||||
}
|
||||
|
||||
ServerBuilder::~ServerBuilder() {
|
||||
if (resource_quota_ != nullptr) {
|
||||
grpc_resource_quota_unref(resource_quota_);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
|
||||
bool is_frequently_polled) {
|
||||
grpc::ServerCompletionQueue* cq = new grpc::ServerCompletionQueue(
|
||||
GRPC_CQ_NEXT,
|
||||
is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING,
|
||||
nullptr);
|
||||
cqs_.push_back(cq);
|
||||
return std::unique_ptr<grpc::ServerCompletionQueue>(cq);
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::RegisterService(Service* service) {
|
||||
services_.emplace_back(new NamedService(service));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::RegisterService(const std::string& host,
|
||||
Service* service) {
|
||||
services_.emplace_back(new NamedService(host, service));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::RegisterAsyncGenericService(
|
||||
AsyncGenericService* service) {
|
||||
if (generic_service_ || callback_generic_service_) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Adding multiple generic services is unsupported for now. "
|
||||
"Dropping the service %p",
|
||||
service);
|
||||
} else {
|
||||
generic_service_ = service;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::RegisterCallbackGenericService(
|
||||
CallbackGenericService* service) {
|
||||
if (generic_service_ || callback_generic_service_) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Adding multiple generic services is unsupported for now. "
|
||||
"Dropping the service %p",
|
||||
service);
|
||||
} else {
|
||||
callback_generic_service_ = service;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetContextAllocator(
|
||||
std::unique_ptr<grpc::ContextAllocator> context_allocator) {
|
||||
context_allocator_ = std::move(context_allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
|
||||
ServerBuilder::experimental_type::AddExternalConnectionAcceptor(
|
||||
experimental_type::ExternalConnectionType type,
|
||||
std::shared_ptr<ServerCredentials> creds) {
|
||||
std::string name_prefix("external:");
|
||||
char count_str[GPR_LTOA_MIN_BUFSIZE];
|
||||
gpr_ltoa(static_cast<long>(builder_->acceptors_.size()), count_str);
|
||||
builder_->acceptors_.emplace_back(
|
||||
std::make_shared<grpc::internal::ExternalConnectionAcceptorImpl>(
|
||||
name_prefix.append(count_str), type, creds));
|
||||
return builder_->acceptors_.back()->GetAcceptor();
|
||||
}
|
||||
|
||||
void ServerBuilder::experimental_type::SetAuthorizationPolicyProvider(
|
||||
std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
|
||||
provider) {
|
||||
builder_->authorization_provider_ = std::move(provider);
|
||||
}
|
||||
|
||||
void ServerBuilder::experimental_type::EnableCallMetricRecording(
|
||||
experimental::ServerMetricRecorder* server_metric_recorder) {
|
||||
builder_->AddChannelArgument(GRPC_ARG_SERVER_CALL_METRIC_RECORDING, 1);
|
||||
GPR_ASSERT(builder_->server_metric_recorder_ == nullptr);
|
||||
builder_->server_metric_recorder_ = server_metric_recorder;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetOption(
|
||||
std::unique_ptr<ServerBuilderOption> option) {
|
||||
options_.push_back(std::move(option));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetSyncServerOption(
|
||||
ServerBuilder::SyncServerOption option, int val) {
|
||||
switch (option) {
|
||||
case NUM_CQS:
|
||||
sync_server_settings_.num_cqs = val;
|
||||
break;
|
||||
case MIN_POLLERS:
|
||||
sync_server_settings_.min_pollers = val;
|
||||
break;
|
||||
case MAX_POLLERS:
|
||||
sync_server_settings_.max_pollers = val;
|
||||
break;
|
||||
case CQ_TIMEOUT_MSEC:
|
||||
sync_server_settings_.cq_timeout_msec = val;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetCompressionAlgorithmSupportStatus(
|
||||
grpc_compression_algorithm algorithm, bool enabled) {
|
||||
if (enabled) {
|
||||
grpc_core::SetBit(&enabled_compression_algorithms_bitset_, algorithm);
|
||||
} else {
|
||||
grpc_core::ClearBit(&enabled_compression_algorithms_bitset_, algorithm);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetDefaultCompressionLevel(
|
||||
grpc_compression_level level) {
|
||||
maybe_default_compression_level_.is_set = true;
|
||||
maybe_default_compression_level_.level = level;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetDefaultCompressionAlgorithm(
|
||||
grpc_compression_algorithm algorithm) {
|
||||
maybe_default_compression_algorithm_.is_set = true;
|
||||
maybe_default_compression_algorithm_.algorithm = algorithm;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::SetResourceQuota(
|
||||
const grpc::ResourceQuota& resource_quota) {
|
||||
if (resource_quota_ != nullptr) {
|
||||
grpc_resource_quota_unref(resource_quota_);
|
||||
}
|
||||
resource_quota_ = resource_quota.c_resource_quota();
|
||||
grpc_resource_quota_ref(resource_quota_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::AddListeningPort(
|
||||
const std::string& addr_uri, std::shared_ptr<ServerCredentials> creds,
|
||||
int* selected_port) {
|
||||
const std::string uri_scheme = "dns:";
|
||||
std::string addr = addr_uri;
|
||||
if (addr_uri.compare(0, uri_scheme.size(), uri_scheme) == 0) {
|
||||
size_t pos = uri_scheme.size();
|
||||
while (addr_uri[pos] == '/') ++pos; // Skip slashes.
|
||||
addr = addr_uri.substr(pos);
|
||||
}
|
||||
Port port = {addr, std::move(creds), selected_port};
|
||||
ports_.push_back(port);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChannelArguments ServerBuilder::BuildChannelArgs() {
|
||||
ChannelArguments args;
|
||||
if (max_receive_message_size_ >= -1) {
|
||||
args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
|
||||
}
|
||||
if (max_send_message_size_ >= -1) {
|
||||
args.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, max_send_message_size_);
|
||||
}
|
||||
for (const auto& option : options_) {
|
||||
option->UpdateArguments(&args);
|
||||
option->UpdatePlugins(&plugins_);
|
||||
}
|
||||
args.SetInt(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
|
||||
enabled_compression_algorithms_bitset_);
|
||||
if (maybe_default_compression_level_.is_set) {
|
||||
args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL,
|
||||
maybe_default_compression_level_.level);
|
||||
}
|
||||
if (maybe_default_compression_algorithm_.is_set) {
|
||||
args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
|
||||
maybe_default_compression_algorithm_.algorithm);
|
||||
}
|
||||
if (resource_quota_ != nullptr) {
|
||||
args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
|
||||
grpc_resource_quota_arg_vtable());
|
||||
}
|
||||
for (const auto& plugin : plugins_) {
|
||||
plugin->UpdateServerBuilder(this);
|
||||
plugin->UpdateChannelArguments(&args);
|
||||
}
|
||||
if (authorization_provider_ != nullptr) {
|
||||
args.SetPointerWithVtable(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER,
|
||||
authorization_provider_->c_provider(),
|
||||
grpc_authorization_policy_provider_arg_vtable());
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::Server> ServerBuilder::BuildAndStart() {
|
||||
ChannelArguments args = BuildChannelArgs();
|
||||
|
||||
// == Determine if the server has any syncrhonous methods ==
|
||||
bool has_sync_methods = false;
|
||||
for (const auto& value : services_) {
|
||||
if (value->service->has_synchronous_methods()) {
|
||||
has_sync_methods = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_sync_methods) {
|
||||
for (const auto& value : plugins_) {
|
||||
if (value->has_sync_methods()) {
|
||||
has_sync_methods = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a Sync server, i.e a server expositing sync API, then the server
|
||||
// needs to create some completion queues to listen for incoming requests.
|
||||
// 'sync_server_cqs' are those internal completion queues.
|
||||
//
|
||||
// This is different from the completion queues added to the server via
|
||||
// ServerBuilder's AddCompletionQueue() method (those completion queues
|
||||
// are in 'cqs_' member variable of ServerBuilder object)
|
||||
std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
|
||||
sync_server_cqs(
|
||||
std::make_shared<
|
||||
std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>());
|
||||
|
||||
bool has_frequently_polled_cqs = false;
|
||||
for (const auto& cq : cqs_) {
|
||||
if (cq->IsFrequentlyPolled()) {
|
||||
has_frequently_polled_cqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// == Determine if the server has any callback methods ==
|
||||
bool has_callback_methods = false;
|
||||
for (const auto& service : services_) {
|
||||
if (service->service->has_callback_methods()) {
|
||||
has_callback_methods = true;
|
||||
has_frequently_polled_cqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback_generic_service_ != nullptr) {
|
||||
has_frequently_polled_cqs = true;
|
||||
}
|
||||
|
||||
const bool is_hybrid_server = has_sync_methods && has_frequently_polled_cqs;
|
||||
|
||||
if (has_sync_methods) {
|
||||
grpc_cq_polling_type polling_type =
|
||||
is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
|
||||
|
||||
// Create completion queues to listen to incoming rpc requests
|
||||
for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
|
||||
sync_server_cqs->emplace_back(
|
||||
new grpc::ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(vjpai): Add a section here for plugins once they can support callback
|
||||
// methods
|
||||
|
||||
if (has_sync_methods) {
|
||||
// This is a Sync server
|
||||
gpr_log(GPR_INFO,
|
||||
"Synchronous server. Num CQs: %d, Min pollers: %d, Max Pollers: "
|
||||
"%d, CQ timeout (msec): %d",
|
||||
sync_server_settings_.num_cqs, sync_server_settings_.min_pollers,
|
||||
sync_server_settings_.max_pollers,
|
||||
sync_server_settings_.cq_timeout_msec);
|
||||
}
|
||||
|
||||
if (has_callback_methods) {
|
||||
gpr_log(GPR_INFO, "Callback server.");
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::Server> server(new grpc::Server(
|
||||
&args, sync_server_cqs, sync_server_settings_.min_pollers,
|
||||
sync_server_settings_.max_pollers, sync_server_settings_.cq_timeout_msec,
|
||||
std::move(acceptors_), server_config_fetcher_, resource_quota_,
|
||||
std::move(interceptor_creators_), server_metric_recorder_));
|
||||
|
||||
ServerInitializer* initializer = server->initializer();
|
||||
|
||||
// Register all the completion queues with the server. i.e
|
||||
// 1. sync_server_cqs: internal completion queues created IF this is a sync
|
||||
// server
|
||||
// 2. cqs_: Completion queues added via AddCompletionQueue() call
|
||||
|
||||
for (const auto& cq : *sync_server_cqs) {
|
||||
grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
|
||||
has_frequently_polled_cqs = true;
|
||||
}
|
||||
|
||||
if (has_callback_methods || callback_generic_service_ != nullptr) {
|
||||
auto* cq = server->CallbackCQ();
|
||||
grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
|
||||
}
|
||||
|
||||
// cqs_ contains the completion queue added by calling the ServerBuilder's
|
||||
// AddCompletionQueue() API. Some of them may not be frequently polled (i.e by
|
||||
// calling Next() or AsyncNext()) and hence are not safe to be used for
|
||||
// listening to incoming channels. Such completion queues must be registered
|
||||
// as non-listening queues. In debug mode, these should have their server list
|
||||
// tracked since these are provided the user and must be Shutdown by the user
|
||||
// after the server is shutdown.
|
||||
for (const auto& cq : cqs_) {
|
||||
grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
|
||||
cq->RegisterServer(server.get());
|
||||
}
|
||||
|
||||
if (!has_frequently_polled_cqs) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"At least one of the completion queues must be frequently polled");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
server->RegisterContextAllocator(std::move(context_allocator_));
|
||||
|
||||
for (const auto& value : services_) {
|
||||
if (!server->RegisterService(value->host.get(), value->service)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& value : plugins_) {
|
||||
value->InitServer(initializer);
|
||||
}
|
||||
|
||||
if (generic_service_) {
|
||||
server->RegisterAsyncGenericService(generic_service_);
|
||||
} else if (callback_generic_service_) {
|
||||
server->RegisterCallbackGenericService(callback_generic_service_);
|
||||
} else {
|
||||
for (const auto& value : services_) {
|
||||
if (value->service->has_generic_methods()) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Some methods were marked generic but there is no "
|
||||
"generic service registered.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool added_port = false;
|
||||
for (auto& port : ports_) {
|
||||
int r = server->AddListeningPort(port.addr, port.creds.get());
|
||||
if (!r) {
|
||||
if (added_port) server->Shutdown();
|
||||
return nullptr;
|
||||
}
|
||||
added_port = true;
|
||||
if (port.selected_port != nullptr) {
|
||||
*port.selected_port = r;
|
||||
}
|
||||
}
|
||||
|
||||
auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
|
||||
server->Start(cqs_data, cqs_.size());
|
||||
|
||||
for (const auto& value : plugins_) {
|
||||
value->Finish(initializer);
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void ServerBuilder::InternalAddPluginFactory(
|
||||
std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)()) {
|
||||
gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
|
||||
(*g_plugin_factory_list).push_back(CreatePlugin);
|
||||
}
|
||||
|
||||
ServerBuilder& ServerBuilder::EnableWorkaround(grpc_workaround_list id) {
|
||||
switch (id) {
|
||||
case GRPC_WORKAROUND_ID_CRONET_COMPRESSION:
|
||||
return AddChannelArgument(GRPC_ARG_WORKAROUND_CRONET_COMPRESSION, 1);
|
||||
default:
|
||||
gpr_log(GPR_ERROR, "Workaround %u does not exist or is obsolete.", id);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
87
Pods/gRPC-C++/src/cpp/server/server_callback.cc
generated
Normal file
87
Pods/gRPC-C++/src/cpp/server/server_callback.cc
generated
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright 2019 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <grpcpp/support/server_callback.h>
|
||||
|
||||
#include "src/core/lib/iomgr/closure.h"
|
||||
#include "src/core/lib/iomgr/error.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/iomgr/executor.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace internal {
|
||||
|
||||
void ServerCallbackCall::ScheduleOnDone(bool inline_ondone) {
|
||||
if (inline_ondone) {
|
||||
CallOnDone();
|
||||
} else {
|
||||
// Unlike other uses of closure, do not Ref or Unref here since at this
|
||||
// point, all the Ref'fing and Unref'fing is done for this call.
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
struct ClosureWithArg {
|
||||
grpc_closure closure;
|
||||
ServerCallbackCall* call;
|
||||
explicit ClosureWithArg(ServerCallbackCall* call_arg) : call(call_arg) {
|
||||
GRPC_CLOSURE_INIT(
|
||||
&closure,
|
||||
[](void* void_arg, grpc_error_handle) {
|
||||
ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
|
||||
arg->call->CallOnDone();
|
||||
delete arg;
|
||||
},
|
||||
this, grpc_schedule_on_exec_ctx);
|
||||
}
|
||||
};
|
||||
ClosureWithArg* arg = new ClosureWithArg(this);
|
||||
grpc_core::Executor::Run(&arg->closure, absl::OkStatus());
|
||||
}
|
||||
}
|
||||
|
||||
void ServerCallbackCall::CallOnCancel(ServerReactor* reactor) {
|
||||
if (reactor->InternalInlineable()) {
|
||||
reactor->OnCancel();
|
||||
} else {
|
||||
// Ref to make sure that the closure executes before the whole call gets
|
||||
// destructed, and Unref within the closure.
|
||||
Ref();
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
struct ClosureWithArg {
|
||||
grpc_closure closure;
|
||||
ServerCallbackCall* call;
|
||||
ServerReactor* reactor;
|
||||
ClosureWithArg(ServerCallbackCall* call_arg, ServerReactor* reactor_arg)
|
||||
: call(call_arg), reactor(reactor_arg) {
|
||||
GRPC_CLOSURE_INIT(
|
||||
&closure,
|
||||
[](void* void_arg, grpc_error_handle) {
|
||||
ClosureWithArg* arg = static_cast<ClosureWithArg*>(void_arg);
|
||||
arg->reactor->OnCancel();
|
||||
arg->call->MaybeDone();
|
||||
delete arg;
|
||||
},
|
||||
this, grpc_schedule_on_exec_ctx);
|
||||
}
|
||||
};
|
||||
ClosureWithArg* arg = new ClosureWithArg(this, reactor);
|
||||
grpc_core::Executor::Run(&arg->closure, absl::OkStatus());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc
|
||||
1397
Pods/gRPC-C++/src/cpp/server/server_cc.cc
generated
Normal file
1397
Pods/gRPC-C++/src/cpp/server/server_cc.cc
generated
Normal file
@@ -0,0 +1,1397 @@
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/channel_arg_names.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/sync.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/channel.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/generic/async_generic_service.h>
|
||||
#include <grpcpp/health_check_service_interface.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set.h>
|
||||
#include <grpcpp/impl/call_op_set_interface.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
#include <grpcpp/impl/interceptor_common.h>
|
||||
#include <grpcpp/impl/metadata_map.h>
|
||||
#include <grpcpp/impl/rpc_method.h>
|
||||
#include <grpcpp/impl/rpc_service_method.h>
|
||||
#include <grpcpp/impl/server_callback_handlers.h>
|
||||
#include <grpcpp/impl/server_initializer.h>
|
||||
#include <grpcpp/impl/service_type.h>
|
||||
#include <grpcpp/impl/sync.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
#include <grpcpp/server.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/server_interface.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/support/client_interceptor.h>
|
||||
#include <grpcpp/support/interceptor.h>
|
||||
#include <grpcpp/support/method_handler.h>
|
||||
#include <grpcpp/support/server_interceptor.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
#include "src/core/ext/transport/inproc/inproc_transport.h"
|
||||
#include "src/core/lib/gprpp/manual_constructor.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/iomgr/iomgr.h"
|
||||
#include "src/core/lib/resource_quota/api.h"
|
||||
#include "src/core/lib/surface/completion_queue.h"
|
||||
#include "src/core/lib/surface/server.h"
|
||||
#include "src/cpp/client/create_channel_internal.h"
|
||||
#include "src/cpp/server/external_connection_acceptor_impl.h"
|
||||
#include "src/cpp/server/health/default_health_check_service.h"
|
||||
#include "src/cpp/thread_manager/thread_manager.h"
|
||||
|
||||
namespace grpc {
|
||||
namespace {
|
||||
|
||||
// The default value for maximum number of threads that can be created in the
|
||||
// sync server. This value of INT_MAX is chosen to match the default behavior if
|
||||
// no ResourceQuota is set. To modify the max number of threads in a sync
|
||||
// server, pass a custom ResourceQuota object (with the desired number of
|
||||
// max-threads set) to the server builder.
|
||||
#define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX
|
||||
|
||||
// Give a useful status error message if the resource is exhausted specifically
|
||||
// because the server threadpool is full.
|
||||
const char* kServerThreadpoolExhausted = "Server Threadpool Exhausted";
|
||||
|
||||
// Although we might like to give a useful status error message on unimplemented
|
||||
// RPCs, it's not always possible since that also would need to be added across
|
||||
// languages and isn't actually required by the spec.
|
||||
const char* kUnknownRpcMethod = "";
|
||||
|
||||
class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
|
||||
public:
|
||||
~DefaultGlobalCallbacks() override {}
|
||||
void PreSynchronousRequest(ServerContext* /*context*/) override {}
|
||||
void PostSynchronousRequest(ServerContext* /*context*/) override {}
|
||||
};
|
||||
|
||||
std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
|
||||
gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
|
||||
|
||||
void InitGlobalCallbacks() {
|
||||
if (!g_callbacks) {
|
||||
g_callbacks.reset(new DefaultGlobalCallbacks());
|
||||
}
|
||||
}
|
||||
|
||||
class ShutdownTag : public internal::CompletionQueueTag {
|
||||
public:
|
||||
bool FinalizeResult(void** /*tag*/, bool* /*status*/) override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class PhonyTag : public internal::CompletionQueueTag {
|
||||
public:
|
||||
bool FinalizeResult(void** /*tag*/, bool* /*status*/) override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class UnimplementedAsyncRequestContext {
|
||||
protected:
|
||||
UnimplementedAsyncRequestContext() : generic_stream_(&server_context_) {}
|
||||
|
||||
GenericServerContext server_context_;
|
||||
GenericServerAsyncReaderWriter generic_stream_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
|
||||
ServerInterface* server, ServerContext* context,
|
||||
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
|
||||
ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
|
||||
: server_(server),
|
||||
context_(context),
|
||||
stream_(stream),
|
||||
call_cq_(call_cq),
|
||||
notification_cq_(notification_cq),
|
||||
tag_(tag),
|
||||
delete_on_finalize_(delete_on_finalize),
|
||||
call_(nullptr),
|
||||
done_intercepting_(false) {
|
||||
// Set up interception state partially for the receive ops. call_wrapper_ is
|
||||
// not filled at this point, but it will be filled before the interceptors are
|
||||
// run.
|
||||
interceptor_methods_.SetCall(&call_wrapper_);
|
||||
interceptor_methods_.SetReverse();
|
||||
call_cq_->RegisterAvalanching(); // This op will trigger more ops
|
||||
call_metric_recording_enabled_ = server_->call_metric_recording_enabled();
|
||||
server_metric_recorder_ = server_->server_metric_recorder();
|
||||
}
|
||||
|
||||
ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() {
|
||||
call_cq_->CompleteAvalanching();
|
||||
}
|
||||
|
||||
bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
|
||||
bool* status) {
|
||||
if (done_intercepting_) {
|
||||
*tag = tag_;
|
||||
if (delete_on_finalize_) {
|
||||
delete this;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
context_->set_call(call_, call_metric_recording_enabled_,
|
||||
server_metric_recorder_);
|
||||
context_->cq_ = call_cq_;
|
||||
if (call_wrapper_.call() == nullptr) {
|
||||
// Fill it since it is empty.
|
||||
call_wrapper_ = internal::Call(
|
||||
call_, server_, call_cq_, server_->max_receive_message_size(), nullptr);
|
||||
}
|
||||
|
||||
// just the pointers inside call are copied here
|
||||
stream_->BindCall(&call_wrapper_);
|
||||
|
||||
if (*status && call_ && call_wrapper_.server_rpc_info()) {
|
||||
done_intercepting_ = true;
|
||||
// Set interception point for RECV INITIAL METADATA
|
||||
interceptor_methods_.AddInterceptionHookPoint(
|
||||
experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
|
||||
interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_);
|
||||
if (interceptor_methods_.RunInterceptors(
|
||||
[this]() { ContinueFinalizeResultAfterInterception(); })) {
|
||||
// There are no interceptors to run. Continue
|
||||
} else {
|
||||
// There were interceptors to be run, so
|
||||
// ContinueFinalizeResultAfterInterception will be run when interceptors
|
||||
// are done.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (*status && call_) {
|
||||
context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr);
|
||||
}
|
||||
*tag = tag_;
|
||||
if (delete_on_finalize_) {
|
||||
delete this;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServerInterface::BaseAsyncRequest::
|
||||
ContinueFinalizeResultAfterInterception() {
|
||||
context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr);
|
||||
// Queue a tag which will be returned immediately
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
grpc_cq_begin_op(notification_cq_->cq(), this);
|
||||
grpc_cq_end_op(
|
||||
notification_cq_->cq(), this, absl::OkStatus(),
|
||||
[](void* /*arg*/, grpc_cq_completion* completion) { delete completion; },
|
||||
nullptr, new grpc_cq_completion());
|
||||
}
|
||||
|
||||
ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest(
|
||||
ServerInterface* server, ServerContext* context,
|
||||
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
|
||||
ServerCompletionQueue* notification_cq, void* tag, const char* name,
|
||||
internal::RpcMethod::RpcType type)
|
||||
: BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
|
||||
true),
|
||||
name_(name),
|
||||
type_(type) {}
|
||||
|
||||
void ServerInterface::RegisteredAsyncRequest::IssueRequest(
|
||||
void* registered_method, grpc_byte_buffer** payload,
|
||||
ServerCompletionQueue* notification_cq) {
|
||||
// The following call_start_batch is internally-generated so no need for an
|
||||
// explanatory log on failure.
|
||||
GPR_ASSERT(grpc_server_request_registered_call(
|
||||
server_->server(), registered_method, &call_,
|
||||
&context_->deadline_, context_->client_metadata_.arr(),
|
||||
payload, call_cq_->cq(), notification_cq->cq(),
|
||||
this) == GRPC_CALL_OK);
|
||||
}
|
||||
|
||||
ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
|
||||
ServerInterface* server, GenericServerContext* context,
|
||||
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
|
||||
ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize,
|
||||
bool issue_request)
|
||||
: BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag,
|
||||
delete_on_finalize) {
|
||||
grpc_call_details_init(&call_details_);
|
||||
GPR_ASSERT(notification_cq);
|
||||
GPR_ASSERT(call_cq);
|
||||
if (issue_request) {
|
||||
IssueRequest();
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
|
||||
bool* status) {
|
||||
// If we are done intercepting, there is nothing more for us to do
|
||||
if (done_intercepting_) {
|
||||
return BaseAsyncRequest::FinalizeResult(tag, status);
|
||||
}
|
||||
// TODO(yangg) remove the copy here.
|
||||
if (*status) {
|
||||
static_cast<GenericServerContext*>(context_)->method_ =
|
||||
StringFromCopiedSlice(call_details_.method);
|
||||
static_cast<GenericServerContext*>(context_)->host_ =
|
||||
StringFromCopiedSlice(call_details_.host);
|
||||
context_->deadline_ = call_details_.deadline;
|
||||
}
|
||||
grpc_slice_unref(call_details_.method);
|
||||
grpc_slice_unref(call_details_.host);
|
||||
call_wrapper_ = internal::Call(
|
||||
call_, server_, call_cq_, server_->max_receive_message_size(),
|
||||
context_->set_server_rpc_info(
|
||||
static_cast<GenericServerContext*>(context_)->method_.c_str(),
|
||||
internal::RpcMethod::BIDI_STREAMING,
|
||||
*server_->interceptor_creators()));
|
||||
return BaseAsyncRequest::FinalizeResult(tag, status);
|
||||
}
|
||||
|
||||
void ServerInterface::GenericAsyncRequest::IssueRequest() {
|
||||
// The following call_start_batch is internally-generated so no need for an
|
||||
// explanatory log on failure.
|
||||
GPR_ASSERT(grpc_server_request_call(server_->server(), &call_, &call_details_,
|
||||
context_->client_metadata_.arr(),
|
||||
call_cq_->cq(), notification_cq_->cq(),
|
||||
this) == GRPC_CALL_OK);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ShutdownCallback : public grpc_completion_queue_functor {
|
||||
public:
|
||||
ShutdownCallback() {
|
||||
functor_run = &ShutdownCallback::Run;
|
||||
// Set inlineable to true since this callback is trivial and thus does not
|
||||
// need to be run from the executor (triggering a thread hop). This should
|
||||
// only be used by internal callbacks like this and not by user application
|
||||
// code.
|
||||
inlineable = true;
|
||||
}
|
||||
// TakeCQ takes ownership of the cq into the shutdown callback
|
||||
// so that the shutdown callback will be responsible for destroying it
|
||||
void TakeCQ(CompletionQueue* cq) { cq_ = cq; }
|
||||
|
||||
// The Run function will get invoked by the completion queue library
|
||||
// when the shutdown is actually complete
|
||||
static void Run(grpc_completion_queue_functor* cb, int) {
|
||||
auto* callback = static_cast<ShutdownCallback*>(cb);
|
||||
delete callback->cq_;
|
||||
delete callback;
|
||||
}
|
||||
|
||||
private:
|
||||
CompletionQueue* cq_ = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/// Use private inheritance rather than composition only to establish order
|
||||
/// of construction, since the public base class should be constructed after the
|
||||
/// elements belonging to the private base class are constructed. This is not
|
||||
/// possible using true composition.
|
||||
class Server::UnimplementedAsyncRequest final
|
||||
: private grpc::UnimplementedAsyncRequestContext,
|
||||
public GenericAsyncRequest {
|
||||
public:
|
||||
UnimplementedAsyncRequest(ServerInterface* server,
|
||||
grpc::ServerCompletionQueue* cq)
|
||||
: GenericAsyncRequest(server, &server_context_, &generic_stream_, cq, cq,
|
||||
/*tag=*/nullptr, /*delete_on_finalize=*/false,
|
||||
/*issue_request=*/false) {
|
||||
// Issue request here instead of the base class to prevent race on vptr.
|
||||
IssueRequest();
|
||||
}
|
||||
|
||||
bool FinalizeResult(void** tag, bool* status) override;
|
||||
|
||||
grpc::ServerContext* context() { return &server_context_; }
|
||||
grpc::GenericServerAsyncReaderWriter* stream() { return &generic_stream_; }
|
||||
};
|
||||
|
||||
/// UnimplementedAsyncResponse should not post user-visible completions to the
|
||||
/// C++ completion queue, but is generated as a CQ event by the core
|
||||
class Server::UnimplementedAsyncResponse final
|
||||
: public grpc::internal::CallOpSet<
|
||||
grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus> {
|
||||
public:
|
||||
explicit UnimplementedAsyncResponse(UnimplementedAsyncRequest* request);
|
||||
~UnimplementedAsyncResponse() override { delete request_; }
|
||||
|
||||
bool FinalizeResult(void** tag, bool* status) override {
|
||||
if (grpc::internal::CallOpSet<
|
||||
grpc::internal::CallOpSendInitialMetadata,
|
||||
grpc::internal::CallOpServerSendStatus>::FinalizeResult(tag,
|
||||
status)) {
|
||||
delete this;
|
||||
} else {
|
||||
// The tag was swallowed due to interception. We will see it again.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
UnimplementedAsyncRequest* const request_;
|
||||
};
|
||||
|
||||
class Server::SyncRequest final : public grpc::internal::CompletionQueueTag {
|
||||
public:
|
||||
SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method,
|
||||
grpc_core::Server::RegisteredCallAllocation* data)
|
||||
: SyncRequest(server, method) {
|
||||
CommonSetup(data);
|
||||
data->deadline = &deadline_;
|
||||
data->optional_payload = has_request_payload_ ? &request_payload_ : nullptr;
|
||||
}
|
||||
|
||||
SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method,
|
||||
grpc_core::Server::BatchCallAllocation* data)
|
||||
: SyncRequest(server, method) {
|
||||
CommonSetup(data);
|
||||
call_details_ = new grpc_call_details;
|
||||
grpc_call_details_init(call_details_);
|
||||
data->details = call_details_;
|
||||
}
|
||||
|
||||
~SyncRequest() override {
|
||||
// The destructor should only cleanup those objects created in the
|
||||
// constructor, since some paths may or may not actually go through the
|
||||
// Run stage where other objects are allocated.
|
||||
if (has_request_payload_ && request_payload_) {
|
||||
grpc_byte_buffer_destroy(request_payload_);
|
||||
}
|
||||
if (call_details_ != nullptr) {
|
||||
grpc_call_details_destroy(call_details_);
|
||||
delete call_details_;
|
||||
}
|
||||
grpc_metadata_array_destroy(&request_metadata_);
|
||||
server_->UnrefWithPossibleNotify();
|
||||
}
|
||||
|
||||
bool FinalizeResult(void** /*tag*/, bool* status) override {
|
||||
if (!*status) {
|
||||
delete this;
|
||||
return false;
|
||||
}
|
||||
if (call_details_) {
|
||||
deadline_ = call_details_->deadline;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Run(const std::shared_ptr<GlobalCallbacks>& global_callbacks,
|
||||
bool resources) {
|
||||
ctx_.Init(deadline_, &request_metadata_);
|
||||
wrapped_call_.Init(
|
||||
call_, server_, &cq_, server_->max_receive_message_size(),
|
||||
ctx_->ctx.set_server_rpc_info(method_->name(), method_->method_type(),
|
||||
server_->interceptor_creators_));
|
||||
ctx_->ctx.set_call(call_, server_->call_metric_recording_enabled(),
|
||||
server_->server_metric_recorder());
|
||||
ctx_->ctx.cq_ = &cq_;
|
||||
request_metadata_.count = 0;
|
||||
|
||||
global_callbacks_ = global_callbacks;
|
||||
resources_ = resources;
|
||||
|
||||
interceptor_methods_.SetCall(&*wrapped_call_);
|
||||
interceptor_methods_.SetReverse();
|
||||
// Set interception point for RECV INITIAL METADATA
|
||||
interceptor_methods_.AddInterceptionHookPoint(
|
||||
grpc::experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
|
||||
interceptor_methods_.SetRecvInitialMetadata(&ctx_->ctx.client_metadata_);
|
||||
|
||||
if (has_request_payload_) {
|
||||
// Set interception point for RECV MESSAGE
|
||||
auto* handler = resources_ ? method_->handler()
|
||||
: server_->resource_exhausted_handler_.get();
|
||||
deserialized_request_ = handler->Deserialize(call_, request_payload_,
|
||||
&request_status_, nullptr);
|
||||
if (!request_status_.ok()) {
|
||||
gpr_log(GPR_DEBUG, "Failed to deserialize message.");
|
||||
}
|
||||
request_payload_ = nullptr;
|
||||
interceptor_methods_.AddInterceptionHookPoint(
|
||||
grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
|
||||
interceptor_methods_.SetRecvMessage(deserialized_request_, nullptr);
|
||||
}
|
||||
|
||||
if (interceptor_methods_.RunInterceptors(
|
||||
[this]() { ContinueRunAfterInterception(); })) {
|
||||
ContinueRunAfterInterception();
|
||||
} else {
|
||||
// There were interceptors to be run, so ContinueRunAfterInterception
|
||||
// will be run when interceptors are done.
|
||||
}
|
||||
}
|
||||
|
||||
void ContinueRunAfterInterception() {
|
||||
ctx_->ctx.BeginCompletionOp(&*wrapped_call_, nullptr, nullptr);
|
||||
global_callbacks_->PreSynchronousRequest(&ctx_->ctx);
|
||||
auto* handler = resources_ ? method_->handler()
|
||||
: server_->resource_exhausted_handler_.get();
|
||||
handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
|
||||
&*wrapped_call_, &ctx_->ctx, deserialized_request_, request_status_,
|
||||
nullptr, nullptr));
|
||||
global_callbacks_->PostSynchronousRequest(&ctx_->ctx);
|
||||
|
||||
cq_.Shutdown();
|
||||
|
||||
grpc::internal::CompletionQueueTag* op_tag = ctx_->ctx.GetCompletionOpTag();
|
||||
cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME));
|
||||
|
||||
// Ensure the cq_ is shutdown
|
||||
grpc::PhonyTag ignored_tag;
|
||||
GPR_ASSERT(cq_.Pluck(&ignored_tag) == false);
|
||||
|
||||
// Cleanup structures allocated during Run/ContinueRunAfterInterception
|
||||
wrapped_call_.Destroy();
|
||||
ctx_.Destroy();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
// For requests that must be only cleaned up but not actually Run
|
||||
void Cleanup() {
|
||||
cq_.Shutdown();
|
||||
grpc_call_unref(call_);
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
SyncRequest(Server* server, grpc::internal::RpcServiceMethod* method)
|
||||
: server_(server),
|
||||
method_(method),
|
||||
has_request_payload_(method->method_type() ==
|
||||
grpc::internal::RpcMethod::NORMAL_RPC ||
|
||||
method->method_type() ==
|
||||
grpc::internal::RpcMethod::SERVER_STREAMING),
|
||||
cq_(grpc_completion_queue_create_for_pluck(nullptr)) {}
|
||||
|
||||
template <class CallAllocation>
|
||||
void CommonSetup(CallAllocation* data) {
|
||||
server_->Ref();
|
||||
grpc_metadata_array_init(&request_metadata_);
|
||||
data->tag = static_cast<void*>(this);
|
||||
data->call = &call_;
|
||||
data->initial_metadata = &request_metadata_;
|
||||
data->cq = cq_.cq();
|
||||
}
|
||||
|
||||
Server* const server_;
|
||||
grpc::internal::RpcServiceMethod* const method_;
|
||||
const bool has_request_payload_;
|
||||
grpc_call* call_;
|
||||
grpc_call_details* call_details_ = nullptr;
|
||||
gpr_timespec deadline_;
|
||||
grpc_metadata_array request_metadata_;
|
||||
grpc_byte_buffer* request_payload_ = nullptr;
|
||||
grpc::CompletionQueue cq_;
|
||||
grpc::Status request_status_;
|
||||
std::shared_ptr<GlobalCallbacks> global_callbacks_;
|
||||
bool resources_;
|
||||
void* deserialized_request_ = nullptr;
|
||||
grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
|
||||
|
||||
// ServerContextWrapper allows ManualConstructor while using a private
|
||||
// contructor of ServerContext via this friend class.
|
||||
struct ServerContextWrapper {
|
||||
ServerContext ctx;
|
||||
|
||||
ServerContextWrapper(gpr_timespec deadline, grpc_metadata_array* arr)
|
||||
: ctx(deadline, arr) {}
|
||||
};
|
||||
|
||||
grpc_core::ManualConstructor<ServerContextWrapper> ctx_;
|
||||
grpc_core::ManualConstructor<internal::Call> wrapped_call_;
|
||||
};
|
||||
|
||||
template <class ServerContextType>
|
||||
class Server::CallbackRequest final
|
||||
: public grpc::internal::CompletionQueueTag {
|
||||
public:
|
||||
static_assert(
|
||||
std::is_base_of<grpc::CallbackServerContext, ServerContextType>::value,
|
||||
"ServerContextType must be derived from CallbackServerContext");
|
||||
|
||||
// For codegen services, the value of method represents the defined
|
||||
// characteristics of the method being requested. For generic services, method
|
||||
// is nullptr since these services don't have pre-defined methods.
|
||||
CallbackRequest(Server* server, grpc::internal::RpcServiceMethod* method,
|
||||
grpc::CompletionQueue* cq,
|
||||
grpc_core::Server::RegisteredCallAllocation* data)
|
||||
: server_(server),
|
||||
method_(method),
|
||||
has_request_payload_(method->method_type() ==
|
||||
grpc::internal::RpcMethod::NORMAL_RPC ||
|
||||
method->method_type() ==
|
||||
grpc::internal::RpcMethod::SERVER_STREAMING),
|
||||
cq_(cq),
|
||||
tag_(this),
|
||||
ctx_(server_->context_allocator() != nullptr
|
||||
? server_->context_allocator()->NewCallbackServerContext()
|
||||
: nullptr) {
|
||||
CommonSetup(server, data);
|
||||
data->deadline = &deadline_;
|
||||
data->optional_payload = has_request_payload_ ? &request_payload_ : nullptr;
|
||||
}
|
||||
|
||||
// For generic services, method is nullptr since these services don't have
|
||||
// pre-defined methods.
|
||||
CallbackRequest(Server* server, grpc::CompletionQueue* cq,
|
||||
grpc_core::Server::BatchCallAllocation* data)
|
||||
: server_(server),
|
||||
method_(nullptr),
|
||||
has_request_payload_(false),
|
||||
call_details_(new grpc_call_details),
|
||||
cq_(cq),
|
||||
tag_(this),
|
||||
ctx_(server_->context_allocator() != nullptr
|
||||
? server_->context_allocator()
|
||||
->NewGenericCallbackServerContext()
|
||||
: nullptr) {
|
||||
CommonSetup(server, data);
|
||||
grpc_call_details_init(call_details_);
|
||||
data->details = call_details_;
|
||||
}
|
||||
|
||||
~CallbackRequest() override {
|
||||
delete call_details_;
|
||||
grpc_metadata_array_destroy(&request_metadata_);
|
||||
if (has_request_payload_ && request_payload_) {
|
||||
grpc_byte_buffer_destroy(request_payload_);
|
||||
}
|
||||
if (ctx_alloc_by_default_ || server_->context_allocator() == nullptr) {
|
||||
default_ctx_.Destroy();
|
||||
}
|
||||
server_->UnrefWithPossibleNotify();
|
||||
}
|
||||
|
||||
// Needs specialization to account for different processing of metadata
|
||||
// in generic API
|
||||
bool FinalizeResult(void** tag, bool* status) override;
|
||||
|
||||
private:
|
||||
// method_name needs to be specialized between named method and generic
|
||||
const char* method_name() const;
|
||||
|
||||
class CallbackCallTag : public grpc_completion_queue_functor {
|
||||
public:
|
||||
explicit CallbackCallTag(Server::CallbackRequest<ServerContextType>* req)
|
||||
: req_(req) {
|
||||
functor_run = &CallbackCallTag::StaticRun;
|
||||
// Set inlineable to true since this callback is internally-controlled
|
||||
// without taking any locks, and thus does not need to be run from the
|
||||
// executor (which triggers a thread hop). This should only be used by
|
||||
// internal callbacks like this and not by user application code. The work
|
||||
// here is actually non-trivial, but there is no chance of having user
|
||||
// locks conflict with each other so it's ok to run inlined.
|
||||
inlineable = true;
|
||||
}
|
||||
|
||||
// force_run can not be performed on a tag if operations using this tag
|
||||
// have been sent to PerformOpsOnCall. It is intended for error conditions
|
||||
// that are detected before the operations are internally processed.
|
||||
void force_run(bool ok) { Run(ok); }
|
||||
|
||||
private:
|
||||
Server::CallbackRequest<ServerContextType>* req_;
|
||||
grpc::internal::Call* call_;
|
||||
|
||||
static void StaticRun(grpc_completion_queue_functor* cb, int ok) {
|
||||
static_cast<CallbackCallTag*>(cb)->Run(static_cast<bool>(ok));
|
||||
}
|
||||
void Run(bool ok) {
|
||||
void* ignored = req_;
|
||||
bool new_ok = ok;
|
||||
GPR_ASSERT(!req_->FinalizeResult(&ignored, &new_ok));
|
||||
GPR_ASSERT(ignored == req_);
|
||||
|
||||
if (!ok) {
|
||||
// The call has been shutdown.
|
||||
// Delete its contents to free up the request.
|
||||
delete req_;
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind the call, deadline, and metadata from what we got
|
||||
req_->ctx_->set_call(req_->call_,
|
||||
req_->server_->call_metric_recording_enabled(),
|
||||
req_->server_->server_metric_recorder());
|
||||
req_->ctx_->cq_ = req_->cq_;
|
||||
req_->ctx_->BindDeadlineAndMetadata(req_->deadline_,
|
||||
&req_->request_metadata_);
|
||||
req_->request_metadata_.count = 0;
|
||||
|
||||
// Create a C++ Call to control the underlying core call
|
||||
call_ =
|
||||
new (grpc_call_arena_alloc(req_->call_, sizeof(grpc::internal::Call)))
|
||||
grpc::internal::Call(
|
||||
req_->call_, req_->server_, req_->cq_,
|
||||
req_->server_->max_receive_message_size(),
|
||||
req_->ctx_->set_server_rpc_info(
|
||||
req_->method_name(),
|
||||
(req_->method_ != nullptr)
|
||||
? req_->method_->method_type()
|
||||
: grpc::internal::RpcMethod::BIDI_STREAMING,
|
||||
req_->server_->interceptor_creators_));
|
||||
|
||||
req_->interceptor_methods_.SetCall(call_);
|
||||
req_->interceptor_methods_.SetReverse();
|
||||
// Set interception point for RECV INITIAL METADATA
|
||||
req_->interceptor_methods_.AddInterceptionHookPoint(
|
||||
grpc::experimental::InterceptionHookPoints::
|
||||
POST_RECV_INITIAL_METADATA);
|
||||
req_->interceptor_methods_.SetRecvInitialMetadata(
|
||||
&req_->ctx_->client_metadata_);
|
||||
|
||||
if (req_->has_request_payload_) {
|
||||
// Set interception point for RECV MESSAGE
|
||||
req_->request_ = req_->method_->handler()->Deserialize(
|
||||
req_->call_, req_->request_payload_, &req_->request_status_,
|
||||
&req_->handler_data_);
|
||||
if (!(req_->request_status_.ok())) {
|
||||
gpr_log(GPR_DEBUG, "Failed to deserialize message.");
|
||||
}
|
||||
req_->request_payload_ = nullptr;
|
||||
req_->interceptor_methods_.AddInterceptionHookPoint(
|
||||
grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
|
||||
req_->interceptor_methods_.SetRecvMessage(req_->request_, nullptr);
|
||||
}
|
||||
|
||||
if (req_->interceptor_methods_.RunInterceptors(
|
||||
[this] { ContinueRunAfterInterception(); })) {
|
||||
ContinueRunAfterInterception();
|
||||
} else {
|
||||
// There were interceptors to be run, so ContinueRunAfterInterception
|
||||
// will be run when interceptors are done.
|
||||
}
|
||||
}
|
||||
void ContinueRunAfterInterception() {
|
||||
auto* handler = (req_->method_ != nullptr)
|
||||
? req_->method_->handler()
|
||||
: req_->server_->generic_handler_.get();
|
||||
handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter(
|
||||
call_, req_->ctx_, req_->request_, req_->request_status_,
|
||||
req_->handler_data_, [this] { delete req_; }));
|
||||
}
|
||||
};
|
||||
|
||||
template <class CallAllocation>
|
||||
void CommonSetup(Server* server, CallAllocation* data) {
|
||||
server->Ref();
|
||||
grpc_metadata_array_init(&request_metadata_);
|
||||
data->tag = static_cast<void*>(&tag_);
|
||||
data->call = &call_;
|
||||
data->initial_metadata = &request_metadata_;
|
||||
if (ctx_ == nullptr) {
|
||||
default_ctx_.Init();
|
||||
ctx_ = &*default_ctx_;
|
||||
ctx_alloc_by_default_ = true;
|
||||
}
|
||||
ctx_->set_context_allocator(server->context_allocator());
|
||||
data->cq = cq_->cq();
|
||||
}
|
||||
|
||||
Server* const server_;
|
||||
grpc::internal::RpcServiceMethod* const method_;
|
||||
const bool has_request_payload_;
|
||||
grpc_byte_buffer* request_payload_ = nullptr;
|
||||
void* request_ = nullptr;
|
||||
void* handler_data_ = nullptr;
|
||||
grpc::Status request_status_;
|
||||
grpc_call_details* const call_details_ = nullptr;
|
||||
grpc_call* call_;
|
||||
gpr_timespec deadline_;
|
||||
grpc_metadata_array request_metadata_;
|
||||
grpc::CompletionQueue* const cq_;
|
||||
bool ctx_alloc_by_default_ = false;
|
||||
CallbackCallTag tag_;
|
||||
ServerContextType* ctx_ = nullptr;
|
||||
grpc_core::ManualConstructor<ServerContextType> default_ctx_;
|
||||
grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
|
||||
};
|
||||
|
||||
template <>
|
||||
bool Server::CallbackRequest<grpc::CallbackServerContext>::FinalizeResult(
|
||||
void** /*tag*/, bool* /*status*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Server::CallbackRequest<
|
||||
grpc::GenericCallbackServerContext>::FinalizeResult(void** /*tag*/,
|
||||
bool* status) {
|
||||
if (*status) {
|
||||
deadline_ = call_details_->deadline;
|
||||
// TODO(yangg) remove the copy here
|
||||
ctx_->method_ = grpc::StringFromCopiedSlice(call_details_->method);
|
||||
ctx_->host_ = grpc::StringFromCopiedSlice(call_details_->host);
|
||||
}
|
||||
grpc_slice_unref(call_details_->method);
|
||||
grpc_slice_unref(call_details_->host);
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* Server::CallbackRequest<grpc::CallbackServerContext>::method_name()
|
||||
const {
|
||||
return method_->name();
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* Server::CallbackRequest<
|
||||
grpc::GenericCallbackServerContext>::method_name() const {
|
||||
return ctx_->method().c_str();
|
||||
}
|
||||
|
||||
// Implementation of ThreadManager. Each instance of SyncRequestThreadManager
|
||||
// manages a pool of threads that poll for incoming Sync RPCs and call the
|
||||
// appropriate RPC handlers
|
||||
class Server::SyncRequestThreadManager : public grpc::ThreadManager {
|
||||
public:
|
||||
SyncRequestThreadManager(Server* server, grpc::CompletionQueue* server_cq,
|
||||
std::shared_ptr<GlobalCallbacks> global_callbacks,
|
||||
grpc_resource_quota* rq, int min_pollers,
|
||||
int max_pollers, int cq_timeout_msec)
|
||||
: ThreadManager("SyncServer", rq, min_pollers, max_pollers),
|
||||
server_(server),
|
||||
server_cq_(server_cq),
|
||||
cq_timeout_msec_(cq_timeout_msec),
|
||||
global_callbacks_(std::move(global_callbacks)) {}
|
||||
|
||||
WorkStatus PollForWork(void** tag, bool* ok) override {
|
||||
*tag = nullptr;
|
||||
// TODO(ctiller): workaround for GPR_TIMESPAN based deadlines not working
|
||||
// right now
|
||||
gpr_timespec deadline =
|
||||
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN));
|
||||
|
||||
switch (server_cq_->AsyncNext(tag, ok, deadline)) {
|
||||
case grpc::CompletionQueue::TIMEOUT:
|
||||
return TIMEOUT;
|
||||
case grpc::CompletionQueue::SHUTDOWN:
|
||||
return SHUTDOWN;
|
||||
case grpc::CompletionQueue::GOT_EVENT:
|
||||
return WORK_FOUND;
|
||||
}
|
||||
|
||||
GPR_UNREACHABLE_CODE(return TIMEOUT);
|
||||
}
|
||||
|
||||
void DoWork(void* tag, bool ok, bool resources) override {
|
||||
(void)ok;
|
||||
SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
|
||||
|
||||
// Under the AllocatingRequestMatcher model we will never see an invalid tag
|
||||
// here.
|
||||
GPR_DEBUG_ASSERT(sync_req != nullptr);
|
||||
GPR_DEBUG_ASSERT(ok);
|
||||
|
||||
sync_req->Run(global_callbacks_, resources);
|
||||
}
|
||||
|
||||
void AddSyncMethod(grpc::internal::RpcServiceMethod* method, void* tag) {
|
||||
grpc_core::Server::FromC(server_->server())
|
||||
->SetRegisteredMethodAllocator(server_cq_->cq(), tag, [this, method] {
|
||||
grpc_core::Server::RegisteredCallAllocation result;
|
||||
new SyncRequest(server_, method, &result);
|
||||
return result;
|
||||
});
|
||||
has_sync_method_ = true;
|
||||
}
|
||||
|
||||
void AddUnknownSyncMethod() {
|
||||
if (has_sync_method_) {
|
||||
unknown_method_ = std::make_unique<grpc::internal::RpcServiceMethod>(
|
||||
"unknown", grpc::internal::RpcMethod::BIDI_STREAMING,
|
||||
new grpc::internal::UnknownMethodHandler(kUnknownRpcMethod));
|
||||
grpc_core::Server::FromC(server_->server())
|
||||
->SetBatchMethodAllocator(server_cq_->cq(), [this] {
|
||||
grpc_core::Server::BatchCallAllocation result;
|
||||
new SyncRequest(server_, unknown_method_.get(), &result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown() override {
|
||||
ThreadManager::Shutdown();
|
||||
server_cq_->Shutdown();
|
||||
}
|
||||
|
||||
void Wait() override {
|
||||
ThreadManager::Wait();
|
||||
// Drain any pending items from the queue
|
||||
void* tag;
|
||||
bool ok;
|
||||
while (server_cq_->Next(&tag, &ok)) {
|
||||
// This problem can arise if the server CQ gets a request queued to it
|
||||
// before it gets shutdown but then pulls it after shutdown.
|
||||
static_cast<SyncRequest*>(tag)->Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void Start() {
|
||||
if (has_sync_method_) {
|
||||
Initialize(); // ThreadManager's Initialize()
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Server* server_;
|
||||
grpc::CompletionQueue* server_cq_;
|
||||
int cq_timeout_msec_;
|
||||
bool has_sync_method_ = false;
|
||||
std::unique_ptr<grpc::internal::RpcServiceMethod> unknown_method_;
|
||||
std::shared_ptr<Server::GlobalCallbacks> global_callbacks_;
|
||||
};
|
||||
|
||||
Server::Server(
|
||||
grpc::ChannelArguments* args,
|
||||
std::shared_ptr<std::vector<std::unique_ptr<grpc::ServerCompletionQueue>>>
|
||||
sync_server_cqs,
|
||||
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
|
||||
std::vector<std::shared_ptr<grpc::internal::ExternalConnectionAcceptorImpl>>
|
||||
acceptors,
|
||||
grpc_server_config_fetcher* server_config_fetcher,
|
||||
grpc_resource_quota* server_rq,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ServerInterceptorFactoryInterface>>
|
||||
interceptor_creators,
|
||||
experimental::ServerMetricRecorder* server_metric_recorder)
|
||||
: acceptors_(std::move(acceptors)),
|
||||
interceptor_creators_(std::move(interceptor_creators)),
|
||||
max_receive_message_size_(INT_MIN),
|
||||
sync_server_cqs_(std::move(sync_server_cqs)),
|
||||
started_(false),
|
||||
shutdown_(false),
|
||||
shutdown_notified_(false),
|
||||
server_(nullptr),
|
||||
server_initializer_(new ServerInitializer(this)),
|
||||
health_check_service_disabled_(false),
|
||||
server_metric_recorder_(server_metric_recorder) {
|
||||
gpr_once_init(&grpc::g_once_init_callbacks, grpc::InitGlobalCallbacks);
|
||||
global_callbacks_ = grpc::g_callbacks;
|
||||
global_callbacks_->UpdateArguments(args);
|
||||
|
||||
if (sync_server_cqs_ != nullptr) {
|
||||
bool default_rq_created = false;
|
||||
if (server_rq == nullptr) {
|
||||
server_rq = grpc_resource_quota_create("SyncServer-default-rq");
|
||||
grpc_resource_quota_set_max_threads(server_rq,
|
||||
DEFAULT_MAX_SYNC_SERVER_THREADS);
|
||||
default_rq_created = true;
|
||||
}
|
||||
|
||||
for (const auto& it : *sync_server_cqs_) {
|
||||
sync_req_mgrs_.emplace_back(new SyncRequestThreadManager(
|
||||
this, it.get(), global_callbacks_, server_rq, min_pollers,
|
||||
max_pollers, sync_cq_timeout_msec));
|
||||
}
|
||||
|
||||
if (default_rq_created) {
|
||||
grpc_resource_quota_unref(server_rq);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& acceptor : acceptors_) {
|
||||
acceptor->SetToChannelArgs(args);
|
||||
}
|
||||
|
||||
grpc_channel_args channel_args;
|
||||
args->SetChannelArgs(&channel_args);
|
||||
|
||||
for (size_t i = 0; i < channel_args.num_args; i++) {
|
||||
if (0 == strcmp(channel_args.args[i].key,
|
||||
grpc::kHealthCheckServiceInterfaceArg)) {
|
||||
if (channel_args.args[i].value.pointer.p == nullptr) {
|
||||
health_check_service_disabled_ = true;
|
||||
} else {
|
||||
health_check_service_.reset(
|
||||
static_cast<grpc::HealthCheckServiceInterface*>(
|
||||
channel_args.args[i].value.pointer.p));
|
||||
}
|
||||
}
|
||||
if (0 ==
|
||||
strcmp(channel_args.args[i].key, GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH)) {
|
||||
max_receive_message_size_ = channel_args.args[i].value.integer;
|
||||
}
|
||||
if (0 == strcmp(channel_args.args[i].key,
|
||||
GRPC_ARG_SERVER_CALL_METRIC_RECORDING)) {
|
||||
call_metric_recording_enabled_ = channel_args.args[i].value.integer;
|
||||
}
|
||||
}
|
||||
server_ = grpc_server_create(&channel_args, nullptr);
|
||||
grpc_server_set_config_fetcher(server_, server_config_fetcher);
|
||||
}
|
||||
|
||||
Server::~Server() {
|
||||
{
|
||||
grpc::internal::ReleasableMutexLock lock(&mu_);
|
||||
if (started_ && !shutdown_) {
|
||||
lock.Release();
|
||||
Shutdown();
|
||||
} else if (!started_) {
|
||||
// Shutdown the completion queues
|
||||
for (const auto& value : sync_req_mgrs_) {
|
||||
value->Shutdown();
|
||||
}
|
||||
CompletionQueue* callback_cq =
|
||||
callback_cq_.load(std::memory_order_relaxed);
|
||||
if (callback_cq != nullptr) {
|
||||
if (grpc_iomgr_run_in_background()) {
|
||||
// gRPC-core provides the backing needed for the preferred CQ type
|
||||
callback_cq->Shutdown();
|
||||
} else {
|
||||
CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
|
||||
}
|
||||
callback_cq_.store(nullptr, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Destroy health check service before we destroy the C server so that
|
||||
// it does not call grpc_server_request_registered_call() after the C
|
||||
// server has been destroyed.
|
||||
health_check_service_.reset();
|
||||
grpc_server_destroy(server_);
|
||||
}
|
||||
|
||||
void Server::SetGlobalCallbacks(GlobalCallbacks* callbacks) {
|
||||
GPR_ASSERT(!grpc::g_callbacks);
|
||||
GPR_ASSERT(callbacks);
|
||||
grpc::g_callbacks.reset(callbacks);
|
||||
}
|
||||
|
||||
grpc_server* Server::c_server() { return server_; }
|
||||
|
||||
std::shared_ptr<grpc::Channel> Server::InProcessChannel(
|
||||
const grpc::ChannelArguments& args) {
|
||||
grpc_channel_args channel_args = args.c_channel_args();
|
||||
return grpc::CreateChannelInternal(
|
||||
"inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr),
|
||||
std::vector<std::unique_ptr<
|
||||
grpc::experimental::ClientInterceptorFactoryInterface>>());
|
||||
}
|
||||
|
||||
std::shared_ptr<grpc::Channel>
|
||||
Server::experimental_type::InProcessChannelWithInterceptors(
|
||||
const grpc::ChannelArguments& args,
|
||||
std::vector<
|
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
||||
interceptor_creators) {
|
||||
grpc_channel_args channel_args = args.c_channel_args();
|
||||
return grpc::CreateChannelInternal(
|
||||
"inproc",
|
||||
grpc_inproc_channel_create(server_->server_, &channel_args, nullptr),
|
||||
std::move(interceptor_creators));
|
||||
}
|
||||
|
||||
static grpc_server_register_method_payload_handling PayloadHandlingForMethod(
|
||||
grpc::internal::RpcServiceMethod* method) {
|
||||
switch (method->method_type()) {
|
||||
case grpc::internal::RpcMethod::NORMAL_RPC:
|
||||
case grpc::internal::RpcMethod::SERVER_STREAMING:
|
||||
return GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER;
|
||||
case grpc::internal::RpcMethod::CLIENT_STREAMING:
|
||||
case grpc::internal::RpcMethod::BIDI_STREAMING:
|
||||
return GRPC_SRM_PAYLOAD_NONE;
|
||||
}
|
||||
GPR_UNREACHABLE_CODE(return GRPC_SRM_PAYLOAD_NONE;);
|
||||
}
|
||||
|
||||
bool Server::RegisterService(const std::string* addr, grpc::Service* service) {
|
||||
bool has_async_methods = service->has_async_methods();
|
||||
if (has_async_methods) {
|
||||
GPR_ASSERT(service->server_ == nullptr &&
|
||||
"Can only register an asynchronous service against one server.");
|
||||
service->server_ = this;
|
||||
}
|
||||
|
||||
const char* method_name = nullptr;
|
||||
|
||||
for (const auto& method : service->methods_) {
|
||||
if (method == nullptr) { // Handled by generic service if any.
|
||||
continue;
|
||||
}
|
||||
|
||||
void* method_registration_tag = grpc_server_register_method(
|
||||
server_, method->name(), addr ? addr->c_str() : nullptr,
|
||||
PayloadHandlingForMethod(method.get()), 0);
|
||||
if (method_registration_tag == nullptr) {
|
||||
gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
|
||||
method->name());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method->handler() == nullptr) { // Async method without handler
|
||||
method->set_server_tag(method_registration_tag);
|
||||
} else if (method->api_type() ==
|
||||
grpc::internal::RpcServiceMethod::ApiType::SYNC) {
|
||||
for (const auto& value : sync_req_mgrs_) {
|
||||
value->AddSyncMethod(method.get(), method_registration_tag);
|
||||
}
|
||||
} else {
|
||||
has_callback_methods_ = true;
|
||||
grpc::internal::RpcServiceMethod* method_value = method.get();
|
||||
grpc::CompletionQueue* cq = CallbackCQ();
|
||||
grpc_server_register_completion_queue(server_, cq->cq(), nullptr);
|
||||
grpc_core::Server::FromC(server_)->SetRegisteredMethodAllocator(
|
||||
cq->cq(), method_registration_tag, [this, cq, method_value] {
|
||||
grpc_core::Server::RegisteredCallAllocation result;
|
||||
new CallbackRequest<grpc::CallbackServerContext>(this, method_value,
|
||||
cq, &result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
method_name = method->name();
|
||||
}
|
||||
|
||||
// Parse service name.
|
||||
if (method_name != nullptr) {
|
||||
std::stringstream ss(method_name);
|
||||
std::string service_name;
|
||||
if (std::getline(ss, service_name, '/') &&
|
||||
std::getline(ss, service_name, '/')) {
|
||||
services_.push_back(service_name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Server::RegisterAsyncGenericService(grpc::AsyncGenericService* service) {
|
||||
GPR_ASSERT(service->server_ == nullptr &&
|
||||
"Can only register an async generic service against one server.");
|
||||
service->server_ = this;
|
||||
has_async_generic_service_ = true;
|
||||
}
|
||||
|
||||
void Server::RegisterCallbackGenericService(
|
||||
grpc::CallbackGenericService* service) {
|
||||
GPR_ASSERT(
|
||||
service->server_ == nullptr &&
|
||||
"Can only register a callback generic service against one server.");
|
||||
service->server_ = this;
|
||||
has_callback_generic_service_ = true;
|
||||
generic_handler_.reset(service->Handler());
|
||||
|
||||
grpc::CompletionQueue* cq = CallbackCQ();
|
||||
grpc_core::Server::FromC(server_)->SetBatchMethodAllocator(cq->cq(), [this,
|
||||
cq] {
|
||||
grpc_core::Server::BatchCallAllocation result;
|
||||
new CallbackRequest<grpc::GenericCallbackServerContext>(this, cq, &result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
int Server::AddListeningPort(const std::string& addr,
|
||||
grpc::ServerCredentials* creds) {
|
||||
GPR_ASSERT(!started_);
|
||||
int port = creds->AddPortToServer(addr, server_);
|
||||
global_callbacks_->AddPort(this, addr, creds, port);
|
||||
return port;
|
||||
}
|
||||
|
||||
void Server::Ref() {
|
||||
shutdown_refs_outstanding_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Server::UnrefWithPossibleNotify() {
|
||||
if (GPR_UNLIKELY(shutdown_refs_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
// No refs outstanding means that shutdown has been initiated and no more
|
||||
// callback requests are outstanding.
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
GPR_ASSERT(shutdown_);
|
||||
shutdown_done_ = true;
|
||||
shutdown_done_cv_.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::UnrefAndWaitLocked() {
|
||||
if (GPR_UNLIKELY(shutdown_refs_outstanding_.fetch_sub(
|
||||
1, std::memory_order_acq_rel) == 1)) {
|
||||
shutdown_done_ = true;
|
||||
return; // no need to wait on CV since done condition already set
|
||||
}
|
||||
while (!shutdown_done_) {
|
||||
shutdown_done_cv_.Wait(&mu_);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
|
||||
GPR_ASSERT(!started_);
|
||||
global_callbacks_->PreServerStart(this);
|
||||
started_ = true;
|
||||
|
||||
// Only create default health check service when user did not provide an
|
||||
// explicit one.
|
||||
if (health_check_service_ == nullptr && !health_check_service_disabled_ &&
|
||||
grpc::DefaultHealthCheckServiceEnabled()) {
|
||||
auto default_hc_service = std::make_unique<DefaultHealthCheckService>();
|
||||
auto* hc_service_impl = default_hc_service->GetHealthCheckService();
|
||||
health_check_service_ = std::move(default_hc_service);
|
||||
RegisterService(nullptr, hc_service_impl);
|
||||
}
|
||||
|
||||
for (auto& acceptor : acceptors_) {
|
||||
acceptor->GetCredentials()->AddPortToServer(acceptor->name(), server_);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 0; i < num_cqs; i++) {
|
||||
cq_list_.push_back(cqs[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// We must have exactly one generic service to handle requests for
|
||||
// unmatched method names (i.e., to return UNIMPLEMENTED for any RPC
|
||||
// method for which we don't have a registered implementation). This
|
||||
// service comes from one of the following places (first match wins):
|
||||
// - If the application supplied a generic service via either the async
|
||||
// or callback APIs, we use that.
|
||||
// - If there are callback methods, register a callback generic service.
|
||||
// - If there are sync methods, register a sync generic service.
|
||||
// (This must be done before server start to initialize an
|
||||
// AllocatingRequestMatcher.)
|
||||
// - Otherwise (we have only async methods), we wait until the server
|
||||
// is started and then start an UnimplementedAsyncRequest on each
|
||||
// async CQ, so that the requests will be moved along by polling
|
||||
// done in application threads.
|
||||
bool unknown_rpc_needed =
|
||||
!has_async_generic_service_ && !has_callback_generic_service_;
|
||||
if (unknown_rpc_needed && has_callback_methods_) {
|
||||
unimplemented_service_ = std::make_unique<grpc::CallbackGenericService>();
|
||||
RegisterCallbackGenericService(unimplemented_service_.get());
|
||||
unknown_rpc_needed = false;
|
||||
}
|
||||
if (unknown_rpc_needed && !sync_req_mgrs_.empty()) {
|
||||
sync_req_mgrs_[0]->AddUnknownSyncMethod();
|
||||
unknown_rpc_needed = false;
|
||||
}
|
||||
|
||||
grpc_server_start(server_);
|
||||
|
||||
if (unknown_rpc_needed) {
|
||||
for (size_t i = 0; i < num_cqs; i++) {
|
||||
if (cqs[i]->IsFrequentlyPolled()) {
|
||||
new UnimplementedAsyncRequest(this, cqs[i]);
|
||||
}
|
||||
}
|
||||
unknown_rpc_needed = false;
|
||||
}
|
||||
|
||||
// If this server has any support for synchronous methods (has any sync
|
||||
// server CQs), make sure that we have a ResourceExhausted handler
|
||||
// to deal with the case of thread exhaustion
|
||||
if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) {
|
||||
resource_exhausted_handler_ =
|
||||
std::make_unique<grpc::internal::ResourceExhaustedHandler>(
|
||||
kServerThreadpoolExhausted);
|
||||
}
|
||||
|
||||
for (const auto& value : sync_req_mgrs_) {
|
||||
value->Start();
|
||||
}
|
||||
|
||||
for (auto& acceptor : acceptors_) {
|
||||
acceptor->Start();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::ShutdownInternal(gpr_timespec deadline) {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
if (shutdown_) {
|
||||
return;
|
||||
}
|
||||
|
||||
shutdown_ = true;
|
||||
|
||||
for (auto& acceptor : acceptors_) {
|
||||
acceptor->Shutdown();
|
||||
}
|
||||
|
||||
/// The completion queue to use for server shutdown completion notification
|
||||
grpc::CompletionQueue shutdown_cq;
|
||||
grpc::ShutdownTag shutdown_tag; // Phony shutdown tag
|
||||
grpc_server_shutdown_and_notify(server_, shutdown_cq.cq(), &shutdown_tag);
|
||||
|
||||
shutdown_cq.Shutdown();
|
||||
|
||||
void* tag;
|
||||
bool ok;
|
||||
grpc::CompletionQueue::NextStatus status =
|
||||
shutdown_cq.AsyncNext(&tag, &ok, deadline);
|
||||
|
||||
// If this timed out, it means we are done with the grace period for a clean
|
||||
// shutdown. We should force a shutdown now by cancelling all inflight calls
|
||||
if (status == grpc::CompletionQueue::NextStatus::TIMEOUT) {
|
||||
grpc_server_cancel_all_calls(server_);
|
||||
status =
|
||||
shutdown_cq.AsyncNext(&tag, &ok, gpr_inf_future(GPR_CLOCK_MONOTONIC));
|
||||
}
|
||||
// Else in case of SHUTDOWN or GOT_EVENT, it means that the server has
|
||||
// successfully shutdown
|
||||
|
||||
// Drop the shutdown ref and wait for all other refs to drop as well.
|
||||
UnrefAndWaitLocked();
|
||||
|
||||
// Shutdown all ThreadManagers. This will try to gracefully stop all the
|
||||
// threads in the ThreadManagers (once they process any inflight requests)
|
||||
for (const auto& value : sync_req_mgrs_) {
|
||||
value->Shutdown(); // ThreadManager's Shutdown()
|
||||
}
|
||||
|
||||
// Wait for threads in all ThreadManagers to terminate
|
||||
for (const auto& value : sync_req_mgrs_) {
|
||||
value->Wait();
|
||||
}
|
||||
|
||||
// Shutdown the callback CQ. The CQ is owned by its own shutdown tag, so it
|
||||
// will delete itself at true shutdown.
|
||||
CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_relaxed);
|
||||
if (callback_cq != nullptr) {
|
||||
if (grpc_iomgr_run_in_background()) {
|
||||
// gRPC-core provides the backing needed for the preferred CQ type
|
||||
callback_cq->Shutdown();
|
||||
} else {
|
||||
CompletionQueue::ReleaseCallbackAlternativeCQ(callback_cq);
|
||||
}
|
||||
callback_cq_.store(nullptr, std::memory_order_release);
|
||||
}
|
||||
|
||||
// Drain the shutdown queue (if the previous call to AsyncNext() timed out
|
||||
// and we didn't remove the tag from the queue yet)
|
||||
while (shutdown_cq.Next(&tag, &ok)) {
|
||||
// Nothing to be done here. Just ignore ok and tag values
|
||||
}
|
||||
|
||||
shutdown_notified_ = true;
|
||||
shutdown_cv_.SignalAll();
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Unregister this server with the CQs passed into it by the user so that
|
||||
// those can be checked for properly-ordered shutdown.
|
||||
for (auto* cq : cq_list_) {
|
||||
cq->UnregisterServer(this);
|
||||
}
|
||||
cq_list_.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Server::Wait() {
|
||||
grpc::internal::MutexLock lock(&mu_);
|
||||
while (started_ && !shutdown_notified_) {
|
||||
shutdown_cv_.Wait(&mu_);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::PerformOpsOnCall(grpc::internal::CallOpSetInterface* ops,
|
||||
grpc::internal::Call* call) {
|
||||
ops->FillOps(call);
|
||||
}
|
||||
|
||||
bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag,
|
||||
bool* status) {
|
||||
if (GenericAsyncRequest::FinalizeResult(tag, status)) {
|
||||
// We either had no interceptors run or we are done intercepting
|
||||
if (*status) {
|
||||
// Create a new request/response pair using the server and CQ values
|
||||
// stored in this object's base class.
|
||||
new UnimplementedAsyncRequest(server_, notification_cq_);
|
||||
new UnimplementedAsyncResponse(this);
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
} else {
|
||||
// The tag was swallowed due to interception. We will see it again.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse(
|
||||
UnimplementedAsyncRequest* request)
|
||||
: request_(request) {
|
||||
grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, kUnknownRpcMethod);
|
||||
grpc::internal::UnknownMethodHandler::FillOps(request_->context(),
|
||||
kUnknownRpcMethod, this);
|
||||
request_->stream()->call_.PerformOps(this);
|
||||
}
|
||||
|
||||
grpc::ServerInitializer* Server::initializer() {
|
||||
return server_initializer_.get();
|
||||
}
|
||||
|
||||
grpc::CompletionQueue* Server::CallbackCQ() {
|
||||
// TODO(vjpai): Consider using a single global CQ for the default CQ
|
||||
// if there is no explicit per-server CQ registered
|
||||
CompletionQueue* callback_cq = callback_cq_.load(std::memory_order_acquire);
|
||||
if (callback_cq != nullptr) {
|
||||
return callback_cq;
|
||||
}
|
||||
// The callback_cq_ wasn't already set, so grab a lock and set it up exactly
|
||||
// once for this server.
|
||||
grpc::internal::MutexLock l(&mu_);
|
||||
callback_cq = callback_cq_.load(std::memory_order_relaxed);
|
||||
if (callback_cq != nullptr) {
|
||||
return callback_cq;
|
||||
}
|
||||
if (grpc_iomgr_run_in_background()) {
|
||||
// gRPC-core provides the backing needed for the preferred CQ type
|
||||
auto* shutdown_callback = new grpc::ShutdownCallback;
|
||||
callback_cq = new grpc::CompletionQueue(grpc_completion_queue_attributes{
|
||||
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
|
||||
shutdown_callback});
|
||||
|
||||
// Transfer ownership of the new cq to its own shutdown callback
|
||||
shutdown_callback->TakeCQ(callback_cq);
|
||||
} else {
|
||||
// Otherwise we need to use the alternative CQ variant
|
||||
callback_cq = CompletionQueue::CallbackAlternativeCQ();
|
||||
}
|
||||
|
||||
callback_cq_.store(callback_cq, std::memory_order_release);
|
||||
return callback_cq;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
421
Pods/gRPC-C++/src/cpp/server/server_context.cc
generated
Normal file
421
Pods/gRPC-C++/src/cpp/server/server_context.cc
generated
Normal file
@@ -0,0 +1,421 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#include <grpc/compression.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/compression_types.h>
|
||||
#include <grpc/load_reporting.h>
|
||||
#include <grpc/status.h>
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/completion_queue.h>
|
||||
#include <grpcpp/ext/call_metric_recorder.h>
|
||||
#include <grpcpp/ext/server_metric_recorder.h>
|
||||
#include <grpcpp/impl/call.h>
|
||||
#include <grpcpp/impl/call_op_set.h>
|
||||
#include <grpcpp/impl/call_op_set_interface.h>
|
||||
#include <grpcpp/impl/completion_queue_tag.h>
|
||||
#include <grpcpp/impl/interceptor_common.h>
|
||||
#include <grpcpp/impl/metadata_map.h>
|
||||
#include <grpcpp/server_context.h>
|
||||
#include <grpcpp/support/callback_common.h>
|
||||
#include <grpcpp/support/interceptor.h>
|
||||
#include <grpcpp/support/server_callback.h>
|
||||
#include <grpcpp/support/server_interceptor.h>
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
#include "src/core/lib/channel/context.h"
|
||||
#include "src/core/lib/gprpp/crash.h"
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/resource_quota/arena.h"
|
||||
#include "src/core/lib/surface/call.h"
|
||||
#include "src/cpp/server/backend_metric_recorder.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// CompletionOp
|
||||
|
||||
class ServerContextBase::CompletionOp final
|
||||
: public internal::CallOpSetInterface {
|
||||
public:
|
||||
// initial refs: one in the server context, one in the cq
|
||||
// must ref the call before calling constructor and after deleting this
|
||||
CompletionOp(internal::Call* call,
|
||||
grpc::internal::ServerCallbackCall* callback_controller)
|
||||
: call_(*call),
|
||||
callback_controller_(callback_controller),
|
||||
has_tag_(false),
|
||||
tag_(nullptr),
|
||||
core_cq_tag_(this),
|
||||
refs_(2),
|
||||
finalized_(false),
|
||||
cancelled_(0),
|
||||
done_intercepting_(false) {}
|
||||
|
||||
// CompletionOp isn't copyable or movable
|
||||
CompletionOp(const CompletionOp&) = delete;
|
||||
CompletionOp& operator=(const CompletionOp&) = delete;
|
||||
CompletionOp(CompletionOp&&) = delete;
|
||||
CompletionOp& operator=(CompletionOp&&) = delete;
|
||||
|
||||
~CompletionOp() override {
|
||||
if (call_.server_rpc_info()) {
|
||||
call_.server_rpc_info()->Unref();
|
||||
}
|
||||
}
|
||||
|
||||
void FillOps(internal::Call* call) override;
|
||||
|
||||
// This should always be arena allocated in the call, so override delete.
|
||||
// But this class is not trivially destructible, so must actually call delete
|
||||
// before allowing the arena to be freed
|
||||
static void operator delete(void* /*ptr*/, std::size_t size) {
|
||||
// Use size to avoid unused-parameter warning since assert seems to be
|
||||
// compiled out and treated as unused in some gcc optimized versions.
|
||||
(void)size;
|
||||
assert(size == sizeof(CompletionOp));
|
||||
}
|
||||
|
||||
// This operator should never be called as the memory should be freed as part
|
||||
// of the arena destruction. It only exists to provide a matching operator
|
||||
// delete to the operator new so that some compilers will not complain (see
|
||||
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
|
||||
// there are no tests catching the compiler warning.
|
||||
static void operator delete(void*, void*) { assert(0); }
|
||||
|
||||
bool FinalizeResult(void** tag, bool* status) override;
|
||||
|
||||
bool CheckCancelled(CompletionQueue* cq) {
|
||||
cq->TryPluck(this);
|
||||
return CheckCancelledNoPluck();
|
||||
}
|
||||
bool CheckCancelledAsync() { return CheckCancelledNoPluck(); }
|
||||
|
||||
void set_tag(void* tag) {
|
||||
has_tag_ = true;
|
||||
tag_ = tag;
|
||||
}
|
||||
|
||||
void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; }
|
||||
|
||||
void* core_cq_tag() override { return core_cq_tag_; }
|
||||
|
||||
void Unref();
|
||||
|
||||
// This will be called while interceptors are run if the RPC is a hijacked
|
||||
// RPC. This should set hijacking state for each of the ops.
|
||||
void SetHijackingState() override {
|
||||
// Servers don't allow hijacking
|
||||
grpc_core::Crash("unreachable");
|
||||
}
|
||||
|
||||
// Should be called after interceptors are done running
|
||||
void ContinueFillOpsAfterInterception() override {}
|
||||
|
||||
// Should be called after interceptors are done running on the finalize result
|
||||
// path
|
||||
void ContinueFinalizeResultAfterInterception() override {
|
||||
done_intercepting_ = true;
|
||||
if (!has_tag_) {
|
||||
// We don't have a tag to return.
|
||||
Unref();
|
||||
// Unref can delete this, so do not access anything from this afterward.
|
||||
return;
|
||||
}
|
||||
// Start a phony op so that we can return the tag
|
||||
GPR_ASSERT(grpc_call_start_batch(call_.call(), nullptr, 0, core_cq_tag_,
|
||||
nullptr) == GRPC_CALL_OK);
|
||||
}
|
||||
|
||||
private:
|
||||
bool CheckCancelledNoPluck() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
return finalized_ ? (cancelled_ != 0) : false;
|
||||
}
|
||||
|
||||
internal::Call call_;
|
||||
grpc::internal::ServerCallbackCall* const callback_controller_;
|
||||
bool has_tag_;
|
||||
void* tag_;
|
||||
void* core_cq_tag_;
|
||||
grpc_core::RefCount refs_;
|
||||
grpc_core::Mutex mu_;
|
||||
bool finalized_;
|
||||
int cancelled_; // This is an int (not bool) because it is passed to core
|
||||
bool done_intercepting_;
|
||||
internal::InterceptorBatchMethodsImpl interceptor_methods_;
|
||||
};
|
||||
|
||||
void ServerContextBase::CompletionOp::Unref() {
|
||||
if (refs_.Unref()) {
|
||||
grpc_call* call = call_.call();
|
||||
delete this;
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerContextBase::CompletionOp::FillOps(internal::Call* call) {
|
||||
grpc_op ops;
|
||||
ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
|
||||
ops.data.recv_close_on_server.cancelled = &cancelled_;
|
||||
ops.flags = 0;
|
||||
ops.reserved = nullptr;
|
||||
interceptor_methods_.SetCall(&call_);
|
||||
interceptor_methods_.SetReverse();
|
||||
interceptor_methods_.SetCallOpSetInterface(this);
|
||||
// The following call_start_batch is internally-generated so no need for an
|
||||
// explanatory log on failure.
|
||||
GPR_ASSERT(grpc_call_start_batch(call->call(), &ops, 1, core_cq_tag_,
|
||||
nullptr) == GRPC_CALL_OK);
|
||||
// No interceptors to run here
|
||||
}
|
||||
|
||||
bool ServerContextBase::CompletionOp::FinalizeResult(void** tag, bool* status) {
|
||||
// Decide whether to do the unref or call the cancel callback within the lock
|
||||
bool do_unref = false;
|
||||
bool has_tag = false;
|
||||
bool call_cancel = false;
|
||||
|
||||
{
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
if (done_intercepting_) {
|
||||
// We are done intercepting.
|
||||
has_tag = has_tag_;
|
||||
if (has_tag) {
|
||||
*tag = tag_;
|
||||
}
|
||||
// Release the lock before unreffing as Unref may delete this object
|
||||
do_unref = true;
|
||||
} else {
|
||||
finalized_ = true;
|
||||
|
||||
// If for some reason the incoming status is false, mark that as a
|
||||
// cancellation.
|
||||
// TODO(vjpai): does this ever happen?
|
||||
if (!*status) {
|
||||
cancelled_ = 1;
|
||||
}
|
||||
|
||||
call_cancel = (cancelled_ != 0);
|
||||
// Release the lock since we may call a callback and interceptors.
|
||||
}
|
||||
}
|
||||
|
||||
if (do_unref) {
|
||||
Unref();
|
||||
// Unref can delete this, so do not access anything from this afterward.
|
||||
return has_tag;
|
||||
}
|
||||
if (call_cancel && callback_controller_ != nullptr) {
|
||||
callback_controller_->MaybeCallOnCancel();
|
||||
}
|
||||
// Add interception point and run through interceptors
|
||||
interceptor_methods_.AddInterceptionHookPoint(
|
||||
experimental::InterceptionHookPoints::POST_RECV_CLOSE);
|
||||
if (interceptor_methods_.RunInterceptors()) {
|
||||
// No interceptors were run
|
||||
bool has_tag = has_tag_;
|
||||
if (has_tag) {
|
||||
*tag = tag_;
|
||||
}
|
||||
Unref();
|
||||
// Unref can delete this, so do not access anything from this afterward.
|
||||
return has_tag;
|
||||
}
|
||||
// There are interceptors to be run. Return false for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
// ServerContextBase body
|
||||
|
||||
ServerContextBase::ServerContextBase()
|
||||
: deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)) {}
|
||||
|
||||
ServerContextBase::ServerContextBase(gpr_timespec deadline,
|
||||
grpc_metadata_array* arr)
|
||||
: deadline_(deadline) {
|
||||
std::swap(*client_metadata_.arr(), *arr);
|
||||
}
|
||||
|
||||
void ServerContextBase::BindDeadlineAndMetadata(gpr_timespec deadline,
|
||||
grpc_metadata_array* arr) {
|
||||
deadline_ = deadline;
|
||||
std::swap(*client_metadata_.arr(), *arr);
|
||||
}
|
||||
|
||||
ServerContextBase::~ServerContextBase() {
|
||||
if (completion_op_) {
|
||||
completion_op_->Unref();
|
||||
// Unref can delete completion_op_, so do not access it afterward.
|
||||
}
|
||||
if (rpc_info_) {
|
||||
rpc_info_->Unref();
|
||||
}
|
||||
if (default_reactor_used_.load(std::memory_order_relaxed)) {
|
||||
reinterpret_cast<Reactor*>(&default_reactor_)->~Reactor();
|
||||
}
|
||||
if (call_metric_recorder_ != nullptr) {
|
||||
call_metric_recorder_->~CallMetricRecorder();
|
||||
}
|
||||
}
|
||||
|
||||
ServerContextBase::CallWrapper::~CallWrapper() {
|
||||
if (call) {
|
||||
// If the ServerContext is part of the call's arena, this could free the
|
||||
// object itself.
|
||||
grpc_call_unref(call);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerContextBase::BeginCompletionOp(
|
||||
internal::Call* call, std::function<void(bool)> callback,
|
||||
grpc::internal::ServerCallbackCall* callback_controller) {
|
||||
GPR_ASSERT(!completion_op_);
|
||||
if (rpc_info_) {
|
||||
rpc_info_->Ref();
|
||||
}
|
||||
grpc_call_ref(call->call());
|
||||
completion_op_ =
|
||||
new (grpc_call_arena_alloc(call->call(), sizeof(CompletionOp)))
|
||||
CompletionOp(call, callback_controller);
|
||||
if (callback_controller != nullptr) {
|
||||
completion_tag_.Set(call->call(), std::move(callback), completion_op_,
|
||||
true);
|
||||
completion_op_->set_core_cq_tag(&completion_tag_);
|
||||
completion_op_->set_tag(completion_op_);
|
||||
} else if (has_notify_when_done_tag_) {
|
||||
completion_op_->set_tag(async_notify_when_done_tag_);
|
||||
}
|
||||
call->PerformOps(completion_op_);
|
||||
}
|
||||
|
||||
internal::CompletionQueueTag* ServerContextBase::GetCompletionOpTag() {
|
||||
return static_cast<internal::CompletionQueueTag*>(completion_op_);
|
||||
}
|
||||
|
||||
void ServerContextBase::AddInitialMetadata(const std::string& key,
|
||||
const std::string& value) {
|
||||
initial_metadata_.insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
void ServerContextBase::AddTrailingMetadata(const std::string& key,
|
||||
const std::string& value) {
|
||||
trailing_metadata_.insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
void ServerContextBase::TryCancel() const {
|
||||
internal::CancelInterceptorBatchMethods cancel_methods;
|
||||
if (rpc_info_) {
|
||||
for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) {
|
||||
rpc_info_->RunInterceptor(&cancel_methods, i);
|
||||
}
|
||||
}
|
||||
grpc_call_error err =
|
||||
grpc_call_cancel_with_status(call_.call, GRPC_STATUS_CANCELLED,
|
||||
"Cancelled on the server side", nullptr);
|
||||
if (err != GRPC_CALL_OK) {
|
||||
gpr_log(GPR_ERROR, "TryCancel failed with: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerContextBase::IsCancelled() const {
|
||||
if (completion_tag_) {
|
||||
// When using callback API, this result is always valid.
|
||||
return marked_cancelled_.load(std::memory_order_acquire) ||
|
||||
completion_op_->CheckCancelledAsync();
|
||||
} else if (has_notify_when_done_tag_) {
|
||||
// When using async API, the result is only valid
|
||||
// if the tag has already been delivered at the completion queue
|
||||
return completion_op_ && completion_op_->CheckCancelledAsync();
|
||||
} else {
|
||||
// when using sync API, the result is always valid
|
||||
return marked_cancelled_.load(std::memory_order_acquire) ||
|
||||
(completion_op_ && completion_op_->CheckCancelled(cq_));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerContextBase::set_compression_algorithm(
|
||||
grpc_compression_algorithm algorithm) {
|
||||
compression_algorithm_ = algorithm;
|
||||
const char* algorithm_name = nullptr;
|
||||
if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
|
||||
grpc_core::Crash(absl::StrFormat(
|
||||
"Name for compression algorithm '%d' unknown.", algorithm));
|
||||
}
|
||||
GPR_ASSERT(algorithm_name != nullptr);
|
||||
AddInitialMetadata(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY, algorithm_name);
|
||||
}
|
||||
|
||||
std::string ServerContextBase::peer() const {
|
||||
std::string peer;
|
||||
if (call_.call) {
|
||||
char* c_peer = grpc_call_get_peer(call_.call);
|
||||
peer = c_peer;
|
||||
gpr_free(c_peer);
|
||||
}
|
||||
return peer;
|
||||
}
|
||||
|
||||
const struct census_context* ServerContextBase::census_context() const {
|
||||
return call_.call == nullptr ? nullptr
|
||||
: grpc_census_call_get_context(call_.call);
|
||||
}
|
||||
|
||||
void ServerContextBase::SetLoadReportingCosts(
|
||||
const std::vector<std::string>& cost_data) {
|
||||
if (call_.call == nullptr) return;
|
||||
for (const auto& cost_datum : cost_data) {
|
||||
AddTrailingMetadata(GRPC_LB_COST_MD_KEY, cost_datum);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerContextBase::CreateCallMetricRecorder(
|
||||
experimental::ServerMetricRecorder* server_metric_recorder) {
|
||||
if (call_.call == nullptr) return;
|
||||
GPR_ASSERT(call_metric_recorder_ == nullptr);
|
||||
grpc_core::Arena* arena = grpc_call_get_arena(call_.call);
|
||||
auto* backend_metric_state =
|
||||
arena->New<BackendMetricState>(server_metric_recorder);
|
||||
call_metric_recorder_ = backend_metric_state;
|
||||
grpc_call_context_set(call_.call, GRPC_CONTEXT_BACKEND_METRIC_PROVIDER,
|
||||
backend_metric_state, nullptr);
|
||||
}
|
||||
|
||||
grpc::string_ref ServerContextBase::ExperimentalGetAuthority() const {
|
||||
absl::string_view authority = grpc_call_server_authority(call_.call);
|
||||
return grpc::string_ref(authority.data(), authority.size());
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
37
Pods/gRPC-C++/src/cpp/server/server_posix.cc
generated
Normal file
37
Pods/gRPC-C++/src/cpp/server/server_posix.cc
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_posix.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpcpp/server.h>
|
||||
#include <grpcpp/server_posix.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
|
||||
|
||||
void AddInsecureChannelFromFd(grpc::Server* server, int fd) {
|
||||
grpc_server_credentials* creds = grpc_insecure_server_credentials_create();
|
||||
grpc_server_add_channel_from_fd(server->c_server(), fd, creds);
|
||||
grpc_server_credentials_release(creds);
|
||||
}
|
||||
|
||||
#endif // GPR_SUPPORT_CHANNELS_FROM_FD
|
||||
|
||||
} // namespace grpc
|
||||
43
Pods/gRPC-C++/src/cpp/server/thread_pool_interface.h
generated
Normal file
43
Pods/gRPC-C++/src/cpp/server/thread_pool_interface.h
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_SERVER_THREAD_POOL_INTERFACE_H
|
||||
#define GRPC_SRC_CPP_SERVER_THREAD_POOL_INTERFACE_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
// A thread pool interface for running callbacks.
|
||||
class ThreadPoolInterface {
|
||||
public:
|
||||
virtual ~ThreadPoolInterface() {}
|
||||
|
||||
// Schedule the given callback for execution.
|
||||
virtual void Add(const std::function<void()>& callback) = 0;
|
||||
};
|
||||
|
||||
// Allows different codebases to use their own thread pool impls
|
||||
typedef ThreadPoolInterface* (*CreateThreadPoolFunc)(void);
|
||||
void SetCreateThreadPool(CreateThreadPoolFunc func);
|
||||
|
||||
ThreadPoolInterface* CreateDefaultThreadPool();
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_SERVER_THREAD_POOL_INTERFACE_H
|
||||
43
Pods/gRPC-C++/src/cpp/server/xds_server_builder.cc
generated
Normal file
43
Pods/gRPC-C++/src/cpp/server/xds_server_builder.cc
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2023 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/channel_arg_names.h>
|
||||
#include <grpcpp/server_builder.h>
|
||||
#include <grpcpp/support/channel_arguments.h>
|
||||
#include <grpcpp/xds_server_builder.h>
|
||||
|
||||
#include "src/core/ext/xds/xds_enabled_server.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
ChannelArguments XdsServerBuilder::BuildChannelArgs() {
|
||||
ChannelArguments args = ServerBuilder::BuildChannelArgs();
|
||||
if (drain_grace_time_ms_ >= 0) {
|
||||
args.SetInt(GRPC_ARG_SERVER_CONFIG_CHANGE_DRAIN_GRACE_TIME_MS,
|
||||
drain_grace_time_ms_);
|
||||
}
|
||||
args.SetInt(GRPC_ARG_XDS_ENABLED_SERVER, 1);
|
||||
grpc_channel_args c_channel_args = args.c_channel_args();
|
||||
grpc_server_config_fetcher* fetcher = grpc_server_config_fetcher_xds_create(
|
||||
{OnServingStatusUpdate, notifier_}, &c_channel_args);
|
||||
if (fetcher != nullptr) set_fetcher(fetcher);
|
||||
return args;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
54
Pods/gRPC-C++/src/cpp/server/xds_server_credentials.cc
generated
Normal file
54
Pods/gRPC-C++/src/cpp/server/xds_server_credentials.cc
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2020 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpcpp/security/server_credentials.h>
|
||||
|
||||
#include "src/cpp/server/secure_server_credentials.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
std::shared_ptr<ServerCredentials> XdsServerCredentials(
|
||||
const std::shared_ptr<ServerCredentials>& fallback_credentials) {
|
||||
GPR_ASSERT(fallback_credentials != nullptr);
|
||||
if (fallback_credentials->IsInsecure()) {
|
||||
grpc_server_credentials* insecure_creds =
|
||||
grpc_insecure_server_credentials_create();
|
||||
auto xds_creds = std::make_shared<SecureServerCredentials>(
|
||||
grpc_xds_server_credentials_create(insecure_creds));
|
||||
grpc_server_credentials_release(insecure_creds);
|
||||
return xds_creds;
|
||||
}
|
||||
return std::make_shared<SecureServerCredentials>(
|
||||
grpc_xds_server_credentials_create(
|
||||
fallback_credentials->AsSecureServerCredentials()->c_creds()));
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
|
||||
std::shared_ptr<ServerCredentials> XdsServerCredentials(
|
||||
const std::shared_ptr<ServerCredentials>& fallback_credentials) {
|
||||
return grpc::XdsServerCredentials(fallback_credentials);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
266
Pods/gRPC-C++/src/cpp/thread_manager/thread_manager.cc
generated
Normal file
266
Pods/gRPC-C++/src/cpp/thread_manager/thread_manager.cc
generated
Normal file
@@ -0,0 +1,266 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include "src/cpp/thread_manager/thread_manager.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
|
||||
#include "src/core/lib/gprpp/crash.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/gprpp/thd.h"
|
||||
#include "src/core/lib/resource_quota/resource_quota.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
ThreadManager::WorkerThread::WorkerThread(ThreadManager* thd_mgr)
|
||||
: thd_mgr_(thd_mgr) {
|
||||
// Make thread creation exclusive with respect to its join happening in
|
||||
// ~WorkerThread().
|
||||
thd_ = grpc_core::Thread(
|
||||
"grpcpp_sync_server",
|
||||
[](void* th) { static_cast<ThreadManager::WorkerThread*>(th)->Run(); },
|
||||
this, &created_);
|
||||
if (!created_) {
|
||||
gpr_log(GPR_ERROR, "Could not create grpc_sync_server worker-thread");
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::WorkerThread::Run() {
|
||||
thd_mgr_->MainWorkLoop();
|
||||
thd_mgr_->MarkAsCompleted(this);
|
||||
}
|
||||
|
||||
ThreadManager::WorkerThread::~WorkerThread() {
|
||||
// Don't join until the thread is fully constructed.
|
||||
thd_.Join();
|
||||
}
|
||||
|
||||
ThreadManager::ThreadManager(const char*, grpc_resource_quota* resource_quota,
|
||||
int min_pollers, int max_pollers)
|
||||
: shutdown_(false),
|
||||
thread_quota_(
|
||||
grpc_core::ResourceQuota::FromC(resource_quota)->thread_quota()),
|
||||
num_pollers_(0),
|
||||
min_pollers_(min_pollers),
|
||||
max_pollers_(max_pollers == -1 ? INT_MAX : max_pollers),
|
||||
num_threads_(0),
|
||||
max_active_threads_sofar_(0) {}
|
||||
|
||||
ThreadManager::~ThreadManager() {
|
||||
{
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
GPR_ASSERT(num_threads_ == 0);
|
||||
}
|
||||
|
||||
CleanupCompletedThreads();
|
||||
}
|
||||
|
||||
void ThreadManager::Wait() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
while (num_threads_ != 0) {
|
||||
shutdown_cv_.Wait(&mu_);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::Shutdown() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
shutdown_ = true;
|
||||
}
|
||||
|
||||
bool ThreadManager::IsShutdown() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
return shutdown_;
|
||||
}
|
||||
|
||||
int ThreadManager::GetMaxActiveThreadsSoFar() {
|
||||
grpc_core::MutexLock list_lock(&list_mu_);
|
||||
return max_active_threads_sofar_;
|
||||
}
|
||||
|
||||
void ThreadManager::MarkAsCompleted(WorkerThread* thd) {
|
||||
{
|
||||
grpc_core::MutexLock list_lock(&list_mu_);
|
||||
completed_threads_.push_back(thd);
|
||||
}
|
||||
|
||||
{
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
num_threads_--;
|
||||
if (num_threads_ == 0) {
|
||||
shutdown_cv_.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
// Give a thread back to the resource quota
|
||||
thread_quota_->Release(1);
|
||||
}
|
||||
|
||||
void ThreadManager::CleanupCompletedThreads() {
|
||||
std::list<WorkerThread*> completed_threads;
|
||||
{
|
||||
// swap out the completed threads list: allows other threads to clean up
|
||||
// more quickly
|
||||
grpc_core::MutexLock lock(&list_mu_);
|
||||
completed_threads.swap(completed_threads_);
|
||||
}
|
||||
for (auto thd : completed_threads) delete thd;
|
||||
}
|
||||
|
||||
void ThreadManager::Initialize() {
|
||||
if (!thread_quota_->Reserve(min_pollers_)) {
|
||||
grpc_core::Crash(absl::StrFormat(
|
||||
"No thread quota available to even create the minimum required "
|
||||
"polling threads (i.e %d). Unable to start the thread manager",
|
||||
min_pollers_));
|
||||
}
|
||||
|
||||
{
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
num_pollers_ = min_pollers_;
|
||||
num_threads_ = min_pollers_;
|
||||
max_active_threads_sofar_ = min_pollers_;
|
||||
}
|
||||
|
||||
for (int i = 0; i < min_pollers_; i++) {
|
||||
WorkerThread* worker = new WorkerThread(this);
|
||||
GPR_ASSERT(worker->created()); // Must be able to create the minimum
|
||||
worker->Start();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::MainWorkLoop() {
|
||||
while (true) {
|
||||
void* tag;
|
||||
bool ok;
|
||||
WorkStatus work_status = PollForWork(&tag, &ok);
|
||||
|
||||
grpc_core::LockableAndReleasableMutexLock lock(&mu_);
|
||||
// Reduce the number of pollers by 1 and check what happened with the poll
|
||||
num_pollers_--;
|
||||
bool done = false;
|
||||
switch (work_status) {
|
||||
case TIMEOUT:
|
||||
// If we timed out and we have more pollers than we need (or we are
|
||||
// shutdown), finish this thread
|
||||
if (shutdown_ || num_pollers_ > max_pollers_) done = true;
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
// If the thread manager is shutdown, finish this thread
|
||||
done = true;
|
||||
break;
|
||||
case WORK_FOUND:
|
||||
// If we got work and there are now insufficient pollers and there is
|
||||
// quota available to create a new thread, start a new poller thread
|
||||
bool resource_exhausted = false;
|
||||
if (!shutdown_ && num_pollers_ < min_pollers_) {
|
||||
if (thread_quota_->Reserve(1)) {
|
||||
// We can allocate a new poller thread
|
||||
num_pollers_++;
|
||||
num_threads_++;
|
||||
if (num_threads_ > max_active_threads_sofar_) {
|
||||
max_active_threads_sofar_ = num_threads_;
|
||||
}
|
||||
// Drop lock before spawning thread to avoid contention
|
||||
lock.Release();
|
||||
WorkerThread* worker = new WorkerThread(this);
|
||||
if (worker->created()) {
|
||||
worker->Start();
|
||||
} else {
|
||||
// Get lock again to undo changes to poller/thread counters.
|
||||
grpc_core::MutexLock failure_lock(&mu_);
|
||||
num_pollers_--;
|
||||
num_threads_--;
|
||||
resource_exhausted = true;
|
||||
delete worker;
|
||||
}
|
||||
} else if (num_pollers_ > 0) {
|
||||
// There is still at least some thread polling, so we can go on
|
||||
// even though we are below the number of pollers that we would
|
||||
// like to have (min_pollers_)
|
||||
lock.Release();
|
||||
} else {
|
||||
// There are no pollers to spare and we couldn't allocate
|
||||
// a new thread, so resources are exhausted!
|
||||
lock.Release();
|
||||
resource_exhausted = true;
|
||||
}
|
||||
} else {
|
||||
// There are a sufficient number of pollers available so we can do
|
||||
// the work and continue polling with our existing poller threads
|
||||
lock.Release();
|
||||
}
|
||||
// Lock is always released at this point - do the application work
|
||||
// or return resource exhausted if there is new work but we couldn't
|
||||
// get a thread in which to do it.
|
||||
DoWork(tag, ok, !resource_exhausted);
|
||||
// Take the lock again to check post conditions
|
||||
lock.Lock();
|
||||
// If we're shutdown, we should finish at this point.
|
||||
if (shutdown_) done = true;
|
||||
break;
|
||||
}
|
||||
// If we decided to finish the thread, break out of the while loop
|
||||
if (done) break;
|
||||
|
||||
// Otherwise go back to polling as long as it doesn't exceed max_pollers_
|
||||
//
|
||||
// **WARNING**:
|
||||
// There is a possibility of threads thrashing here (i.e excessive thread
|
||||
// shutdowns and creations than the ideal case). This happens if max_poller_
|
||||
// count is small and the rate of incoming requests is also small. In such
|
||||
// scenarios we can possibly configure max_pollers_ to a higher value and/or
|
||||
// increase the cq timeout.
|
||||
//
|
||||
// However, not doing this check here and unconditionally incrementing
|
||||
// num_pollers (and hoping that the system will eventually settle down) has
|
||||
// far worse consequences i.e huge number of threads getting created to the
|
||||
// point of thread-exhaustion. For example: if the incoming request rate is
|
||||
// very high, all the polling threads will return very quickly from
|
||||
// PollForWork() with WORK_FOUND. They all briefly decrement num_pollers_
|
||||
// counter thereby possibly - and briefly - making it go below min_pollers;
|
||||
// This will most likely result in the creation of a new poller since
|
||||
// num_pollers_ dipped below min_pollers_.
|
||||
//
|
||||
// Now, If we didn't do the max_poller_ check here, all these threads will
|
||||
// go back to doing PollForWork() and the whole cycle repeats (with a new
|
||||
// thread being added in each cycle). Once the total number of threads in
|
||||
// the system crosses a certain threshold (around ~1500), there is heavy
|
||||
// contention on mutexes (the mu_ here or the mutexes in gRPC core like the
|
||||
// pollset mutex) that makes DoWork() take longer to finish thereby causing
|
||||
// new poller threads to be created even faster. This results in a thread
|
||||
// avalanche.
|
||||
if (num_pollers_ < max_pollers_) {
|
||||
num_pollers_++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// This thread is exiting. Do some cleanup work i.e delete already completed
|
||||
// worker threads
|
||||
CleanupCompletedThreads();
|
||||
|
||||
// If we are here, either ThreadManager is shutting down or it already has
|
||||
// enough threads.
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
179
Pods/gRPC-C++/src/cpp/thread_manager/thread_manager.h
generated
Normal file
179
Pods/gRPC-C++/src/cpp/thread_manager/thread_manager.h
generated
Normal file
@@ -0,0 +1,179 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2016 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CPP_THREAD_MANAGER_THREAD_MANAGER_H
|
||||
#define GRPC_SRC_CPP_THREAD_MANAGER_THREAD_MANAGER_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/gprpp/thd.h"
|
||||
#include "src/core/lib/resource_quota/api.h"
|
||||
#include "src/core/lib/resource_quota/thread_quota.h"
|
||||
|
||||
namespace grpc {
|
||||
|
||||
class ThreadManager {
|
||||
public:
|
||||
explicit ThreadManager(const char* name, grpc_resource_quota* resource_quota,
|
||||
int min_pollers, int max_pollers);
|
||||
virtual ~ThreadManager();
|
||||
|
||||
// Initializes and Starts the Rpc Manager threads
|
||||
void Initialize();
|
||||
|
||||
// The return type of PollForWork() function
|
||||
enum WorkStatus { WORK_FOUND, SHUTDOWN, TIMEOUT };
|
||||
|
||||
// "Polls" for new work.
|
||||
// If the return value is WORK_FOUND:
|
||||
// - The implementaion of PollForWork() MAY set some opaque identifier to
|
||||
// (identify the work item found) via the '*tag' parameter
|
||||
// - The implementaion MUST set the value of 'ok' to 'true' or 'false'. A
|
||||
// value of 'false' indicates some implemenation specific error (that is
|
||||
// neither SHUTDOWN nor TIMEOUT)
|
||||
// - ThreadManager does not interpret the values of 'tag' and 'ok'
|
||||
// - ThreadManager WILL call DoWork() and pass '*tag' and 'ok' as input to
|
||||
// DoWork()
|
||||
//
|
||||
// If the return value is SHUTDOWN:,
|
||||
// - ThreadManager WILL NOT call DoWork() and terminates the thread
|
||||
//
|
||||
// If the return value is TIMEOUT:,
|
||||
// - ThreadManager WILL NOT call DoWork()
|
||||
// - ThreadManager MAY terminate the thread depending on the current number
|
||||
// of active poller threads and mix_pollers/max_pollers settings
|
||||
// - Also, the value of timeout is specific to the derived class
|
||||
// implementation
|
||||
virtual WorkStatus PollForWork(void** tag, bool* ok) = 0;
|
||||
|
||||
// The implementation of DoWork() is supposed to perform the work found by
|
||||
// PollForWork(). The tag and ok parameters are the same as returned by
|
||||
// PollForWork(). The resources parameter indicates that the call actually
|
||||
// has the resources available for performing the RPC's work. If it doesn't,
|
||||
// the implementation should fail it appropriately.
|
||||
//
|
||||
// The implementation of DoWork() should also do any setup needed to ensure
|
||||
// that the next call to PollForWork() (not necessarily by the current thread)
|
||||
// actually finds some work
|
||||
virtual void DoWork(void* tag, bool ok, bool resources) = 0;
|
||||
|
||||
// Mark the ThreadManager as shutdown and begin draining the work. This is a
|
||||
// non-blocking call and the caller should call Wait(), a blocking call which
|
||||
// returns only once the shutdown is complete
|
||||
virtual void Shutdown();
|
||||
|
||||
// Has Shutdown() been called
|
||||
bool IsShutdown();
|
||||
|
||||
// A blocking call that returns only after the ThreadManager has shutdown and
|
||||
// all the threads have drained all the outstanding work
|
||||
virtual void Wait();
|
||||
|
||||
// Max number of concurrent threads that were ever active in this thread
|
||||
// manager so far. This is useful for debugging purposes (and in unit tests)
|
||||
// to check if resource_quota is properly being enforced.
|
||||
int GetMaxActiveThreadsSoFar();
|
||||
|
||||
private:
|
||||
// Helper wrapper class around grpc_core::Thread. Takes a ThreadManager object
|
||||
// and starts a new grpc_core::Thread to calls the Run() function.
|
||||
//
|
||||
// The Run() function calls ThreadManager::MainWorkLoop() function and once
|
||||
// that completes, it marks the WorkerThread completed by calling
|
||||
// ThreadManager::MarkAsCompleted()
|
||||
//
|
||||
// WHY IS THIS NEEDED?:
|
||||
// When a thread terminates, some other thread *must* call Join() on that
|
||||
// thread so that the resources are released. Having a WorkerThread wrapper
|
||||
// will make this easier. Once Run() completes, each thread calls the
|
||||
// following two functions:
|
||||
// ThreadManager::CleanupCompletedThreads()
|
||||
// ThreadManager::MarkAsCompleted()
|
||||
//
|
||||
// - MarkAsCompleted() puts the WorkerThread object in the ThreadManger's
|
||||
// completed_threads_ list
|
||||
// - CleanupCompletedThreads() calls "Join()" on the threads that are already
|
||||
// in the completed_threads_ list (since a thread cannot call Join() on
|
||||
// itself, it calls CleanupCompletedThreads() *before* calling
|
||||
// MarkAsCompleted())
|
||||
//
|
||||
// TODO(sreek): Consider creating the threads 'detached' so that Join() need
|
||||
// not be called (and the need for this WorkerThread class is eliminated)
|
||||
class WorkerThread {
|
||||
public:
|
||||
explicit WorkerThread(ThreadManager* thd_mgr);
|
||||
~WorkerThread();
|
||||
|
||||
bool created() const { return created_; }
|
||||
void Start() { thd_.Start(); }
|
||||
|
||||
private:
|
||||
// Calls thd_mgr_->MainWorkLoop() and once that completes, calls
|
||||
// thd_mgr_>MarkAsCompleted(this) to mark the thread as completed
|
||||
void Run();
|
||||
|
||||
ThreadManager* const thd_mgr_;
|
||||
grpc_core::Thread thd_;
|
||||
bool created_;
|
||||
};
|
||||
|
||||
// The main function in ThreadManager
|
||||
void MainWorkLoop();
|
||||
|
||||
void MarkAsCompleted(WorkerThread* thd);
|
||||
void CleanupCompletedThreads();
|
||||
|
||||
// Protects shutdown_, num_pollers_, num_threads_ and
|
||||
// max_active_threads_sofar_
|
||||
grpc_core::Mutex mu_;
|
||||
|
||||
bool shutdown_;
|
||||
grpc_core::CondVar shutdown_cv_;
|
||||
|
||||
// The resource user object to use when requesting quota to create threads
|
||||
//
|
||||
// Note: The user of this ThreadManager object must create grpc_resource_quota
|
||||
// object (that contains the actual max thread quota) and a grpc_resource_user
|
||||
// object through which quota is requested whenever new threads need to be
|
||||
// created
|
||||
grpc_core::ThreadQuotaPtr thread_quota_;
|
||||
|
||||
// Number of threads doing polling
|
||||
int num_pollers_;
|
||||
|
||||
// The minimum and maximum number of threads that should be doing polling
|
||||
int min_pollers_;
|
||||
int max_pollers_;
|
||||
|
||||
// The total number of threads currently active (includes threads includes the
|
||||
// threads that are currently polling i.e num_pollers_)
|
||||
int num_threads_;
|
||||
|
||||
// See GetMaxActiveThreadsSoFar()'s description.
|
||||
// To be more specific, this variable tracks the max value num_threads_ was
|
||||
// ever set so far
|
||||
int max_active_threads_sofar_;
|
||||
|
||||
grpc_core::Mutex list_mu_;
|
||||
std::list<WorkerThread*> completed_threads_;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPC_SRC_CPP_THREAD_MANAGER_THREAD_MANAGER_H
|
||||
82
Pods/gRPC-C++/src/cpp/util/byte_buffer_cc.cc
generated
Normal file
82
Pods/gRPC-C++/src/cpp/util/byte_buffer_cc.cc
generated
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <grpc/byte_buffer.h>
|
||||
#include <grpc/byte_buffer_reader.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/impl/compression_types.h>
|
||||
#include <grpc/slice.h>
|
||||
#include <grpcpp/support/byte_buffer.h>
|
||||
#include <grpcpp/support/slice.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
Status ByteBuffer::TrySingleSlice(Slice* slice) const {
|
||||
if (!buffer_) {
|
||||
return Status(StatusCode::FAILED_PRECONDITION, "Buffer not initialized");
|
||||
}
|
||||
if ((buffer_->type == GRPC_BB_RAW) &&
|
||||
(buffer_->data.raw.compression == GRPC_COMPRESS_NONE) &&
|
||||
(buffer_->data.raw.slice_buffer.count == 1)) {
|
||||
grpc_slice internal_slice = buffer_->data.raw.slice_buffer.slices[0];
|
||||
*slice = Slice(internal_slice, Slice::ADD_REF);
|
||||
return Status::OK;
|
||||
} else {
|
||||
return Status(StatusCode::FAILED_PRECONDITION,
|
||||
"Buffer isn't made up of a single uncompressed slice.");
|
||||
}
|
||||
}
|
||||
|
||||
Status ByteBuffer::DumpToSingleSlice(Slice* slice) const {
|
||||
if (!buffer_) {
|
||||
return Status(StatusCode::FAILED_PRECONDITION, "Buffer not initialized");
|
||||
}
|
||||
grpc_byte_buffer_reader reader;
|
||||
if (!grpc_byte_buffer_reader_init(&reader, buffer_)) {
|
||||
return Status(StatusCode::INTERNAL,
|
||||
"Couldn't initialize byte buffer reader");
|
||||
}
|
||||
grpc_slice s = grpc_byte_buffer_reader_readall(&reader);
|
||||
*slice = Slice(s, Slice::STEAL_REF);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status ByteBuffer::Dump(std::vector<Slice>* slices) const {
|
||||
slices->clear();
|
||||
if (!buffer_) {
|
||||
return Status(StatusCode::FAILED_PRECONDITION, "Buffer not initialized");
|
||||
}
|
||||
grpc_byte_buffer_reader reader;
|
||||
if (!grpc_byte_buffer_reader_init(&reader, buffer_)) {
|
||||
return Status(StatusCode::INTERNAL,
|
||||
"Couldn't initialize byte buffer reader");
|
||||
}
|
||||
grpc_slice s;
|
||||
while (grpc_byte_buffer_reader_next(&reader, &s)) {
|
||||
slices->push_back(Slice(s, Slice::STEAL_REF));
|
||||
}
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
28
Pods/gRPC-C++/src/cpp/util/status.cc
generated
Normal file
28
Pods/gRPC-C++/src/cpp/util/status.cc
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <grpcpp/support/status.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
const Status& Status::OK = Status();
|
||||
const Status& Status::CANCELLED = Status(StatusCode::CANCELLED, "");
|
||||
|
||||
} // namespace grpc
|
||||
27
Pods/gRPC-C++/src/cpp/util/string_ref.cc
generated
Normal file
27
Pods/gRPC-C++/src/cpp/util/string_ref.cc
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <grpcpp/support/string_ref.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
const size_t string_ref::npos = static_cast<size_t>(-1);
|
||||
|
||||
} // namespace grpc
|
||||
79
Pods/gRPC-C++/src/cpp/util/time_cc.cc
generated
Normal file
79
Pods/gRPC-C++/src/cpp/util/time_cc.cc
generated
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
#include <grpc/support/time.h>
|
||||
#include <grpcpp/support/time.h>
|
||||
|
||||
// IWYU pragma: no_include <ratio>
|
||||
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::nanoseconds;
|
||||
using std::chrono::seconds;
|
||||
using std::chrono::system_clock;
|
||||
|
||||
namespace grpc {
|
||||
|
||||
void Timepoint2Timespec(const system_clock::time_point& from,
|
||||
gpr_timespec* to) {
|
||||
system_clock::duration deadline = from.time_since_epoch();
|
||||
seconds secs = duration_cast<seconds>(deadline);
|
||||
if (from == system_clock::time_point::max() ||
|
||||
secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec ||
|
||||
secs.count() < 0) {
|
||||
*to = gpr_inf_future(GPR_CLOCK_REALTIME);
|
||||
return;
|
||||
}
|
||||
nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
|
||||
to->tv_sec = static_cast<int64_t>(secs.count());
|
||||
to->tv_nsec = static_cast<int32_t>(nsecs.count());
|
||||
to->clock_type = GPR_CLOCK_REALTIME;
|
||||
}
|
||||
|
||||
void TimepointHR2Timespec(const high_resolution_clock::time_point& from,
|
||||
gpr_timespec* to) {
|
||||
high_resolution_clock::duration deadline = from.time_since_epoch();
|
||||
seconds secs = duration_cast<seconds>(deadline);
|
||||
if (from == high_resolution_clock::time_point::max() ||
|
||||
secs.count() >= gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec ||
|
||||
secs.count() < 0) {
|
||||
*to = gpr_inf_future(GPR_CLOCK_REALTIME);
|
||||
return;
|
||||
}
|
||||
nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
|
||||
to->tv_sec = static_cast<int64_t>(secs.count());
|
||||
to->tv_nsec = static_cast<int32_t>(nsecs.count());
|
||||
to->clock_type = GPR_CLOCK_REALTIME;
|
||||
}
|
||||
|
||||
system_clock::time_point Timespec2Timepoint(gpr_timespec t) {
|
||||
if (gpr_time_cmp(t, gpr_inf_future(t.clock_type)) == 0) {
|
||||
return system_clock::time_point::max();
|
||||
}
|
||||
t = gpr_convert_clock_type(t, GPR_CLOCK_REALTIME);
|
||||
system_clock::time_point tp;
|
||||
tp += duration_cast<system_clock::time_point::duration>(seconds(t.tv_sec));
|
||||
tp +=
|
||||
duration_cast<system_clock::time_point::duration>(nanoseconds(t.tv_nsec));
|
||||
return tp;
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
Reference in New Issue
Block a user