MEDIUM: server: add support for changing a server's address

Ability to change a server IP address during HAProxy run time.
For now this is provided via function update_server_addr() which
currently is not called.

A log is emitted on each change. For now we do it inconditionally,
but later we'll want to do it only on certain circumstances, which
explains why the logging block is enclosed in if(1).
diff --git a/include/proto/server.h b/include/proto/server.h
index a87c8d5..7e32995 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -38,6 +38,7 @@
 int srv_lastsession(const struct server *s);
 int srv_getinter(const struct check *check);
 int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy);
+int update_server_addr(struct server *s, void *ip, int ip_sin_family, char *updater);
 
 /* increase the number of cumulated connections on the designated server */
 static void inline srv_inc_sess_ctr(struct server *s)
diff --git a/src/server.c b/src/server.c
index ee6b850..369dd79 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1697,6 +1697,72 @@
 }
 
 /*
+ * update a server's current IP address.
+ * ip is a pointer to the new IP address, whose address family is ip_sin_family.
+ * ip is in network format.
+ * updater is a string which contains an information about the requester of the update.
+ * updater is used if not NULL.
+ *
+ * A log line and a stderr warning message is generated based on server's backend options.
+ */
+int update_server_addr(struct server *s, void *ip, int ip_sin_family, char *updater)
+{
+	/* generates a log line and a warning on stderr */
+	if (1) {
+		/* book enough space for both IPv4 and IPv6 */
+		char oldip[INET6_ADDRSTRLEN];
+		char newip[INET6_ADDRSTRLEN];
+
+		memset(oldip, '\0', INET6_ADDRSTRLEN);
+		memset(newip, '\0', INET6_ADDRSTRLEN);
+
+		/* copy old IP address in a string */
+		switch (s->addr.ss_family) {
+		case AF_INET:
+			inet_ntop(s->addr.ss_family, &((struct sockaddr_in *)&s->addr)->sin_addr, oldip, INET_ADDRSTRLEN);
+			break;
+		case AF_INET6:
+			inet_ntop(s->addr.ss_family, &((struct sockaddr_in6 *)&s->addr)->sin6_addr, oldip, INET6_ADDRSTRLEN);
+			break;
+		};
+
+		/* copy new IP address in a string */
+		switch (ip_sin_family) {
+		case AF_INET:
+			inet_ntop(ip_sin_family, ip, newip, INET_ADDRSTRLEN);
+			break;
+		case AF_INET6:
+			inet_ntop(ip_sin_family, ip, newip, INET6_ADDRSTRLEN);
+			break;
+		};
+
+		/* save log line into a buffer */
+		chunk_printf(&trash, "%s/%s changed its IP from %s to %s by %s",
+				s->proxy->id, s->id, oldip, newip, updater);
+
+		/* write the buffer on stderr */
+		Warning("%s.\n", trash.str);
+
+		/* send a log */
+		send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
+	}
+
+	/* save the new IP family */
+	s->addr.ss_family = ip_sin_family;
+	/* save the new IP address */
+	switch (ip_sin_family) {
+	case AF_INET:
+		((struct sockaddr_in *)&s->addr)->sin_addr.s_addr = *(uint32_t *)ip;
+		break;
+	case AF_INET6:
+		memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, ip, 16);
+		break;
+	};
+
+	return 0;
+}
+
+/*
  * Local variables:
  *  c-indent-level: 8
  *  c-basic-offset: 8