MINOR: server/event_hdl: add SERVER_ADMIN event

Adding a new SERVER event in the event_hdl API.

SERVER_ADMIN is implemented as an advanced server event.
It is published each time the administrative state changes.
(when s->cur_admin changes)

SERVER_ADMIN data is an event_hdl_cb_data_server_admin struct that
provides additional info related to the admin state change, but can
be casted as a regular event_hdl_cb_data_server struct if additional
info is not needed.
diff --git a/include/haproxy/event_hdl-t.h b/include/haproxy/event_hdl-t.h
index 55d4da8..249cfed 100644
--- a/include/haproxy/event_hdl-t.h
+++ b/include/haproxy/event_hdl-t.h
@@ -270,6 +270,8 @@
 #define EVENT_HDL_SUB_SERVER_DOWN                       EVENT_HDL_SUB_TYPE(1,4)
 /* server state change */
 #define EVENT_HDL_SUB_SERVER_STATE                      EVENT_HDL_SUB_TYPE(1,5)
+/* server admin change */
+#define EVENT_HDL_SUB_SERVER_ADMIN                      EVENT_HDL_SUB_TYPE(1,6)
 
 /*	---------------------------------------        */
 
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index c9986db..60eb925 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -442,6 +442,7 @@
 	 *   EVENT_HDL_SUB_SERVER_UP
 	 *   EVENT_HDL_SUB_SERVER_DOWN
 	 *   EVENT_HDL_SUB_SERVER_STATE
+	 *   EVENT_HDL_SUB_SERVER_ADMIN
 	 */
 	struct {
 		/* safe data can be safely used from both
@@ -522,6 +523,26 @@
 	/* no unsafe data */
 };
 
+/* data provided to EVENT_HDL_SUB_SERVER_ADMIN handlers through
+ * event_hdl facility
+ *
+ * Note that this may be casted to regular event_hdl_cb_data_server if
+ * you don't care about admin related optional info
+ */
+struct event_hdl_cb_data_server_admin {
+	/* provided by:
+	 *   EVENT_HDL_SUB_SERVER_ADMIN
+	 */
+	struct event_hdl_cb_data_server server; /* must be at the beginning */
+	struct {
+		enum srv_admin old_admin, new_admin;
+		uint32_t requeued; /* requeued connections due to server admin change */
+		/* admin change cause */
+		enum srv_adm_st_chg_cause cause;
+	} safe;
+	/* no unsafe data */
+};
+
 /* Storage structure to load server-state lines from a flat file into
  * an ebtree, for faster processing
  */
diff --git a/src/event_hdl.c b/src/event_hdl.c
index 87b77eb..5fc1935 100644
--- a/src/event_hdl.c
+++ b/src/event_hdl.c
@@ -30,6 +30,7 @@
 	{"SERVER_UP",           EVENT_HDL_SUB_SERVER_UP},
 	{"SERVER_DOWN",         EVENT_HDL_SUB_SERVER_DOWN},
 	{"SERVER_STATE",        EVENT_HDL_SUB_SERVER_STATE},
+	{"SERVER_ADMIN",        EVENT_HDL_SUB_SERVER_ADMIN},
 };
 
 /* internal types (only used in this file) */
diff --git a/src/server.c b/src/server.c
index 83faf6b..272e4e9 100644
--- a/src/server.c
+++ b/src/server.c
@@ -5776,6 +5776,7 @@
 	enum srv_state srv_prev_state = s->cur_state;
 	union {
 		struct event_hdl_cb_data_server_state state;
+		struct event_hdl_cb_data_server_admin admin;
 		struct event_hdl_cb_data_server common;
 	} cb_data;
 	int requeued;
@@ -5783,8 +5784,15 @@
 	/* prepare common server event data */
 	_srv_event_hdl_prepare(&cb_data.common, s, 0);
 
-	if (type)
+	if (type) {
+		cb_data.admin.safe.cause = cause;
+		cb_data.admin.safe.old_admin = s->cur_admin;
+		cb_data.admin.safe.new_admin = s->next_admin;
 		requeued = _srv_update_status_adm(s, cause);
+		cb_data.admin.safe.requeued = requeued;
+		/* publish admin change */
+		_srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_ADMIN, cb_data.admin, s);
+	}
 	else
 		requeued = _srv_update_status_op(s, cause);