c++ 调用adns库实现DNS解析(全网唯一正确示例)

c++ 调用adns库实现DNS解析(全网唯一正确示例),第1张

可以使用一个adnsc库,版本是1.6,官方地址:adns - advanced, alternative, asynchronous resolver

下载地址是:http://www.chiark.greenend.org.uk/~ian/adns/ftp/adns-1.6.0.tar.gz

我实验环境是ubuntu20.04

解压,并编译

tar xzvf adns-1.6.0.tar.gz
cd adns-1.6.0
./configure
make

我没有make install

直接创建了一个测试目录,拷贝静态库


mkdir test
cp ./src/adns.h ./test
cp ./src/libadns.a ./test

建立一个测试文件

test.c

#include "adns.h"
#include 
#include 
#include 
#include 

int test_dns(char *host) {

	adns_state ads;
	adns_initflags flags;
	flags = (adns_initflags)(adns_if_nosigpipe | adns_if_noerrprint);
	adns_init(&ads, flags, NULL);
	adns_query quer = NULL;
	adns_submit(ads, host, (adns_rrtype)adns_r_a, (adns_queryflags)0, NULL, &quer);

	int tryCount = -1;
	int adns_cname = 0;

	adns_answer *ans = NULL;
	while (tryCount < 32)
	{
		tryCount += 1;
		

		int res = adns_check(ads, &quer, &ans, NULL);
		if (res == 0)
		{

			if (ans->status == adns_s_prohibitedcname)
			{
				
				char cname[128];
				strncpy(cname, ans->cname, 127);
				printf("cname = %s \n", ans->cname );
				cname[strlen(ans->cname)] = '\0';
				//if (quer)
				//	free(quer);
				if (ans)
					free(ans);
				ans = NULL;
				quer = NULL;
				adns_submit(ads, cname, (adns_rrtype)adns_r_addr, (adns_queryflags)0, NULL, &quer);
				adns_cname = 1;
			}
			else
			{
				// resolve IPv4 address
				if (adns_cname)
				{
					printf("ip: %s\n", ans->status == adns_s_ok ? inet_ntoa(ans->rrs.addr->addr.inet.sin_addr) : "no");
				}
				else {
					printf("ip: %s\n", ans->status == adns_s_ok ? inet_ntoa(*(ans->rrs.inaddr)) : "no");
				}

				adns_finish(ads);
				ads = NULL;
				break;
			}

		}
		else if (res == ESRCH || res == EAGAIN)
		{

			usleep(1000);

		}
		else
		{

			printf("host(%s) is err!\n", host);
		}
	}
	//if (quer)
	//	free(quer);

	if (ans)
		free(ans);

	if (ads)
	{
		printf("time out to find\n");
		adns_finish(ads);
	}	

	return 0;
}

int main(int argc, char *argv[])
{

	char host[128];
	while (1)
	{

		scanf("%s", host);
		if (strlen(host) == 4 && 0 == strcmp(host, "exit"))
			break;

		test_dns(host);
	}

	return 0;
}

这里解释一下,为什么不直接用wait,而非要做一个循环检测,主要是因为首次返回的可能是别名,而不是地址,必须要递归检测一下才能获取真实地址;

另外注意内存释放!!!

手动编译

gcc -o test ./test.c -L./ -ladns

生成test文件,

执行一下内存测试:

valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --undef-value-errors=no --log-file=log.txt ./test
www.sohu.com
cname = gs.a.sohu.com 
ip: 123.125.116.12
www.baidu.com
ip: 182.61.200.7
www.github.com
ip: 20.205.243.166
exit

==============华丽的分割线======================================

这里再附赠一个真正可以用的c++版本:

/**
 * @file dns_test.cpp
 * @author robin ([email protected])
 * @brief  example to show how to use libadns to parse domain name, and use it in a worker thread
 * @version 0.1
 * @date 2022-05-12
 * 
 * @copyright Copyright (c) 2022
 * 
 * build: gcc ./test.cpp -std=c++11 -L./  -ladns -lpthread -lstdc++  -w -g -o test
 * valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --undef-value-errors=no --log-file=log.txt ./test
 */


#include 
#include 
#include 
#include 
// just for cpp,
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#ifdef __cplusplus
extern "C"
{
#include "adns.h"
}
#endif
	



class Info
{
public:
	Info(const string & s, const adns_query& q) : url(s), quer(q), state(0), ipv4(""), isCName(false)
	{

	}
	string url;
	adns_query quer;
	int state;
	string ipv4;
	bool isCName;
	
	Info() = delete;
	//Info(const Info &) = delete;
	// time;
};

using InfoPtr = std::shared_ptr;

using dnsCallback = std::function;

class Dns
{
public:
	Dns();
	virtual ~Dns();

	void init(dnsCallback & fn);

	void query(const std::string & url);
	void pollStat();
	size_t getQueSize() { return infoQue.size(); }
	

private:
	adns_state ads;
	adns_initflags flags;

	std::deque urlQue;  // client push url into it 
	std::mutex mutexQue;

	std::deque infoQue; // work use this que without lock


	dnsCallback cb;
private:
	bool checkState(InfoPtr & info);
};

Dns::Dns()
{
	cb = nullptr;
	flags = (adns_initflags)(adns_if_nosigpipe | adns_if_noerrprint);
	ads = NULL;
	
}

Dns::~Dns()
{
	if (ads)
	{
		adns_finish(ads);
	}	

	cb = nullptr;
}

void Dns::init(dnsCallback & fn)
{
	cb = fn;
	adns_init(&ads, flags, NULL);
}

void Dns::query(const std::string & url)
{
	std::lock_guard guard(mutexQue);
	urlQue.emplace_back(url);
}

void Dns::pollStat()
{
	// auto lock
	{
		std::lock_guard guard(mutexQue);
		for (string & url : urlQue)
		{
			adns_query quer;
			int ret = adns_submit(ads, url.c_str(), (adns_rrtype)adns_r_a, (adns_queryflags)0, NULL, &quer);

			InfoPtr info = std::make_shared(url, quer);
			infoQue.emplace_back(info);
		}
		urlQue.clear();
	}
	
	std::deque temp;
	while (infoQue.size() > 0)
	{
		// get one and test it 
		InfoPtr info = infoQue[0];
		infoQue.pop_front();

		bool bFinish = checkState(info);
		if (bFinish)
		{
			// notify user that, we finished one
			if (cb != nullptr)
			{
				cb(info);
			}
		}
		else
		{
			temp.emplace_back(info);
		}
	}
	infoQue.swap(temp);
}

bool  Dns::checkState(InfoPtr & info)
{
	adns_answer *ans = nullptr;

	int res = adns_check(ads, &(info->quer), &ans, NULL);
	if (res == 0)
	{

		if (ans->status == adns_s_prohibitedcname)
		{
			info->isCName  = true;
			string cname(ans->cname, 0, 127);		
			if (ans != nullptr)
				free(ans);

			ans = NULL;
			
			info->quer = nullptr;
			adns_submit(ads, cname.c_str(), (adns_rrtype)adns_r_addr, (adns_queryflags)0, NULL, &(info->quer));
			return false;
		}
		else
		{
			// resolve IPv4 address
			//printf("status = %d\n", ans->status);
			if (info->isCName)
			{
				if (ans->status == adns_s_ok)
				{
					info->ipv4 = inet_ntoa(ans->rrs.addr->addr.inet.sin_addr);
				}
			}
			else
			{
				if (ans->status == adns_s_ok)
				{
					info->ipv4 = inet_ntoa(*(ans->rrs.inaddr));
				}
			}
			info->state = ans->status;

			if (ans != nullptr)
				free(ans);

			ans = NULL;
			return true;
			
		}

	}
	else if (res == ESRCH || res == EAGAIN)
	{
		info->state = -1;
		//usleep(100000);
		return false;

	}
	else
	{
		info->state = -2;
		return true;
	}

}


// test the callback function
void onFinishDns(const InfoPtr  & info)
{
	cout << info->state << ", ";
	cout << info->url << " : ";
	cout << info->ipv4 << endl;
}

bool bStop = false;
void workerFun(Dns * dns)
{
	while (bStop  == false)
	{
		dns->pollStat();
		usleep(1000);
	}
}

int main(int argc, char *argv[])
{
	Dns dns;
	dnsCallback cb = onFinishDns;
	dns.init(cb);

	char host[128];
	std::thread workerThread = std::thread(workerFun, &dns);
	while (1)
	{

		scanf("%s", host);
		if (strlen(host) == 4 && 0 == strcmp(host, "exit"))
			break;

		dns.query(host);
	}
	bStop = true;
	if (workerThread.joinable())
	{
		workerThread.join();

	}
	cout << "process exit!" << endl;
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/914734.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存