#ifndef	ACL_DNS_INCLUDE_H
#define	ACL_DNS_INCLUDE_H

#ifdef	__cplusplus
extern "C" {
#endif

#include "../stdlib/acl_define.h"
#include "../stdlib/acl_htable.h"
#include "../stdlib/acl_cache2.h"
#ifdef  ACL_UNIX
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "../event/acl_events.h"
#include "../aio/acl_aio.h"
#include "acl_rfc1035.h"
#include "acl_sane_inet.h"
#include "acl_netdb.h"

/* DNS ѯʱĴ붨 */

#define	ACL_DNS_OK		0
#define	ACL_DNS_OK_CACHE	1
#define	ACL_DNS_ERR_FMT		-1
#define	ACL_DNS_ERR_SVR		-2
#define	ACL_DNS_ERR_NO_EXIST	-3
#define	ACL_DNS_ERR_NO_SUPPORT	-4
#define	ACL_DNS_ERR_DENY	-5
#define	ACL_DNS_ERR_YX		-6
#define	ACL_DNS_ERR_YXRR	-7
#define	ACL_DNS_ERR_NXRR	-8
#define	ACL_DNS_ERR_NO_AUTH	-9
#define	ACL_DNS_ERR_NOT_ZONE	-10
#define	ACL_DNS_ERR_UNPACK	-15
#define	ACL_DNS_ERR_TIMEOUT	-16
#define	ACL_DNS_ERR_EXIST	-17
#define	ACL_DNS_ERR_BUILD_REQ	-18

typedef struct ACL_DNS_ADDR {
	char  ip[64];			/* DNS ַ */
	unsigned short port;	/* DNS ˿ */
	ACL_SOCKADDR   addr;	/* DNS ַ */
	int   addr_len;			/* addr С */
	int   mask_length;		/* DNS 볤(> 0 && < 32) */
	struct in_addr in;		/* addr εַ */
} ACL_DNS_ADDR;

typedef struct ACL_DNS {
	ACL_AIO *aio;			/* 첽IO */
	unsigned short qid;		/* IDʶ */
	ACL_ASTREAM *astream;	/* 첽 */

	ACL_ARRAY *groups;		/* б */
	ACL_ARRAY *dns_list;	/* DNS ַб */
	unsigned   dns_idx;		/* ǰʹõ dns_list ± */
	ACL_DNS_ADDR addr_from;		/* Դ DNS ַ */
	ACL_HTABLE *lookup_table;	/* ѯ */
	ACL_CACHE2 *dns_cache;		/* ڻDNSѯ */
	int   timeout;			/* ÿβѯĳʱʱֵ() */
	int   retry_limit;		/* ѯʱʱԵĴ */
	unsigned int flag;		/* ־λ */
#define	ACL_DNS_FLAG_ALLOC	    	(1 << 0)	/* 첽Ƕ̬ */
#define	ACL_DNS_FLAG_CHECK_DNS_IP	(1 << 1)	/* DNSַǷƥ */
#define	ACL_DNS_FLAG_CHECK_DNS_NET	(1 << 2)	/* DNSǷƥ */

	/* úָ⶯̬ؿķʵַһ */
	ACL_EVENT_NOTIFY_TIME lookup_timeout;
} ACL_DNS;

typedef struct ACL_DNS_REQ ACL_DNS_REQ;

/**
 * ʼDNS첽ѯṹ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param aio {ACL_AIO*} 첽
 * @param timeout {int} ÿDNSѯʱĳʱֵ
 * @return {int} ʼǷɹ 0 ʾɹ-1 ʾʧ
 */
ACL_API int acl_dns_init(ACL_DNS *dns, ACL_AIO *aio, int timeout);

/**
 * һDNS첽ѯͬʱгʼ
 * @param aio {ACL_AIO*} 첽
 * @param timeout {int} ÿDNSѯʱĳʱֵ
 * @return {ACL_DNS*} DNS첽ѯ NULL ʾ DNS ѯʧ
 */
ACL_API ACL_DNS *acl_dns_create(ACL_AIO *aio, int timeout);

/**
 * DNS
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param limit {int} DNS 󻺴Ŀ
 */
ACL_API void acl_dns_open_cache(ACL_DNS *dns, int limit);

/**
 * һDNSַ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param dns_ip {const char*} DNSIPַ
 * @param dns_port {unsigned short} DNS˿
 * @param mask_length {int} DNSڵ볤(0 < && < 32)
 */
ACL_API void acl_dns_add_dns(ACL_DNS *dns, const char *dns_ip,
	unsigned short dns_port, int mask_length);

/**
 *  DNS ַб
 * @param dns {ACL_DNS*} DNS첽ѯ
 */
ACL_API void acl_dns_clear_dns(ACL_DNS *dns);

/**
 *  DNS б
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @return {ACL_ARRAY*}  ACL_DNS_ADDR 󣬷ֵԶ NULL
 */
ACL_API ACL_ARRAY *acl_dns_list(ACL_DNS *dns);

/**
 *  DNS ַб
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @return {size_t}
 */
ACL_API size_t acl_dns_size(ACL_DNS *dns);

/**
 * ж DNS ַбǷΪ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @retrn {int} ֵ 0 ʾΪ
 */
ACL_API int acl_dns_empty(ACL_DNS *dns);

/**
 * ɾһDNSַ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param ip {const char*} DNSIPַ
 * @param port {unsigned short} DNS˿
 */
ACL_API void acl_dns_del_dns(ACL_DNS *dns, const char *ip, unsigned short port);

/**
 * ر첽ѯͬʱͷԴ
 * @param dns {ACL_DNS*} DNS첽ѯ
 */
ACL_API void acl_dns_close(ACL_DNS *dns);

/**
 * ñ־λDNSԴIPַǷĿַͬͬ
 * ݰҪΪ˷ֹDNSѯʱUDP
 * @param dns {ACL_DNS*} DNS첽ѯ
 */
ACL_API void acl_dns_check_dns_ip(ACL_DNS *dns);

/**
 * ñ־λDNSԴIPǷĿͬͬ
 * ݰҪΪ˷ֹDNSѯʱUDP
 * @param dns {ACL_DNS*} DNS첽ѯ
 */
ACL_API void acl_dns_check_dns_net(ACL_DNS *dns);

/**
 * DNSѯʱʱԴ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param retry_limit {int} Դ
 */
ACL_API void acl_dns_set_retry_limit(ACL_DNS *dns, int retry_limit);

/**
 * 첽ѯһӦA¼IPַ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param domain {const char*} 
 * @param callback {void (*)(ACL_DNS_DB*, void*, int, const ACL_RFC1035_MESSAGE*)}
 *  ѯɹʧܵĻص, ظ callback  ACL_DNS_DB Ϊʾѯʧ,
 *  ڶΪûõĲ, ΪѯʧʱĴ
 * @param ctx {void*} callback Ĳ֮һ
 */
ACL_API void acl_dns_lookup(ACL_DNS *dns, const char *domain,
	void (*callback)(ACL_DNS_DB*, void*, int, const ACL_RFC1035_MESSAGE*),
	void *ctx);

/**
 * 첽ѯһӦļ¼͵IPַ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param domain {const char*} 
 * @param type {unsigned short} ѯͣμ acl_rfc1035.h е ACL_RFC1035_TYPE_XXX
 * @param callback {void (*)(ACL_DNS_DB*, void*, int, const ACL_RFC1035_MESSAGE*)}
 *  ѯɹʧܵĻص, ظ callback  ACL_DNS_DB Ϊʾѯʧ,
 *  ڶΪûõĲ, ΪѯʧʱĴ
 * @param ctx {void*} callback Ĳ֮һ
 */
ACL_API void acl_dns_lookup2(ACL_DNS *dns, const char *domain, unsigned short type,
	void (*callback)(ACL_DNS_DB*, void*, int, const ACL_RFC1035_MESSAGE*),
	void *ctx);

/**
 * DNSѯӾ̬Ϣ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param domain {const char*} 
 * @param ip_list {const char*} IPַбָΪ ';': 192.168.0.1;192.168.0.2
 */
ACL_API void acl_dns_add_host(ACL_DNS *dns, const char *domain, const char *ip_list);

/**
 * DNSѯӲѯϢ
 * @param dns {ACL_DNS*} DNS첽ѯ
 * @param group {const char*} : .test.com,  a.test.com, b.test.com
 *   .test.com 
 * @param ip_list {const char*} ǿþ̬ʽIPַб
 * @param refer {const char*} Ĵ, ôȥDNSѯ
 * @param excepts {ACL_ARGV*} ȻЩ group ȴ
 *  Ա
 */
ACL_API void acl_dns_add_group(ACL_DNS *dns, const char *group, const char *refer,
		const char *ip_list, const char *excepts);
/**
 * ȡĳѯ¼
 * @param handle {ACL_DNS_REQ*} ĳѯ¼
 */
ACL_API void acl_dns_cancel(ACL_DNS_REQ *handle);

/**
 * ݴŵõϢ
 * @param errnum {int} DNSѯʱصĴ
 * @return {const char*} Ϣ
 */
ACL_API const char *acl_dns_serror(int errnum);

#ifdef	__cplusplus
}
#endif

#endif

