MEDIUM: proxy: store the default proxies in a tree by name

Now default proxies are stored into a dedicated tree, sorted by name.
Only unnamed entries are not kept upon new section creation. The very
first call to cfg_parse_listen() will automatically allocate a dummy
defaults section which corresponds to the previous static one, since
the code requires to have one at a few places.

The first immediately visible benefit is that it allows to reuse
alloc_new_proxy() to allocate a defaults section instead of doing it by
hand. And the secret goal is to allow to keep multiple named defaults
section in memory to reuse them from various proxies.
diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h
index b4b04c5..a08ea52 100644
--- a/include/haproxy/proxy.h
+++ b/include/haproxy/proxy.h
@@ -59,6 +59,7 @@
 void proxy_preset_defaults(struct proxy *defproxy);
 void proxy_free_defaults(struct proxy *defproxy);
 void proxy_destroy_defaults(struct proxy *px);
+void proxy_destroy_all_defaults();
 struct proxy *alloc_new_proxy(const char *name, unsigned int cap, const char *file, int linenum,
                               const struct proxy *defproxy, char **errmsg);
 int get_backend_server(const char *bk_name, const char *sv_name,
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 3c252d2..a87358a 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -34,8 +34,6 @@
 #include <haproxy/uri_auth.h>
 
 
-static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
-
 /* Report a warning if a rule is placed after a 'tcp-request session' rule.
  * Return 1 if the warning has been emitted, otherwise 0.
  */
@@ -173,6 +171,7 @@
 {
 	static struct proxy *curproxy = NULL;
 	static struct proxy *curr_defproxy = NULL;
+	static struct proxy *last_defproxy = NULL;
 	const char *err;
 	int rc;
 	unsigned val;
@@ -181,27 +180,33 @@
 	char *errmsg = NULL;
 	struct bind_conf *bind_conf;
 
-	if (defproxy.obj_type != OBJ_TYPE_PROXY) {
-		/* defproxy not initialized yet */
-		init_new_proxy(&defproxy);
-		proxy_preset_defaults(&defproxy);
+	if (!last_defproxy) {
+		/* we need a default proxy and none was created yet */
+		last_defproxy = alloc_new_proxy("", PR_CAP_DEF|PR_CAP_LISTEN, "INIT", 0, NULL, &errmsg);
+		curr_defproxy = last_defproxy;
+		if (!last_defproxy) {
+			ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
+			err_code |= ERR_ALERT | ERR_ABORT;
+			goto out;
+		}
 	}
 
-	if (!curr_defproxy)
-		curr_defproxy = &defproxy;
-
 	if (strcmp(args[0], "listen") == 0)
 		rc = PR_CAP_LISTEN;
 	else if (strcmp(args[0], "frontend") == 0)
 		rc = PR_CAP_FE;
 	else if (strcmp(args[0], "backend") == 0)
 		rc = PR_CAP_BE;
-	else if (strcmp(args[0], "defaults") == 0)
-		rc = PR_CAP_DEF;
+	else if (strcmp(args[0], "defaults") == 0) {
+		/* "defaults" must first delete the last no-name defaults if any */
+		proxy_destroy_defaults(proxy_find_by_name("", PR_CAP_DEF, 0));
+		curr_defproxy = NULL;
+		rc = PR_CAP_DEF | PR_CAP_LISTEN;
+	}
 	else
 		rc = PR_CAP_NONE;
 
-	if (rc & PR_CAP_LISTEN) {  /* new proxy */
+	if ((rc & PR_CAP_LISTEN) && !(rc & PR_CAP_DEF)) {  /* new proxy */
 		if (!*args[1]) {
 			ha_alert("parsing [%s:%d] : '%s' expects an <id> argument\n",
 				 file, linenum, args[0]);
@@ -237,34 +242,24 @@
 				ha_alert("parsing [%s:%d] : please use the 'bind' keyword for listening addresses.\n", file, linenum);
 			goto out;
 		}
+	}
 
+	if (rc & PR_CAP_LISTEN) {  /* new proxy or defaults section */
 		curproxy = alloc_new_proxy(args[1], rc, file, linenum, curr_defproxy, &errmsg);
 		if (!curproxy) {
-			/* message already printed by alloc_new_proxy() */
 			ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
 			err_code |= ERR_ALERT | ERR_ABORT;
 			goto out;
 		}
-		curproxy->next = proxies_list;
-		proxies_list = curproxy;
 
-		goto out;
-	}
-	else if (strcmp(args[0], "defaults") == 0) {  /* use this one to assign default values */
-		if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
-			err_code |= ERR_ABORT;
-			goto out;
+		if (rc & PR_CAP_DEF) {
+			/* last and current proxies must be updated to this one */
+			curr_defproxy = last_defproxy = curproxy;
+		} else {
+			/* regular proxies are in a list */
+			curproxy->next = proxies_list;
+			proxies_list = curproxy;
 		}
-
-		/* let's first free previous defaults */
-		proxy_free_defaults(curr_defproxy);
-		init_new_proxy(curr_defproxy);
-		proxy_preset_defaults(curr_defproxy);
-		curproxy = curr_defproxy;
-		curproxy->id = strdup(args[1]); // may be empty
-		curproxy->conf.args.file = curproxy->conf.file = strdup(file);
-		curproxy->conf.args.line = curproxy->conf.line = linenum;
-		defproxy.cap = PR_CAP_DEF | PR_CAP_LISTEN; /* all caps for now */
 		goto out;
 	}
 	else if (curproxy == NULL) {
diff --git a/src/haproxy.c b/src/haproxy.c
index 69ddb90..dc194c9 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1963,6 +1963,9 @@
 		           global.nbproc);
 	}
 
+	/* defaults sections are not needed anymore */
+	proxy_destroy_all_defaults();
+
 	err_code |= check_config_validity();
 	for (px = proxies_list; px; px = px->next) {
 		struct server *srv;
diff --git a/src/proxy.c b/src/proxy.c
index e703041..96fc176 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -1179,6 +1179,17 @@
 	free(px);
 }
 
+void proxy_destroy_all_defaults()
+{
+	struct ebpt_node *n;
+
+	while ((n = ebpt_first(&defproxy_by_name))) {
+		struct proxy *px = container_of(n, struct proxy, conf.by_name);
+		BUG_ON(!(px->cap & PR_CAP_DEF));
+		proxy_destroy_defaults(px);
+	}
+}
+
 /* Allocates a new proxy <name> of type <cap> found at position <file:linenum>,
  * preset it from the defaults of <defproxy> and returns it. Un case of error,
  * an alert is printed and NULL is returned. If <errmsg> is not NULL, an error