MAJOR/REORG: dns: DNS resolution task and requester queues

This patch is a major upgrade of the internal run-time DNS resolver in
HAProxy and it brings the following 2 main changes:

1. DNS resolution task

Up to now, DNS resolution was triggered by the health check task.
From now, DNS resolution task is autonomous. It is started by HAProxy
right after the scheduler is available and it is woken either when a
network IO occurs for one of its nameserver or when a timeout is
matched.

From now, this means we can enable DNS resolution for a server without
enabling health checking.

2. Introduction of a dns_requester structure

Up to now, DNS resolution was purposely made for resolving server
hostnames.
The idea, is to ensure that any HAProxy internal object should be able
to trigger a DNS resolution. For this purpose, 2 things has to be done:
  - clean up the DNS code from the server structure (this was already
    quite clean actually) and clean up the server's callbacks from
    manipulating too much DNS resolution
  - create an agnostic structure which allows linking a DNS resolution
    and a requester of any type (using obj_type enum)

3. Manage requesters through queues

Up to now, there was an uniq relationship between a resolution and it's
owner (aka the requester now). It's a shame, because in some cases,
multiple objects may share the same hostname and may benefit from a
resolution being performed by a third party.
This patch introduces the notion of queues, which are basically lists of
either currently running resolution or waiting ones.

The resolutions are now available as a pool, which belongs to the resolvers.
The pool has has a default size of 64 resolutions per resolvers and is
allocated at configuration parsing.
diff --git a/include/proto/checks.h b/include/proto/checks.h
index eb26c9a..853daad 100644
--- a/include/proto/checks.h
+++ b/include/proto/checks.h
@@ -28,7 +28,6 @@
 const char *get_check_status_description(short check_status);
 const char *get_check_status_info(short check_status);
 void __health_adjust(struct server *s, short status);
-int trigger_resolution(struct server *s);
 
 extern struct data_cb check_conn_cb;
 
diff --git a/include/proto/dns.h b/include/proto/dns.h
index 00a6f4a..6675d50 100644
--- a/include/proto/dns.h
+++ b/include/proto/dns.h
@@ -44,11 +44,24 @@
 void dns_print_current_resolutions(struct dns_resolvers *resolvers);
 void dns_update_resolvers_timeout(struct dns_resolvers *resolvers);
 void dns_reset_resolution(struct dns_resolution *resolution);
+void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution);
+void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution);
 int dns_check_resolution_queue(struct dns_resolvers *resolvers);
 unsigned short dns_response_get_query_id(unsigned char *resp);
 struct dns_resolution *dns_alloc_resolution(void);
 void dns_free_resolution(struct dns_resolution *resolution);
 struct chunk *dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf);
 struct lru64 *dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain);
+int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution);
+struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type);
+int dns_trigger_resolution(struct dns_resolution *resolution);
+int dns_alloc_resolution_pool(struct dns_resolvers *resolvers);
+
+void dump_dns_config(void);
+
+/*
+ * erases all information of a dns_requester structure
+ */
+#define		dns_clear_requester(requester)	memset(requester, '\0', sizeof(*requester));
 
 #endif // _PROTO_DNS_H
diff --git a/include/proto/server.h b/include/proto/server.h
index 53df241..43e4e42 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -53,8 +53,8 @@
 
 /* functions related to server name resolution */
 int snr_update_srv_status(struct server *s);
-int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver);
-int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code);
+int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver);
+int snr_resolution_error_cb(struct dns_requester *requester, int error_code);
 struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family);
 
 /* increase the number of cumulated connections on the designated server */
diff --git a/include/types/dns.h b/include/types/dns.h
index de9c713..7a19aa3 100644
--- a/include/types/dns.h
+++ b/include/types/dns.h
@@ -82,6 +82,9 @@
 /* DNS header size */
 #define DNS_HEADER_SIZE		sizeof(struct dns_header)
 
+/* DNS resolution pool size, per resolvers section */
+#define DNS_DEFAULT_RESOLUTION_POOL_SIZE	64
+
 /* DNS request or response header structure */
 struct dns_header {
 	uint16_t id;
@@ -157,7 +160,12 @@
 		int other;              /*   other dns response errors */
 	} hold;
 	struct task *t;			/* timeout management */
-	struct list curr_resolution;	/* current running resolutions */
+	int resolution_pool_size;	/* size of the resolution pool associated to this resolvers section */
+	struct {
+		struct list pool;	/* resolution pool dedicated to this resolvers section */
+		struct list wait;	/* resolutions managed to this resolvers section */
+		struct list curr;	/* current running resolutions */
+	} resolution;
 	struct eb_root query_ids;	/* tree to quickly lookup/retrieve query ids currently in use */
 					/* used by each nameserver, but stored in resolvers since there must */
 					/* be a unique relation between an eb_root and an eb_node (resolution) */
@@ -218,11 +226,15 @@
  */
 struct dns_resolution {
 	struct list list;		/* resolution list */
-	void *requester;		/* owner of this name resolution */
+	struct {
+		struct list wait;	/* list of standby requesters for this resolution */
+		struct list curr;	/* list of requesters currently active on this resolution */
+	} requester;
 	int (*requester_cb)(struct dns_resolution *, struct dns_nameserver *);
 					/* requester callback for valid response */
 	int (*requester_error_cb)(struct dns_resolution *, int);
 					/* requester callback, for error management */
+	int uuid;			/* unique id (used for debugging purpose) */
 	char *hostname_dn;		/* server hostname in domain name label format */
 	int hostname_dn_len;		/* server domain name label len */
 	unsigned int last_resolution;	/* time of the lastest valid resolution */
@@ -244,6 +256,19 @@
 	struct chunk response_buffer;	/* buffer used as a data store for <response> above TODO: optimize the size (might be smaller) */
 };
 
+/*
+ * structure used to describe the owner of a DNS resolution.
+ */
+struct dns_requester {
+	struct list list;		/* requester list */
+	enum obj_type *requester;	/* pointer to the requester */
+	int prefered_query_type;	/* prefered query type */
+	int (*requester_cb)(struct dns_requester *, struct dns_nameserver *);
+					/* requester callback for valid response */
+	int (*requester_error_cb)(struct dns_requester *, int);
+					/* requester callback, for error management */
+};
+
 /* last resolution status code */
 enum {
 	RSLV_STATUS_NONE	= 0,	/* no resolution occured yet */
diff --git a/include/types/server.h b/include/types/server.h
index 7c6df5a..8fb6f2e 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -254,6 +254,7 @@
 	struct check check;                     /* health-check specific configuration */
 	struct check agent;                     /* agent specific configuration */
 
+	struct dns_requester *dns_requester;	/* used to link a server to its DNS resolution */
 	char *resolvers_id;			/* resolvers section used by this server */
 	struct dns_resolvers *resolvers;	/* pointer to the resolvers structure used by this server */
 	char *hostname;				/* server hostname */