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 "src/core/resolver/fake/fake_resolver.h"
21
22 #include <grpc/support/port_platform.h>
23
24 #include <memory>
25 #include <type_traits>
26 #include <utility>
27
28 #include "absl/log/check.h"
29 #include "absl/strings/string_view.h"
30 #include "src/core/config/core_configuration.h"
31 #include "src/core/lib/channel/channel_args.h"
32 #include "src/core/resolver/resolver_factory.h"
33 #include "src/core/util/debug_location.h"
34 #include "src/core/util/orphanable.h"
35 #include "src/core/util/uri.h"
36 #include "src/core/util/useful.h"
37 #include "src/core/util/work_serializer.h"
38
39 namespace grpc_core {
40
41 // This cannot be in an anonymous namespace, because it is a friend of
42 // FakeResolverResponseGenerator.
43 class FakeResolver final : public Resolver {
44 public:
45 explicit FakeResolver(ResolverArgs args);
46
47 void StartLocked() override;
48
49 void RequestReresolutionLocked() override;
50
51 private:
52 friend class FakeResolverResponseGenerator;
53
54 void ShutdownLocked() override;
55
56 void MaybeSendResultLocked();
57
58 // passed-in parameters
59 std::shared_ptr<WorkSerializer> work_serializer_;
60 std::unique_ptr<ResultHandler> result_handler_;
61 ChannelArgs channel_args_;
62 RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
63 // The next resolution result to be returned, if any. Present when we
64 // get a result before the resolver is started.
65 absl::optional<Result> next_result_;
66 // True after the call to StartLocked().
67 bool started_ = false;
68 // True after the call to ShutdownLocked().
69 bool shutdown_ = false;
70 };
71
FakeResolver(ResolverArgs args)72 FakeResolver::FakeResolver(ResolverArgs args)
73 : work_serializer_(std::move(args.work_serializer)),
74 result_handler_(std::move(args.result_handler)),
75 channel_args_(
76 // Channels sharing the same subchannels may have different resolver
77 // response generators. If we don't remove this arg, subchannel pool
78 // will create new subchannels for the same address instead of
79 // reusing existing ones because of different values of this channel
80 // arg. Can't just use GRPC_ARG_NO_SUBCHANNEL_PREFIX, since
81 // that can't be passed into the channel from test code.
82 args.args.Remove(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR)),
83 response_generator_(
84 args.args.GetObjectRef<FakeResolverResponseGenerator>()) {
85 if (response_generator_ != nullptr) {
86 response_generator_->SetFakeResolver(RefAsSubclass<FakeResolver>());
87 }
88 }
89
StartLocked()90 void FakeResolver::StartLocked() {
91 started_ = true;
92 MaybeSendResultLocked();
93 }
94
RequestReresolutionLocked()95 void FakeResolver::RequestReresolutionLocked() {
96 // Re-resolution can't happen until after we return an initial result.
97 CHECK(response_generator_ != nullptr);
98 response_generator_->ReresolutionRequested();
99 }
100
ShutdownLocked()101 void FakeResolver::ShutdownLocked() {
102 shutdown_ = true;
103 if (response_generator_ != nullptr) {
104 response_generator_->SetFakeResolver(nullptr);
105 response_generator_.reset();
106 }
107 }
108
MaybeSendResultLocked()109 void FakeResolver::MaybeSendResultLocked() {
110 if (!started_ || shutdown_) return;
111 if (next_result_.has_value()) {
112 // When both next_results_ and channel_args_ contain an arg with the same
113 // name, use the one in next_results_.
114 next_result_->args = next_result_->args.UnionWith(channel_args_);
115 result_handler_->ReportResult(std::move(*next_result_));
116 next_result_.reset();
117 }
118 }
119
120 //
121 // FakeResolverResponseGenerator
122 //
123
FakeResolverResponseGenerator()124 FakeResolverResponseGenerator::FakeResolverResponseGenerator() {}
125
~FakeResolverResponseGenerator()126 FakeResolverResponseGenerator::~FakeResolverResponseGenerator() {}
127
SetResponseAndNotify(Resolver::Result result,Notification * notify_when_set)128 void FakeResolverResponseGenerator::SetResponseAndNotify(
129 Resolver::Result result, Notification* notify_when_set) {
130 RefCountedPtr<FakeResolver> resolver;
131 {
132 MutexLock lock(&mu_);
133 if (resolver_ == nullptr) {
134 result_ = std::move(result);
135 if (notify_when_set != nullptr) notify_when_set->Notify();
136 return;
137 }
138 resolver = resolver_;
139 }
140 SendResultToResolver(std::move(resolver), std::move(result), notify_when_set);
141 }
142
SetFakeResolver(RefCountedPtr<FakeResolver> resolver)143 void FakeResolverResponseGenerator::SetFakeResolver(
144 RefCountedPtr<FakeResolver> resolver) {
145 Resolver::Result result;
146 {
147 MutexLock lock(&mu_);
148 resolver_ = resolver;
149 if (resolver_set_cv_ != nullptr) resolver_set_cv_->SignalAll();
150 if (resolver == nullptr) return;
151 if (!result_.has_value()) return;
152 result = std::move(*result_);
153 result_.reset();
154 }
155 SendResultToResolver(std::move(resolver), std::move(result), nullptr);
156 }
157
SendResultToResolver(RefCountedPtr<FakeResolver> resolver,Resolver::Result result,Notification * notify_when_set)158 void FakeResolverResponseGenerator::SendResultToResolver(
159 RefCountedPtr<FakeResolver> resolver, Resolver::Result result,
160 Notification* notify_when_set) {
161 auto* resolver_ptr = resolver.get();
162 resolver_ptr->work_serializer_->Run(
163 [resolver = std::move(resolver), result = std::move(result),
164 notify_when_set]() mutable {
165 if (!resolver->shutdown_) {
166 resolver->next_result_ = std::move(result);
167 resolver->MaybeSendResultLocked();
168 }
169 if (notify_when_set != nullptr) notify_when_set->Notify();
170 },
171 DEBUG_LOCATION);
172 }
173
WaitForResolverSet(absl::Duration timeout)174 bool FakeResolverResponseGenerator::WaitForResolverSet(absl::Duration timeout) {
175 MutexLock lock(&mu_);
176 if (resolver_ == nullptr) {
177 CondVar condition;
178 resolver_set_cv_ = &condition;
179 condition.WaitWithTimeout(&mu_, timeout);
180 resolver_set_cv_ = nullptr;
181 }
182 return resolver_ != nullptr;
183 }
184
WaitForReresolutionRequest(absl::Duration timeout)185 bool FakeResolverResponseGenerator::WaitForReresolutionRequest(
186 absl::Duration timeout) {
187 MutexLock lock(&reresolution_mu_);
188 if (!reresolution_requested_) {
189 CondVar condition;
190 reresolution_cv_ = &condition;
191 condition.WaitWithTimeout(&reresolution_mu_, timeout);
192 reresolution_cv_ = nullptr;
193 }
194 return std::exchange(reresolution_requested_, false);
195 }
196
ReresolutionRequested()197 void FakeResolverResponseGenerator::ReresolutionRequested() {
198 MutexLock lock(&reresolution_mu_);
199 reresolution_requested_ = true;
200 if (reresolution_cv_ != nullptr) reresolution_cv_->SignalAll();
201 }
202
203 namespace {
204
ResponseGeneratorChannelArgCopy(void * p)205 void* ResponseGeneratorChannelArgCopy(void* p) {
206 auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
207 generator->Ref().release();
208 return p;
209 }
210
ResponseGeneratorChannelArgDestroy(void * p)211 void ResponseGeneratorChannelArgDestroy(void* p) {
212 auto* generator = static_cast<FakeResolverResponseGenerator*>(p);
213 generator->Unref();
214 }
215
ResponseGeneratorChannelArgCmp(void * a,void * b)216 int ResponseGeneratorChannelArgCmp(void* a, void* b) {
217 return QsortCompare(a, b);
218 }
219
220 } // namespace
221
222 const grpc_arg_pointer_vtable
223 FakeResolverResponseGenerator::kChannelArgPointerVtable = {
224 ResponseGeneratorChannelArgCopy, ResponseGeneratorChannelArgDestroy,
225 ResponseGeneratorChannelArgCmp};
226
227 //
228 // Factory
229 //
230
231 namespace {
232
233 class FakeResolverFactory final : public ResolverFactory {
234 public:
scheme() const235 absl::string_view scheme() const override { return "fake"; }
236
IsValidUri(const URI &) const237 bool IsValidUri(const URI& /*uri*/) const override { return true; }
238
CreateResolver(ResolverArgs args) const239 OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
240 return MakeOrphanable<FakeResolver>(std::move(args));
241 }
242 };
243
244 } // namespace
245
RegisterFakeResolver(CoreConfiguration::Builder * builder)246 void RegisterFakeResolver(CoreConfiguration::Builder* builder) {
247 builder->resolver_registry()->RegisterResolverFactory(
248 std::make_unique<FakeResolverFactory>());
249 }
250
251 } // namespace grpc_core
252
grpc_resolver_fake_shutdown()253 void grpc_resolver_fake_shutdown() {}
254