It's fundamentally incompatible with usage of SSL, doesn't support
source filtering, and imposes the presence of file descriptors with
hard-coded syscalls directly in the generic accept path.
It's very unlikely that anyone has used it in the last 10 years for
anything beyond testing. In the worst case if anyone would depend
on it, replacing it with "http-request return status 200" and "mode
http" would certainly do the trick.
The keyword is still detected as special by the config parser to help
users update their configurations appropriately.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:11 +0000 (18:17 +0200)]
MEDIUM: fcgi: remove conn from session on detach
FCGI mux is marked with HOL blocking. On safe reuse mode, the connection
using it are placed on the sessions instead of the available lists to
avoid sharing it with several clients. On detach, if they are no more
streams, remove the connection from the session before adding it to the
idle list. If there is still used streams, do not add it to available
list as it should be already on the session list.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:10 +0000 (18:17 +0200)]
MEDIUM: h2: remove conn from session on detach
H2 mux is marked with HOL blocking. On safe reuse mode, the connection
using it are placed on the sessions instead of the available lists to
avoid sharing it with several clients. On detach, if they are no more
streams, remove the connection from the session before adding it to the
idle list. If there is still used streams, do not add it to available
list as it should be already on the session list.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:09 +0000 (18:17 +0200)]
MEDIUM: backend: add reused conn to sess if mux marked as HOL blocking
If a connection is using a mux protocol subject to HOL blocking, add it
to the session instead of the available list to avoid sharing it with
other clients on connection reuse.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:08 +0000 (18:17 +0200)]
MEDIUM: backend: add new conn to session if mux marked as HOL blocking
When allocating a new session on connect_server, if the mux protocol is
marked as subject of HOL blocking, add it into session instead of
available list to avoid sharing it with other clients.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:07 +0000 (18:17 +0200)]
MINOR: connection: don't check priv flag on free
Do not check CO_FL_PRIVATE flag to check if the connection is in session
list on conn_free. This is necessary due to the future patches which add
server connections in the session list even if not private, if the mux
protocol is the subject of HOL blocking.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:04 +0000 (18:17 +0200)]
BUG/MEDIUM: connection: fix srv idle count on conn takeover
On server connection migration from one thread to another, the wrong
idle thread-specific counter is decremented. This bug was introduced
since commit 3d52f0f1f828acb2a74b3f13fcc3fa069106d09f due to the
factorization with srv_use_idle_conn. However, this statement is only
executed from conn_backend_get. Extract the decrement from
srv_use_idle_conn in conn_backend_get and use the correct
thread-specific counter.
Rename the function to srv_use_conn to better reflect its purpose as it
is also used with a newly initialized connection not in the idle list.
As a side change, the connection insertion to available list has also
been extracted to conn_backend_get. This will be useful to be able to
specify an alternative list for protocol subject to HOL risk that should
not be shared between several clients.
This bug is only present in this release and thus do not need a backport.
Amaury Denoyelle [Wed, 14 Oct 2020 16:17:03 +0000 (18:17 +0200)]
BUG/MINOR: connection: fix loop iter on connection takeover
The loop always missed one iteration due to the incrementation done on
the for check. Move the incrementation on the loop last statement to fix
this behaviour.
This bug has a very limited impact, not at all visible to the user, but
could be backported to 2.2.
Willy Tarreau [Wed, 14 Oct 2020 10:13:51 +0000 (12:13 +0200)]
BUG/MEDIUM: deinit: check fdtab before fdtab[fd].owner
When running a pure config check (haproxy -c) we go through the deinit
phase without having allocated fdtab, so we can't blindly dereference
it. The issue was added by recent commit ae7bc4a23 ("MEDIUM: deinit:
close all receivers/listeners before scanning proxies"), no backport is
needed.
Willy Tarreau [Wed, 14 Oct 2020 08:50:41 +0000 (10:50 +0200)]
CLEANUP: protocol: intitialize all of the sockaddr when disconnecting
In issue #894, Coverity suspects uninitialized values for a socket's
address whose family is AF_UNSPEC but it doesn't know that the address
is not used in this case. It's not on a critical path and working around
it is trivial, let's fully declare the address. We're doing it for both
TCP and UDP, because the same principle appears at two places.
Willy Tarreau [Wed, 14 Oct 2020 06:09:48 +0000 (08:09 +0200)]
CONTRIB: tcploop: implement a disconnect operation 'D'
This performs a connect(AF_UNSPEC) over an existing connection. This is
mainly for compatibility testing. At this step it only seems to work on
linux for TCP sockets (both listening and established), while SO_LINGER
successfully resets established connections on freebsd and aix.
Willy Tarreau [Tue, 13 Oct 2020 15:46:05 +0000 (17:46 +0200)]
BUG/MINOR: listener: detect and handle shared sockets stopped in other processes
It may happen that during a temporary listener pause resulting from a
SIGTTOU, one process gets one of its sockets disabled by another process
and will not be able to recover from this situation by itself. For the
protocols supporting this (TCPv4 and TCPv6 at the moment) this situation
is detectable, so when this happens, let's put the listener into the
PAUSED state so that it remains consistent with the real socket state.
One nice effect is that just sending the SIGTTIN signal to the process
is enough to recover the socket in this case.
There is no need to backport this, this behavior has been there forever
and the fix requires to reimplement the getsockopt() call there.
Willy Tarreau [Tue, 13 Oct 2020 15:27:34 +0000 (17:27 +0200)]
MINOR: sockpair: implement the .rx_listening function
For socket pairs we don't rely on a real listening socket but we need to
have a properly connected UNIX stream socket. This is what the new
sockpair_accept_conn() tries to report. Some corner cases like half
shutdown will still not be detected but that should be sufficient for
most cases we really care about.
Willy Tarreau [Tue, 13 Oct 2020 15:26:00 +0000 (17:26 +0200)]
MINOR: protocol: make proto_tcp & proto_uxst report listening sockets
Now we introdce a new .rx_listening() function to report if a receiver is
actually a listening socket. The reason for this is to help detect shared
sockets that might have been broken by sibling processes.
Willy Tarreau [Tue, 13 Oct 2020 15:06:12 +0000 (17:06 +0200)]
MINOR: sock: add sock_accept_conn() to test a listening socket
At several places we need to check if a socket is still valid and still
willing to accept connections. Instead of open-coding this, each time,
let's add a new function for this.
Willy Tarreau [Tue, 13 Oct 2020 14:34:19 +0000 (16:34 +0200)]
MINOR: proto-tcp: make use of connect(AF_UNSPEC) for the pause
Currently the suspend/resume mechanism for listeners only works on Linux
and we resort to a number of tricks involving shutdown+listen+shutdown
to try to detect failures on other operating systems that do not support
it. But on Linux connect(AF_UNSPEC) also works pretty well and is much
cleaner. It still doesn't work on other operating systems but the error
is easier to detect and appears safer. So let's switch to this.
Willy Tarreau [Tue, 13 Oct 2020 13:45:07 +0000 (15:45 +0200)]
MINOR: fd: report an error message when failing initial allocations
When starting with a huge maxconn (say 1 billion), the only error seen
is "No polling mechanism available". This doesn't help at all to resolve
the problem. Let's add specific alerts for the failed mallocs. Now we can
get this instead:
[ALERT] 286/154439 (23408) : Not enough memory to allocate 2000000033 entries for fdtab!
This may be backported as far as 2.0 as it helps debugging bad configurations.
Willy Tarreau [Tue, 13 Oct 2020 16:09:15 +0000 (18:09 +0200)]
BUG/MINOR: mux-h2: do not stop outgoing connections on stopping
There are reports of a few "SC" in logs during reloads when H2 is used
on the backend side. Christopher analysed this as being caused by the
proxy disabled test in h2_process(). As the comment says, this was done
for frontends only, and must absolutely not send a GOAWAY to the backend,
as all it will result in is to make newly queued streams fail.
The fix consists in simply testing the connection side before deciding
to send the GOAWAY.
This may be backported as far as 2.0, though for whatever reason it seems
to manifest itself only since 2.2 (probably due to changes in the outgoing
connection setup sequence).
Willy Tarreau [Tue, 13 Oct 2020 13:36:08 +0000 (15:36 +0200)]
BUG/MINOR: init: only keep rlim_fd_cur if max is unlimited
On some operating systems, RLIM_INFINITY is set to -1 so that when the
hard limit on the number of FDs is set to unlimited, taking the MAX
of both values keeps rlim_fd_cur and everything works. But on other
systems this values is defined as the highest positive integer. This
is what was observed on a 32-bit AIX 5.1. The effect is that maxsock
becomes 2^31-1 and that fdtab allocation fails.
Note that a simple workaround consists in manually setting maxconn in
the global section.
Let's ignore unlimited as soon as we retrieve rlim_fd_max so that all
systems behave consistently.
This may be backported as far as 2.0, though it doesn't seem like it
has annoyed anyone.
Ilya Shipitsin [Sun, 11 Oct 2020 18:42:51 +0000 (23:42 +0500)]
CI: travis-ci: replace not defined SSL_LIB, SSL_INC for BotringSSL builds
after 73b520b958be4ee79b4f09a32d6718a13dc2d1fd variables SSL_LIB, SSL_INC
are not set, but still used by BoringSSL builds. That leads to error
(I wish we could stop on such errors) and using stock openssl instead
of boringssl
Willy Tarreau [Sat, 10 Oct 2020 08:45:13 +0000 (10:45 +0200)]
[RELEASE] Released version 2.3-dev6
Released version 2.3-dev6 with the following main changes :
- REGTESTS: use "command" instead of "which" for better POSIX compatibility
- BUILD: makefile: Update feature flags for OpenBSD
- DOC: agent-check: fix typo in "fail" word expected reply
- DOC: crt: advise to move away from cert bundle
- BUG/MINOR: ssl/crt-list: exit on warning out of crtlist_parse_line()
- REGTEST: fix host part in balance-uri-path-only.vtc
- REGTEST: make ssl_client_samples and ssl_server_samples requiret to 2.3
- REGTEST: the iif converter test requires 2.3
- REGTEST: make agent-check.vtc require 1.8
- REGTEST: make abns_socket.vtc require 1.8
- REGTEST: make map_regm_with_backref require 1.7
- BUILD: makefile: Update feature flags for FreeBSD
- OPTIM: backend/random: never queue on the server, always on the backend
- OPTIM: backend: skip LB when we know the backend is full
- BUILD: makefile: Fix building with closefrom() support enabled
- BUILD: makefile: add an EXTRAVERSION variable to ease local naming
- MINOR: tools: support for word expansion of environment in parse_line
- BUILD: tools: fix minor build issue on isspace()
- BUILD: makefile: Enable closefrom() support on Solaris
- CLEANUP: ssl: Use structured format for error line report during crt-list parsing
- MINOR: ssl: Add error if a crt-list might be truncated
- MINOR: ssl: remove uneeded check in crtlist_parse_file
- BUG/MINOR: Fix several leaks of 'log_tag' in init().
- DOC: tcp-rules: Refresh details about L7 matching for tcp-request content rules
- MEDIUM: tcp-rules: Warn if a track-sc* content rule doesn't depend on content
- BUG/MINOR: tcpcheck: Set socks4 and send-proxy flags before the connect call
- DOC: ssl: new "cert bundle" behavior
- BUG/MEDIUM: queue: make pendconn_cond_unlink() really thread-safe
- CLEANUP: ssl: "bundle" is not an OpenSSL wording
- MINOR: counters: fix a typo in comment
- BUG/MINOR: stats: fix validity of the json schema
- REORG: stats: export some functions
- MINOR: stats: add stats size as a parameter for csv/json dump
- MINOR: stats: hide px/sv/li fields in applet struct
- REORG: stats: extract proxy json dump
- REORG: stats: extract proxies dump loop in a function
- MINOR: hlua: Display debug messages on stderr only in debug mode
- MINOR: stats: define the concept of domain for statistics
- MINOR: stats: define additional flag px cap on domain
- MEDIUM: stats: add delimiter for static proxy stats on csv
- MEDIUM: stats: define an API to register stat modules
- MEDIUM: stats: add abstract type to store counters
- MEDIUM: stats: integrate static proxies stats in new stats
- MINOR: stats: support clear counters for dynamic stats
- MINOR: stats: display extra proxy stats on the html page
- MINOR: stats: add config "stats show modules"
- MINOR: dns/stats: integrate dns counters in stats
- MINOR: stats: remove for loop declaration
- DOC: ssl: fix typo about ocsp files
- BUG/MINOR: peers: Inconsistency when dumping peer status codes.
- DOC: update INSTALL with supported OpenBSD / FreeBSD versions
- BUG/MINOR: proto_tcp: Report warning messages when listeners are bound
- CLEANUP: cache: Fix leak of cconf->c.name during config check
- CLEANUP: ssl: Release cached SSL sessions on deinit
- BUG/MINOR: mux-h1: Be sure to only set CO_RFL_READ_ONCE for the first read
- BUG/MINOR: mux-h1: Always set the session on frontend h1 stream
- MINOR: mux-h1: Don't wakeup the H1C when output buffer become available
- CLEANUP: sock-unix: Remove an unreachable goto clause
- BUG/MINOR: proxy: inc req counter on new syslog messages.
- BUG/MEDIUM: log: old processes with log foward section don't die on soft stop.
- MINOR: stats: inc req counter on listeners.
- MINOR: channel: new getword and getchar functions on channel.
- MEDIUM: log: syslog TCP support on log forward section.
- BUG/MINOR: proxy/log: frontend/backend and log forward names must differ
- DOC: re-work log forward bind statement documentation.
- DOC: fix a confusing typo on a regsub example
- BUILD: Add a DragonFlyBSD target
- BUG/MINOR: makefile: fix a tiny typo in the target list
- BUILD: makefile: Update feature flags for NetBSD
- CI: travis-ci: help Coverity to detect BUG_ON() as a real stop
- DOC: Add missing stats fields in the management doc
- BUG/MEDIUM: mux-fcgi: Don't handle pending read0 too early on streams
- BUG/MEDIUM: mux-h2: Don't handle pending read0 too early on streams
- DOC: Fix typos in configuration.txt
- BUG/MINOR: http: Fix content-length of the default 500 error
- BUG/MINOR: http-htx: Expect no body for 204/304 internal HTTP responses
- REGTESTS: mark abns_socket as broken
- MEDIUM: fd: always wake up one thread when enabling a foreing FD
- MEDIUM: listeners: don't bounce listeners management between queues
- MEDIUM: init: stop disabled proxies after initializing fdtab
- MEDIUM: listeners: make unbind_listener() converge if needed
- MEDIUM: deinit: close all receivers/listeners before scanning proxies
- MEDIUM: listeners: remove the now unused ZOMBIE state
- MINOR: listeners: do not uselessly try to close zombie listeners in soft_stop()
- CLEANUP: proxy: remove the first_to_listen hack in zombify_proxy()
- MINOR: listeners: introduce listener_set_state()
- MINOR: proxy: maintain per-state counters of listeners
- MEDIUM: proxy: remove the unused PR_STFULL state
- MEDIUM: proxy: remove the PR_STERROR state
- MEDIUM: proxy: remove state PR_STPAUSED
- MINOR: startup: don't rely on PR_STNEW to check for listeners
- CLEANUP: peers: don't use the PR_ST* states to mark enabled/disabled
- MEDIUM: proxy: replace proxy->state with proxy->disabled
- MEDIUM: proxy: remove start_proxies()
- MEDIUM: proxy: merge zombify_proxy() with stop_proxy()
- MINOR: listeners: check the current listener state in pause_listener()
- MINOR: listeners: check the current listener earlier state in resume_listener()
- MEDIUM: listener/proxy: make the listeners notify about proxy pause/resume
- MINOR: protocol: introduce protocol_{pause,resume}_all()
- MAJOR: signals: use protocol_pause_all() and protocol_resume_all()
- CLEANUP: proxy: remove the now unused pause_proxies() and resume_proxies()
- MEDIUM: proto_tcp: make the pause() more robust in multi-process
- BUG/MEDIUM: listeners: correctly report pause() errors
- MINOR: listeners: move fd_stop_recv() to the receiver's socket code
- CLEANUP: protocol: remove the ->disable_all method
- CLEANUP: listeners: remove unused disable_listener and disable_all_listeners
- MINOR: listeners: export enable_listener()
- MINOR: protocol: directly call enable_listener() from protocol_enable_all()
- CLEANUP: protocol: remove the ->enable_all method
- CLEANUP: listeners: remove the now unused enable_all_listeners()
- MINOR: protocol: rename the ->listeners field to ->receivers
- MINOR: protocol: replace ->pause(listener) with ->rx_suspend(receiver)
- MINOR: protocol: implement an ->rx_resume() method
- MINOR: listener: use the protocol's ->rx_resume() method when available
- MINOR: sock: provide a set of generic enable/disable functions
- MINOR: protocol: add a new pair of rx_enable/rx_disable methods
- MINOR: protocol: add a new pair of enable/disable methods for listeners
- MEDIUM: listeners: now use the listener's ->enable/disable
- MINOR: listeners: split delete_listener() in two versions
- MINOR: listeners: count unstoppable jobs on creation, not deletion
- MINOR: listeners: add a new stop_listener() function
- MEDIUM: proxy: make stop_proxy() now use stop_listener()
- MEDIUM: proxy: add mode PR_MODE_PEERS to flag peers frontends
- MEDIUM: proxy: centralize proxy status update and reporting
- MINOR: protocol: add protocol_stop_now() to instant-stop listeners
- MEDIUM: proxy: make soft_stop() stop most listeners using protocol_stop_now()
- MEDIUM: udp: implement udp_suspend() and udp_resume()
- MINOR: listener: add a few BUG_ON() statements to detect inconsistencies
- MEDIUM: listeners: always close master vs worker listeners
- BROKEN/MEDIUM: listeners: rework the unbind logic to make it idempotent
- MEDIUM: listener: let do_unbind_listener() decide whether to close or not
- CLEANUP: listeners: remove the do_close argument to unbind_listener()
- MINOR: listeners: move the LI_O_MWORKER flag to the receiver
- MEDIUM: receivers: add an rx_unbind() method in the protocols
- MINOR: listeners: split do_unbind_listener() in two
- MEDIUM: listeners: implement protocol level ->suspend/resume() calls
- MEDIUM: config: mark "grace" as deprecated
- MEDIUM: config: remove the deprecated and dangerous global "debug" directive
- BUG/MINOR: proxy: respect the proper format string in sig_pause/sig_listen
- MINOR: peers: heartbeat, collisions and handshake information for "show peers" command.
- BUILD: makefile: Enable getaddrinfo() on OS/X
MINOR: peers: heartbeat, collisions and handshake information for "show peers" command.
This patch adds "coll" new counter and the heartbeat timer values to "show peers"
command. It also adds the elapsed time since the last handshake to new "last_hdshk"
new peer dump field.
Willy Tarreau [Fri, 9 Oct 2020 17:26:27 +0000 (19:26 +0200)]
BUG/MINOR: proxy: respect the proper format string in sig_pause/sig_listen
When factoring out the pause/resume error messages in commit 775e00158
("MAJOR: signals: use protocol_pause_all() and protocol_resume_all()")
I forgot that ha_warning() and send_log() take a format string and not
just a const string. No backport is needed, this is 2.3-dev.
Willy Tarreau [Fri, 9 Oct 2020 17:15:03 +0000 (19:15 +0200)]
MEDIUM: config: remove the deprecated and dangerous global "debug" directive
This one was scheduled for removal in 2.3 since 2.2-dev3 by commit 1b85785bc ("MINOR: config: mark global.debug as deprecated"). Let's
remove it now. It remains totally possible to use -d on the command
line though.
Willy Tarreau [Fri, 9 Oct 2020 17:07:01 +0000 (19:07 +0200)]
MEDIUM: config: mark "grace" as deprecated
This was introduced 15 years ago or so to delay the stopping of some
services so that a monitoring device could detect its port being down
before services were stopped. Since then, clean reloads were implemented
and this doesn't cope well with reload at all, preventing the new process
from seamlessly binding, and forcing processes to coexist with half-baked
configurations.
Now it has become a real problem because there's a significant code
portion in the proxies that is solely dedicated to this obsolete feature,
and dealing with its special cases eases the introduction of bugs in
other places so it's about time that it goes.
We could tentatively schedule its removal for 2.4 with a hard deadline
for 2.5 in any case.
Now we have ->suspend() and ->resume() for listeners at the protocol
level. This means that it now becomes possible for a protocol to redefine
its own way to suspend and resume. The default functions are provided for
TCP, UDP and unix, and they are pass-through to the receiver equivalent
as it used to be till now. Nothing was defined for sockpair since it does
not need to suspend/resume during reloads, hence it will succeed.
Willy Tarreau [Fri, 9 Oct 2020 15:18:29 +0000 (17:18 +0200)]
MINOR: listeners: split do_unbind_listener() in two
The inner part now goes into the protocol and is used to decide how to
unbind a given protocol's listener. The existing code which is able to
also unbind the receiver was provided as a default function that we
currently use everywhere. Some complex listeners like QUIC will use this
to decide how to unbind without impacting existing connections, possibly
by setting up other incoming paths for the traffic.
Willy Tarreau [Fri, 9 Oct 2020 14:32:08 +0000 (16:32 +0200)]
MEDIUM: receivers: add an rx_unbind() method in the protocols
This is used as a generic way to unbind a receiver at the end of
do_unbind_listener(). This allows to considerably simplify that function
since we can now let the protocol perform the cleanup. The generic code
was moved to sock.c, along with the conditional rx_disable() call. Now
the code also supports that the ->disable() function of the protocol
which acts on the listener performs the close itself and adjusts the
RX_F_BUOND flag accordingly.
Willy Tarreau [Fri, 9 Oct 2020 14:11:46 +0000 (16:11 +0200)]
MINOR: listeners: move the LI_O_MWORKER flag to the receiver
This listener flag indicates whether the receiver part of the listener
is specific to the master or to the workers. In practice it's only used
by the master's CLI right now. It's used to know whether or not the FD
must be closed before forking the workers. For this reason it's way more
of a receiver's property than a listener's property, so let's move it
there under the name RX_F_MWORKER. The rest of the code remains
unchanged.
Willy Tarreau [Fri, 9 Oct 2020 13:55:23 +0000 (15:55 +0200)]
CLEANUP: listeners: remove the do_close argument to unbind_listener()
And also remove it from its callers. This subtle distinction was added as
sort of a hack for the seamless reload feature but is not needed anymore
since the do_close turned unused since commit previous commit ("MEDIUM:
listener: let do_unbind_listener() decide whether to close or not").
This also removes the unbind_listener_no_close() function.
Willy Tarreau [Fri, 9 Oct 2020 13:47:17 +0000 (15:47 +0200)]
MEDIUM: listener: let do_unbind_listener() decide whether to close or not
The listener contains all the information needed to decide to close on
unbind or not. The rule is the following (when we're not stopping):
- worker process unbinding from a worker's FD with socket transfer enabled => keep
- master process unbinding from a master's inherited FD => keep
- master process unbinding from a master's FD => close
- master process unbinding from a worker's FD => close
- worker process unbinding from a master's FD => close
- worker process unbinding from a worker's FD => close
Let's translate that into the function and stop using the do_close
argument that is a bit obscure for callers. It was not yet removed
to ease code testing.
Willy Tarreau [Thu, 8 Oct 2020 13:36:46 +0000 (15:36 +0200)]
BROKEN/MEDIUM: listeners: rework the unbind logic to make it idempotent
BROKEN: the failure rate on reg-tests/seamless-reload/abns_socket.vtc has
significantly increased for no obvious reason. It fails 99% of the time vs
10% before.
do_unbind_listener() is not logical and is not even idempotent. It must
not touch the fd if already -1, which also means not touch the receiver.
In addition, when performing a partial stop on a socket (not closing),
we know the socket remains in the listening state yet it's marked as
LI_ASSIGNED, which is confusing as it doesn't translate its real state.
With this change, we make sure that FDs marked for close end up in
ASSIGNED state and that those which are really bound and on which a
listen() was made (i.e. not pause) remain in LISTEN state. This is what
is closest to reality.
Ideally this function should become a default proto->unbind() one but
it may still keep a bit too much state logic to become generalized to
other protocols (e.g. QUIC).
Willy Tarreau [Fri, 9 Oct 2020 08:35:40 +0000 (10:35 +0200)]
MEDIUM: listeners: always close master vs worker listeners
Right now in enable_listener(), we used to start all enabled
listeners then kill from the workers those that were for the master.
But this is incomplete. We must also close from the master the
listeners that are solely for workers, and do it before we even
start them. Otherwise we end up with a master responding to the
worker CLI connections if the listener remains in listen mode to
translate the socket's real state.
It doesn't seem like it could have caused bugs in the past because we
used to aggressively mark disabled listeners as LI_ASSIGNED despite
the fact that they were still bound and listening. If this patch were
ever seen as a candidate solution for any obscure bug, be careful in
that it subtly relies on the fact that fd_delete() doesn't close
inherited FDs anymore, otherwise that could break the master's ability
to pass inherited FDs on reloads.
Willy Tarreau [Wed, 7 Oct 2020 17:55:15 +0000 (19:55 +0200)]
MEDIUM: udp: implement udp_suspend() and udp_resume()
In Linux kernel's net/ipv4/udp.c there's a udp_disconnect() function
which is called when connecting to AF_UNSPEC, and which unhashes a
"connection". This property, which is also documented in connect(2)
both in Linux and Open Group's man pages for datagrams, is interesting
because it allows to reverse a connect() which is in fact a filter on
the source. As such we can suspend a receiver by making it connect to
itself, which will cause it not to receive any traffic anymore, letting
a new one receive it all, then resume it by breaking this connection.
This was tested to work well on Linux, other operating systems should
also be tested. Before this, sending a SIGTTOU to a process having a
UDP syslog forwarder would cause this error:
On Linux this also works with TCP listeners (which can then be resumed
using listen()) and established TCP sockets (which we currently kill
using setsockopt(so_linger)), both not being portable on other OSes.
UNIX sockets and ABNS sockets do not support it however (connect
always fails). This needs to be further explored to see if other OSes
might benefit from this to perform portable and reliable resets
particularly on the backend side.
Willy Tarreau [Wed, 7 Oct 2020 14:52:43 +0000 (16:52 +0200)]
MEDIUM: proxy: make soft_stop() stop most listeners using protocol_stop_now()
One difficulty in soft-stopping is to make sure not to forget unlisted
listeners. By first doing a pass using protocol_stop_now() we catch the
vast majority of them. The few remaining ones are the ones belonging to
a proxy having a grace period. For these ones, the proxy will arm its
stop_time timer and emit a log message.
Since neither UDP listeners nor peers use the grace period, we can already
get rid of the special cases there since we know they will have been stopped
by the protocols.
Willy Tarreau [Wed, 7 Oct 2020 14:50:49 +0000 (16:50 +0200)]
MINOR: protocol: add protocol_stop_now() to instant-stop listeners
This will instantly stop all listeners except those which belong to
a proxy configured with a grace time. This means that UDP listeners,
and peers will also be stopped when called this way.
Willy Tarreau [Wed, 7 Oct 2020 14:31:39 +0000 (16:31 +0200)]
MEDIUM: proxy: centralize proxy status update and reporting
There are multiple ways a proxy may switch to the disabled state,
but now it's essentially once it loses its last listener. Instead
of keeping duplicate code around and reporting the state change
before actually seeing it, we now report it at the moment it's
performed (from the last listener leaving) which allows to remove
the message from all other places.
Willy Tarreau [Wed, 7 Oct 2020 15:49:42 +0000 (17:49 +0200)]
MEDIUM: proxy: add mode PR_MODE_PEERS to flag peers frontends
For now we cannot easily distinguish a peers frontend from another one,
which will be problematic to avoid reporting them when stopping their
listeners. Let's add PR_MODE_PEERS for this. It's not supposed to cause
any issue since all non-HTTP proxies are handled similarly now.
Willy Tarreau [Wed, 7 Oct 2020 13:58:50 +0000 (15:58 +0200)]
MINOR: listeners: add a new stop_listener() function
This function will be used to definitely stop a listener (e.g. during a
soft_stop). This is actually tricky because it may be called for a proxy
or for a protocol, both of which require locks and already hold some. The
function takes booleans indicating which ones are already held, hoping
this will be enough. It's not well defined wether proto->disable() and
proto->rx_disable() are supposed to be called with any lock held, and
they are used from do_unbind_listener() with all these locks. Some back
annotations ought to be added on this point.
The proxy's listeners count is updated, and the proxy is marked as
disabled and woken up after the last one is gone. Note that a
listener in listen state is already not attached anymore since it
was disabled.
Willy Tarreau [Fri, 9 Oct 2020 16:25:14 +0000 (18:25 +0200)]
MINOR: listeners: count unstoppable jobs on creation, not deletion
We have to count unstoppable jobs which correspond to worker sockpairs, in
order to know when to count. However the way it's currently done is quite
awkward because these are counted when stopping making the stop mechanism
non-idempotent. This is definitely something we want to fix before stopping
by protocol or our listeners count will quickly go wrong. Now they are
counted when the listeners are created.
Willy Tarreau [Wed, 7 Oct 2020 13:36:16 +0000 (15:36 +0200)]
MINOR: listeners: split delete_listener() in two versions
We'll need an already locked variant of this function so let's make
__delete_listener() which will be called with the protocol lock held
and the listener's lock held.
MEDIUM: listeners: now use the listener's ->enable/disable
At each place we used to manipulate the FDs directly we can now call
the listener protocol's enable/disable/rx_enable/rx_disable depending
on whether the state changes on the listener or the receiver. One
exception currently remains in listener_accept() which is a bit special
and which should be split into 2 or 3 parts in the various protocol
layers.
The test of fd_updt in do_unbind_listener() that was added by commit a51885621 ("BUG/MEDIUM: listeners: Don't call fd_stop_recv() if fd_updt
is NULL.") could finally be removed since that part is correctly handled
in the low-level disable() function.
One disable() was added in resume_listener() before switching to LI_FULL
because rx_resume() enables polling on the FD for the receiver while
we want to disable it if the listener is full. There are different
ways to clean this up in the future. One of them could be to consider
that TCP receivers only act at the listener level. But in fact it does
not translate reality. The reality is that only the receiver is paused
and that the listener's state ought not be affected here. Ultimately
the resume_listener() function should be split so that the part
controlled by the protocols only acts on the receiver, and that the
receiver itself notifies the upper listener about the change so that
the listener protocol may decide to disable or enable polling. Conversely
the listener should automatically update its receiver when they share the
same state. Since there is no harm proceeding like this, let's keep this
for now.
MINOR: protocol: add a new pair of enable/disable methods for listeners
These methods will be used to enable/disable accepting new connections
so that listeners do not play with FD directly anymore. Since all the
currently supported protocols work on socket for now, these are identical
to the rx_enable/rx_disable functions. However they were not defined in
sock.c since it's likely that some will quickly start to differ. At the
moment they're not used.
We have to take care of fd_updt before calling fd_{want,stop}_recv()
because it's allocated fairly late in the boot process and some such
functions may be called very early (e.g. to stop a disabled frontend's
listeners).
MINOR: protocol: add a new pair of rx_enable/rx_disable methods
These methods will be used to enable/disable rx at the receiver level so
that callers don't play with FDs directly anymore. All our protocols use
the generic ones from sock.c at the moment. For now they're not used.
MINOR: sock: provide a set of generic enable/disable functions
These will be used on receivers, to enable or disable receiving on a
listener, which most of the time just consists in enabling/disabling
the file descriptor.
We have to take care of the existence of fd_updt to know if we may
or not call fd_{want,stop}_recv() since it's not permitted in very
early boot.
MINOR: listener: use the protocol's ->rx_resume() method when available
Instead of calling listen() for IPPROTO_TCP in resume_listener(), let's
call the protocol's ->rx_resume() method when defined, which does the same.
This removes another hard-dependency on the fd and underlying protocol
from the generic functions.
MINOR: protocol: implement an ->rx_resume() method
This one undoes ->rx_suspend(), it tries to restore an operational socket.
It was only implemented for TCP since it's the only one we support right
now.
MINOR: protocol: replace ->pause(listener) with ->rx_suspend(receiver)
The ->pause method is inappropriate since it doesn't exactly "pause" a
listener but rather temporarily disables it so that it's not visible at
all to let another process take its place. The term "suspend" is more
suitable, since the "pause" is actually what we'll need to apply to the
FULL and LIMITED states which really need to make a pause in the accept
process. And it goes well with the use of the "resume" function that
will also need to be made per-protocol.
Let's rename the function and make it act on the receiver since it's
already what it essentially does, hence the prefix "_rx" to make it
more explicit.
The protocol struct was a bit reordered because it was becoming a real
mess between the parts related to the listeners and those for the
receivers.
MINOR: protocol: rename the ->listeners field to ->receivers
Since the listeners were split into receiver+listener, this field ought
to have been renamed because it's confusing. It really links receivers
and not listeners, as most of the time it's used via rx.proto_list!
The nb_listeners field was updated accordingly.
MINOR: protocol: directly call enable_listener() from protocol_enable_all()
protocol_enable_all() calls proto->enable_all() for all protocols,
which is always equal to enable_all_listeners() which in turn simply is
a generic loop calling enable_listener() always returning ERR_NONE. Let's
clean this madness by first calling enable_listener() directly from
protocol_enable_all().
CLEANUP: listeners: remove unused disable_listener and disable_all_listeners
These ones have never been called, they were referenced by the protocol's
disable_all for some protocols but there are no traces of their use, so
in addition to not being sure the code works, it has never been tested.
Let's remove a bit of complexity starting from there.
MINOR: listeners: move fd_stop_recv() to the receiver's socket code
fd_stop_recv() has nothing to do in the generic listener code, it's per
protocol as some don't need it. For instance with abns@ it could even
lead to fd_stop_recv(-1). And later with QUIC we don't want to touch
the fd at all! It used to be that since commit f2cb169487 delegating
fd manipulation to their respective threads it wasn't possible to call
it down there but it's not the case anymore, so let's perform the action
in the protocol-specific code.
By using the same "ret" variable in the "if" block to test the return
value of pause(), the second one shadows the first one and when forcing
the result to zero in case of an error, it doesn't do anything. The
problem is that some listeners used to fail to pause in multi-process
mode and this was not reported, but their failure was automatically
resolved by the last process to pause. By properly checking for errors
we might now possibly report a race once in a while so we may have to
roll this back later if some users meet it.
The test on ==0 is wrong too since technically speaking a total stop
validates the need for a pause, but stops the listener so it's just
the resume that won't work anymore. We could switch to stopped but
it's an involuntary switch and the user will not know. Better then
mark it as paused and let the resume continue to fail so that only
the resume will eventually report an error (e.g. abns@).
This must not be backported as there is a risk of side effect by fixing
this bug, given that it hides other bugs itself.
Willy Tarreau [Thu, 8 Oct 2020 14:51:09 +0000 (16:51 +0200)]
MEDIUM: proto_tcp: make the pause() more robust in multi-process
In multi-process, the TCP pause is very brittle and we never noticed
it because the error was lost in the upper layers. The problem is that
shutdown() may fail if another process already did it, and will cause
a process to fail to pause.
What we do here in case of error is that we double-check the socket's
state to verify if it's still accepting connections, and if not, we
can conclude that another process already did the job in parallel.
The difficulty here is that we're trying to eliminate false positives
where some OSes will silently report a success on shutdown() while they
don't shut the socket down, hence this dance of shutw/listen/shutr that
only keeps the compatible ones. Probably that a new approach relying on
connect(AF_UNSPEC) would provide better results.
MAJOR: signals: use protocol_pause_all() and protocol_resume_all()
When temporarily pausing the listeners with SIG_TTOU, we now pause
all listeners via the protocols instead of the proxies. This has the
benefits that listeners are paused regardless of whether or not they
belong to a visible proxy. And for resuming via SIG_TTIN we do the
same, which allows to report binding conflicts and address them,
since the operation can be repeated on a per-listener basis instead
of a per-proxy basis.
While in appearance all cases were properly handled, it's impossible
to completely rule out the possibility that something broken used to
work by luck due to the scan ordering which is naturally different,
hence the major tag.
These two functions are used to pause and resume all listeners of
all protocols. They use the standard listener functions for this
so they're supposed to handle the situation gracefully regardless
of the upper proxies' states, and they will report completion on
proxies once the switch is performed.
It might be nice to define a particular "failed" state for listeners
that cannot resume and to count them on proxies in order to mention
that they're definitely stuck. On the other hand, the current
situation is retryable which is quite appreciable as well.
MEDIUM: listener/proxy: make the listeners notify about proxy pause/resume
Till now, we used to call pause_proxy()/resume_proxy() to enable/disable
processing on a proxy, which is used during soft reloads. But since we want
to drive this process from the listeners themselves, we have to instead
proceed the other way around so that when we enable/disable a listener,
it checks if it changed anything for the proxy and notifies about updates
at this level.
The detection is made using li_ready=0 for pause(), and li_paused=0
for resume(). Note that we must not include any test for li_bound because
this state is seen by processes which share the listener with another one
and which must not act on it since the other process will do it. As such
the socket behind the FD will automatically be paused and resume without
its local state changing, but this is the limit of a multi-process system
with shared listeners.
MINOR: listeners: check the current listener earlier state in resume_listener()
It's quite confusing to have the test on LI_READY very low in the function
as it should be made much earlier. Just like with previous commit, let's
do it when entering. The additional states, however (limited, full) continue
to go through the whole function.
MINOR: listeners: check the current listener state in pause_listener()
It's better not to try to perform pause() actions on wrong states, so
let's check this and make sure that all callers are now safe. This
means that we must not try to pause a listener which is already paused
(e.g. it could possibly fail if the pause operation isn't idempotent at
the socket level), nor should we try it on earlier states.
MEDIUM: proxy: merge zombify_proxy() with stop_proxy()
The two functions don't need to be distinguished anymore since they have
all the necessary info to act as needed on their listeners. Let's just
pass via stop_proxy() and make it check for each listener which one to
close or not.
Its sole remaining purpose was to display "proxy foo started", which
has little benefit and pollutes output for those with plenty of proxies.
Let's remove it now.
The VTCs were updated to reflect this, because many of them had explicit
counts of dropped lines to match this message.
This is tagged as MEDIUM because some users may be surprized by the
loss of this quite old message.
MEDIUM: proxy: replace proxy->state with proxy->disabled
The remaining proxy states were only used to distinguish an enabled
proxy from a disabled one. Due to the initialization order, both
PR_STNEW and PR_STREADY were equivalent after startup, and they
would only differ from PR_STSTOPPED when the proxy is disabled or
shutdown (which is effectively another way to disable it).
Now we just have a "disabled" field which allows to distinguish them.
It's becoming obvious that start_proxies() is only used to print a
greeting message now, that we'd rather get rid of. Probably that
zombify_proxy() and stop_proxy() should be merged once their
differences move to the right place.
CLEANUP: peers: don't use the PR_ST* states to mark enabled/disabled
The enabled/disabled config options were stored into a "state" field
that is an integer but contained only PR_STNEW or PR_STSTOPPED, which
is a bit confusing, and causes a dependency with proxies. This was
renamed to "disabled" and is used as a boolean. The field was also
moved to the end of the struct to stop creating a hole and fill another
one.
MINOR: startup: don't rely on PR_STNEW to check for listeners
Instead of looking at listeners in proxies in PR_STNEW state, we'd
rather check for listeners in those not in PR_STSTOPPED as it's only
this state which indicates the proxy was disabled. And let's check
the listeners count instead of testing the list's head.
This state was used to mention that a proxy was in PAUSED state, as opposed
to the READY state. This was causing some trouble because if a listener
failed to resume (e.g. because its port was temporarily in use during the
resume), it was not possible to retry the operation later. Now by checking
the number of READY or PAUSED listeners instead, we can accurately know if
something went bad and try to fix it again later. The case of the temporary
port conflict during resume now works well:
This state is only set when a pause() fails but isn't even set when a
resume() fails. And we cannot recover from this state. Instead, let's
just count remaining ready listeners to decide to emit an error or not.
It's more accurate and will better support new attempts if needed.
Since v1.4 or so, it's almost not possible anymore to set this state. The
only exception is by using the CLI to change a frontend's maxconn setting
below its current usage. This case makes no sense, and for other cases it
doesn't make sense either because "full" is a vague concept when only
certain listeners are full and not all. Let's just remove this unused
state and make it clear that it's not reported. The "ready" or "open"
states will continue to be reported without being misleading as they
will be opposed to "stop".
MINOR: proxy: maintain per-state counters of listeners
The proxy state tries to be synthetic but that doesn't work well with
many listeners, especially for transition phases or after a failed
pause/resume.
In order to address this, we'll instead rely on counters of listeners in
a given state for the 3 major states (ready, paused, listen) and a total
counter. We'll now be able to determine a proxy's state by comparing these
counters only.
This function is used as a wrapper to set a listener's state everywhere.
We'll use it later to maintain some counters in a consistent state when
switching state so it's capital that all state changes go through it.
No functional change was made beyond calling the wrapper.
CLEANUP: proxy: remove the first_to_listen hack in zombify_proxy()
This thing was needed for an optimization used in soft_stop() which
doesn't exist anymore, so let's remove it as it's cryptic and hinders
the listeners cleanup.
MINOR: listeners: do not uselessly try to close zombie listeners in soft_stop()
The loop doesn't match anymore since the non-started listeners are in
LI_INIT and even if it had ever worked the benefit of closing zombies
at this point looks void at best.
MEDIUM: listeners: remove the now unused ZOMBIE state
The zombie state is not used anymore by the listeners, because in the
last two cases where it was tested it couldn't match as it was covered
by the test on the process mask. Instead now the FD is either in the
LISTEN state or the INIT state. This also avoids forcing the listener
to be single-dimensional because actually belonging to another process
isn't totally exclusive with the other states, which explains some of
the difficulties requiring to check the proc_mask and the fd sometimes.
So let's get rid of it now not to be tempted to reuse it.
MEDIUM: deinit: close all receivers/listeners before scanning proxies
Because of the zombie state, proxies have a skewed vision of the state
of listeners, which explains why there are hacks switching the state
from ZOMBIE to INIT in the proxy cleaning loop. This is particularly
complicated and not needed, as all the information is now available
in the protocol list and the fdtab.
What we do here instead is to first close all active listeners or
receivers by protocol and clean their protocol parts. Then we scan the
fdtab to get rid of remaining ones that were necessarily in INIT state
after a previous invocation of delete_listener(). From this point, we
know the listeners are cleaned, the can safely be freed by scanning the
proxies.
MEDIUM: listeners: make unbind_listener() converge if needed
The ZOMBIE state on listener is a real mess. Listeners passing through
this state have lost their consistency with the proxy AND with the fdtab.
Plus this state is not used for all foreign listeners, only for those
belonging to a proxy that entirely runs on another process, otherwise it
stays in INIT state, which makes the usefulness extremely questionable.
But the real issue is that it's impossible to untangle the receivers
from the proxy state as long as we have this because of deinit()...
So what we do here is to start by making unbind_listener() support being
called more than once. This will permit to call it again to really close
the FD and finish the operations if it's called with an FD that's in a
fake state (such as INIT but with a valid fd).
Willy Tarreau [Wed, 7 Oct 2020 16:36:54 +0000 (18:36 +0200)]
MEDIUM: init: stop disabled proxies after initializing fdtab
During the startup process we don't have any fdtab nor fd_updt for quite
a long time, and as such some operations on the listeners are not
permitted, such as fd_want_*/fd_stop_* or fd_delete(). The latter is of
particular concern because it's used when stopping a disabled frontend,
and it's performed very early during check_config_validity() while there
is no fdtab yet. The trick till now relies on the listener's state which
is a bit brittle.
There is absolutely no valid reason for stopping a proxy's listeners this
early, we can postpone it after init_pollers() which will at least have
allocated fdtab.
MEDIUM: listeners: don't bounce listeners management between queues
During 2.1 development, commit f2cb16948 ("BUG/MAJOR: listener: fix
thread safety in resume_listener()") was introduced to bounce the
enabling/disabling of a listener's FD to one of its threads because
the remains of fd_update_cache() were fundamentally incompatible with
the need to call fd_want_recv() or fd_stop_recv() for another thread.
However since then we've totally dropped such code and it's totally
safe to use these functions on an FD that is solely used by another
thread (this is even used by the FD migration code). The only remaining
limitation concerning the wake up delay was addressed by previous commit
"MEDIUM: fd: always wake up one thread when enabling a foreing FD".
The current situation forces the FD management to remain in the
pause_listener() and resume_listener() functions just so that it can
bounce between threads, without having the ability to delegate it to
the suitable protocol layer.
So let's first remove this now unneeded workaround.
MEDIUM: fd: always wake up one thread when enabling a foreing FD
Since 2.2 it's safe to enable/disable another thread's FD but the fd_wake
calls will not immediately be considered because nothing wakes the other
threads up. This will have an impact on listeners when deciding to resume
them after they were paused, so at minima we want to wake up one of their
threads, just like the scheduler does on task_kill(). This is what this
patch does.
Willy Tarreau [Fri, 9 Oct 2020 09:14:35 +0000 (11:14 +0200)]
REGTESTS: mark abns_socket as broken
This test is inherently racy. It regularly pops up on the CI, and I've
spent one hour chasing a bug that apparently doesn't exist, just because
I'm running it 10 times in a row and it reports from 4 to 8 failures
when built at -O2 and generally even more at -O0. The logs are very
confusing, often reporting that it failed with status 0, with nothing
else wrong. I suspect it might sometimes be the shell command that fails
if it executes faster than haproxy finishes to start up, which would
also explain the relation with the optimization level. E.g:
> Testing with haproxy version: 2.2.0
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.006) exit=2
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.006) exit=2
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.009) exit=2
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.008) exit=2
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.007) exit=2
> # top TEST reg-tests/seamless-reload/abns_socket.vtc FAILED (3.007) exit=2
> 6 tests failed, 0 tests skipped, 4 tests passed
Some of the failures include this, suggesting that some barriers could
help:
---- h1 haproxy h1 PID file check failed:
Could not read PID file '/tmp/haregtests-2020-10-09_11-19-40.kgsDB4/vtc.30539.04dbea7f/h1/pid
Since it has been causing false positives and consumed way more
troubleshooting time than it saved, let's mark it as broken so that it
doesn't waste more time. We can bring it back when someone manages to
figure what the problem is.
BUG/MINOR: http-htx: Expect no body for 204/304 internal HTTP responses
204 and 304 HTTP responses must no contain message body. These status codes are
correctly handled when the responses are received from a server. But there is no
specific processing for internal HTTP reponses (errorfile and http replies).
Now, when errorfiles or an http replies are parsed during the configuration
parsing, an error is triggered if a 204/304 message contains a body. An extra
check is also performed to ensure the body length matches the announce
content-length.
This patch should fix the issue #891. It must be backported as far as 2.0. For
2.1 and 2.0, only the http_str_to_htx() function must be fixed.
http_parse_http_reply() function does not exist.
BUG/MINOR: http: Fix content-length of the default 500 error
96 bytes is announce in the C-L header for a message of body of 97 bytes. This
bug was introduced by the patch 46a030cdd ("CLEANUP: assorted typo fixes in the
code and comments").
This patch must be backported in all versions where the patch above is (the 2.2
for now).
BUG/MEDIUM: mux-h2: Don't handle pending read0 too early on streams
This patch is similar to the previous one on the fcgi. Same is true for the
H2. But the bug is far harder to trigger because of the protocol cinematic. But
it may explain strange aborts in some edge cases.
A read0 received on the connection must not be handled too early by H2 streams.
If the demux buffer is not empty, the pending read0 must not be considered. The
H2 streams must not be passed in half-closed remote state in
h2s_wake_one_stream() and the CS_FL_EOS flag must not be set on the associated
conn-stream in h2_rcv_buf(). To sum up, it means, if there are still data
pending in the demux buffer, no abort must be reported to the streams.
To fix the issue, a dedicated function has been added, responsible for detecting
pending read0 for a H2 connection. A read0 is reported only if the demux buffer
is empty. This function is used instead of conn_xprt_read0_pending() at some
places.
Note that the HREM stream state should not be used to report aborts. It is
performed on h2s_wake_one_stream() function and it is a legacy of the very first
versions of the mux-h2.
This patch should be backported as far as 2.0. In the 1.8, the code is too
different to apply it like that. But it is probably useless because the mux-h2
can only be installed on the client side.
BUG/MEDIUM: mux-fcgi: Don't handle pending read0 too early on streams
A read0 received on the connection must not be handled too early by FCGI
streams. If the demux buffer is not empty, the pending read0 must not be
considered. The FCGI streams must not be passed in half-closed remote state in
fcgi_strm_wake_one_stream() and the CS_FL_EOS flag must not be set on the
associated conn-stream in fcgi_rcv_buf(). To sum up, it means, if there are
still data pending in the demux buffer, no abort must be reported to the
streams.
To fix the issue, a dedicated function has been added, responsible for detecting
pending read0 for a FCGI connection. A read0 is reported only if the demux
buffer is empty. This function is used instead of conn_xprt_read0_pending() at
some places.
This patch should fix the issue #886. It must be backported as far as 2.1.
Willy Tarreau [Fri, 9 Oct 2020 03:56:56 +0000 (05:56 +0200)]
BUG/MINOR: makefile: fix a tiny typo in the target list
Previous commit 382001b46 ("BUILD: Add a DragonFlyBSD target") introduced
a tiny typo in the target list ("iopenbs" vs "openbsd"). This will have to
be backported if that patch is backported.