dns.h
源文件路径:
midware/ethernt/lan/dns.h所属模块:midware/ethernt/lan(W5500 以太网协议栈应用层 — DHCP/DNS/Socket) 代码行数:101
1. 文件职责
本文件是 WIZnet W5500 官方 DNS 客户端库的头文件,声明域名解析所需的三个接口(初始化、解析、1 秒计时)以及超时/重试/缓冲区尺寸等常量。
在 EMS 中它定义了"把服务器域名翻译成 IP"这条路径的契约:ethernet.c:296 用 DNS_init(SOCK_DNS, g_u8DNSBuf) 绑定 socket 0 与缓冲区,ethernet.c:497 在 dns_pro_fun() 里调用 DNS_run(),ethernet.c:1087 由 internet_time_handle() 每秒调用 DNS_time_handler()。
解析结果 ip_from_dns 输出到 g_stNetSysInfo.Domain_IP,是 TCP 客户端 connect() 的前置依赖,因此本文件处在"DHCP 拿到地址之后、TCP 建链之前"的环节。文件本身只有宏、返回值约定和函数原型,实现在 dns.c。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
_DNS_DEBUG_ | 宏 | 调试开关,被注释掉(第 59 行)。打开后引入 <stdio.h>,并让 dns.c 中大量 printf 生效;注意 dns.c 里还有一处拼写错误 _DNS_DEUBG_ |
MAX_DNS_BUF_SIZE | 宏 | DNS 报文缓冲区上限 512,同时也是 UDP 收包的单包最大长度(第 61 行) |
MAX_DOMAIN_NAME | 宏 | 待查询域名的最大长度 168(第 67 行);注释警告会用它的 1.5 倍在栈上开 MAXCNAME 缓冲 |
MAX_DNS_RETRY | 宏 | 重新查询次数 1(第 69 行) |
DNS_WAIT_TIME | 宏 | 等待应答时间 3,单位秒(第 70 行) |
IPPORT_DOMAIN | 宏 | DNS 服务端口 53(第 72 行) |
DNS_MSG_ID | 宏 | DNS 报文初始 ID 0x1122,实际发送时由 DNS_MSGID++ 递增(第 74 行) |
本文件没有定义结构体、枚举、联合体或位域;DNS 报文头 dhdr 与各类 TYPE_* 记录类型定义在 dns.c(第 65-115 行),不对外暴露。
3. 函数清单
本文件只有函数声明,没有函数定义。
| 函数名 | 作用域 | 说明(一句话) |
|---|---|---|
DNS_init(uint8_t s, uint8_t * buf) | 全局(声明,第 80 行) | DNS 客户端初始化:绑定 socket 号、报文缓冲区和初始报文 ID |
DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns) | 全局(声明,第 93 行) | 发送 DNS 查询并接收应答;非阻塞,返回 -1/0/1,另在实际实现中返回 2 表示"处理中" |
DNS_time_handler(void) | 全局(声明,第 99 行) | 1 秒节拍回调,需注册到系统 1s tick,供 DNS_run() 超时判断 |
4. 核心逻辑解析
4.1 返回值约定(第 88-91 行的注释与实际实现的差异)
头注释声明的返回值是:
-1:失败,原因是MAX_DOMAIN_NAME太小;0:失败(超时或解析错误);1:成功。
但 dns.c 的实际实现把函数改成了分次调用的非阻塞状态机(dns.c:509 处的 static u8 s_u8_flag),因此多出一个未在头文件中说明的返回值 2 = 正在处理中,请再次调用。调用方 ethernet.c:499 必须靠 if(ret == 2) return; 显式处理这个未文档化的值——这是本头文件与实际行为最值得注意的偏差。
4.2 缓冲区尺寸契约
MAX_DNS_BUF_SIZE(512) 在 dns.c 中同时承担三个角色:sendto 的长度参数、recvfrom 的截断上限、parse_name()/dns_makequery() 的边界参照。实际缓冲区由 ethernet.c:38 的 u8 g_u8DNSBuf[MAX_DNS_BUF_SIZE] 提供并透传给 DNS_init()。由于域名(MAX_DOMAIN_NAME=168)在组帧时对名称点分段后的总长度未做校验,缓冲区尺寸与域名长度之间的约束并不真正由这两个宏保证。
4.3 计时契约
DNS_time_handler() 的约定是"注册到系统 1s tick"。本工程接线同样在 ethernet.c:1087,由 task_system_aux(优先级 8)驱动,与 DHCP_time_handler() 共用同一个 1 秒闸门。真正查询/收包的 DNS_run() 则在 task_ethernet(优先级 17)中被 dns_pro_fun() 以 500 tick(0.5 s)间隔调用(ethernet.c:424),因此一次域名解析是"跨多次任务调度分步完成"的。
5. 对外接口
本文件导出的函数(均在 dns.c 中实现):DNS_init()、DNS_run()、DNS_time_handler()。
本文件导出的宏(供调用方使用):MAX_DNS_BUF_SIZE(ethernet.c:38 用它定义缓冲区)、MAX_DOMAIN_NAME、MAX_DNS_RETRY、DNS_WAIT_TIME、IPPORT_DOMAIN、DNS_MSG_ID。
本文件自身显式 include 了 <stdint.h>(第 54 行),因此函数原型中的 uint8_t/int8_t 不依赖包含顺序——这一点比 dhcp.h 严谨。
6. 依赖关系
- 依赖:
<stdint.h>(第 54 行)。不含其它工程头文件。 - 被依赖:
midware/ethernt/lan/dns.c(第 56 行 include)、midware/ethernt/ethernet.c(第 17 行#include "dns.h")。全工程仅此两处。
7. 备注与风险点
- 头注释与实现不一致:注释未提及返回值 2("处理中"),也未说明该函数是分次调用的状态机;调用方若严格按注释只处理 -1/0/1,会把"处理中"误判为失败。
dns.h:88-91的说明已过时。 MAX_DOMAIN_NAME的@todo注释(第 64-66 行)明确要求调用者自行保证域名长度 + 1 ≤ 168,但DNS_run()的签名里没有长度参数,实现里也没有长度校验(dns.c:432处的strcpy(sname, name)直接拷贝),约束完全靠人肉遵守。MAX_DNS_BUF_SIZE的 512 是经典 DNS over UDP 的保守上限,注释未说明;与dhcp.h的OPT_SIZE一样属硬编码魔法数。_DNS_DEBUG_保持注释状态,但dns.c内的守卫宏还有一处拼成_DNS_DEUBG_,即使打开调试也会有代码块不生效(dns.c:369、dns.c:379)。DNS_MSG_ID常量0x1122只是初值,容易被误读为固定 ID;实际 ID 由dns.c中的DNS_MSGID++递增。