-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# | ||
# This file is open source software, licensed to you under the terms | ||
# of the Apache License, Version 2.0 (the "License"). See the NOTICE file | ||
# distributed with this work for additional information regarding copyright | ||
# ownership. 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. | ||
# | ||
|
||
# | ||
# Copyright (C) 2018 Scylladb, Ltd. | ||
# | ||
|
||
find_package (PkgConfig REQUIRED) | ||
|
||
pkg_check_modules (c-ares_PC libcares) | ||
|
||
find_library (c-ares_LIBRARY | ||
NAMES cares | ||
HINTS | ||
${c-ares_PC_LIBDIR} | ||
${c-ares_PC_LIBRARY_DIRS}) | ||
|
||
find_path (c-ares_INCLUDE_DIR | ||
NAMES ares_dns.h | ||
HINTS | ||
${c-ares_PC_INCLUDEDIR} | ||
${c-ares_PC_INCLUDE_DIRS}) | ||
|
||
mark_as_advanced ( | ||
c-ares_LIBRARY | ||
c-ares_INCLUDE_DIR) | ||
|
||
include (FindPackageHandleStandardArgs) | ||
|
||
find_package_handle_standard_args (c-ares | ||
REQUIRED_VARS | ||
c-ares_LIBRARY | ||
c-ares_INCLUDE_DIR | ||
VERSION_VAR c-ares_PC_VERSION) | ||
|
||
set (c-ares_LIBRARIES ${c-ares_LIBRARY}) | ||
set (c-ares_INCLUDE_DIRS ${c-ares_INCLUDE_DIR}) | ||
|
||
if (c-ares_FOUND AND NOT (TARGET c-ares::cares)) | ||
add_library (c-ares::cares UNKNOWN IMPORTED) | ||
|
||
set_target_properties (c-ares::cares | ||
PROPERTIES | ||
IMPORTED_LOCATION ${c-ares_LIBRARY} | ||
INTERFACE_INCLUDE_DIRECTORIES ${c-ares_INCLUDE_DIRS}) | ||
endif () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
add_executable(testc-ares test.cpp) | ||
target_link_libraries(testc-ares ucoro c-ares::cares) | ||
|
||
add_test(NAME testc-ares COMMAND testc-ares) | ||
set_target_properties(testc-ares PROPERTIES FOLDER "ucoro_tests") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
#include <iostream> | ||
#include "ucoro/awaitable.hpp" | ||
|
||
#include <ares.h> | ||
|
||
|
||
//////////////////////////////////////////////////////////////////// | ||
|
||
template <typename ArgType> | ||
struct __freeer_traits | ||
{ | ||
typedef void (*freefunc)(ArgType*); | ||
}; | ||
|
||
// NOTE: struct_free 不是一个类型,它就是一个函数本身! | ||
template<typename StructType, __freeer_traits<StructType>::freefunc struct_free> | ||
struct raii_c_ptr | ||
{ | ||
raii_c_ptr(const raii_c_ptr&) = delete; | ||
raii_c_ptr(raii_c_ptr&&) = delete; | ||
|
||
StructType* _managed_resource; | ||
|
||
~raii_c_ptr() | ||
{ | ||
struct_free(_managed_resource); | ||
} | ||
|
||
template<typename Initializer> | ||
raii_c_ptr(Initializer&& initdata) | ||
: _managed_resource(std::forward<Initializer>(initdata)) | ||
{ | ||
} | ||
|
||
StructType* operator->() | ||
{ | ||
return _managed_resource; | ||
} | ||
|
||
const StructType* operator->() const | ||
{ | ||
return _managed_resource; | ||
} | ||
|
||
operator bool() const | ||
{ | ||
return _managed_resource; | ||
} | ||
}; | ||
|
||
//////////////////////////////////////////////////////////////////// | ||
ucoro::awaitable<std::vector<sockaddr>> aync_cares_query(std::string host) | ||
{ | ||
ares_channel_t* channel = co_await ucoro::local_storage_t<ares_channel_t*>(); | ||
|
||
ares_addrinfo_hints hints = { 0 }; | ||
|
||
/* Perform an IPv4 and IPv6 request for the provided domain name */ | ||
co_return co_await callback_awaitable<std::vector<sockaddr>>([&](auto continuation_handle) mutable | ||
{ | ||
hints.ai_family = AF_UNSPEC; | ||
hints.ai_flags = ARES_AI_CANONNAME; | ||
|
||
/* Callback that is called when DNS query is finished */ | ||
auto addrinfo_cb = [](void *arg, int status, int timeouts, struct ares_addrinfo *result_) | ||
{ | ||
// 这里的 magic 是 decltype(continuation_handle) 类型,获取到了 resume 对象的指针. | ||
auto continuation_handle_p = reinterpret_cast<decltype(continuation_handle)*>(arg); | ||
|
||
std::vector<sockaddr> ret; | ||
|
||
raii_c_ptr<ares_addrinfo, &ares_freeaddrinfo> result(result_); | ||
|
||
if (result_) | ||
{ | ||
struct ares_addrinfo_node *node; | ||
for (node = result->nodes; node != NULL; node = node->ai_next) | ||
{ | ||
ret.push_back(*(node->ai_addr)); | ||
} | ||
} | ||
|
||
(*continuation_handle_p)(ret); | ||
delete continuation_handle_p; | ||
}; | ||
|
||
// continuation_handle 这里被移动构造了一个 堆 上的版本。 | ||
ares_getaddrinfo(channel, host.c_str(), NULL, &hints, addrinfo_cb, new decltype(continuation_handle){std::move(continuation_handle)}); | ||
}); | ||
} | ||
|
||
|
||
ucoro::awaitable<void> coro_cares_query() | ||
{ | ||
for (auto host : {"microcai.org", "github.com", "google.com", "baidu.com", "boost.org"}) | ||
{ | ||
auto dns_result = co_await aync_cares_query(host); | ||
|
||
printf("===================\n"); | ||
std::cout << "query for \"" << host << "\" result:" << std::endl; | ||
|
||
for (auto sock_address : dns_result) | ||
{ | ||
char addr_buf[64] = ""; | ||
const void *ptr = NULL; | ||
if (sock_address.sa_family == AF_INET) | ||
{ | ||
const struct sockaddr_in *in_addr = | ||
(const struct sockaddr_in *)((void *) &sock_address); | ||
ptr = &in_addr->sin_addr; | ||
} | ||
else if (sock_address.sa_family == AF_INET6) | ||
{ | ||
const struct sockaddr_in6 *in_addr = | ||
(const struct sockaddr_in6 *)((void *) &sock_address); | ||
ptr = &in_addr->sin6_addr; | ||
} | ||
else | ||
{ | ||
continue; | ||
} | ||
ares_inet_ntop(sock_address.sa_family, ptr, addr_buf, sizeof(addr_buf)); | ||
printf("Addr: %s\n", addr_buf); | ||
} | ||
} | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
ares_library_init(ARES_LIB_INIT_ALL); | ||
|
||
ares_channel_t *channel = NULL; | ||
ares_options options = { 0 }; | ||
|
||
/* Enable event thread so we don't have to monitor file descriptors */ | ||
options.evsys = ARES_EVSYS_DEFAULT; | ||
|
||
/* Initialize channel to run queries, a single channel can accept unlimited | ||
* queries */ | ||
if (ares_init_options(&channel, &options, ARES_OPT_EVENT_THREAD) != ARES_SUCCESS) | ||
{ | ||
printf("c-ares initialization issue\n"); | ||
return 1; | ||
} | ||
|
||
coro_start(coro_cares_query(), channel); | ||
|
||
/* Wait until no more requests are left to be processed */ | ||
ares_queue_wait_empty(channel, -1); | ||
|
||
/* Cleanup */ | ||
ares_destroy(channel); | ||
ares_library_cleanup(); | ||
return 0; | ||
} |