From df5741a0d391a7107157d0051ba81ef48d87b8f5 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen@gmail.com>
Date: Mon, 15 Jul 2024 22:20:33 +0100
Subject: [PATCH] BUILD/MEDIUM: haproxy : fix SO_LINGER usage on macOS.

SO_LINGER on macOS works in term of clock ticks rather than seconds
leading to behavior differences. SO_LINGER_SEC is available to
be more in line so we create HA_SO_LINGER internal.
---
 include/haproxy/compat.h | 10 ++++++++++
 src/fd.c                 |  2 +-
 src/proto_tcp.c          |  6 +++---
 src/session.c            |  2 +-
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/haproxy/compat.h b/include/haproxy/compat.h
index 3829060b7..ac80fc77c 100644
--- a/include/haproxy/compat.h
+++ b/include/haproxy/compat.h
@@ -202,6 +202,16 @@ typedef struct { } empty_t;
 #endif /* SO_REUSEADDR */
 #endif /* SO_REUSEPORT */
 
+#if defined(SO_LINGER_SEC)
+/* SO_LINGER on macOS works differently from other unixes.
+ * It does not perform in term of seconds but clock ticks.
+ * Thus Apple provides, in addition, SO_LINGER_SEC.
+ */
+#define HA_SO_LINGER SO_LINGER_SEC
+#else
+#define HA_SO_LINGER SO_LINGER
+#endif
+
 /* only Linux defines TCP_FASTOPEN */
 #ifdef USE_TFO
 #ifndef TCP_FASTOPEN
diff --git a/src/fd.c b/src/fd.c
index cf77884b1..44f9a68a1 100644
--- a/src/fd.c
+++ b/src/fd.c
@@ -309,7 +309,7 @@ void _fd_delete_orphan(int fd)
 	fd_disown = fdtab[fd].state & FD_DISOWN;
 	if (fdtab[fd].state & FD_LINGER_RISK) {
 		/* this is generally set when connecting to servers */
-		DISGUISE(setsockopt(fd, SOL_SOCKET, SO_LINGER,
+		DISGUISE(setsockopt(fd, SOL_SOCKET, HA_SO_LINGER,
 			   (struct linger *) &nolinger, sizeof(struct linger)));
 	}
 
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 63be77508..831ce3b4c 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -561,15 +561,15 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
 	fd = listener->rx.fd;
 
 	if (listener->bind_conf->options & BC_O_NOLINGER)
-		setsockopt(fd, SOL_SOCKET, SO_LINGER, &nolinger, sizeof(struct linger));
+		setsockopt(fd, SOL_SOCKET, HA_SO_LINGER, &nolinger, sizeof(struct linger));
 	else {
 		struct linger tmplinger;
 		socklen_t len = sizeof(tmplinger);
-		if (getsockopt(fd, SOL_SOCKET, SO_LINGER, &tmplinger, &len) == 0 &&
+		if (getsockopt(fd, SOL_SOCKET, HA_SO_LINGER, &tmplinger, &len) == 0 &&
 		    (tmplinger.l_onoff == 1 || tmplinger.l_linger == 0)) {
 			tmplinger.l_onoff = 0;
 			tmplinger.l_linger = 0;
-			setsockopt(fd, SOL_SOCKET, SO_LINGER, &tmplinger,
+			setsockopt(fd, SOL_SOCKET, HA_SO_LINGER, &tmplinger,
 			    sizeof(tmplinger));
 		}
 	}
diff --git a/src/session.c b/src/session.c
index 710118024..47a1b94d5 100644
--- a/src/session.c
+++ b/src/session.c
@@ -205,7 +205,7 @@ int session_accept_fd(struct connection *cli_conn)
 	     !LIST_ISEMPTY(&p->tcp_req.l4_rules)) && !tcp_exec_l4_rules(sess)) {
 		/* let's do a no-linger now to close with a single RST. */
 		if (!(cli_conn->flags & CO_FL_FDLESS))
-			setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
+			setsockopt(cfd, SOL_SOCKET, HA_SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
 		ret = 0; /* successful termination */
 		goto out_free_sess;
 	}
-- 
2.45.2

