LWIP之DNS域名解析(二)
来源:互联网 发布:软件著作权申请条件 编辑:程序博客网 时间:2024/06/04 14:00
(一)交代了下DNS.C文件的代码,那么在(二)中我再补充下 DNS.h的代码,并做简要说明。
之后是netdb.h的代码和netdb.c的代码!
代码已经注释完。
代码中可能加了注释后,可能会出现一些<p></p>类似这种代码,是因为我编辑时,出现的插入,在csdn提供的编写环境里,会自动添加一些语句。
大家可以根据经验,手动剔除掉,如果大家想直接复制粘贴代码的话。。。
#ifndef __LWIP_DNS_H__#define __LWIP_DNS_H__#include "lwip/opt.h"#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */#ifdef __cplusplusextern "C" {#endif/** DNS timer period */#define DNS_TMR_INTERVAL 1000/** DNS field TYPE used for "Resource Records" */#define DNS_RRTYPE_A 1 /* a host address ipv4的地址*/#define DNS_RRTYPE_NS 2 /* an authoritative name server 授权的名字服务*/#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) 已作废*/#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) 已作废*/#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias 别名,可以理解为外号*/#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority 初始授权区域*/#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) 实验性质的邮箱域名*/#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) 实验性质的*/#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) 实验性质的*/#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) 实验性质的*/#define DNS_RRTYPE_WKS 11 /* a well known service description 众所周知的服务*/#define DNS_RRTYPE_PTR 12 /* a domain name pointer 域名指针,用于指向域名,有时候域名会出现多次,那么重复的就用指针偏移来取代*/#define DNS_RRTYPE_HINFO 13 /* host information 主机信息 */#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information 邮箱列表信息*/#define DNS_RRTYPE_MX 15 /* mail exchange 邮箱交换*/#define DNS_RRTYPE_TXT 16 /* text strings 文本字符串*//*#define DNS_RRTYPE_AAAA 28 /* ipv6 addr*/ 如果要实现ipv6的DNS,这个必须实现。在请求和响应报文中都要有此类型 */
/** DNS field CLASS used for "Resource Records" 类型 */#define DNS_RRCLASS_IN 1 /* the Internet 我们最常用的也最常见的,也就是这个*/#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */#define DNS_RRCLASS_CH 3 /* the CHAOS class */#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit *//* The size used for the next line is rather a hack, but it prevents including socket.h in all files that include memp.h, and that would possibly break portability (since socket.h defines some types and constants possibly already define by the OS). Calculation rule: sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)#if DNS_LOCAL_HOSTLIST/** struct used for local host-list */struct local_hostlist_entry { /** static hostname 域名字符串*/ const char *name; /** static host address in network byteorder 网络字节序的主机地址*/ ip_addr_t addr; struct local_hostlist_entry *next;};#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH#endif#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */#endif /* DNS_LOCAL_HOSTLIST *//** Callback which is invoked when a hostname is found. 如果找到了,就回调,callback是回调函数的指针 * A function of this type must be implemented by the application using the DNS resolver. * @param name pointer to the name that was looked up. * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, * or NULL if the name could not be found (or on any other error). * @param callback_arg a user-specified callback argument passed to dns_gethostbyname*/typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);void dns_init(void); /*初始化DNS*/void dns_tmr(void); /*时间管理*/void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);/*设置服务器,可以理解为配置主次域名DNS*/ip_addr_t dns_getserver(u8_t numdns);/*读域名服务器的地址*/err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); /*我们上层应用最常用的API接口*/#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMICint dns_local_removehost(const char *hostname, const ip_addr_t *addr);/*删除缓存记录*/err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);/*增加缓存记录*/#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */#ifdef __cplusplus}#endif#endif /* LWIP_DNS */#endif /* __LWIP_DNS_H__ */
一下是 netdb.h 中的代码部分。
#ifndef __LWIP_NETDB_H__#define __LWIP_NETDB_H__#include "lwip/opt.h"#if LWIP_DNS && LWIP_SOCKET#include <stddef.h> /* for size_t */#include "lwip/inet.h"#include "lwip/sockets.h"#ifdef __cplusplusextern "C" {#endif/* some rarely used options */#ifndef LWIP_DNS_API_DECLARE_H_ERRNO#define LWIP_DNS_API_DECLARE_H_ERRNO 1#endif#ifndef LWIP_DNS_API_DEFINE_ERRORS#define LWIP_DNS_API_DEFINE_ERRORS 1#endif#ifndef LWIP_DNS_API_DECLARE_STRUCTS#define LWIP_DNS_API_DECLARE_STRUCTS 1#endif#if LWIP_DNS_API_DEFINE_ERRORS /* 定义的错误号*//** Errors used by the DNS API functions, h_errno can be one of them */#define EAI_NONAME 200 /*无名字*/#define EAI_SERVICE 201 /*服务错误*/#define EAI_FAIL 202#define EAI_MEMORY 203#define HOST_NOT_FOUND 210#define NO_DATA 211#define NO_RECOVERY 212#define TRY_AGAIN 213#endif /* LWIP_DNS_API_DEFINE_ERRORS */#if LWIP_DNS_API_DECLARE_STRUCTSstruct hostent { char *h_name; /* Official name of the host. */ char **h_aliases; /* A pointer to an array of pointers to alternative host names, terminated by a null pointer. */ int h_addrtype; /* Address type. */ int h_length; /* The length, in bytes, of the address. */ char **h_addr_list; /* A pointer to an array of pointers to network addresses (in network byte order) for the host, terminated by a null pointer. */#define h_addr h_addr_list[0] /* for backward compatibility */};/*地址信息*/struct addrinfo { int ai_flags; /* Input flags. */ int ai_family; /* Address family of socket. */ int ai_socktype; /* Socket type. */ int ai_protocol; /* Protocol of socket. */ socklen_t ai_addrlen; /* Length of socket address. */ struct sockaddr *ai_addr; /* Socket address of socket. */ char *ai_canonname; /* Canonical name of service location. */ struct addrinfo *ai_next; /* Pointer to next in list. */};#endif /* LWIP_DNS_API_DECLARE_STRUCTS */#if LWIP_DNS_API_DECLARE_H_ERRNO/* application accessable error code set by the DNS API functions */extern int h_errno;#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/
/*下面是一些API函数声明,读信息的函数接口和释放地址信息的接口声明*/struct hostent *lwip_gethostbyname(const char *name); int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);void lwip_freeaddrinfo(struct addrinfo *ai);int lwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);#if LWIP_COMPAT_SOCKETS#define gethostbyname(name) lwip_gethostbyname(name)#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)#define getaddrinfo(nodname, servname, hints, res) \ lwip_getaddrinfo(nodname, servname, hints, res)#endif /* LWIP_COMPAT_SOCKETS */#ifdef __cplusplus}#endif#endif /* LWIP_DNS && LWIP_SOCKET */#endif /* __LWIP_NETDB_H__ */
下面是netdb.c 的代码,首先是一些宏定义,条件编译宏。
#include "lwip/netdb.h"#if LWIP_DNS && LWIP_SOCKET#include "lwip/err.h"#include "lwip/mem.h"#include "lwip/memp.h"#include "lwip/ip_addr.h"#include "lwip/api.h"#include "lwip/dns.h"#include <string.h>#include <stdlib.h>/** helper struct for gethostbyname_r to access the char* buffer */struct gethostbyname_r_helper { ip_addr_t *addrs; ip_addr_t addr; char *aliases;};/** h_errno is exported in netdb.h for access by applications. */#if LWIP_DNS_API_DECLARE_H_ERRNOint h_errno;#endif /* LWIP_DNS_API_DECLARE_H_ERRNO *//** define "hostent" variables storage: 0 if we use a static (but unprotected) * set of variables for lwip_gethostbyname, 1 if we use a local storage */#ifndef LWIP_DNS_API_HOSTENT_STORAGE#define LWIP_DNS_API_HOSTENT_STORAGE 0#endif/** define "hostent" variables storage */#if LWIP_DNS_API_HOSTENT_STORAGE#define HOSTENT_STORAGE#else#define HOSTENT_STORAGE static#endif /* LWIP_DNS_API_STATIC_HOSTENT */
紧接着是 lwip_gethostbyname 函数,它的返回值是hostent指针,关于主机域名的地址信息。
/** * Returns an entry containing addresses of address family AF_INET * for the host with name name. * Due to dns_gethostbyname limitations, only one address is returned. * * @param name the hostname to resolve * @return an entry containing addresses of address family AF_INET * for the host with name name */struct hostent*lwip_gethostbyname(const char *name){ err_t err; ip_addr_t addr; /* buffer variables for lwip_gethostbyname() */ HOSTENT_STORAGE struct hostent s_hostent; HOSTENT_STORAGE char *s_aliases; HOSTENT_STORAGE ip_addr_t s_hostent_addr; HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; /* query host IP address */ err = netconn_gethostbyname(name, &addr); /*这个函数里封装了一些其他函数,同样是通过域名解析地址返回*/ if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); /* 出错的话,打印LOG */ h_errno = HOST_NOT_FOUND; return NULL; } /* fill hostent 如果没错误,就填充结构体*/ s_hostent_addr = addr; s_phostent_addr[0] = &s_hostent_addr; s_phostent_addr[1] = NULL; s_hostent.h_name = (char*)name; s_hostent.h_aliases = &s_aliases; s_hostent.h_addrtype = AF_INET; /*这是v4的,如果要是v6的话,要改成条件编译语句*/ s_hostent.h_length = sizeof(ip_addr_t); s_hostent.h_addr_list = (char**)&s_phostent_addr;#if DNS_DEBUG /* dump hostent */ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases)); if (s_hostent.h_aliases != NULL) { u8_t idx; for ( idx=0; s_hostent.h_aliases[idx]; idx++) { LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx])); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx])); } } LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list)); if (s_hostent.h_addr_list != NULL) { u8_t idx; for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); } }#endif /* DNS_DEBUG */#if LWIP_DNS_API_HOSTENT_STORAGE /* this function should return the "per-thread" hostent after copy from s_hostent */ return sys_thread_hostent(&s_hostent);#else return &s_hostent;#endif /* LWIP_DNS_API_HOSTENT_STORAGE */}
下面是lwip_gethostbyname_r 函数
/** * Thread-safe variant of lwip_gethostbyname: instead of using a static * buffer, this function takes buffer and errno pointers as arguments * and uses these for the result. *注意返回值只有整形,0表示成功!非零表示错误,根据非零的值再宏定义错误值号! * @param name the hostname to resolve * @param ret pre-allocated struct where to store the result * @param buf pre-allocated buffer where to store additional data * @param buflen the size of buf * @param result pointer to a hostent pointer that is set to ret on success * and set to zero on error * @param h_errnop pointer to an int where to store errors (instead of modifying * the global h_errno) * @return 0 on success, non-zero on error, additional error information * is stored in *h_errnop instead of h_errno to be thread-safe */intlwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop){ err_t err; struct gethostbyname_r_helper *h; char *hostname; size_t namelen; int lh_errno; if (h_errnop == NULL) { /* ensure h_errnop is never NULL */ h_errnop = &lh_errno; } if (result == NULL) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } /* first thing to do: set *result to nothing */ *result = NULL; if ((name == NULL) || (ret == NULL) || (buf == 0)) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } namelen = strlen(name); if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { /* buf can't hold the data needed + a copy of name */ *h_errnop = ERANGE; return -1; } h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); /*这是一个字符串指针加一个偏移量,指向真的名字*/ /* query host IP address */ err = netconn_gethostbyname(name, &(h->addr)); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); *h_errnop = ENSRNOTFOUND; return -1; } /* copy the hostname into buf */ MEMCPY(hostname, name, namelen);/*拷贝*/ hostname[namelen] = 0; /* fill hostent 填充*/ h->addrs = &(h->addr); h->aliases = NULL; ret->h_name = (char*)hostname; ret->h_aliases = &(h->aliases); ret->h_addrtype = AF_INET; /*v4的*/ ret->h_length = sizeof(ip_addr_t); ret->h_addr_list = (char**)&(h->addrs); /* set result != NULL */ *result = ret; /* return success */ return 0;}
下面是lwip_freeaddrinfo 函数和lwip_getaddrinfo 函数/* Frees one or more addrinfo structures returned by getaddrinfo(), along with * any additional storage associated with those structures. If the ai_next field * of the structure is not null, the entire list of structures is freed. * * @param ai struct addrinfo to free */void lwip_freeaddrinfo(struct addrinfo *ai){ struct addrinfo *next; while (ai != NULL) { next = ai-> ai_next; memp_free(MEMP_NETDB, ai); /*释放链表节点*/ ai = next; }}** * Translates the name of a service location (for example, a host name) and/or * a service name and returns a set of socket addresses and associated * information to be used in creating a socket with which to address the * specified service. * Memory for the result is allocated internally and must be freed by calling * lwip_freeaddrinfo()! * 读地址信息 * Due to a limitation in dns_gethostbyname, only the first address of a * host is returned. * Also, service names are not supported (only port numbers)! * * @param nodename descriptive name or address string of the host * (may be NULL -> local address) * @param servname port number as string of NULL * @param hints structure containing input values that set socktype and protocol * @param res pointer to a pointer where to store the result (set to NULL on failure) * @return 0 on success, non-zero on failure */intlwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res){ err_t err; ip_addr_t addr; struct addrinfo *ai; struct sockaddr_in *sa = NULL; int port_nr = 0; size_t total_size; size_t namelen = 0; if (res == NULL) { return EAI_FAIL; } *res = NULL; if ((nodename == NULL) && (servname == NULL)) { return EAI_NONAME; } if (servname != NULL) { /* service name specified: convert to port number * @todo?: currently, only ASCII integers (port numbers) are supported! */ port_nr = atoi(servname); /*字符串转整形*/ if ((port_nr <= 0) || (port_nr > 0xffff)) { return EAI_SERVICE; } } if (nodename != NULL) { /* service location specified, try to resolve */ err = netconn_gethostbyname(nodename, &addr); /* 调API函数 */ if (err != ERR_OK) { return EAI_FAIL; } } else { /* service location specified, use loopback address */ ip_addr_set_loopback(&addr); /*环回地址*/ } total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); if (nodename != NULL) { namelen = strlen(nodename); LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); total_size += namelen + 1; } /* If this fails, please report to lwip-devel! :-) */ LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", total_size <= NETDB_ELEM_SIZE); ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); /*申请一块内存*/ if (ai == NULL) { goto memerr; } memset(ai, 0, total_size);/*初始化*/ sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo)); /* set up sockaddr 设置sockaddr*/ inet_addr_from_ipaddr(&sa->sin_addr, &addr); sa->sin_family = AF_INET; sa->sin_len = sizeof(struct sockaddr_in); sa->sin_port = htons((u16_t)port_nr); /* set up addrinfo */ ai->ai_family = AF_INET;‘ if (hints != NULL) { /* copy socktype & protocol from hints if specified */ ai->ai_socktype = hints->ai_socktype; ai->ai_protocol = hints->ai_protocol; } if (nodename != NULL) { /* copy nodename to canonname if specified */ ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); MEMCPY(ai->ai_canonname, nodename, namelen); /* 一次拷贝 */ ai->ai_canonname[namelen] = 0; } ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr = (struct sockaddr*)sa; *res = ai; return 0;memerr: if (ai != NULL) { memp_free(MEMP_NETDB, ai); } return EAI_MEMORY;}#endif /* LWIP_DNS && LWIP_SOCKET */
- LWIP之DNS域名解析(二)
- LWIP之DNS域名解析分析 (一)
- LWIP 实现DNS域名解析
- 二、负载均衡之DNS域名解析
- DNS扫盲系列之二:域名解析及DNS功能分类
- DNS域名解析二方法
- [Java Web]Web请求过程之二:DNS 域名解析
- lwip之IP(二)
- 负载均衡之DNS域名解析
- RHEL 5服务篇—部署DNS域名解析服务(二)搭建缓存域名解析服务器
- 域名解析服务协议(DNS)
- 域名解析服务协议(DNS)
- DNS域名解析
- DNS域名解析
- DNS域名解析
- DNS域名解析
- DNS域名解析
- DNS域名解析
- Java编程中“为了性能”需做的26件事
- printk
- c 语言的特点
- 线性表
- lua面向对象编程之点号与冒号的差异详细比较
- LWIP之DNS域名解析(二)
- 字符编码笔记:ASCII,Unicode和UTF-8
- struts学习第一天------action各种重定向
- 友元函数和友元类
- oracle dmt,lmt,mssm,assm的含义
- 关于URL编码
- 动态改变页面中iframe
- windows下架设subversion服务器
- encodeURIComponent为什么使用两遍?