BUG/MEDIUM: server: do not auto insert a dynamic server in px addr_node

Until then, the servers were automatically attached on their creation
into the proxy addr_node tree via _srv_parse_init. In case of an invalid
dynamic server which is instantly freed, no detach operation was made
leaving a NULL server in the tree.

Change this mode of operation by marking the attach operation as
optional in _srv_parse_init. This operation is not conduct for a dynamic
server. The server is attached only at the end of the CLI handler when
it is marked as valid.

This must be backported up to 2.4.
diff --git a/src/server.c b/src/server.c
index 05c5de1..b3d82f1 100644
--- a/src/server.c
+++ b/src/server.c
@@ -198,9 +198,12 @@
 }
 
 /*
- * Must be called with the server lock held, and will write-lock the proxy.
+ * Must be called with the server lock held. The server is first removed from
+ * the proxy tree if it was already attached. If <reattach> is true, the server
+ * will then be attached in the proxy tree. The proxy lock is held to
+ * manipulate the tree.
  */
-static void srv_set_addr_desc(struct server *s)
+static void srv_set_addr_desc(struct server *s, int reattach)
 {
 	struct proxy *p = s->proxy;
 	char *key;
@@ -222,10 +225,12 @@
 
 	s->addr_node.key = key;
 
-	if (s->addr_node.key) {
-		HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
-		ebis_insert(&p->used_server_addr, &s->addr_node);
-		HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
+	if (reattach) {
+		if (s->addr_node.key) {
+			HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
+			ebis_insert(&p->used_server_addr, &s->addr_node);
+			HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
+		}
 	}
 }
 
@@ -2477,9 +2482,14 @@
 
 		newsrv->addr = *sk;
 		newsrv->svc_port = port;
-		// we don't need to lock the server here, because
-		// we are in the process of initializing
-		srv_set_addr_desc(newsrv);
+		/*
+		 * we don't need to lock the server here, because
+		 * we are in the process of initializing.
+		 *
+		 * Note that the server is not attached into the proxy tree if
+		 * this is a dynamic server.
+		 */
+		srv_set_addr_desc(newsrv, !(parse_flags & SRV_PARSE_DYNAMIC));
 
 		if (!newsrv->srvrq && !newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
 			ha_alert("Unknown protocol family %d '%s'\n",
@@ -2936,7 +2946,7 @@
 		break;
 	};
 	srv_set_dyncookie(s);
-	srv_set_addr_desc(s);
+	srv_set_addr_desc(s, 1);
 
 	return 0;
 }
@@ -3193,7 +3203,7 @@
 		/* force connection cleanup on the given server */
 		srv_cleanup_connections(s);
 		srv_set_dyncookie(s);
-		srv_set_addr_desc(s);
+		srv_set_addr_desc(s, 1);
 	}
 	if (updater)
 		chunk_appendf(msg, " by '%s'", updater);
@@ -3763,7 +3773,7 @@
 	return return_code;
 out:
 	srv_set_dyncookie(srv);
-	srv_set_addr_desc(srv);
+	srv_set_addr_desc(srv, 1);
 	return return_code;
 }
 
@@ -4474,6 +4484,7 @@
 	/* insert the server in the backend trees */
 	eb32_insert(&be->conf.used_server_id, &srv->conf.id);
 	ebis_insert(&be->conf.used_server_name, &srv->conf.name);
+	ebis_insert(&be->used_server_addr, &srv->addr_node);
 
 	thread_release();