mirror of https://github.com/grpc/grpc.git
commit
5eea97b7d6
461 changed files with 21680 additions and 15642 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@ |
||||
"""Loads the dependencies necessary for the external repositories defined in grpc_deps.bzl.""" |
||||
|
||||
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") |
||||
load("@upb//bazel:workspace_deps.bzl", "upb_deps") |
||||
load("@envoy_api//bazel:repositories.bzl", "api_dependencies") |
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") |
||||
load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies") |
||||
load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies") |
||||
|
||||
def grpc_extra_deps(): |
||||
"""Loads the extra dependencies. |
||||
|
||||
These are necessary for using the external repositories defined in |
||||
grpc_deps.bzl. Projects that depend on gRPC as an external repository need |
||||
to call both grpc_deps and grpc_extra_deps, if they have not already loaded |
||||
the extra dependencies. For example, they can do the following in their |
||||
WORKSPACE |
||||
``` |
||||
load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps") |
||||
grpc_deps() |
||||
|
||||
grpc_test_only_deps() |
||||
|
||||
load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") |
||||
|
||||
grpc_extra_deps() |
||||
``` |
||||
""" |
||||
protobuf_deps() |
||||
|
||||
upb_deps() |
||||
|
||||
api_dependencies() |
||||
|
||||
go_rules_dependencies() |
||||
go_register_toolchains() |
||||
|
||||
apple_rules_dependencies() |
||||
|
||||
apple_support_dependencies() |
@ -0,0 +1,37 @@ |
||||
# Copyright 2019 the 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. |
||||
"""A dummy plugin for testing""" |
||||
|
||||
import sys |
||||
|
||||
from google.protobuf.compiler.plugin_pb2 import CodeGeneratorRequest |
||||
from google.protobuf.compiler.plugin_pb2 import CodeGeneratorResponse |
||||
|
||||
|
||||
def main(input_file=sys.stdin, output_file=sys.stdout): |
||||
request = CodeGeneratorRequest.FromString(input_file.buffer.read()) |
||||
answer = [] |
||||
for fname in request.file_to_generate: |
||||
answer.append(CodeGeneratorResponse.File( |
||||
name=fname.replace('.proto', '_pb2.py'), |
||||
insertion_point='module_scope', |
||||
content="# Hello {}, I'm a dummy plugin!".format(fname), |
||||
)) |
||||
|
||||
cgr = CodeGeneratorResponse(file=answer) |
||||
output_file.buffer.write(cgr.SerializeToString()) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
@ -1,8 +1,8 @@ |
||||
# Depend packages |
||||
@_gRPC_FIND_ZLIB@ |
||||
@_gRPC_FIND_PROTOBUF@ |
||||
@_gRPC_FIND_SSL@ |
||||
@_gRPC_FIND_CARES@ |
||||
|
||||
# Targets |
||||
include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake) |
||||
# Depend packages |
||||
@_gRPC_FIND_ZLIB@ |
||||
@_gRPC_FIND_PROTOBUF@ |
||||
@_gRPC_FIND_SSL@ |
||||
@_gRPC_FIND_CARES@ |
||||
|
||||
# Targets |
||||
include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake) |
||||
|
@ -1,11 +0,0 @@ |
||||
set(PACKAGE_VERSION "@PACKAGE_VERSION@") |
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible |
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") |
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE) |
||||
else() |
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE) |
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") |
||||
set(PACKAGE_VERSION_EXACT TRUE) |
||||
endif() |
||||
endif() |
Binary file not shown.
@ -0,0 +1,70 @@ |
||||
# gRPC Security Audit |
||||
|
||||
A third-party security audit of gRPC C++ stack was performed by [Cure53](https://cure53.de) in October 2019. The full report can be found [here](https://github.com/grpc/grpc/tree/master/doc/grpc_security_audit.pdf). |
||||
|
||||
# Addressing grpc_security_audit |
||||
|
||||
The following describes how gRPC team has or will address each of the security issues pointed out in the report. |
||||
|
||||
## GRP-01-001 DoS through uninitialized pointer dereference |
||||
|
||||
GRP-01-001 was fixed in version 1.24.0 and above with https://github.com/grpc/grpc/pull/20351. The fix was also patched in version 1.23.1. |
||||
|
||||
## GRP-01-002 Refs to freed memory not automatically nulled |
||||
GRP-01-002 describes a programming pattern in gRPC Core where `gpr_free` is called and then the pointer is nulled afterwards. GRP-01-002 can be split into two concerns: 1) dangling pointer bugs and 2) the potential vulnerability of leveraging other bugs to access data through a freed pointer. |
||||
|
||||
Regarding 1), gRPC uses a suite of sanitizer tests (asan, tsan, etc) to detect and fix any memory-related bugs. gRPC is also in the process of moving to c++ and the standard library, enabling the use of smart pointers in Core and thus making it harder to generate memory-related bugs. There are also plans to remove `gpr_free` in general. |
||||
|
||||
Regarding 2), moving to smart pointers (in particular, unique_ptr) will help this issue as well. In addition, gRPC has continuous fuzzing tests to find and resolve security issues, and the pen test did not discover any concrete vulnerabilities in this area. |
||||
|
||||
Below is a list of alternatives that gRPC team considered. |
||||
|
||||
|
||||
### Alternative #1: Rewrite gpr_free to take void\*\* |
||||
One solution is to change the API of `gpr_free` so that it automatically nulls the given pointer after freeing it. |
||||
|
||||
``` |
||||
gpr_free (void** ptr) { |
||||
... |
||||
*ptr = nullptr; |
||||
} |
||||
``` |
||||
|
||||
This defensive programming pattern would help protect gRPC from the potential exploits and latent dangling pointer bugs mentioned in the security report. |
||||
|
||||
However, performance would be a significant concern as we are now unconditionally adding a store to every gpr_free call, and there are potentially hundreds of these per RPC. At the RPC layer, this can add up to prohibitive costs. |
||||
|
||||
Maintainability is also an issue since this approach impacts use of `*const`. Member pointers that are set in the initialization list of a constructor and not changed thereafter can be declared `*const`. This is a useful compile-time check if the member is taking ownership of something that was passed in by argument or allocated through a helper function called by the constructor initializer list. If this thing needs to be `gpr_free`'d using the proposed syntax, it can no longer be `*const` and we lose these checks (or we have to const_cast it which is also error-prone). |
||||
|
||||
Another concern is readability - this `gpr_free` interface is less intuitive than the current one. |
||||
|
||||
Yet another concern is that the use of non-smart pointers doesn’t imply ownership - it doesn’t protect against spare copies of the same pointers. |
||||
|
||||
### Alternative #2: Add another gpr_free to the Core API |
||||
Adding an alternative `gpr_free` that nulls the given pointer is undesirable because we cannot enforce that we’re using this version of `gpr_free` everywhere we need to. It doesn’t solve the original problem because it doesn’t reduce the chance of programmer error. |
||||
|
||||
Like alternative #1, this solution doesn’t protect against spare copies of the same pointers and is subject to the same maintainability concerns. |
||||
|
||||
### Alternative #3: Rewrite gpr_free to take void\*& |
||||
``` |
||||
gpr_free (void*& ptr) { |
||||
... |
||||
ptr = nullptr; |
||||
} |
||||
``` |
||||
This falls into the same pitfalls as solution #1 and furthermore is C89 non-compliant, which is a current requirement for `gpr_free`. Moreover, Google’s style guide discourages non-const reference parameters, so this is even less desirable than solution #1. |
||||
|
||||
|
||||
### Conclusion |
||||
Because of performance and maintainability concerns, GRP-01-002 will be addressed through the ongoing work to move gRPC Core to C++ and smart pointers and the future work of removing `gpr_free` in general. We will continue to leverage our sanitizer and fuzzing tests to help expose vulnerabilities. |
||||
|
||||
## GRP-01-003 Calls to malloc suffer from potential integer overflows |
||||
The vulnerability, as defined by the report, is that calls to `gpr_malloc` in the C-core codebase may suffer from potential integer overflow in cases where we multiply the array element size by the size of the array. The penetration testers did not identify a concrete place where this occurred, but rather emphasized that the coding pattern itself had potential to lead to vulnerabilities. The report’s suggested solution for GRP-01-003 was to create a `calloc(size_t nmemb, size_t size)` wrapper that contains integer overflow checks. |
||||
|
||||
However, gRPC team firmly believes that gRPC Core should only use integer overflow checks in the places where they’re needed; for example, any place where remote input influences the input to `gpr_malloc` in an unverified way. This is because bounds-checking is very expensive at the RPC layer. |
||||
|
||||
Determining exactly where bounds-checking is needed requires an audit of tracing each `gpr_malloc` (or `gpr_realloc` or `gpr_zalloc`) call up the stack to determine if the sufficient bounds-checking was performed. This kind of audit, done manually, is fairly expensive engineer-wise. |
||||
|
||||
### Conclusion |
||||
GRP-01-003 will be addressed through leveraging gRPC Core fuzzer tests to actively identify and resolve any integer overflow issues. If any issues are identified, we may create a `gpr_safe_malloc(size_t nmemb, size_t size)` wrapper to consolidate bounds-checking in one place. This function will *not* zero out memory because of performance concerns, and so will not be a calloc-style wrapper. |
||||
|
@ -0,0 +1,368 @@ |
||||
//
|
||||
// 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 <grpc/support/port_platform.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/lb_policy.h" |
||||
#include "src/core/ext/filters/client_channel/lb_policy_factory.h" |
||||
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" |
||||
#include "src/core/ext/filters/client_channel/service_config.h" |
||||
#include "src/core/ext/filters/client_channel/xds/xds_client.h" |
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
#include "src/core/lib/gprpp/orphanable.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
TraceFlag grpc_cds_lb_trace(false, "cds_lb"); |
||||
|
||||
namespace { |
||||
|
||||
constexpr char kCds[] = "cds_experimental"; |
||||
|
||||
// Parsed config for this LB policy.
|
||||
class ParsedCdsConfig : public LoadBalancingPolicy::Config { |
||||
public: |
||||
explicit ParsedCdsConfig(UniquePtr<char> cluster) |
||||
: cluster_(std::move(cluster)) {} |
||||
const char* cluster() const { return cluster_.get(); } |
||||
const char* name() const override { return kCds; } |
||||
|
||||
private: |
||||
UniquePtr<char> cluster_; |
||||
}; |
||||
|
||||
// CDS LB policy.
|
||||
class CdsLb : public LoadBalancingPolicy { |
||||
public: |
||||
explicit CdsLb(Args args); |
||||
|
||||
const char* name() const override { return kCds; } |
||||
|
||||
void UpdateLocked(UpdateArgs args) override; |
||||
void ResetBackoffLocked() override; |
||||
|
||||
private: |
||||
// Watcher for getting cluster data from XdsClient.
|
||||
class ClusterWatcher : public XdsClient::ClusterWatcherInterface { |
||||
public: |
||||
explicit ClusterWatcher(RefCountedPtr<CdsLb> parent) |
||||
: parent_(std::move(parent)) {} |
||||
void OnClusterChanged(CdsUpdate cluster_data) override; |
||||
void OnError(grpc_error* error) override; |
||||
|
||||
private: |
||||
RefCountedPtr<CdsLb> parent_; |
||||
}; |
||||
|
||||
// Delegating helper to be passed to child policy.
|
||||
class Helper : public ChannelControlHelper { |
||||
public: |
||||
explicit Helper(RefCountedPtr<CdsLb> parent) : parent_(std::move(parent)) {} |
||||
RefCountedPtr<SubchannelInterface> CreateSubchannel( |
||||
const grpc_channel_args& args) override; |
||||
void UpdateState(grpc_connectivity_state state, |
||||
UniquePtr<SubchannelPicker> picker) override; |
||||
void RequestReresolution() override; |
||||
void AddTraceEvent(TraceSeverity severity, StringView message) override; |
||||
|
||||
private: |
||||
RefCountedPtr<CdsLb> parent_; |
||||
}; |
||||
|
||||
~CdsLb(); |
||||
|
||||
void ShutdownLocked() override; |
||||
|
||||
RefCountedPtr<ParsedCdsConfig> config_; |
||||
|
||||
// Current channel args from the resolver.
|
||||
const grpc_channel_args* args_ = nullptr; |
||||
|
||||
// The xds client.
|
||||
RefCountedPtr<XdsClient> xds_client_; |
||||
// A pointer to the cluster watcher, to be used when cancelling the watch.
|
||||
// Note that this is not owned, so this pointer must never be derefernced.
|
||||
ClusterWatcher* cluster_watcher_ = nullptr; |
||||
|
||||
// Child LB policy.
|
||||
OrphanablePtr<LoadBalancingPolicy> child_policy_; |
||||
|
||||
// Internal state.
|
||||
bool shutting_down_ = false; |
||||
}; |
||||
|
||||
//
|
||||
// CdsLb::ClusterWatcher
|
||||
//
|
||||
|
||||
void CdsLb::ClusterWatcher::OnClusterChanged(CdsUpdate cluster_data) { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] received CDS update from xds client", |
||||
parent_.get()); |
||||
} |
||||
// Construct config for child policy.
|
||||
char* lrs_str = nullptr; |
||||
if (cluster_data.lrs_load_reporting_server_name != nullptr) { |
||||
gpr_asprintf(&lrs_str, " \"lrsLoadReportingServerName\": \"%s\",\n", |
||||
cluster_data.lrs_load_reporting_server_name.get()); |
||||
} |
||||
char* json_str; |
||||
gpr_asprintf(&json_str, |
||||
"[{\n" |
||||
" \"xds_experimental\": {\n" |
||||
"%s" |
||||
" \"edsServiceName\": \"%s\"\n" |
||||
" }\n" |
||||
"}]", |
||||
(lrs_str == nullptr ? "" : lrs_str), |
||||
(cluster_data.eds_service_name == nullptr |
||||
? parent_->config_->cluster() |
||||
: cluster_data.eds_service_name.get())); |
||||
gpr_free(lrs_str); |
||||
UniquePtr<char> json_str_deleter(json_str); |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] generated config for child policy: %s", |
||||
parent_.get(), json_str); |
||||
} |
||||
grpc_json* json = grpc_json_parse_string(json_str); |
||||
if (json == nullptr) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "Could not parse LB config: %s", json_str); |
||||
OnError(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
||||
gpr_free(msg); |
||||
return; |
||||
} |
||||
grpc_error* error = GRPC_ERROR_NONE; |
||||
RefCountedPtr<LoadBalancingPolicy::Config> config = |
||||
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error); |
||||
grpc_json_destroy(json); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
OnError(error); |
||||
return; |
||||
} |
||||
// Create child policy if not already present.
|
||||
if (parent_->child_policy_ == nullptr) { |
||||
LoadBalancingPolicy::Args args; |
||||
args.combiner = parent_->combiner(); |
||||
args.args = parent_->args_; |
||||
args.channel_control_helper = MakeUnique<Helper>(parent_->Ref()); |
||||
parent_->child_policy_ = |
||||
LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( |
||||
"xds_experimental", std::move(args)); |
||||
grpc_pollset_set_add_pollset_set( |
||||
parent_->child_policy_->interested_parties(), |
||||
parent_->interested_parties()); |
||||
} |
||||
// Update child policy.
|
||||
UpdateArgs args; |
||||
args.config = std::move(config); |
||||
args.args = grpc_channel_args_copy(parent_->args_); |
||||
parent_->child_policy_->UpdateLocked(std::move(args)); |
||||
} |
||||
|
||||
void CdsLb::ClusterWatcher::OnError(grpc_error* error) { |
||||
gpr_log(GPR_ERROR, "[cdslb %p] xds error obtaining data for cluster %s: %s", |
||||
parent_.get(), parent_->config_->cluster(), grpc_error_string(error)); |
||||
// Go into TRANSIENT_FAILURE if we have not yet created the child
|
||||
// policy (i.e., we have not yet received data from xds). Otherwise,
|
||||
// we keep running with the data we had previously.
|
||||
if (parent_->child_policy_ == nullptr) { |
||||
parent_->channel_control_helper()->UpdateState( |
||||
GRPC_CHANNEL_TRANSIENT_FAILURE, |
||||
MakeUnique<TransientFailurePicker>(error)); |
||||
} else { |
||||
GRPC_ERROR_UNREF(error); |
||||
} |
||||
} |
||||
|
||||
//
|
||||
// CdsLb::Helper
|
||||
//
|
||||
|
||||
RefCountedPtr<SubchannelInterface> CdsLb::Helper::CreateSubchannel( |
||||
const grpc_channel_args& args) { |
||||
if (parent_->shutting_down_) return nullptr; |
||||
return parent_->channel_control_helper()->CreateSubchannel(args); |
||||
} |
||||
|
||||
void CdsLb::Helper::UpdateState(grpc_connectivity_state state, |
||||
UniquePtr<SubchannelPicker> picker) { |
||||
if (parent_->shutting_down_) return; |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] state updated by child: %s", this, |
||||
ConnectivityStateName(state)); |
||||
} |
||||
parent_->channel_control_helper()->UpdateState(state, std::move(picker)); |
||||
} |
||||
|
||||
void CdsLb::Helper::RequestReresolution() { |
||||
if (parent_->shutting_down_) return; |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] Re-resolution requested from child policy.", |
||||
parent_.get()); |
||||
} |
||||
parent_->channel_control_helper()->RequestReresolution(); |
||||
} |
||||
|
||||
void CdsLb::Helper::AddTraceEvent(TraceSeverity severity, StringView message) { |
||||
if (parent_->shutting_down_) return; |
||||
parent_->channel_control_helper()->AddTraceEvent(severity, message); |
||||
} |
||||
|
||||
//
|
||||
// CdsLb
|
||||
//
|
||||
|
||||
CdsLb::CdsLb(Args args) |
||||
: LoadBalancingPolicy(std::move(args)), |
||||
xds_client_(XdsClient::GetFromChannelArgs(*args.args)) { |
||||
if (xds_client_ != nullptr && GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] Using xds client %p from channel", this, |
||||
xds_client_.get()); |
||||
} |
||||
} |
||||
|
||||
CdsLb::~CdsLb() { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] destroying cds LB policy", this); |
||||
} |
||||
grpc_channel_args_destroy(args_); |
||||
} |
||||
|
||||
void CdsLb::ShutdownLocked() { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] shutting down", this); |
||||
} |
||||
shutting_down_ = true; |
||||
if (child_policy_ != nullptr) { |
||||
grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(), |
||||
interested_parties()); |
||||
child_policy_.reset(); |
||||
} |
||||
if (xds_client_ != nullptr) { |
||||
if (cluster_watcher_ != nullptr) { |
||||
xds_client_->CancelClusterDataWatch(StringView(config_->cluster()), |
||||
cluster_watcher_); |
||||
} |
||||
xds_client_.reset(); |
||||
} |
||||
} |
||||
|
||||
void CdsLb::ResetBackoffLocked() { |
||||
if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked(); |
||||
} |
||||
|
||||
void CdsLb::UpdateLocked(UpdateArgs args) { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { |
||||
gpr_log(GPR_INFO, "[cdslb %p] received update", this); |
||||
} |
||||
// Update config.
|
||||
auto old_config = std::move(config_); |
||||
config_ = std::move(args.config); |
||||
// Update args.
|
||||
grpc_channel_args_destroy(args_); |
||||
args_ = args.args; |
||||
args.args = nullptr; |
||||
// If cluster name changed, cancel watcher and restart.
|
||||
if (old_config == nullptr || |
||||
strcmp(old_config->cluster(), config_->cluster()) != 0) { |
||||
if (old_config != nullptr) { |
||||
xds_client_->CancelClusterDataWatch(StringView(old_config->cluster()), |
||||
cluster_watcher_); |
||||
} |
||||
auto watcher = MakeUnique<ClusterWatcher>(Ref()); |
||||
cluster_watcher_ = watcher.get(); |
||||
xds_client_->WatchClusterData(StringView(config_->cluster()), |
||||
std::move(watcher)); |
||||
} |
||||
} |
||||
|
||||
//
|
||||
// factory
|
||||
//
|
||||
|
||||
class CdsFactory : public LoadBalancingPolicyFactory { |
||||
public: |
||||
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
||||
LoadBalancingPolicy::Args args) const override { |
||||
return MakeOrphanable<CdsLb>(std::move(args)); |
||||
} |
||||
|
||||
const char* name() const override { return kCds; } |
||||
|
||||
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig( |
||||
const grpc_json* json, grpc_error** error) const override { |
||||
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); |
||||
if (json == nullptr) { |
||||
// xds was mentioned as a policy in the deprecated loadBalancingPolicy
|
||||
// field or in the client API.
|
||||
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"field:loadBalancingPolicy error:cds policy requires configuration. " |
||||
"Please use loadBalancingConfig field of service config instead."); |
||||
return nullptr; |
||||
} |
||||
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0); |
||||
InlinedVector<grpc_error*, 3> error_list; |
||||
const char* cluster = nullptr; |
||||
for (const grpc_json* field = json->child; field != nullptr; |
||||
field = field->next) { |
||||
if (field->key == nullptr) continue; |
||||
if (strcmp(field->key, "cluster") == 0) { |
||||
if (cluster != nullptr) { |
||||
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"field:cluster error:Duplicate entry")); |
||||
} |
||||
if (field->type != GRPC_JSON_STRING) { |
||||
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"field:cluster error:type should be string")); |
||||
continue; |
||||
} |
||||
cluster = field->value; |
||||
} |
||||
} |
||||
if (cluster == nullptr) { |
||||
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"required field 'cluster' not present")); |
||||
} |
||||
if (error_list.empty()) { |
||||
return MakeRefCounted<ParsedCdsConfig>( |
||||
UniquePtr<char>(gpr_strdup(cluster))); |
||||
} else { |
||||
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Cds Parser", &error_list); |
||||
return nullptr; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
//
|
||||
// Plugin registration
|
||||
//
|
||||
|
||||
void grpc_lb_policy_cds_init() { |
||||
grpc_core::LoadBalancingPolicyRegistry::Builder:: |
||||
RegisterLoadBalancingPolicyFactory( |
||||
grpc_core::MakeUnique<grpc_core::CdsFactory>()); |
||||
} |
||||
|
||||
void grpc_lb_policy_cds_shutdown() {} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue