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