⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns_client.c

📁 《ARM与嵌入式系统基础教程》
💻 C
字号:
//*------------------------------------------------------------------------------------------------
//* 文件名				: dns_clinet.c
//* 功能描述			: dns客户端
//* 作者    			: 焦海波
//* 版本				: 0.1
//* 建立日期、时间		: 2006/08/10 15:23
//* 最近修改日期、时间	: 
//* 修改原因			: 
//*------------------------------------------------------------------------------------------------
//*------------------------------------------ 头文件 -----------------------------------------------
#include	"/uCOS-II/ucos_ii.h"
#include	"/LwIP/include/lwip/tcpip.h"
#include	"/tools/converter.h"
#include	"dns_client.h"
//*================================================================================================
//*                     函 数 区
//*================================================================================================
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ilvPacketDNSQuest
//* 功能描述 : 封装DNS查询包
//*          :     <pszDN>[in] 指向域名的指针
//*          :  <s32DNLen>[in] 域名长度
//*          :   <pstPbuf>[in] 指向st_pbuf结构的指针,它这个结构保存要发送的DNS的查询包
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
__inline void __ilvPacketDNSQuest(INT8S *pszDN, INT32S s32DNLen, ST_PBUF *pstPbuf)
{
	ST_DNS_PACKET_HDR	*__pstDNSPacket;
	BST_ID_AND_FLAGS	*__pbstIDAndFlags;
	
	__pstDNSPacket = (ST_DNS_PACKET_HDR*)pstPbuf->payload;
	__pstDNSPacket->u32IDAndFlags = 0x00000000;
	__pbstIDAndFlags = &__pstDNSPacket->u32IDAndFlags;
	__pbstIDAndFlags->bitID = 0x0608;
	__pbstIDAndFlags->bitIsRD = 0x1;
	__pstDNSPacket->u16QCount = 0x0100;
	__pstDNSPacket->u16ACount = 0x0000;
	__pstDNSPacket->u16AuthCount = 0x0000;
	__pstDNSPacket->u16ARC = 0x0000;
	memcpy((INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN, pszDN, s32DNLen);
	*((INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN + s32DNLen) = 0x00;
	*((INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN + s32DNLen + 1) = DNS_PACKET_QUERY_TYPE;
	*((INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN + s32DNLen + 2) = 0x00;
	*((INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN + s32DNLen + 3) = DNS_PACKET_QUERY_CLASS;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ilu32ParseRespDNSPacket
//* 功能描述 : 解析DNS服务器响应的数据包
//* 入口参数 :  <pstPbuf>[in] 指向ST_NETBUF的指针
//*          :   <pu32IP>[in] 指向接收缓冲区(保存IP地址)的指针
//*          : <s32DNlen>[in] 要查询域名的长度
//* 出口参数 : - DNS_OK	       : 查询成功
//*          : - DNS_NOT_EXIST : 指定的域名不存在
//*          : - DNS_OTHER     : 未知错误
//*------------------------------------------------------------------------------------------------
__inline INT32U __ilu32ParseRespDNSPacket(ST_PBUF *pstPbuf, INT32U *pu32IP, INT32S s32DNLen)
{
	ST_DNS_PACKET_HDR	*__pstDNSPacket;
	INT32U				__u32Val;
	BST_ID_AND_FLAGS	*__pbstIDAndFlags;
	void 				*__pvData;
	INT16U				__u16ACount, __u16AnswerDataLen, __u16Offset;
	
	__pstDNSPacket = (ST_DNS_PACKET_HDR	*)pstPbuf->payload;
	__u32Val = __pstDNSPacket->u32IDAndFlags;
	__pbstIDAndFlags = &__u32Val;
	
	if(__pbstIDAndFlags->bitOptResult == 0)
	{
		__u16ACount = macHighToLowForWord(__pstDNSPacket->u16ACount);
		__u16Offset = s32DNLen + 14;
		while(__u16ACount > 0)
		{
			__pvData = (INT8U*)pstPbuf->payload + DNS_PACKET_HDR_LEN + __u16Offset;
			__u16AnswerDataLen = macHighToLowForWord(*((__packed INT16U*)__pvData));
			
			if((__u16AnswerDataLen == 4) && macHighToLowForWord(*((__packed INT16U*)((INT8U*)__pvData - 8))) == DNS_PACKET_QUERY_TYPE)
			{
				*pu32IP = *((__packed INT32U *)((INT8U*)__pvData + 2));				
				
				return DNS_OK;
			}
			
			__u16Offset += 12 + __u16AnswerDataLen;
			
			__u16ACount--;
		}
		
		return DNS_OTHER;
	}
	else if(__pbstIDAndFlags->bitOptResult == 3)
	{
		return  DNS_NOT_EXIST;
	}
	
	return DNS_OTHER;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __vDNSRecv
//* 功能描述 : 接收并解析DNS服务器响应的数据包,它是一个回调函数,由udp_recv()设置
//* 入口参数 :    <pstArg>[in] 指向ST_RECV_FUN_ARG结构的指针,这个结构保存着该函数需要的入口参数
//*          : <pstUDPPCB>[in] 指向ST_UDP_PCB结构的指针
//*          :   <pstPbuf>[in] 指向st_pbuf结构的指针,它保存着收到的内容
//*          :     <pstIP>[in] IP地址
//*          :   <u16Port>[in] 端口号
//* 出口参数 : - DNS_OK	       : 查询成功
//*          : - DNS_NOT_EXIST : 指定的域名不存在
//*          : - DNS_OTHER     : 未知错误
//*------------------------------------------------------------------------------------------------
static void __vDNSRecv(ST_RECV_FUN_ARG *pstArg, ST_UDP_PCB *pstUDPPCB, 
						ST_PBUF *pstPbuf, ST_IP_ADDR *pstIP, INT16U u16Port)
{
	if(pstPbuf != NULL)
	{
		pstArg->u32RtnCode = __ilu32ParseRespDNSPacket(pstPbuf, pstArg->pu32IP, pstArg->s32DNLen);
	
		pbuf_free(pstPbuf);
	}
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __u32GetIP
//* 功能描述 : 查询DNS服务器,获取指定域名绑定的IP地址,这里只能使用协议栈直接接口实现,使用其提供
//*          : 的API无法满足需求。如果接收DNS响应包使用netconn_recv函数非常容易阻塞系统,因为UDP
//*          : 不可靠。
//*          :  <pstPbuf>[in] 指向st_pbuf结构的指针,它这个结构保存要发送的DNS的查询包
//*          :   <pu32IP>[in] 指向接收缓冲区(保存IP地址)的指针
//*          : <s32DNLen>[in] 要查询的域名长度
//*          : <u32DNSIP>[in] DNS服务器的IP地址
//* 出口参数 : - DNS_OK	       : 查询成功
//*          : - DNS_NOT_EXIST : 指定的域名不存在
//*          : - DNS_NOT_CONN  : 无法连接指定的域名服务器(主、备服务器均不可用)
//*          : - DNS_OTHER     : 未知错误
//*------------------------------------------------------------------------------------------------
INT32U __u32GetIP(ST_PBUF *pstPbuf, INT32U *pu32IP, INT32S s32DNLen, INT32U u32DNSIP)
{
	ST_IP_ADDR 			__stIPAddr;
	ST_UDP_PCB			*__pstUDPPCB;
	ST_RECV_FUN_ARG		__stRecvArg;
	INT32S				i, k = 0;
	INT32U				__u32RtnCode;
	
	__pstUDPPCB = udp_new();
	if(__pstUDPPCB == NULL)
		return DNS_OTHER;
	
	__stIPAddr.addr = htonl(u32DNSIP);
	if(udp_connect(__pstUDPPCB, &__stIPAddr, DNS_PORT) != ERR_OK)
		return DNS_OTHER;
		
	memset(&__stRecvArg, 0, sizeof(ST_RECV_FUN_ARG));
	__stRecvArg.u32RtnCode = -1;
	__stRecvArg.pu32IP = pu32IP;
	__stRecvArg.s32DNLen = s32DNLen;
	
	udp_recv(__pstUDPPCB, __vDNSRecv, &__stRecvArg);
	
	//* 发送和接收
	while(k<15)
	{
		udp_send(__pstUDPPCB, pstPbuf);		

		i = 0;	
		while(i < 30)
		{
			__u32RtnCode = __stRecvArg.u32RtnCode;
			
			if(__u32RtnCode != -1)
				goto __lblEnd;
			
			OSTimeDlyHMSM(0, 0, 0, 100);
			i++;
		}
		
		k++;
	}				
	
__lblEnd:
	//* 收尾工作,回收占用的资源
	udp_disconnect(__pstUDPPCB);
	udp_remove(__pstUDPPCB);
	
	if(__u32RtnCode != -1)
		return __stRecvArg.u32RtnCode;
	else
		return DNS_NOT_CONN;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : u32DNToIP
//* 功能描述 : 查询DNS服务器,将指定的域名转换为IP地址
//* 入口参数 :    <pszDN>[in] 指向域名的指针
//*          : <s32DNLen>[in] 域名长度
//*          :   <pu32IP>[in] 指向接收缓冲区(保存IP地址)的指针
//* 出口参数 : - DNS_OK	       : 查询成功
//*          : - DNS_NOT_EXIST : 指定的域名不存在
//*          : - DNS_NOT_CONN  : 无法连接指定的域名服务器(主、备服务器均不可用)
//*          : - DNS_OTHER     : 未知错误
//*------------------------------------------------------------------------------------------------
INT32U u32DNToIP(INT8S *pszDN, INT32S s32DNLen, INT32U *pu32IP)
{
	ST_PBUF         	*__pstPbuf = NULL;
	INT32S				__s32TotLen;
	INT32U				__u32RtnCode;

	__s32TotLen = DNS_PACKET_HDR_LEN + s32DNLen + 4;
	__pstPbuf = pbuf_alloc(PBUF_RAW, __s32TotLen, PBUF_POOL);
	if(__pstPbuf == NULL)
		return DNS_OTHER;
		
	__ilvPacketDNSQuest(pszDN, s32DNLen, __pstPbuf);

	__u32RtnCode = __u32GetIP(__pstPbuf, pu32IP, s32DNLen, DNS1_IP_ADDR);
	if(__u32RtnCode == DNS_NOT_CONN || __u32RtnCode == DNS_OTHER)
		__u32RtnCode = __u32GetIP(__pstPbuf, pu32IP, s32DNLen, DNS2_IP_ADDR);
	
	pbuf_free(__pstPbuf);
		
	return __u32RtnCode;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -