| /* |
| * |
| * 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 <string.h> |
| |
| #include <grpc/grpc.h> |
| #include <grpc/support/alloc.h> |
| |
| #include "src/core/ext/filters/client_channel/resolver.h" |
| #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" |
| #include "src/core/ext/filters/client_channel/resolver_registry.h" |
| #include "src/core/ext/filters/client_channel/server_address.h" |
| #include "src/core/lib/channel/channel_args.h" |
| #include "src/core/lib/iomgr/combiner.h" |
| #include "src/core/lib/iomgr/resolve_address.h" |
| #include "src/core/lib/iomgr/timer.h" |
| #include "test/core/util/test_config.h" |
| |
| static gpr_mu g_mu; |
| static bool g_fail_resolution = true; |
| static grpc_core::Combiner* g_combiner; |
| |
| static void my_resolve_address(const char* addr, const char* /*default_port*/, |
| grpc_pollset_set* /*interested_parties*/, |
| grpc_closure* on_done, |
| grpc_resolved_addresses** addrs) { |
| gpr_mu_lock(&g_mu); |
| GPR_ASSERT(0 == strcmp("test", addr)); |
| grpc_error* error = GRPC_ERROR_NONE; |
| if (g_fail_resolution) { |
| g_fail_resolution = false; |
| gpr_mu_unlock(&g_mu); |
| error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); |
| } else { |
| gpr_mu_unlock(&g_mu); |
| *addrs = static_cast<grpc_resolved_addresses*>(gpr_malloc(sizeof(**addrs))); |
| (*addrs)->naddrs = 1; |
| (*addrs)->addrs = static_cast<grpc_resolved_address*>( |
| gpr_malloc(sizeof(*(*addrs)->addrs))); |
| (*addrs)->addrs[0].len = 123; |
| } |
| grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, error); |
| } |
| |
| static grpc_address_resolver_vtable test_resolver = {my_resolve_address, |
| nullptr}; |
| |
| static grpc_ares_request* my_dns_lookup_ares_locked( |
| const char* /*dns_server*/, const char* addr, const char* /*default_port*/, |
| grpc_pollset_set* /*interested_parties*/, grpc_closure* on_done, |
| std::unique_ptr<grpc_core::ServerAddressList>* addresses, |
| std::unique_ptr<grpc_core::ServerAddressList>* /*balancer_addresses*/, |
| char** /*service_config_json*/, int /*query_timeout_ms*/, |
| grpc_core::Combiner* /*combiner*/) { |
| gpr_mu_lock(&g_mu); |
| GPR_ASSERT(0 == strcmp("test", addr)); |
| grpc_error* error = GRPC_ERROR_NONE; |
| if (g_fail_resolution) { |
| g_fail_resolution = false; |
| gpr_mu_unlock(&g_mu); |
| error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure"); |
| } else { |
| gpr_mu_unlock(&g_mu); |
| *addresses = grpc_core::MakeUnique<grpc_core::ServerAddressList>(); |
| grpc_resolved_address dummy_resolved_address; |
| memset(&dummy_resolved_address, 0, sizeof(dummy_resolved_address)); |
| dummy_resolved_address.len = 123; |
| (*addresses)->emplace_back(dummy_resolved_address, nullptr); |
| } |
| grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, error); |
| return nullptr; |
| } |
| |
| static void my_cancel_ares_request_locked(grpc_ares_request* request) { |
| GPR_ASSERT(request == nullptr); |
| } |
| |
| static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver( |
| const char* name, |
| std::unique_ptr<grpc_core::Resolver::ResultHandler> result_handler) { |
| grpc_core::ResolverFactory* factory = |
| grpc_core::ResolverRegistry::LookupResolverFactory("dns"); |
| grpc_uri* uri = grpc_uri_parse(name, 0); |
| GPR_ASSERT(uri); |
| grpc_core::ResolverArgs args; |
| args.uri = uri; |
| args.combiner = g_combiner; |
| args.result_handler = std::move(result_handler); |
| grpc_core::OrphanablePtr<grpc_core::Resolver> resolver = |
| factory->CreateResolver(std::move(args)); |
| grpc_uri_destroy(uri); |
| return resolver; |
| } |
| |
| class ResultHandler : public grpc_core::Resolver::ResultHandler { |
| public: |
| struct ResolverOutput { |
| grpc_core::Resolver::Result result; |
| grpc_error* error = nullptr; |
| gpr_event ev; |
| |
| ResolverOutput() { gpr_event_init(&ev); } |
| ~ResolverOutput() { GRPC_ERROR_UNREF(error); } |
| }; |
| |
| void SetOutput(ResolverOutput* output) { |
| gpr_atm_rel_store(&output_, reinterpret_cast<gpr_atm>(output)); |
| } |
| |
| void ReturnResult(grpc_core::Resolver::Result result) override { |
| ResolverOutput* output = |
| reinterpret_cast<ResolverOutput*>(gpr_atm_acq_load(&output_)); |
| GPR_ASSERT(output != nullptr); |
| output->result = std::move(result); |
| output->error = GRPC_ERROR_NONE; |
| gpr_event_set(&output->ev, (void*)1); |
| } |
| |
| void ReturnError(grpc_error* error) override { |
| ResolverOutput* output = |
| reinterpret_cast<ResolverOutput*>(gpr_atm_acq_load(&output_)); |
| GPR_ASSERT(output != nullptr); |
| output->error = error; |
| gpr_event_set(&output->ev, (void*)1); |
| } |
| |
| private: |
| gpr_atm output_ = 0; // ResolverOutput* |
| }; |
| |
| // interleave waiting for an event with a timer check |
| static bool wait_loop(int deadline_seconds, gpr_event* ev) { |
| while (deadline_seconds) { |
| gpr_log(GPR_DEBUG, "Test: waiting for %d more seconds", deadline_seconds); |
| if (gpr_event_wait(ev, grpc_timeout_seconds_to_deadline(1))) return true; |
| deadline_seconds--; |
| |
| grpc_core::ExecCtx exec_ctx; |
| grpc_timer_check(nullptr); |
| } |
| return false; |
| } |
| |
| int main(int argc, char** argv) { |
| grpc::testing::TestEnvironment env(argc, argv); |
| |
| grpc_init(); |
| gpr_mu_init(&g_mu); |
| g_combiner = grpc_combiner_create(); |
| grpc_set_resolver_impl(&test_resolver); |
| grpc_dns_lookup_ares_locked = my_dns_lookup_ares_locked; |
| grpc_cancel_ares_request_locked = my_cancel_ares_request_locked; |
| |
| { |
| grpc_core::ExecCtx exec_ctx; |
| ResultHandler* result_handler = new ResultHandler(); |
| grpc_core::OrphanablePtr<grpc_core::Resolver> resolver = create_resolver( |
| "dns:test", |
| std::unique_ptr<grpc_core::Resolver::ResultHandler>(result_handler)); |
| ResultHandler::ResolverOutput output1; |
| result_handler->SetOutput(&output1); |
| resolver->StartLocked(); |
| grpc_core::ExecCtx::Get()->Flush(); |
| GPR_ASSERT(wait_loop(5, &output1.ev)); |
| GPR_ASSERT(output1.result.addresses.empty()); |
| GPR_ASSERT(output1.error != GRPC_ERROR_NONE); |
| |
| ResultHandler::ResolverOutput output2; |
| result_handler->SetOutput(&output2); |
| grpc_core::ExecCtx::Get()->Flush(); |
| GPR_ASSERT(wait_loop(30, &output2.ev)); |
| GPR_ASSERT(!output2.result.addresses.empty()); |
| GPR_ASSERT(output2.error == GRPC_ERROR_NONE); |
| |
| GRPC_COMBINER_UNREF(g_combiner, "test"); |
| } |
| |
| grpc_shutdown(); |
| gpr_mu_destroy(&g_mu); |
| } |