MINOR: listener: automatically adjust shards based on support for SO_REUSEPORT

Now if multiple shards are explicitly requested, and the listener's
protocol doesn't support SO_REUSEPORT, sharding is disabled, which will
result in the socket being automatically duped if needed. A warning is
emitted when this happens. If "shards by-group" or "shards by-thread"
are used, these will automatically be turned down to 1 since we want
this to be possible easily using -dR on the command line without having
to djust the config. For "by-thread", a diag warning will be emitted to
help troubleshoot possible performance issues.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 396fc5f..d337c88 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -15297,6 +15297,14 @@
   sockets. The load distribution will be a bit less optimal but the contention
   (especially in the system) will still be lower than with a single socket.
 
+  On operating systems that do not support multiple sockets bound to the same
+  address, "by-thread" and "by-group" will automatically fall back to a single
+  shard. For "by-group" this is done without any warning since it doesn't
+  change anything for a single group, and will result in sockets being
+  duplicated for each group anyway. However, for "by-thread", a diagnostic
+  warning will be emitted if this happens since the resulting number of
+  listeners will not be the expected one.
+
 ssl
   This setting is only available when support for OpenSSL was built in. It
   enables SSL deciphering on connections instantiated from this listener. A
diff --git a/src/listener.c b/src/listener.c
index 8a3aa7c..45595cc 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -1668,15 +1668,31 @@
 		todo = thread_set_count(&bind_conf->thread_set);
 
 		/* special values: -1 = "by-thread", -2 = "by-group" */
-		if (shards == -1)
-			shards = todo;
+		if (shards == -1) {
+			if (li->rx.proto->flags & PROTO_F_REUSEPORT_SUPPORTED)
+				shards = todo;
+			else {
+				if (fe != global.cli_fe)
+					ha_diag_warning("[%s:%d]: Disabling per-thread sharding for listener in"
+					                " %s '%s' because SO_REUSEPORT is disabled\n",
+					                bind_conf->file, bind_conf->line, proxy_type_str(fe), fe->id);
+				shards = 1;
+			}
+		}
 		else if (shards == -2)
-			shards = my_popcountl(bind_conf->thread_set.grps);
+			shards = (li->rx.proto->flags & PROTO_F_REUSEPORT_SUPPORTED) ? my_popcountl(bind_conf->thread_set.grps) : 1;
 
 		/* no more shards than total threads */
 		if (shards > todo)
 			shards = todo;
 
+		/* We also need to check if an explicit shards count was set and cannot be honored */
+		if (shards > 1 && !(li->rx.proto->flags & PROTO_F_REUSEPORT_SUPPORTED)) {
+			ha_warning("[%s:%d]: Disabling sharding for listener in %s '%s' because SO_REUSEPORT is disabled\n",
+			           bind_conf->file, bind_conf->line, proxy_type_str(fe), fe->id);
+			shards = 1;
+		}
+
 		shard = done = grp = bit = mask = 0;
 		new_li = li;