blob: 91c0267f95e1419aeaa553a3e6b80f464f8d0691 [file] [log] [blame]
/*
*
* 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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
namespace grpc_core {
namespace {
class RegistryState {
public:
RegistryState() : default_prefix_(gpr_strdup("dns:///")) {}
void SetDefaultPrefix(const char* default_resolver_prefix) {
GPR_ASSERT(default_resolver_prefix != nullptr);
GPR_ASSERT(*default_resolver_prefix != '\0');
default_prefix_.reset(gpr_strdup(default_resolver_prefix));
}
void RegisterResolverFactory(UniquePtr<ResolverFactory> factory) {
for (size_t i = 0; i < factories_.size(); ++i) {
GPR_ASSERT(strcmp(factories_[i]->scheme(), factory->scheme()) != 0);
}
factories_.push_back(std::move(factory));
}
ResolverFactory* LookupResolverFactory(const char* scheme) const {
for (size_t i = 0; i < factories_.size(); ++i) {
if (strcmp(scheme, factories_[i]->scheme()) == 0) {
return factories_[i].get();
}
}
return nullptr;
}
// Returns the factory for the scheme of \a target. If \a target does
// not parse as a URI, prepends \a default_prefix_ and tries again.
// If URI parsing is successful (in either attempt), sets \a uri to
// point to the parsed URI.
// If \a default_prefix_ needs to be prepended, sets \a canonical_target
// to the canonical target string.
ResolverFactory* FindResolverFactory(const char* target, grpc_uri** uri,
char** canonical_target) const {
GPR_ASSERT(uri != nullptr);
*uri = grpc_uri_parse(target, 1);
ResolverFactory* factory =
*uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
if (factory == nullptr) {
grpc_uri_destroy(*uri);
gpr_asprintf(canonical_target, "%s%s", default_prefix_.get(), target);
*uri = grpc_uri_parse(*canonical_target, 1);
factory =
*uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
if (factory == nullptr) {
grpc_uri_destroy(grpc_uri_parse(target, 0));
grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
*canonical_target);
}
}
return factory;
}
private:
// We currently support 10 factories without doing additional
// allocation. This number could be raised if there is a case where
// more factories are needed and the additional allocations are
// hurting performance (which is unlikely, since these allocations
// only occur at gRPC initialization time).
InlinedVector<UniquePtr<ResolverFactory>, 10> factories_;
UniquePtr<char> default_prefix_;
};
static RegistryState* g_state = nullptr;
} // namespace
//
// ResolverRegistry::Builder
//
void ResolverRegistry::Builder::InitRegistry() {
if (g_state == nullptr) g_state = New<RegistryState>();
}
void ResolverRegistry::Builder::ShutdownRegistry() {
Delete(g_state);
g_state = nullptr;
}
void ResolverRegistry::Builder::SetDefaultPrefix(
const char* default_resolver_prefix) {
InitRegistry();
g_state->SetDefaultPrefix(default_resolver_prefix);
}
void ResolverRegistry::Builder::RegisterResolverFactory(
UniquePtr<ResolverFactory> factory) {
InitRegistry();
g_state->RegisterResolverFactory(std::move(factory));
}
//
// ResolverRegistry
//
ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
GPR_ASSERT(g_state != nullptr);
return g_state->LookupResolverFactory(scheme);
}
OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
const char* target, const grpc_channel_args* args,
grpc_pollset_set* pollset_set, grpc_combiner* combiner) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
ResolverFactory* factory =
g_state->FindResolverFactory(target, &uri, &canonical_target);
ResolverArgs resolver_args;
resolver_args.uri = uri;
resolver_args.args = args;
resolver_args.pollset_set = pollset_set;
resolver_args.combiner = combiner;
OrphanablePtr<Resolver> resolver =
factory == nullptr ? nullptr : factory->CreateResolver(resolver_args);
grpc_uri_destroy(uri);
gpr_free(canonical_target);
return resolver;
}
UniquePtr<char> ResolverRegistry::GetDefaultAuthority(const char* target) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
ResolverFactory* factory =
g_state->FindResolverFactory(target, &uri, &canonical_target);
UniquePtr<char> authority =
factory == nullptr ? nullptr : factory->GetDefaultAuthority(uri);
grpc_uri_destroy(uri);
gpr_free(canonical_target);
return authority;
}
UniquePtr<char> ResolverRegistry::AddDefaultPrefixIfNeeded(const char* target) {
GPR_ASSERT(g_state != nullptr);
grpc_uri* uri = nullptr;
char* canonical_target = nullptr;
g_state->FindResolverFactory(target, &uri, &canonical_target);
grpc_uri_destroy(uri);
return UniquePtr<char>(canonical_target == nullptr ? gpr_strdup(target)
: canonical_target);
}
} // namespace grpc_core