[MEDIUM] add support for binding to source port ranges during connect

Some users are already hitting the 64k source port limit when
connecting to servers. The system usually maintains a list of
unused source ports, regardless of the source IP they're bound
to. So in order to go beyond the 64k concurrent connections, we
have to manage the source ip:port lists ourselves.

The solution consists in assigning a source port range to each
server and use a free port in that range when connecting to that
server, either for a proxied connection or for a health check.
The port must then be put back into the server's range when the
connection is closed.

This mechanism is used only when a port range is specified on
a server. It makes it possible to reach 64k connections per
server, possibly all from the same IP address. Right now it
should be more than enough even for huge deployments.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index bfcccf2..b268d59 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -40,6 +40,7 @@
 #include <proto/dumpstats.h>
 #include <proto/httperr.h>
 #include <proto/log.h>
+#include <proto/port_range.h>
 #include <proto/protocols.h>
 #include <proto/proto_tcp.h>
 #include <proto/proto_http.h>
@@ -2179,18 +2180,34 @@
 				cur_arg += 1;
 			}
 			else if (!strcmp(args[cur_arg], "source")) {  /* address to which we bind when connecting */
+				int port_low, port_high;
 				if (!*args[cur_arg + 1]) {
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
-					Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], and optional '%s' <addr> as argument.\n",
+					Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>[-<port>]], and optional '%s' <addr> as argument.\n",
 					      file, linenum, "source", "usesrc");
 #else
-					Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
+					Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>[-<port>]] as argument.\n",
 					      file, linenum, "source");
 #endif
 					return -1;
 				}
 				newsrv->state |= SRV_BIND_SRC;
-				newsrv->source_addr = *str2sa(args[cur_arg + 1]);
+				newsrv->source_addr = *str2sa_range(args[cur_arg + 1], &port_low, &port_high);
+
+				if (port_low != port_high) {
+					int i;
+					if (port_low  <= 0 || port_low > 65535 ||
+					    port_high <= 0 || port_high > 65535 ||
+					    port_low > port_high) {
+						Alert("parsing [%s:%d] : invalid source port range %d-%d.\n",
+						      file, linenum, port_low, port_high);
+						return -1;
+					}
+					newsrv->sport_range = port_range_alloc_range(port_high - port_low + 1);
+					for (i = 0; i < newsrv->sport_range->size; i++)
+						newsrv->sport_range->ports[i] = port_low + i;
+				}
+
 				cur_arg += 2;
 				while (*(args[cur_arg])) {
 					if (!strcmp(args[cur_arg], "usesrc")) {  /* address to use outside */