MEDIUM: stream_sock: add a get_src and get_dst callback and remove SN_FRT_ADDR_SET

These callbacks are used to retrieve the source and destination address
of a socket. The address flags are not hold on the stream interface and
not on the session anymore. The addresses are collected when needed.

This still needs to be improved to store the IP and port separately so
that it is not needed to perform a getsockname() when only the IP address
is desired for outgoing traffic.
diff --git a/src/backend.c b/src/backend.c
index f6e2d73..57acbe7 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -688,8 +688,8 @@
 			 * the client asked, which is handy for remapping ports
 			 * locally on multiple addresses at once.
 			 */
-			if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
-				get_frt_addr(s);
+			if (!(s->be->options & PR_O_TRANSP))
+				stream_sock_get_to_addr(s->req->prod);
 
 			if (s->req->prod->addr.to.ss_family == AF_INET) {
 				((struct sockaddr_in *)&s->req->cons->addr.to)->sin_addr = ((struct sockaddr_in *)&s->req->prod->addr.to)->sin_addr;
@@ -703,8 +703,8 @@
 		if (target_srv(&s->target)->state & SRV_MAPPORTS) {
 			int base_port;
 
-			if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
-				get_frt_addr(s);
+			if (!(s->be->options & PR_O_TRANSP))
+				stream_sock_get_to_addr(s->req->prod);
 
 			/* First, retrieve the port from the incoming connection */
 			base_port = get_host_port(&s->req->prod->addr.to);
@@ -720,8 +720,7 @@
 	}
 	else if (s->be->options & PR_O_TRANSP) {
 		/* in transparent mode, use the original dest addr if no dispatch specified */
-		if (!(s->flags & SN_FRT_ADDR_SET))
-			get_frt_addr(s);
+		stream_sock_get_to_addr(s->req->prod);
 
 		if (s->req->prod->addr.to.ss_family == AF_INET || s->req->prod->addr.to.ss_family == AF_INET6) {
 			memcpy(&s->req->cons->addr.to, &s->req->prod->addr.to, MIN(sizeof(s->req->cons->addr.to), sizeof(s->req->prod->addr.to)));
@@ -973,6 +972,8 @@
 	 */
 	stream_sock_prepare_interface(s->req->cons);
 	s->req->cons->connect = tcp_connect_server;
+	s->req->cons->get_src = getsockname;
+	s->req->cons->get_dst = getpeername;
 	/* the target was only on the session, assign it to the SI now */
 	copy_target(&s->req->cons->target, &s->target);
 
@@ -980,8 +981,7 @@
 	s->req->cons->send_proxy_ofs = 0;
 	if (s->target.type == TARG_TYPE_SERVER && (s->target.ptr.s->state & SRV_SEND_PROXY)) {
 		s->req->cons->send_proxy_ofs = 1; /* must compute size */
-		if (!(s->flags & SN_FRT_ADDR_SET))
-			get_frt_addr(s);
+		stream_sock_get_to_addr(s->req->prod);
 	}
 
 	assign_tproxy_address(s);
diff --git a/src/frontend.c b/src/frontend.c
index 35c3ef3..12f55ad 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -44,20 +44,6 @@
 #include <proto/stream_sock.h>
 #include <proto/task.h>
 
-
-/* Retrieves the original destination address used by the client, and sets the
- * SN_FRT_ADDR_SET flag.
- */
-void get_frt_addr(struct session *s)
-{
-	socklen_t namelen = sizeof(s->si[0].addr.to);
-
-	if (get_original_dst(s->si[0].fd, (struct sockaddr_in *)&s->si[0].addr.to, &namelen) == -1)
-		getsockname(s->si[0].fd, (struct sockaddr *)&s->si[0].addr.to, &namelen);
-	s->si[0].flags |= SI_FL_TO_SET;
-	s->flags |= SN_FRT_ADDR_SET;
-}
-
 /* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative
  * value in case of a critical failure which must cause the listener to be
  * disabled, a positive value in case of success, or zero if it is a success
@@ -152,8 +138,8 @@
 		else {
 			char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
 
-			if (!(s->flags & SN_FRT_ADDR_SET))
-				get_frt_addr(s);
+			stream_sock_get_from_addr(s->req->prod);
+			stream_sock_get_to_addr(s->req->prod);
 
 			switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) {
 			case AF_INET:
@@ -178,8 +164,7 @@
 		char pn[INET6_ADDRSTRLEN];
 		int len = 0;
 
-		if (!(s->flags & SN_FRT_ADDR_SET))
-			get_frt_addr(s);
+		stream_sock_get_from_addr(s->req->prod);
 
 		switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) {
 		case AF_INET:
@@ -334,8 +319,7 @@
 		((struct sockaddr_in *)&s->si[0].addr.to)->sin_family      = AF_INET;
 		((struct sockaddr_in *)&s->si[0].addr.to)->sin_addr.s_addr = htonl(dst3);
 		((struct sockaddr_in *)&s->si[0].addr.to)->sin_port        = htons(dport);
-		s->flags |= SN_FRT_ADDR_SET;
-
+		s->si[0].flags |= SI_FL_FROM_SET | SI_FL_TO_SET;
 	}
 	else if (!memcmp(line, "TCP6 ", 5) != 0) {
 		u32 sport, dport;
@@ -396,7 +380,7 @@
 		((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_family      = AF_INET6;
 		memcpy(&((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_addr, &dst3, sizeof(struct in6_addr));
 		((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_port        = htons(dport);
-		s->flags |= SN_FRT_ADDR_SET;
+		s->si[0].flags |= SI_FL_FROM_SET | SI_FL_TO_SET;
 	}
 	else {
 		goto fail;
diff --git a/src/log.c b/src/log.c
index 00d0e71..a0493dc 100644
--- a/src/log.c
+++ b/src/log.c
@@ -33,6 +33,7 @@
 #include <proto/frontend.h>
 #include <proto/log.h>
 #include <proto/stream_interface.h>
+#include <proto/stream_sock.h>
 
 const char *log_facilities[NB_LOG_FACILITIES] = {
 	"kern", "user", "mail", "daemon",
@@ -858,7 +859,7 @@
 				break;
 
 			case LOG_FMT_FRONTENDIP: // %Fi
-				get_frt_addr(s);
+				stream_sock_get_to_addr(s->req->prod);
 				ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->addr.to,
 					    dst + maxsize - tmplog, tmp);
 				if (ret == NULL)
@@ -868,7 +869,7 @@
 				break;
 
 			case  LOG_FMT_FRONTENDPORT: // %Fp
-				get_frt_addr(s);
+				stream_sock_get_to_addr(s->req->prod);
 				if (s->req->prod->addr.to.ss_family == AF_UNIX) {
 					ret = ltoa_o(s->listener->luid,
 						     tmplog, dst + maxsize - tmplog);
diff --git a/src/peers.c b/src/peers.c
index 250e17f..6c25dcd 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -1156,6 +1156,8 @@
 	s->si[0].err_type = SI_ET_NONE;
 	s->si[0].err_loc = NULL;
 	s->si[0].connect   = NULL;
+	s->si[0].get_src   = NULL;
+	s->si[0].get_dst   = NULL;
 	clear_target(&s->si[0].target);
 	s->si[0].exp = TICK_ETERNITY;
 	s->si[0].flags = SI_FL_NONE;
@@ -1173,6 +1175,8 @@
 	s->si[1].err_type = SI_ET_NONE;
 	s->si[1].err_loc = NULL;
 	s->si[1].connect = tcp_connect_server;
+	s->si[1].get_src = getsockname;
+	s->si[1].get_dst = getpeername;
 	set_target_proxy(&s->si[1].target, s->be);
 	s->si[1].exp = TICK_ETERNITY;
 	s->si[1].flags = SI_FL_NONE;
diff --git a/src/proto_http.c b/src/proto_http.c
index dd2f0d0..3c3bd1c 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3380,8 +3380,7 @@
 			/* Add an X-Original-To header unless the destination IP is
 			 * in the 'except' network range.
 			 */
-			if (!(s->flags & SN_FRT_ADDR_SET))
-				get_frt_addr(s);
+			stream_sock_get_to_addr(s->req->prod);
 
 			if (s->req->prod->addr.to.ss_family == AF_INET &&
 			    ((!s->fe->except_mask_to.s_addr ||
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 7b01586..8966ad3 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -403,6 +403,7 @@
 	if (global.tune.server_rcvbuf)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
+	si->flags &= ~SI_FL_FROM_SET;
 	if ((connect(fd, (struct sockaddr *)&si->addr.to, get_addr_len(&si->addr.to)) == -1) &&
 	    (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
 
@@ -438,13 +439,8 @@
 	}
 
 	/* needs src ip/port for logging */
-	if (si->flags & SI_FL_SRC_ADDR) {
-		socklen_t addrlen = sizeof(si->addr.from);
-		if (getsockname(fd, (struct sockaddr *)&si->addr.from, &addrlen) == -1) {
-			Warning("Cannot get source address for logging.\n");
-		}
-		si->flags |= SI_FL_FROM_SET;
-	}
+	if (si->flags & SI_FL_SRC_ADDR)
+		stream_sock_get_from_addr(si);
 
 	fdtab[fd].owner = si;
 	fdtab[fd].state = FD_STCONN; /* connection in progress */
@@ -1318,8 +1314,7 @@
 acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
               struct acl_expr *expr, struct acl_test *test)
 {
-	if (!(l4->flags & SN_FRT_ADDR_SET))
-		get_frt_addr(l4);
+	stream_sock_get_to_addr(&l4->si[0]);
 
 	switch (l4->si[0].addr.to.ss_family) {
 	case AF_INET:
@@ -1344,8 +1339,7 @@
 pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
                   const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
 {
-	if (!(l4->flags & SN_FRT_ADDR_SET))
-		get_frt_addr(l4);
+	stream_sock_get_to_addr(&l4->si[0]);
 
 	if (l4->si[0].addr.to.ss_family != AF_INET)
 		return 0;
@@ -1359,8 +1353,7 @@
 pattern_fetch_dst6(struct proxy *px, struct session *l4, void *l7, int dir,
                   const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
 {
-	if (!(l4->flags & SN_FRT_ADDR_SET))
-		get_frt_addr(l4);
+	stream_sock_get_to_addr(&l4->si[0]);
 
 	if (l4->si[0].addr.to.ss_family != AF_INET6)
 		return 0;
@@ -1374,8 +1367,7 @@
 acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
                 struct acl_expr *expr, struct acl_test *test)
 {
-	if (!(l4->flags & SN_FRT_ADDR_SET))
-		get_frt_addr(l4);
+	stream_sock_get_to_addr(&l4->si[0]);
 
 	if (!(temp_pattern.data.integer = get_host_port(&l4->si[0].addr.to)))
 		return 0;
@@ -1388,8 +1380,7 @@
 pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
                     const struct pattern_arg *arg, int i, union pattern_data *data)
 {
-	if (!(l4->flags & SN_FRT_ADDR_SET))
-		get_frt_addr(l4);
+	stream_sock_get_to_addr(&l4->si[0]);
 
 	if (!(data->integer = get_host_port(&l4->si[0].addr.to)))
 		return 0;
diff --git a/src/session.c b/src/session.c
index b90b254..e814903 100644
--- a/src/session.c
+++ b/src/session.c
@@ -169,6 +169,8 @@
 	s->si[0].err_loc   = NULL;
 	s->si[0].connect   = NULL;
 	s->si[0].release   = NULL;
+	s->si[0].get_src   = getpeername;
+	s->si[0].get_dst   = getsockname;
 	clear_target(&s->si[0].target);
 	s->si[0].exp       = TICK_ETERNITY;
 	s->si[0].flags     = SI_FL_NONE;
@@ -193,6 +195,8 @@
 	s->si[1].err_loc   = NULL;
 	s->si[1].connect   = NULL;
 	s->si[1].release   = NULL;
+	s->si[1].get_src   = NULL;
+	s->si[1].get_dst   = NULL;
 	clear_target(&s->si[1].target);
 	s->si[1].shutr     = stream_int_shutr;
 	s->si[1].shutw     = stream_int_shutw;