MINOR: server/event_hdl: add support for SERVER_ADD and SERVER_DEL events

Basic support for ADD and DEL server events are added through this commit:
	SERVER_ADD is published on dynamic server addition through cli.
	SERVER_DEL is published on dynamic server deletion through cli.

This work depends on:
	"MINOR: event_hdl: add event handler base api"
	"MINOR: server: add srv->rid (revision id) value"
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index dd42807..dd1a3af 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -40,6 +40,7 @@
 #include <haproxy/stats-t.h>
 #include <haproxy/task-t.h>
 #include <haproxy/thread-t.h>
+#include <haproxy/event_hdl-t.h>
 
 
 /* server states. Only SRV_ST_STOPPED indicates a down server. */
@@ -403,6 +404,8 @@
 	} op_st_chg;				/* operational status change's reason */
 	char adm_st_chg_cause[48];		/* administrative status change's cause */
 
+	event_hdl_sub_list e_subs;		/* event_hdl: server's subscribers list (atomically updated) */
+
 	/* warning, these structs are huge, keep them at the bottom */
 	struct conn_src conn_src;               /* connection source settings */
 	struct sockaddr_storage addr;           /* the address to connect to, doesn't include the port */
@@ -411,6 +414,35 @@
 	EXTRA_COUNTERS(extra_counters);
 };
 
+/* data provided to EVENT_HDL_SUB_SERVER handlers through event_hdl facility */
+struct event_hdl_cb_data_server {
+	/* provided by:
+	 *   EVENT_HDL_SUB_SERVER_ADD
+	 *   EVENT_HDL_SUB_SERVER_DOWN
+	 */
+	struct {
+		/* safe data can be safely used from both
+		 * sync and async handlers
+		 * data consistency is guaranteed
+		 */
+		char name[64];       /* server name/id */
+		char proxy_name[64]; /* id of proxy the server belongs to */
+		int puid;            /* proxy-unique server ID */
+		int rid;             /* server id revision */
+		unsigned int flags;  /* server flags */
+	} safe;
+	struct {
+		/* unsafe data may only be used from sync handlers:
+		 * in async mode, data consistency cannot be guaranteed
+		 * and unsafe data may already be stale, thus using
+		 * it is highly discouraged because it
+		 * could lead to undefined behavior (UAF, null dereference...)
+		 */
+		struct server *ptr;	/* server live ptr */
+		/* lock hints */
+		uint8_t thread_isolate;	/* 1 = thread_isolate is on, no locking required */
+	} unsafe;
+};
 
 /* Storage structure to load server-state lines from a flat file into
  * an ebtree, for faster processing
diff --git a/src/server.c b/src/server.c
index bc8d0cb..eddaf91 100644
--- a/src/server.c
+++ b/src/server.c
@@ -47,6 +47,7 @@
 #include <haproxy/time.h>
 #include <haproxy/tools.h>
 #include <haproxy/xxhash.h>
+#include <haproxy/event_hdl.h>
 
 
 static void srv_update_status(struct server *s);
@@ -133,6 +134,33 @@
 }
 
 /*
+ * Use this to publish EVENT_HDL_SUB_SERVER family type event
+ * from srv facility
+ * Event will be published in both global subscription list and
+ * server dedicated subscription list
+ * server ptr must be valid
+ */
+static inline void srv_event_hdl_publish(struct event_hdl_sub_type event, struct server *srv, uint8_t thread_isolate)
+{
+	struct event_hdl_cb_data_server cb_data;
+
+	/* safe data assignments */
+	cb_data.safe.puid = srv->puid;
+	cb_data.safe.rid = srv->rid;
+	cb_data.safe.flags = srv->flags;
+	snprintf(cb_data.safe.name, sizeof(cb_data.safe.name), "%s", srv->id);
+	if (srv->proxy)
+		snprintf(cb_data.safe.proxy_name, sizeof(cb_data.safe.proxy_name), "%s", srv->proxy->id);
+	/* unsafe data assignments */
+	cb_data.unsafe.ptr = srv;
+	cb_data.unsafe.thread_isolate = thread_isolate;
+	/* publish in server dedicated sub list */
+	event_hdl_publish(&srv->e_subs, event, EVENT_HDL_CB_DATA(&cb_data));
+	/* publish in global subscription list */
+	event_hdl_publish(NULL, event, EVENT_HDL_CB_DATA(&cb_data));
+}
+
+/*
  * Check that we did not get a hash collision.
  * Unlikely, but it can happen. The server's proxy must be at least
  * read-locked.
@@ -2337,6 +2365,7 @@
 	LIST_APPEND(&servers_list, &srv->global_list);
 	LIST_INIT(&srv->srv_rec_item);
 	LIST_INIT(&srv->ip_rec_item);
+	event_hdl_sub_list_init(&srv->e_subs);
 
 	srv->next_state = SRV_ST_RUNNING; /* early server setup */
 	srv->last_change = now.tv_sec;
@@ -2419,6 +2448,7 @@
 	HA_SPIN_DESTROY(&srv->lock);
 
 	LIST_DELETE(&srv->global_list);
+	event_hdl_sub_list_destroy(&srv->e_subs);
 
 	EXTRA_COUNTERS_FREE(srv->extra_counters);
 
@@ -4893,6 +4923,11 @@
 	 */
 	srv->rid = (srv_id_reuse_cnt) ? (srv_id_reuse_cnt / 2) : 0;
 
+	/* adding server cannot fail when we reach this:
+	 * publishing EVENT_HDL_SUB_SERVER_ADD
+	 */
+	srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_ADD, srv, 1);
+
 	thread_release();
 
 	/* Start the check task. The server must be fully initialized.
@@ -5020,6 +5055,11 @@
 		goto out;
 	}
 
+	/* removing cannot fail anymore when we reach this:
+	 * publishing EVENT_HDL_SUB_SERVER_DEL
+	 */
+	srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_DEL, srv, 1);
+
 	/* remove srv from tracking list */
 	if (srv->track)
 		release_server_track(srv);