• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/ext/filters/client_channel/resolver_registry.h"
22 
23 #include <string.h>
24 
25 #include "absl/container/inlined_vector.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/str_format.h"
28 
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31 #include <grpc/support/string_util.h>
32 
33 namespace grpc_core {
34 
35 namespace {
36 
37 class RegistryState {
38  public:
RegistryState()39   RegistryState() : default_prefix_(gpr_strdup("dns:///")) {}
40 
SetDefaultPrefix(const char * default_resolver_prefix)41   void SetDefaultPrefix(const char* default_resolver_prefix) {
42     GPR_ASSERT(default_resolver_prefix != nullptr);
43     GPR_ASSERT(*default_resolver_prefix != '\0');
44     default_prefix_.reset(gpr_strdup(default_resolver_prefix));
45   }
46 
RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory)47   void RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory) {
48     for (size_t i = 0; i < factories_.size(); ++i) {
49       GPR_ASSERT(strcmp(factories_[i]->scheme(), factory->scheme()) != 0);
50     }
51     factories_.push_back(std::move(factory));
52   }
53 
LookupResolverFactory(absl::string_view scheme) const54   ResolverFactory* LookupResolverFactory(absl::string_view scheme) const {
55     for (size_t i = 0; i < factories_.size(); ++i) {
56       if (scheme == factories_[i]->scheme()) {
57         return factories_[i].get();
58       }
59     }
60     return nullptr;
61   }
62 
63   // Returns the factory for the scheme of \a target.  If \a target does
64   // not parse as a URI, prepends \a default_prefix_ and tries again.
65   // If URI parsing is successful (in either attempt), sets \a uri to
66   // point to the parsed URI.
67   // If \a default_prefix_ needs to be prepended, sets \a canonical_target
68   // to the canonical target string.
FindResolverFactory(absl::string_view target,URI * uri,std::string * canonical_target) const69   ResolverFactory* FindResolverFactory(absl::string_view target, URI* uri,
70                                        std::string* canonical_target) const {
71     GPR_ASSERT(uri != nullptr);
72     absl::StatusOr<URI> tmp_uri = URI::Parse(target);
73     ResolverFactory* factory =
74         tmp_uri.ok() ? LookupResolverFactory(tmp_uri->scheme()) : nullptr;
75     if (factory != nullptr) {
76       *uri = *tmp_uri;
77       return factory;
78     }
79     *canonical_target = absl::StrCat(default_prefix_.get(), target);
80     absl::StatusOr<URI> tmp_uri2 = URI::Parse(*canonical_target);
81     factory =
82         tmp_uri2.ok() ? LookupResolverFactory(tmp_uri2->scheme()) : nullptr;
83     if (factory != nullptr) {
84       *uri = *tmp_uri2;
85       return factory;
86     }
87     if (!tmp_uri.ok() || !tmp_uri2.ok()) {
88       gpr_log(GPR_ERROR, "%s",
89               absl::StrFormat("Error parsing URI(s). '%s':%s; '%s':%s", target,
90                               tmp_uri.status().ToString(), *canonical_target,
91                               tmp_uri2.status().ToString())
92                   .c_str());
93       return nullptr;
94     }
95     gpr_log(GPR_ERROR, "Don't know how to resolve '%s' or '%s'.",
96             std::string(target).c_str(), canonical_target->c_str());
97     return nullptr;
98   }
99 
100  private:
101   // We currently support 10 factories without doing additional
102   // allocation.  This number could be raised if there is a case where
103   // more factories are needed and the additional allocations are
104   // hurting performance (which is unlikely, since these allocations
105   // only occur at gRPC initialization time).
106   absl::InlinedVector<std::unique_ptr<ResolverFactory>, 10> factories_;
107   grpc_core::UniquePtr<char> default_prefix_;
108 };
109 
110 static RegistryState* g_state = nullptr;
111 
112 }  // namespace
113 
114 //
115 // ResolverRegistry::Builder
116 //
117 
InitRegistry()118 void ResolverRegistry::Builder::InitRegistry() {
119   if (g_state == nullptr) g_state = new RegistryState();
120 }
121 
ShutdownRegistry()122 void ResolverRegistry::Builder::ShutdownRegistry() {
123   delete g_state;
124   g_state = nullptr;
125 }
126 
SetDefaultPrefix(const char * default_prefix)127 void ResolverRegistry::Builder::SetDefaultPrefix(const char* default_prefix) {
128   InitRegistry();
129   g_state->SetDefaultPrefix(default_prefix);
130 }
131 
RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory)132 void ResolverRegistry::Builder::RegisterResolverFactory(
133     std::unique_ptr<ResolverFactory> factory) {
134   InitRegistry();
135   g_state->RegisterResolverFactory(std::move(factory));
136 }
137 
138 //
139 // ResolverRegistry
140 //
141 
LookupResolverFactory(const char * scheme)142 ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
143   GPR_ASSERT(g_state != nullptr);
144   return g_state->LookupResolverFactory(scheme);
145 }
146 
IsValidTarget(absl::string_view target)147 bool ResolverRegistry::IsValidTarget(absl::string_view target) {
148   URI uri;
149   std::string canonical_target;
150   ResolverFactory* factory =
151       g_state->FindResolverFactory(target, &uri, &canonical_target);
152   return factory == nullptr ? false : factory->IsValidUri(uri);
153 }
154 
CreateResolver(const char * target,const grpc_channel_args * args,grpc_pollset_set * pollset_set,std::shared_ptr<WorkSerializer> work_serializer,std::unique_ptr<Resolver::ResultHandler> result_handler)155 OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
156     const char* target, const grpc_channel_args* args,
157     grpc_pollset_set* pollset_set,
158     std::shared_ptr<WorkSerializer> work_serializer,
159     std::unique_ptr<Resolver::ResultHandler> result_handler) {
160   GPR_ASSERT(g_state != nullptr);
161   std::string canonical_target;
162   ResolverArgs resolver_args;
163   ResolverFactory* factory = g_state->FindResolverFactory(
164       target, &resolver_args.uri, &canonical_target);
165   resolver_args.args = args;
166   resolver_args.pollset_set = pollset_set;
167   resolver_args.work_serializer = std::move(work_serializer);
168   resolver_args.result_handler = std::move(result_handler);
169   OrphanablePtr<Resolver> resolver =
170       factory == nullptr ? nullptr
171                          : factory->CreateResolver(std::move(resolver_args));
172   return resolver;
173 }
174 
GetDefaultAuthority(absl::string_view target)175 std::string ResolverRegistry::GetDefaultAuthority(absl::string_view target) {
176   GPR_ASSERT(g_state != nullptr);
177   URI uri;
178   std::string canonical_target;
179   ResolverFactory* factory =
180       g_state->FindResolverFactory(target, &uri, &canonical_target);
181   std::string authority =
182       factory == nullptr ? "" : factory->GetDefaultAuthority(uri);
183   return authority;
184 }
185 
AddDefaultPrefixIfNeeded(const char * target)186 grpc_core::UniquePtr<char> ResolverRegistry::AddDefaultPrefixIfNeeded(
187     const char* target) {
188   GPR_ASSERT(g_state != nullptr);
189   URI uri;
190   std::string canonical_target;
191   g_state->FindResolverFactory(target, &uri, &canonical_target);
192   return grpc_core::UniquePtr<char>(canonical_target.empty()
193                                         ? gpr_strdup(target)
194                                         : gpr_strdup(canonical_target.c_str()));
195 }
196 
197 }  // namespace grpc_core
198