Fixed: maxchild dropped to 100 on config reload if not explicitly set, system-specific tuning hints added to doc

This commit is contained in:
Vladimir Dubrovin 2026-08-01 10:22:03 +03:00
parent 7b85f6a684
commit 763e21e053
8 changed files with 299 additions and 25 deletions

View File

@ -5,8 +5,8 @@
<h4>Configuring 'maxconn'</h4> <h4>Configuring 'maxconn'</h4>
The number of simultaneous connections per service is limited by the 'maxconn' option. The number of simultaneous connections per service is limited by the 'maxconn' option.
The default maxconn value since 3proxy 0.8 is 500. You may want to set 'maxconn' The default maxconn value is 500. You may want to set 'maxconn'
to a higher value. Under this configuration: to a higher value; it must be set before the services it should apply to. Under this configuration:
<pre> <pre>
maxconn 1000 maxconn 1000
proxy -p3129 proxy -p3129
@ -19,6 +19,10 @@ simultaneous connections to 3proxy.
<p>Avoid setting 'maxconn' to an arbitrarily high value; it should be carefully <p>Avoid setting 'maxconn' to an arbitrarily high value; it should be carefully
chosen to protect the system and proxy from resource exhaustion. Setting maxconn chosen to protect the system and proxy from resource exhaustion. Setting maxconn
above available resources can lead to denial of service conditions. above available resources can lead to denial of service conditions.
<p>'maxconn' is not reduced automatically to fit the open file limit. If the limit is
too low 3proxy only prints a warning at startup
("current open file ulimits are too low") and then fails to accept connections once
the limit is reached, so check for this warning after changing 'maxconn'.
<h4>Understanding Resource Requirements</h4> <h4>Understanding Resource Requirements</h4>
Each running service requires: Each running service requires:
<ul> <ul>
@ -56,19 +60,45 @@ system "ulimit -Sa >>/tmp/3proxy.ulim.soft"
at the beginning (before the first service is started) and at the end of the config file. at the beginning (before the first service is started) and at the end of the config file.
Perform both a hard restart (i.e., kill and start the 3proxy process) and a soft restart Perform both a hard restart (i.e., kill and start the 3proxy process) and a soft restart
by sending SIGUSR1 to the 3proxy process; check that the ulimits recorded to files match your by sending SIGUSR1 to the 3proxy process; check that the ulimits recorded to files match your
expectations. In systemd-based distros (e.g., latest Debian/Ubuntu), changing limits.conf expectations. In systemd-based distros (e.g., latest Debian/Ubuntu) changing limits.conf is not
is not enough; limits must be adjusted in the systemd configuration, e.g., by setting: enough for a service: limits must be set in the unit file. Set them in the 3proxy
unit itself rather than globally, so the rest of the system is unaffected. The
shipped 3proxy.service already contains:
<pre> <pre>
DefaultLimitDATA=infinity LimitNOFILE=1048576
DefaultLimitSTACK=infinity LimitNPROC=infinity
DefaultLimitCORE=infinity TasksMax=infinity
DefaultLimitRSS=infinity </pre>
DefaultLimitNOFILE=102400 To change them on an installed system use an override instead of editing the unit:
DefaultLimitAS=infinity <pre>
DefaultLimitNPROC=10240 systemctl edit 3proxy
DefaultLimitMEMLOCK=infinity systemctl daemon-reload &amp;&amp; systemctl restart 3proxy
systemctl show 3proxy -p LimitNOFILE -p LimitNPROC -p TasksMax
</pre>
<b>TasksMax is the one that is easy to miss.</b> It is the cgroup limit on the number
of threads, and if it is not set the unit inherits DefaultTasksMax, which is 15% of
kernel.threads-max (about 9000 on a typical host). Since 3proxy uses one thread per
connection, that caps concurrent connections at that number regardless of LimitNPROC
and maxconn, and the only symptom is "pthread_create()" errors in the log.
<p>On systemd older than 227, which has no TasksMax, and for limits that must apply to
several services, the same values can be set globally as DefaultLimitNOFILE /
DefaultLimitNPROC in /etc/systemd/system.conf, but prefer the per-unit settings.
<p>With SysV init the limits are not applied by limits.conf either, because
start-stop-daemon does not open a PAM session, so the daemon simply inherits the limits
of init. The shipped init script raises them itself before starting 3proxy:
<pre>
ulimit -n 65536
ulimit -u 32768
</pre>
adjust these values in the script to match 'maxconn'.
<p>On FreeBSD rc.subr applies limits(1) with the login class of the service (the
"daemon" class by default), so the limits can be set either in /etc/login.conf for that
class, or per service in rc.conf:
<pre>
3proxy_limits="-n 65536"
</pre> </pre>
in user.conf / system.conf
<h4>Extending System Limitations</h4> <h4>Extending System Limitations</h4>
@ -83,6 +113,168 @@ proxy -olSO_REUSEADDR,SO_REUSEPORT -ocTCP_TIMESTAMPS,TCP_NODELAY -osTCP_NODELAY
</pre> </pre>
Available options are system-dependent. Available options are system-dependent.
<h4>Linux Tuning Hints</h4>
Values below are examples, not recommendations: check the current value first
(<tt>sysctl NAME</tt>), change only what your workload actually hits, and make changes
persistent in <tt>/etc/sysctl.d/</tt>. Defaults given in parentheses are from a recent
(6.x) kernel and vary between distributions and versions.
<p><b>File descriptors.</b> 3proxy needs 2 descriptors per connection (4 for FTP), plus
one per service, plus temporary ones for name resolution and RADIUS.
<pre>
fs.nr_open = 1048576 # (1048576) upper bound for any process' RLIMIT_NOFILE
</pre>
<tt>ulimit -n</tt> (RLIMIT_NOFILE) is the limit that actually applies and is commonly
left at 1024; it must be raised for the 3proxy process itself, see "Setting ulimits"
above. <tt>fs.file-max</tt> is effectively unlimited on 64-bit kernels and rarely needs
changing.
<p><b>Threads.</b> Because of the "one connection - one thread" model these limits are
reached earlier with 3proxy than with event-driven servers. Each thread also consumes
one or two mappings, so <tt>vm.max_map_count</tt> matters too.
<pre>
kernel.threads-max = 200000 # (~60000 on a 16G host, scales with RAM)
kernel.pid_max = 4194304 # (4194304)
vm.max_map_count = 1048576 # (1048576)
</pre>
RLIMIT_NPROC (<tt>ulimit -u</tt>) limits threads per user and must be raised as well.
Check the actual thread count with <tt>grep Threads /proc/PID/status</tt>.
<p><b>Listen queue.</b> 3proxy uses a listen backlog of 1+(maxconn/8) unless the
'backlog' command is given, so a large 'maxconn' does not automatically give a large
queue, and the kernel caps it at somaxconn:
<pre>
net.core.somaxconn = 4096 # (4096)
net.ipv4.tcp_max_syn_backlog = 4096 # (512) raise for bursty connection rates
net.ipv4.tcp_syncookies = 1 # (1) keep enabled
</pre>
<p><b>Ephemeral ports and TIME_WAIT.</b> See "Extending the Ephemeral Port Range" above
for the multi-IP case. The range gives about 28000 outgoing connections per
destination address by default:
<pre>
net.ipv4.ip_local_port_range = 10240 65535 # (32768 60999)
net.ipv4.tcp_tw_reuse = 2 # (2) reuse TIME_WAIT for outgoing connections
net.ipv4.tcp_fin_timeout = 30 # (60)
</pre>
Do not enable tcp_tw_recycle; it was removed in kernel 4.12 and breaks NAT clients.
<p><b>Socket buffers.</b> Autotuning is usually right. Buffer memory is per connection,
so raising the maximums with tens of thousands of connections costs a lot of RAM:
<pre>
net.core.rmem_max = 4194304 # (212992)
net.core.wmem_max = 4194304 # (212992)
net.ipv4.tcp_rmem = 4096 131072 6291456 # (same) min default max
net.ipv4.tcp_wmem = 4096 16384 4194304 # (same)
</pre>
Raise these only for high bandwidth-delay product links, and prefer raising the third
(max) value and leaving the default alone.
<p><b>Conntrack.</b> Only relevant if netfilter/nftables tracks the proxy's traffic. If
it does, the table is exhausted long before 3proxy's own limits, with
"nf_conntrack: table full, dropping packet" in dmesg:
<pre>
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_buckets = 262144
net.netfilter.nf_conntrack_tcp_timeout_established = 3600 # (432000, i.e. 5 days)
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 # (120)
</pre>
nf_conntrack_max defaults to nf_conntrack_buckets, which itself is derived from the
amount of RAM, so it is often much lower than expected on small machines. Each
connection takes two entries (one per direction). The default established timeout of
5 days matters more than the table size with high connection churn: entries for
connections that are long gone keep occupying the table.
<p>If no rules need conntrack, not loading it at all is faster: the modules are loaded
on demand by the first rule that needs them ("-m state", "-m conntrack", any NAT
rule), so a ruleset without such rules keeps the proxy traffic untracked. If conntrack
is needed for other traffic but not for the proxy's, exempt the proxy's traffic
explicitly in the raw table:
<pre>
iptables -t raw -A PREROUTING -p tcp --dport 3128 -j CT --notrack
iptables -t raw -A OUTPUT -p tcp -m owner --uid-owner proxy -j CT --notrack
</pre>
<p><b>Conntrack helpers (ALGs).</b> The helper modules - nf_conntrack_ftp,
nf_conntrack_sip, nf_conntrack_h323, nf_conntrack_pptp, nf_conntrack_irc,
nf_conntrack_tftp - inspect the payload of every matching packet and create additional
"expectation" entries, so they cost both CPU and table space, and they have a long
history of security issues. Unload and blacklist the ones you do not actually need:
<pre>
lsmod | grep nf_conntrack
modprobe -r nf_conntrack_sip nf_conntrack_h323 nf_conntrack_ftp nf_conntrack_pptp
echo "blacklist nf_conntrack_sip" >> /etc/modprobe.d/no-alg.conf
</pre>
On current kernels a helper only acts when it is attached explicitly
("-j CT --helper ftp"), so simply not attaching it is enough; automatic helper
assignment was deprecated and later removed. Older kernels, and most router firmware,
still enable them by default.
<p><b>Checking the result.</b> <tt>ss -s</tt> for socket state totals,
<tt>ss -lnt</tt> for listen queue overflow, <tt>nstat -az TcpExtListenOverflows
TcpExtListenDrops</tt> for accept queue drops, and
<tt>cat /proc/PID/limits</tt> for the limits actually applied to the running process.
<h4>Windows Tuning Hints</h4>
<p><b>Dynamic (ephemeral) port range.</b> Since Windows Vista / Server 2008 the default
range is 49152-65535, i.e. only 16384 outgoing connections per local address, which is
reached quickly by a busy proxy. Show and change it with:
<pre>
netsh int ipv4 show dynamicport tcp
netsh int ipv4 set dynamicport tcp start=10000 num=55535
</pre>
The minimum start port is 1025, the minimum size of the range is 255, and the end of
the range cannot exceed 65535. The range is set separately for TCP and UDP, and for
IPv4 and IPv6. On pre-Vista systems the equivalent is the MaxUserPort registry value
in HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters.
<p><b>Listening socket.</b> 3proxy sets SO_REUSEADDR on the listening socket by
default on Unix, but not on Windows: there it is not needed to rebind the port, and it
only allows another local process to bind the same address and port, with undefined
behaviour as to which of them receives the connections. If the machine is shared or
untrusted, harden the listening socket instead:
<pre>
proxy -olSO_EXCLUSIVEADDRUSE
</pre>
Note that a socket with SO_EXCLUSIVEADDRUSE may not be immediately rebindable after a
restart if accepted connections are still active, so test restarts before using it.
<p><b>Port reuse.</b> 3proxy always binds the outgoing socket before connecting, so
Windows does not apply its automatic ephemeral port reuse (which it does only for
connections with an implicit bind). Setting the option explicitly on the
proxy-to-server socket therefore helps against port exhaustion:
<pre>
proxy -osSO_REUSE_UNICASTPORT
</pre>
SO_REUSE_UNICASTPORT requires Windows 10 / Server 2019 or later. On older systems
(Windows 7 / Server 2008 and later) use SO_PORT_SCALABILITY instead; where both are
available Microsoft recommends SO_REUSE_UNICASTPORT. Note that SO_REUSEADDR has
different, weaker semantics on Windows than on Unix and allows another socket to bind
the same address and port, so do not use it on the listening socket as a substitute.
<p><b>TIME_WAIT.</b> Closed connections hold their port for the TcpTimedWaitDelay
period, set in
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters (DWORD, seconds). The
effective default differs between Windows versions (2 to 4 minutes); check the current
behaviour before changing it, and lower it only together with an extended port range.
Count the connections in that state with:
<pre>
netstat -ano -p tcp | find /c "TIME_WAIT"
</pre>
<p><b>Threads and address space.</b> Windows has no ulimit equivalent, and the handle
count is not normally the limit. On 32-bit builds the 2 GB of user address space is:
each connection thread reserves its stack there, so a few thousand connections can
exhaust the address space while physical memory is still free. Use a 64-bit build for high load, and
see "Setting Stack Size" above.
<p><b>Filter drivers.</b> Antivirus, endpoint protection and other LSP/WFP filter
drivers inspect every connection and are frequently the actual bottleneck on Windows,
costing far more than any tuning above can recover. Exclude the 3proxy process and its
ports, or test with the protection temporarily disabled to see the difference before
tuning anything else.
<h4>Using 3proxy in a Virtual Environment</h4> <h4>Using 3proxy in a Virtual Environment</h4>
If 3proxy is used in a VPS environment, there can be additional limitations. If 3proxy is used in a VPS environment, there can be additional limitations.
@ -148,10 +340,10 @@ Under the latest Linux versions, you can also start multiple services with diffe
external addresses on a single port with SO_REUSEPORT on the listening socket to external addresses on a single port with SO_REUSEPORT on the listening socket to
evenly distribute incoming connections between outgoing interfaces: evenly distribute incoming connections between outgoing interfaces:
<pre> <pre>
socks -olSO_REUSEPORT -p3128 -e 1.1.1.1 socks -olSO_REUSEPORT -p3128 -e1.1.1.1
socks -olSO_REUSEPORT -p3128 -e 2.2.2.2 socks -olSO_REUSEPORT -p3128 -e2.2.2.2
socks -olSO_REUSEPORT -p3128 -e 3.3.3.3 socks -olSO_REUSEPORT -p3128 -e3.3.3.3
socks -olSO_REUSEPORT -p3128 -e 4.4.4.4 socks -olSO_REUSEPORT -p3128 -e4.4.4.4
</pre> </pre>
For web browsing, the last two examples are not recommended because the same client can get For web browsing, the last two examples are not recommended because the same client can get
a different external address for different requests; you should choose the external a different external address for different requests; you should choose the external
@ -172,6 +364,39 @@ randomly fail due to IP+port pair collisions if the remote or local system
doesn't support this trick. doesn't support this trick.
</ol> </ol>
<h4>NAT on the Path Must Be Tuned Too</h4>
Everything above tunes the machine 3proxy runs on. If the outgoing traffic passes
through NAT - a router, a firewall, a CGNAT of the provider, or a cloud NAT gateway -
that device keeps its own translation table and its own pool of source ports, and it
limits the number of connections independently of the proxy. Extending
ip_local_port_range on the 3proxy host changes nothing if the NAT device rewrites the
source port from its own, smaller pool.
<p>On a Linux based router the same knobs apply and have to be raised there as well:
nf_conntrack_max / nf_conntrack_buckets and the conntrack timeouts (see "Linux Tuning
Hints" above), plus the port range used for translation, which is ip_local_port_range
for MASQUERADE, or the explicit range if SNAT is configured with --to-ports. Note that
the range is per translated address: with a single public IP, all clients share it.
<p>Entry level and SOHO routers are the usual bottleneck here. They typically have a
small fixed NAT/conntrack table (a few thousand entries), aggressive or non-adjustable
timeouts, and no way to change either. Symptoms are seen on the proxy but caused by the
router: connections that fail or hang at random under load while the proxy is far from
its own limits, no error in the 3proxy log except a failed outgoing connect, and
recovery after a pause or a router reboot. Before tuning 3proxy further, check the
router's session/NAT table counters. For high load either give the proxy a public
address without NAT in the path, or use a router where the table size and timeouts are
configurable.
<p>On the router, also turn off the application layer gateways that are not actually
used - they usually appear in the web interface as "SIP ALG", "FTP ALG", "H.323 ALG",
"PPTP passthrough", "IPsec/VPN passthrough". They are commonly enabled by default, they
parse the payload of matching connections, and they consume additional session table
entries for the connections they expect. If nothing behind the proxy uses FTP, VoIP or
those VPN protocols, disabling them frees table space and CPU on exactly the device
that is the bottleneck.
<h4>Setting Stack Size</h4> <h4>Setting Stack Size</h4>
'stacksize' is a size added to all stack allocations and can be both positive and 'stacksize' is a size added to all stack allocations and can be both positive and
@ -187,7 +412,11 @@ the need to add additional physical memory,
but it's system/libc dependent and requires additional testing under your but it's system/libc dependent and requires additional testing under your
installation. Don't forget about memory-related ulimits. installation. Don't forget about memory-related ulimits.
<p>For 32-bit systems, address space can be a bottleneck you should consider. If <p>For 32-bit systems, address space can be a bottleneck you should consider. If
you're short on address space, you can try using a negative stack size. you're short on address space, you can try using a negative stack size. The result is
never lowered below the system minimum (PTHREAD_STACK_MIN), so a large negative value
can not disable the thread stack. The base value the 'stacksize' is added to is 48K
(64K on FreeBSD/NetBSD/OpenBSD/DragonFly, where libc uses more stack, e.g. in
vfprintf() called by syslog()).
<h4>Known System Issues</h4> <h4>Known System Issues</h4>
@ -266,5 +495,5 @@ The example above adds a 10-millisecond delay before reading data if the average
polling size is below 8000 bytes and 3 read operations have been made in the same polling size is below 8000 bytes and 3 read operations have been made in the same
direction. <pre>logdump 1 1</pre> is useful direction. <pre>logdump 1 1</pre> is useful
to see how grace delays work; choose a delay value to avoid filling the read to see how grace delays work; choose a delay value to avoid filling the read
pipe/buffer (typically 64K) but keep the request sizes close to the chosen average buffer (typically 64K) but keep the request sizes close to the chosen average
on large file uploads/downloads. on large file uploads/downloads.

View File

@ -178,7 +178,8 @@ connect to given remote HOST:port instead of listening local connection on -p or
.br .br
.B -oc\fIOPTIONS\fB, -os\fIOPTIONS\fB, -ol\fIOPTIONS\fB, -or\fIOPTIONS\fB, -oR\fIOPTIONS\fR .B -oc\fIOPTIONS\fB, -os\fIOPTIONS\fB, -ol\fIOPTIONS\fB, -or\fIOPTIONS\fB, -oR\fIOPTIONS\fR
options for proxy-to-client (\fB-oc\fR), proxy-to-server (\fB-os\fR), proxy listening (\fB-ol\fR), connect back client (\fB-or\fR), connect back listening (\fB-oR\fR) sockets. options for proxy-to-client (\fB-oc\fR), proxy-to-server (\fB-os\fR), proxy listening (\fB-ol\fR), connect back client (\fB-or\fR), connect back listening (\fB-oR\fR) sockets.
Options like TCP_CORK, TCP_NODELAY, TCP_DEFER_ACCEPT, TCP_QUICKACK, TCP_TIMESTAMPS, USE_TCP_FASTOPEN, SO_REUSEADDR, SO_REUSEPORT, SO_PORT_SCALABILITY, SO_REUSE_UNICASTPORT, SO_KEEPALIVE, SO_DONTROUTE may be supported depending on OS. Options like TCP_CORK, TCP_NODELAY, TCP_DEFER_ACCEPT, TCP_QUICKACK, TCP_TIMESTAMPS, TCP_FASTOPEN, SO_REUSEADDR, SO_REUSEPORT, SO_EXCLUSIVEADDRUSE, SO_PORT_SCALABILITY, SO_REUSE_UNICASTPORT, SO_KEEPALIVE, SO_DONTROUTE may be supported depending on OS.
SO_REUSEADDR and SO_REUSEPORT are set on the listening socket by default on Unix. On Windows SO_REUSEADDR is not set: it is not required to rebind a listening port and it only lets another local process bind the same address and port. Use SO_EXCLUSIVEADDRUSE (Windows) on the listening socket (\fB-ol\fR) to prevent that.
.br .br
.B -H .B -H
(for all services) Expect HAProxy PROXY protocol v1 header on incoming connection. (for all services) Expect HAProxy PROXY protocol v1 header on incoming connection.

View File

@ -1,6 +1,6 @@
[Unit] [Unit]
Description=3proxy tiny proxy server Description=3proxy tiny proxy server
Documentation=man:3proxy(1) Documentation=man:3proxy(8) man:3proxy.cfg(5)
After=network.target After=network.target
[Service] [Service]
@ -13,8 +13,15 @@ ExecReload=/bin/kill -SIGUSR1 $MAINPID
KillMode=process KillMode=process
Restart=on-failure Restart=on-failure
RestartSec=60s RestartSec=60s
LimitNOFILE=65536 # 3proxy uses one thread and two descriptors per connection (four for ftppr),
LimitNPROC=32768 # so it reaches these limits much earlier than event driven servers. They are
# ceilings only: the actual number of connections is governed by 'maxconn' in
# the configuration file. TasksMax must be set explicitly, systemd's
# DefaultTasksMax (15% of kernel.threads-max, e.g. ~9000) otherwise caps the
# number of threads, and thus connections, regardless of LimitNPROC.
LimitNOFILE=1048576
LimitNPROC=infinity
TasksMax=infinity
RuntimeDirectory=3proxy RuntimeDirectory=3proxy
RuntimeDirectoryMode=0755 RuntimeDirectoryMode=0755

View File

@ -24,9 +24,19 @@ if [ -f /etc/init.d/functions ]; then
. /etc/init.d/functions . /etc/init.d/functions
fi fi
# SysV init does not apply limits.conf consistently: start-stop-daemon does not
# open a PAM session, so pam_limits is not involved and the daemon inherits the
# limits of init. 3proxy needs two descriptors per connection (four for ftppr),
# so raise them here. Adjust to match 'maxconn' in the configuration file.
set_limits() {
ulimit -n 65536 2>/dev/null || ulimit -n 4096 2>/dev/null || true
ulimit -u 32768 2>/dev/null || true
}
case "$1" in case "$1" in
start) start)
echo -n "Starting 3Proxy: " echo -n "Starting 3Proxy: "
set_limits
if [ ! -d /var/run/3proxy ]; then if [ ! -d /var/run/3proxy ]; then
mkdir -p /var/run/3proxy mkdir -p /var/run/3proxy

View File

@ -190,7 +190,7 @@ struct extparam conf = {
.paused = 0, .paused = 0,
.archiverc = 0, .archiverc = 0,
.demon = 0, .demon = 0,
.maxchild = 500, .maxchild = DEFAULT_MAXCHILD,
.backlog = 0, .backlog = 0,
.needreload = 0, .needreload = 0,
.timetoexit = 0, .timetoexit = 0,

View File

@ -2025,7 +2025,7 @@ void freeconf(struct extparam *confp){
#endif #endif
*SAFAMILY(&confp->intsa) = AF_INET; *SAFAMILY(&confp->intsa) = AF_INET;
*SAFAMILY(&confp->extsa) = AF_INET; *SAFAMILY(&confp->extsa) = AF_INET;
confp->maxchild = 100; confp->maxchild = DEFAULT_MAXCHILD;
confp->backlog = 0; confp->backlog = 0;
resolvfunc = NULL; resolvfunc = NULL;
numservers = 0; numservers = 0;

View File

@ -34,6 +34,7 @@
#define MAXUSERNAME 128 #define MAXUSERNAME 128
#define _PASSWORD_LEN 256 #define _PASSWORD_LEN 256
#define MAXNSERVERS 5 #define MAXNSERVERS 5
#define DEFAULT_MAXCHILD 500
#define TCPBUFSIZE 65536 #define TCPBUFSIZE 65536
#define SRVBUFSIZE (param->srv->bufsize?param->srv->bufsize:((param->service == S_UDPPM)?UDPBUFSIZE:TCPBUFSIZE)) #define SRVBUFSIZE (param->srv->bufsize?param->srv->bufsize:((param->service == S_UDPPM)?UDPBUFSIZE:TCPBUFSIZE))

View File

@ -149,6 +149,20 @@ void * threadfunc (void *p) {
} }
#undef param #undef param
#ifdef _WIN32
/* Present since Windows 7 (SO_PORT_SCALABILITY) and Windows 10 / Server 2019
(SO_REUSE_UNICASTPORT), define them if the SDK is older so the options can
still be requested. setsockopt() just fails on a system which does not
support them and the failure is ignored.
*/
#ifndef SO_PORT_SCALABILITY
#define SO_PORT_SCALABILITY 0x3006
#endif
#ifndef SO_REUSE_UNICASTPORT
#define SO_REUSE_UNICASTPORT 0x3007
#endif
#endif
struct socketoptions sockopts[] = { struct socketoptions sockopts[] = {
#ifdef TCP_NODELAY #ifdef TCP_NODELAY
{TCP_NODELAY, "TCP_NODELAY"}, {TCP_NODELAY, "TCP_NODELAY"},
@ -171,6 +185,9 @@ struct socketoptions sockopts[] = {
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
{SO_REUSEPORT, "SO_REUSEPORT"}, {SO_REUSEPORT, "SO_REUSEPORT"},
#endif #endif
#ifdef SO_EXCLUSIVEADDRUSE
{SO_EXCLUSIVEADDRUSE, "SO_EXCLUSIVEADDRUSE"},
#endif
#ifdef SO_PORT_SCALABILITY #ifdef SO_PORT_SCALABILITY
{SO_PORT_SCALABILITY, "SO_PORT_SCALABILITY"}, {SO_PORT_SCALABILITY, "SO_PORT_SCALABILITY"},
#endif #endif
@ -794,8 +811,15 @@ int MODULEMAINFUNC (int argc, char** argv){
if(*SAFAMILY(&srv.intsa) != AF_UNIX) if(*SAFAMILY(&srv.intsa) != AF_UNIX)
#endif #endif
{ {
/* SO_REUSEADDR is not set on Windows: it is not needed to rebind a listening
port there, and it only allows another local process to bind the same
address and port, with undefined behaviour as to which socket receives the
connections. Use -olSO_EXCLUSIVEADDRUSE to prevent that instead.
*/
#ifndef _WIN32
opt = 1; opt = 1;
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()"); if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
#endif
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
opt = 1; opt = 1;
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int)); srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
@ -911,8 +935,10 @@ int MODULEMAINFUNC (int argc, char** argv){
freesrvstrings(&srv, cbc_string, cbl_string); freesrvstrings(&srv, cbc_string, cbl_string);
return -6; return -6;
} }
#ifndef _WIN32
opt = 1; opt = 1;
srv.so._setsockopt(srv.so.state, srv.cbsock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)); srv.so._setsockopt(srv.so.state, srv.cbsock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
#endif
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
opt = 1; opt = 1;
srv.so._setsockopt(srv.so.state, srv.cbsock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int)); srv.so._setsockopt(srv.so.state, srv.cbsock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));