1 //
2 // Copyright 2016 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // This is similar to the sockaddr resolver, except that it supports a
18 // bunch of query args that are useful for dependency injection in tests.
19
20 #include <grpc/support/port_platform.h>
21
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/string_util.h>
30
31 #include "src/core/ext/filters/client_channel/parse_address.h"
32 #include "src/core/ext/filters/client_channel/resolver_registry.h"
33 #include "src/core/ext/filters/client_channel/server_address.h"
34 #include "src/core/lib/channel/channel_args.h"
35 #include "src/core/lib/gpr/string.h"
36 #include "src/core/lib/gpr/useful.h"
37 #include "src/core/lib/iomgr/closure.h"
38 #include "src/core/lib/iomgr/resolve_address.h"
39 #include "src/core/lib/iomgr/unix_sockets_posix.h"
40 #include "src/core/lib/iomgr/work_serializer.h"
41 #include "src/core/lib/slice/slice_internal.h"
42 #include "src/core/lib/slice/slice_string_helpers.h"
43
44 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
45
46 namespace grpc_core {
47
48 // This cannot be in an anonymous namespace, because it is a friend of
49 // FakeResolverResponseGenerator.
50 class FakeResolver : public Resolver {
51 public:
52 explicit FakeResolver(ResolverArgs args);
53
54 void StartLocked() override;
55
56 void RequestReresolutionLocked() override;
57
58 private:
59 friend class FakeResolverResponseGenerator;
60 friend class FakeResolverResponseSetter;
61
62 virtual ~FakeResolver();
63
64 void ShutdownLocked() override;
65
66 void MaybeSendResultLocked();
67
68 void ReturnReresolutionResult();
69
70 // passed-in parameters
71 grpc_channel_args* channel_args_ = nullptr;
72 RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
73 // If has_next_result_ is true, next_result_ is the next resolution result
74 // to be returned.
75 bool has_next_result_ = false;
76 Result next_result_;
77 // Result to use for the pretended re-resolution in
78 // RequestReresolutionLocked().
79 bool has_reresolution_result_ = false;
80 Result reresolution_result_;
81 // True after the call to StartLocked().
82 bool started_ = false;
83 // True after the call to ShutdownLocked().
84 bool shutdown_ = false;
85 // if true, return failure
86 bool return_failure_ = false;
87 // pending re-resolution
88 bool reresolution_closure_pending_ = false;
89 };
90
FakeResolver(ResolverArgs args)91 FakeResolver::FakeResolver(ResolverArgs args)
92 : Resolver(std::move(args.work_serializer), std::move(args.result_handler)),
93 response_generator_(
94 FakeResolverResponseGenerator::GetFromArgs(args.args)) {
95 // Channels sharing the same subchannels may have different resolver response
96 // generators. If we don't remove this arg, subchannel pool will create new
97 // subchannels for the same address instead of reusing existing ones because
98 // of different values of this channel arg.
99 const char* args_to_remove[] = {GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR};
100 channel_args_ = grpc_channel_args_copy_and_remove(
101 args.args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove));
102 if (response_generator_ != nullptr) {
103 response_generator_->SetFakeResolver(Ref());
104 }
105 }
106
~FakeResolver()107 FakeResolver::~FakeResolver() { grpc_channel_args_destroy(channel_args_); }
108
StartLocked()109 void FakeResolver::StartLocked() {
110 started_ = true;
111 MaybeSendResultLocked();
112 }
113
RequestReresolutionLocked()114 void FakeResolver::RequestReresolutionLocked() {
115 if (has_reresolution_result_ || return_failure_) {
116 next_result_ = reresolution_result_;
117 has_next_result_ = true;
118 // Return the result in a different closure, so that we don't call
119 // back into the LB policy while it's still processing the previous
120 // update.
121 if (!reresolution_closure_pending_) {
122 reresolution_closure_pending_ = true;
123 Ref().release(); // ref held by closure
124 work_serializer()->Run([this]() { ReturnReresolutionResult(); },
125 DEBUG_LOCATION);
126 }
127 }
128 }
129
ShutdownLocked()130 void FakeResolver::ShutdownLocked() {
131 shutdown_ = true;
132 if (response_generator_ != nullptr) {
133 response_generator_->SetFakeResolver(nullptr);
134 response_generator_.reset();
135 }
136 }
137
MaybeSendResultLocked()138 void FakeResolver::MaybeSendResultLocked() {
139 if (!started_ || shutdown_) return;
140 if (return_failure_) {
141 // TODO(roth): Change resolver result generator to be able to inject
142 // the error to be returned.
143 result_handler()->ReturnError(grpc_error_set_int(
144 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resolver transient failure"),
145 GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
146 return_failure_ = false;
147 } else if (has_next_result_) {
148 Result result;
149 result.addresses = std::move(next_result_.addresses);
150 result.service_config = std::move(next_result_.service_config);
151 // TODO(roth): Use std::move() once grpc_error is converted to C++.
152 result.service_config_error = next_result_.service_config_error;
153 next_result_.service_config_error = GRPC_ERROR_NONE;
154 // When both next_results_ and channel_args_ contain an arg with the same
155 // name, only the one in next_results_ will be kept since next_results_ is
156 // before channel_args_.
157 result.args = grpc_channel_args_union(next_result_.args, channel_args_);
158 result_handler()->ReturnResult(std::move(result));
159 has_next_result_ = false;
160 }
161 }
162
ReturnReresolutionResult()163 void FakeResolver::ReturnReresolutionResult() {
164 reresolution_closure_pending_ = false;
165 MaybeSendResultLocked();
166 Unref();
167 }
168
169 class FakeResolverResponseSetter {
170 public:
FakeResolverResponseSetter(RefCountedPtr<FakeResolver> resolver,Resolver::Result result,bool has_result=false,bool immediate=true)171 explicit FakeResolverResponseSetter(RefCountedPtr<FakeResolver> resolver,
172 Resolver::Result result,
173 bool has_result = false,
174 bool immediate = true)
175 : resolver_(std::move(resolver)),
176 result_(std::move(result)),
177 has_result_(has_result),
178 immediate_(immediate) {}
179 void SetResponseLocked();
180 void SetReresolutionResponseLocked();
181 void SetFailureLocked();
182
183 private:
184 RefCountedPtr<FakeResolver> resolver_;
185 Resolver::Result result_;
186 bool has_result_;
187 bool immediate_;
188 };
189
190 // Deletes object when done
SetReresolutionResponseLocked()191 void FakeResolverResponseSetter::SetReresolutionResponseLocked() {
192 if (!resolver_->shutdown_) {
193 resolver_->reresolution_result_ = std::move(result_);
194 resolver_->has_reresolution_result_ = has_result_;
195 }
196 delete this;
197 }
198
199 // Deletes object when done
SetResponseLocked()200 void FakeResolverResponseSetter::SetResponseLocked() {
201 if (!resolver_->shutdown_) {
202 resolver_->next_result_ = std::move(result_);
203 resolver_->has_next_result_ = true;
204 resolver_->MaybeSendResultLocked();
205 }
206 delete this;
207 }
208
209 // Deletes object when done
SetFailureLocked()210 void FakeResolverResponseSetter::SetFailureLocked() {
211 if (!resolver_->shutdown_) {
212 resolver_->return_failure_ = true;
213 if (immediate_) resolver_->MaybeSendResultLocked();
214 }
215 delete this;
216 }
217
218 //
219 // FakeResolverResponseGenerator
220 //
221
FakeResolverResponseGenerator()222 FakeResolverResponseGenerator::FakeResolverResponseGenerator() {}
223
~FakeResolverResponseGenerator()224 FakeResolverResponseGenerator::~FakeResolverResponseGenerator() {}
225
SetResponse(Resolver::Result result)226 void FakeResolverResponseGenerator::SetResponse(Resolver::Result result) {
227 RefCountedPtr<FakeResolver> resolver;
228 {
229 MutexLock lock(&mu_);
230 if (resolver_ == nullptr) {
231 has_result_ = true;
232 result_ = std::move(result);
233 return;
234 }
235 resolver = resolver_->Ref();
236 }
237 FakeResolverResponseSetter* arg =
238 new FakeResolverResponseSetter(resolver, std::move(result));
239 resolver->work_serializer()->Run([arg]() { arg->SetResponseLocked(); },
240 DEBUG_LOCATION);
241 }
242
SetReresolutionResponse(Resolver::Result result)243 void FakeResolverResponseGenerator::SetReresolutionResponse(
244 Resolver::Result result) {
245 RefCountedPtr<FakeResolver> resolver;
246 {
247 MutexLock lock(&mu_);
248 GPR_ASSERT(resolver_ != nullptr);
249 resolver = resolver_->Ref();
250 }
251 FakeResolverResponseSetter* arg = new FakeResolverResponseSetter(
252 resolver, std::move(result), true /* has_result */);
253 resolver->work_serializer()->Run(
254 [arg]() { arg->SetReresolutionResponseLocked(); }, DEBUG_LOCATION);
255 }
256
UnsetReresolutionResponse()257 void FakeResolverResponseGenerator::UnsetReresolutionResponse() {
258 RefCountedPtr<FakeResolver> resolver;
259 {
260 MutexLock lock(&mu_);
261 GPR_ASSERT(resolver_ != nullptr);
262 resolver = resolver_->Ref();
263 }
264 FakeResolverResponseSetter* arg =
265 new FakeResolverResponseSetter(resolver, Resolver::Result());
266 resolver->work_serializer()->Run(
267 [arg]() { arg->SetReresolutionResponseLocked(); }, DEBUG_LOCATION);
268 }
269
SetFailure()270 void FakeResolverResponseGenerator::SetFailure() {
271 RefCountedPtr<FakeResolver> resolver;
272 {
273 MutexLock lock(&mu_);
274 GPR_ASSERT(resolver_ != nullptr);
275 resolver = resolver_->Ref();
276 }
277 FakeResolverResponseSetter* arg =
278 new FakeResolverResponseSetter(resolver, Resolver::Result());
279 resolver->work_serializer()->Run([arg]() { arg->SetFailureLocked(); },
280 DEBUG_LOCATION);
281 }
282
SetFailureOnReresolution()283 void FakeResolverResponseGenerator::SetFailureOnReresolution() {
284 RefCountedPtr<FakeResolver> resolver;
285 {
286 MutexLock lock(&mu_);
287 GPR_ASSERT(resolver_ != nullptr);
288 resolver = resolver_->Ref();
289 }
290 FakeResolverResponseSetter* arg = new FakeResolverResponseSetter(
291 resolver, Resolver::Result(), false /* has_result */,
292 false /* immediate */);
293 resolver->work_serializer()->Run([arg]() { arg->SetFailureLocked(); },
294 DEBUG_LOCATION);
295 }
296
SetFakeResolver(RefCountedPtr<FakeResolver> resolver)297 void FakeResolverResponseGenerator::SetFakeResolver(
298 RefCountedPtr<FakeResolver> resolver) {
299 MutexLock lock(&mu_);
300 resolver_ = std::move(resolver);
301 if (resolver_ == nullptr) return;
302 if (has_result_) {
303 FakeResolverResponseSetter* arg =
304 new FakeResolverResponseSetter(resolver_, std::move(result_));
305 resolver_->work_serializer()->Run([arg]() { arg->SetResponseLocked(); },
306 DEBUG_LOCATION);
307 has_result_ = false;
308 }
309 }
310
311 namespace {
312
response_generator_arg_copy(void * p)313 static void* response_generator_arg_copy(void* p) {
314 FakeResolverResponseGenerator* generator =
315 static_cast<FakeResolverResponseGenerator*>(p);
316 // TODO(roth): We currently deal with this ref manually. Once the
317 // new channel args code is converted to C++, find a way to track this ref
318 // in a cleaner way.
319 RefCountedPtr<FakeResolverResponseGenerator> copy = generator->Ref();
320 copy.release();
321 return p;
322 }
323
response_generator_arg_destroy(void * p)324 static void response_generator_arg_destroy(void* p) {
325 FakeResolverResponseGenerator* generator =
326 static_cast<FakeResolverResponseGenerator*>(p);
327 generator->Unref();
328 }
329
response_generator_cmp(void * a,void * b)330 static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
331
332 static const grpc_arg_pointer_vtable response_generator_arg_vtable = {
333 response_generator_arg_copy, response_generator_arg_destroy,
334 response_generator_cmp};
335
336 } // namespace
337
MakeChannelArg(FakeResolverResponseGenerator * generator)338 grpc_arg FakeResolverResponseGenerator::MakeChannelArg(
339 FakeResolverResponseGenerator* generator) {
340 grpc_arg arg;
341 arg.type = GRPC_ARG_POINTER;
342 arg.key = (char*)GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR;
343 arg.value.pointer.p = generator;
344 arg.value.pointer.vtable = &response_generator_arg_vtable;
345 return arg;
346 }
347
348 RefCountedPtr<FakeResolverResponseGenerator>
GetFromArgs(const grpc_channel_args * args)349 FakeResolverResponseGenerator::GetFromArgs(const grpc_channel_args* args) {
350 const grpc_arg* arg =
351 grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
352 if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr;
353 return static_cast<FakeResolverResponseGenerator*>(arg->value.pointer.p)
354 ->Ref();
355 }
356
357 //
358 // Factory
359 //
360
361 namespace {
362
363 class FakeResolverFactory : public ResolverFactory {
364 public:
IsValidUri(const grpc_uri *) const365 bool IsValidUri(const grpc_uri* /*uri*/) const override { return true; }
366
CreateResolver(ResolverArgs args) const367 OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
368 return MakeOrphanable<FakeResolver>(std::move(args));
369 }
370
scheme() const371 const char* scheme() const override { return "fake"; }
372 };
373
374 } // namespace
375
376 } // namespace grpc_core
377
grpc_resolver_fake_init()378 void grpc_resolver_fake_init() {
379 grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
380 absl::make_unique<grpc_core::FakeResolverFactory>());
381 }
382
grpc_resolver_fake_shutdown()383 void grpc_resolver_fake_shutdown() {}
384