mirror of
https://github.com/haproxy/haproxy.git
synced 2026-05-26 03:03:51 -04:00
Compare commits
No commits in common. "master" and "v3.4-dev11" have entirely different histories.
master
...
v3.4-dev11
170 changed files with 952 additions and 2622 deletions
2
BRANCHES
2
BRANCHES
|
|
@ -137,7 +137,7 @@ release. These branches were emitted at a pace of one per year since 1.5 in
|
|||
2014. As of 2019, 1.5 is still supported and widely used, even though it very
|
||||
rarely receives updates. After a few years these LTS branches enter a
|
||||
"critical fixes only" status, which means that they will rarely receive a fix
|
||||
but if that a critical issue affects them, a release will be made, with or
|
||||
but if that a critital issue affects them, a release will be made, with or
|
||||
without any other fix. Once a version is not supported anymore, it will not
|
||||
receive any fix at all and it will really be time for you to upgrade to a more
|
||||
recent branch. Please note that even when an upgrade is needed, a great care is
|
||||
|
|
|
|||
144
CHANGELOG
144
CHANGELOG
|
|
@ -1,150 +1,6 @@
|
|||
ChangeLog :
|
||||
===========
|
||||
|
||||
2026/05/20 : 3.4-dev13
|
||||
- BUG/MINOR: backend: correct parameter value validation in get_server_ph_post()
|
||||
- BUG/MINOR: config/dns: properly fail on duplicate nameserver name detection
|
||||
- BUG/MEDIUM: dns: fix long loops in additional records parse on name failure
|
||||
- BUG/MEDIUM: resolvers: fix name compression pointer validation in resolv_read_name()
|
||||
- BUG/MEDIUM: dns: fix memory leak of sockaddr in dns_session_init() error path
|
||||
- CLEANUP: proxy: fix tiny mistakes in parse error messages
|
||||
- CLEANUP: dns: fix misleading error messages in dns_stream_init()
|
||||
- BUG/MINOR: server: better handling of OOM in srv_set_fqdn()
|
||||
- BUG/MINOR: servers: use proper source of pool_conn_name in srv_settings_cpy()
|
||||
- BUG/MEDIUM: server/cli: unlock server lock on failure in cli_parse_set_server
|
||||
- BUG/MINOR: resolvers: fix dangling list pointer in resolvers_new() error paths
|
||||
- BUG/MINOR: dns: fix dangling dgram pointer on dns_dgram_init() failure path
|
||||
- BUG/MINOR: proxy: use proxy_drop() in parse_new_proxy() error path
|
||||
- CLEANUP: resolvers: properly initialize the sample in resolv_action_do_resolve()
|
||||
- BUG/MINOR: resolvers: report the expression error in the do-resolve() action parser
|
||||
- BUG/MINOR: resolvers: fix leaked dgram and dns_ring struct in parse_resolve_conf()
|
||||
- BUG/MINOR: resolvers: fix leaked fields on cfg_parse_resolvers() error paths
|
||||
- BUG/MINOR: resolvers: fix missing task_idle destruction in resolvers_destroy()
|
||||
- CLEANUP: proxy: fix duplicate declaration of cli_find_frontend in proxy.h
|
||||
- CLEANUP: address a few typos and copy-paste errors in httpclient and dns
|
||||
- DOC: internal: add a few rules about internal core principles
|
||||
- BUG/MINOR: session/trace: use distinct flags for SESS_EV_END and _ERR
|
||||
- CLEANUP: stick-table: uniformize the different action_inc_gpc*()
|
||||
- REGTESTS: do not run quic/tls13_ssl_crt-list_filters in quic openssl compat mode
|
||||
- REGTESTS: quic/issuers_chain_path: do not forget to enable QUIC compat mode
|
||||
- BUG/MINOR: sock: store the connection error status
|
||||
- BUG/MINOR: check: properly report errno in chk_report_conn_err()
|
||||
- CLEANUP: tcpcheck: mention that we're a bit far for a sync errno
|
||||
- BUG/MINOR: jwt: fix possible memory leak in convert_ecdsa_sig() error path
|
||||
- CLEANUP: jwe: fix theoretical overflow in AAD length calculation
|
||||
- DOC: config: further clarify that resolvers "default" exists
|
||||
- MINOR: proxy: remove the experimental status on dynamic backends
|
||||
- BUG/MEDIUM: limits: properly account for global.maxpipes in compute_ideal_maxconn()
|
||||
- BUG/MINOR: jws: fix OpenSSL 3.0 version check from > to >=
|
||||
- BUG/MINOR: jws: Add missing return value check (EVP_PKEY_get_bn_param)
|
||||
- BUG/MINOR: server: Properly handle init-state value during haproxy startup
|
||||
- BUG/MINOR: httpclient-cli: Destroy http-client context if failing to start it
|
||||
- BUG/MEDIUM: h1: Skip all h2c values from Upgrade headers during parsing
|
||||
- BUG/MINOR: h1: Don't mask websocket protocol if multiple protocols used
|
||||
- MINOR: haterm: Don't init haterm master pipe if not used
|
||||
- CLEANUP: haterm: Remove "(too old kernel)" from warning message during init
|
||||
- BUG/MINOR: httpclient-cli: fix uninit variable in error label
|
||||
- MINOR: mux: Rename the "token" from mux_proto_list to mux_proto
|
||||
- MEDIUM: connections: Use both mux_proto and alpn to pick a mux
|
||||
- MINOR: connection: define conn_select_mux_fe()
|
||||
- MINOR: connection: define conn_select_mux_be()
|
||||
- MINOR: connection/mux_quic: add MUX <init_xprt> field for QMux handshake
|
||||
- MINOR: proxy/server: reject TCP ALPN h3 without experimental
|
||||
- MEDIUM: ssl: allow h3/QMux negotiation without explicit proto
|
||||
- BUG/MINOR: server: accept server IDs above 2^31 and clarify error message
|
||||
- BUG/MINOR: backend: fix balance hash calculation when using hash-type none
|
||||
- MINOR: server: support hash-key id32 for a cleaner distribution
|
||||
- MINOR: backend: support hash-key guid for a stabler distribution
|
||||
- MINOR: startup: support unprivileged chroot if possible
|
||||
- MEDIUM: startup: add automatic chroot feature
|
||||
- MINOR: h2: explain committed_extra_streams dec on h2_init() error
|
||||
- OPTIM: h2: do not update committed streams if elasticity disabled
|
||||
- MINOR: mux_quic: implement basic committed_extra_streams accounting
|
||||
- MINOR: quic: use stream elasticity value for initial advertisement
|
||||
- MINOR: mux_quic: define ms_bidi_rel QCC member
|
||||
- MAJOR: mux_quic: support stream elasticity during connection lifetime
|
||||
- BUG/MEDIUM: servers: Store the connection hash with the parameter cache
|
||||
- BUG/MINOR: prevent conn leak in case of xprt_qmux init failure
|
||||
- BUILD: traces: set a few __maybe_unused on vars used only for traces
|
||||
- BUILD: traces: add USE_TRACE allowing to disable traces
|
||||
- MINOR: startup: do not execute chroot() when "/"
|
||||
- MEDIUM: startup: warn when chroot is not set for root
|
||||
- BUG/MEDIUM: servers: Don't forget to set srv_hash when needed
|
||||
- DOC: fix typo on QUIC stream.max-concurrent reference
|
||||
- BUG/MINOR: mux_quic: do not exceed stream.max-concurrent on backend side
|
||||
- BUG/MINOR: htx: Fix value of HTX_XFER_HDRS_ONLY flag
|
||||
- MEDIUM: htx: Improve htx_xfer API to not count HTX meta-data
|
||||
- BUG/MEDIUM: applet: Fix transfer of HTX data to the applet
|
||||
- BUG/MEDIUM: htx: Alloc a chunk of right size in htx_replace_blk_value()
|
||||
- MEDIUM: stick-tables: Avoid freeing elements while holding a lock
|
||||
- MINOR: intops: add a multiply overflow detection for ulong and size_t
|
||||
- CLEANUP: tree-wide: use array_size_or_fail() in array size for allocations
|
||||
- DOC: update supported gcc and openssl versions in INSTALL
|
||||
|
||||
2026/05/13 : 3.4-dev12
|
||||
- SCRIPTS: announce-release: add a link to the OpenTelemetry filter
|
||||
- BUG/MEDIUM: servers: Only requeue servers if they are up
|
||||
- MINOR: tinfo: store the number of committed extra streams in the tgroup
|
||||
- MINOR: connection: add a function to calculate elastic streams limit
|
||||
- MINOR: mux-h2: consider the elastic streams limit on frontend
|
||||
- MINOR: lb: make LB initialization even more declarative
|
||||
- BUG/MINOR: cfgparse-listen: do not emit extraneous line in rule order warnings
|
||||
- CLEANUP: tree-wide: fix typos in non user-visible comments in 15 files
|
||||
- CLEANUP: h1/htx: fix a few typos in warning, debug and trace messages
|
||||
- BUG/MINOR: mux-h1: only check h1s if not NULL
|
||||
- BUG/MINOR: http-fetch: fix smp_fetch_hdr_ip()'s handling of brackets for IPv6
|
||||
- BUG/MINOR: http-fetch: make http_first_req() check for HTTP first
|
||||
- BUG/MINOR: http-act: set-status() must check the response message, not the request
|
||||
- BUG/MINOR: tools: fix memory leak in env_expand() error path
|
||||
- BUG/MINOR: auth: free user groups on error paths in userlist_postinit()
|
||||
- BUG/MINOR: uri-auth: avoid leaks on initialization error
|
||||
- BUG/MINOR: cache: fix memory leak in parse_cache_rule error path
|
||||
- BUG/MINOR: cfgcond: make KQUEUE check for GTUNE_USE_KQUEUE not GTUNE_USE_EPOLL
|
||||
- BUG/MINOR: mqtt: connack parser returns MQTT_NEED_MORE_DATA on unknown property
|
||||
- BUG/MINOR: mqtt: connect parser uses wrong bit field for TOPIC_ALIAS_MAXIMUM
|
||||
- BUG/MINOR: mqtt: connack parser uses wrong bit for SUBSCRIPTION_IDENTIFIERS_AVAILABLE
|
||||
- BUG/MINOR: mqtt: fix PUBLISH flags validation that want all bits to be set
|
||||
- CLEANUP: http_htx: rename inner 'type' to 'ptype' to avoid variable shadowing
|
||||
- CLEANUP: mux-h2: fix minor output debugging format issues
|
||||
- CLEANUP: http-rules: fix a few '&' vs '&&' checks for clarity
|
||||
- CLEANUP: auth: remove undeclared auth_resolve_groups() from auth.h
|
||||
- CLEANUP: cache: remove redundant res_htx assignment in http_cache_io_handler()
|
||||
- CLEANUP: channel: remove bogus and unused definition of channel_empty()
|
||||
- CLEANUP: flt_http_comp: remove duplicate rate limit and CPU usage checks
|
||||
- CLEANUP: mqtt: remove duplicate MQTT_FN_BIT_USER_PROPERTY in CONNECT fields
|
||||
- BUG/MINOR: uri-auth: fix possible null-deref in latest fix for leaks
|
||||
- BUG/MEDIUM: tasks: Keep the TASK_RUNNING flag until queued
|
||||
- CLEANUP: mqtt: fix spelling of shared_subscription_available
|
||||
- CLEANUP: regex: pre-initialize error variable in regex_comp() to calm analysis
|
||||
- BUILD: compiler: fix redefinition of __nonstring
|
||||
- CLEANUP: defaults: adjust MAX_THREADS multiplier number in comment
|
||||
- CLEANUP: src/cpuset.c: fix missing return in functions returning int
|
||||
- REGTESTS: Use ${tmpdir} instead of hardcoded /tmp/
|
||||
- REGTESTS: Don't try to use real nameservers for testcases
|
||||
- CLEANUP: tree-wide: fix typos in non user-visible comments in 3 more files
|
||||
- MINOR: cli: improve forward compatibility for show fd
|
||||
- DOC: management: document the <tgid>/<fd> form of show fd
|
||||
- CLEANUP: tree-wide: fix more typos and outdated explanations in comments
|
||||
- BUG/MEDIUM: dict: hold read lock while incrementing refcount in dict_insert
|
||||
- BUG/MEDIUM: http-client: Only consume input buffer when hc one is empty
|
||||
- BUG/MINOR: xprt_qstrm: fix conflicting prototype
|
||||
- REORG: mux_quic: use newer qcm prefix for legacy qmux files
|
||||
- MINOR: mux_quic: use qcm prefix for mux callbacks
|
||||
- MINOR: mux_quic: use qcm prefix for mux functions
|
||||
- MINOR: mux_quic: use qcm prefix for traces functions/structs
|
||||
- MINOR: mux_quic: rename qstrm files to qmux
|
||||
- MINOR: mux_quic: remove qstrm naming in QUIC MUX
|
||||
- MINOR: connection: rename QMux related flags
|
||||
- MINOR: xprt_qmux: use qmux instead of qstrm naming
|
||||
- MINOR: trace: implement source alias
|
||||
- MEDIUM: mux_quic: rename qmux traces to qcm
|
||||
- MINOR: sample: add a generic reverse converter
|
||||
- MINOR: sample: add a reverse_dom converter
|
||||
- DOC: proxy-protocol: clarify UDP usage
|
||||
- BUILD: 51d.c: cleanup, fix preprocessor ifdefs
|
||||
- CLEANUP: tree-wide: fix typos in user-invisible files
|
||||
- CLEANUP: htx: Adjust numbering of HTX blocks' types in the description
|
||||
|
||||
2026/05/08 : 3.4-dev11
|
||||
- BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
|
||||
- BUG/MINOR: acme: skip auth/challenge steps when newOrder returns a certificate
|
||||
|
|
|
|||
6
INSTALL
6
INSTALL
|
|
@ -111,12 +111,12 @@ HAProxy requires a working GCC or Clang toolchain and GNU make :
|
|||
may want to retry with "gmake" which is the name commonly used for GNU make
|
||||
on BSD systems.
|
||||
|
||||
- GCC >= 4.7 (up to 16 tested). Older versions are no longer supported due to
|
||||
- GCC >= 4.7 (up to 15 tested). Older versions are no longer supported due to
|
||||
the latest mt_list update which only uses c11-like atomics. Newer versions
|
||||
may sometimes break due to compiler regressions or behaviour changes. The
|
||||
version shipped with your operating system is very likely to work with no
|
||||
trouble. Clang >= 3.0 is also known to work as an alternative solution, and
|
||||
versions up to 21 were successfully tested. Recent versions may emit a bit
|
||||
versions up to 19 were successfully tested. Recent versions may emit a bit
|
||||
more warnings that are worth reporting as they may reveal real bugs. TCC
|
||||
(https://repo.or.cz/tinycc.git) is also usable for developers but will not
|
||||
support threading and was found at least once to produce bad code in some
|
||||
|
|
@ -237,7 +237,7 @@ to forcefully enable it using "USE_LIBCRYPT=1".
|
|||
-----------------
|
||||
For SSL/TLS, it is necessary to use a cryptography library. HAProxy currently
|
||||
supports the OpenSSL library, and is known to build and work with branches
|
||||
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 4.0. It is recommended to use
|
||||
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 3.6. It is recommended to use
|
||||
at least OpenSSL 1.1.1 to have support for all SSL keywords and configuration
|
||||
in HAProxy. OpenSSL follows a long-term support cycle similar to HAProxy's,
|
||||
and each of the branches above receives its own fixes, without forcing you to
|
||||
|
|
|
|||
10
Makefile
10
Makefile
|
|
@ -44,7 +44,6 @@
|
|||
# USE_CLOSEFROM : enable use of closefrom() on *bsd, solaris. Automatic.
|
||||
# USE_PRCTL : enable use of prctl(). Automatic.
|
||||
# USE_PROCCTL : enable use of procctl(). Automatic.
|
||||
# USE_TRACE : enable trace subsystem. Always on.
|
||||
# USE_ZLIB : enable zlib library support and disable SLZ
|
||||
# USE_SLZ : enable slz library instead of zlib (default=enabled)
|
||||
# USE_CPU_AFFINITY : enable pinning processes to CPU on Linux. Automatic.
|
||||
|
|
@ -344,7 +343,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER USE_POLL \
|
|||
USE_TPROXY USE_LINUX_TPROXY USE_LINUX_CAP \
|
||||
USE_LINUX_SPLICE USE_LIBCRYPT USE_CRYPT_H USE_ENGINE \
|
||||
USE_GETADDRINFO USE_OPENSSL USE_OPENSSL_WOLFSSL USE_OPENSSL_AWSLC \
|
||||
USE_ECH USE_TRACE \
|
||||
USE_ECH \
|
||||
USE_SSL USE_LUA USE_ACCEPT4 USE_CLOSEFROM USE_ZLIB USE_SLZ \
|
||||
USE_CPU_AFFINITY USE_TFO USE_NS USE_DL USE_RT USE_LIBATOMIC \
|
||||
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
|
||||
|
|
@ -367,9 +366,6 @@ $(warn_unknown_options)
|
|||
# on the make command line.
|
||||
USE_POLL = default
|
||||
|
||||
# traces are always enabled
|
||||
USE_TRACE = default
|
||||
|
||||
# SLZ is always supported unless explicitly disabled by passing USE_SLZ=""
|
||||
# or disabled by enabling ZLIB using USE_ZLIB=1
|
||||
ifeq ($(USE_ZLIB:0=),)
|
||||
|
|
@ -671,11 +667,11 @@ OPTIONS_OBJS += src/mux_quic.o src/h3.o src/quic_rx.o src/quic_tx.o \
|
|||
src/quic_cc_bbr.o src/quic_retry.o \
|
||||
src/cfgparse-quic.o src/xprt_quic.o src/quic_token.o \
|
||||
src/quic_ack.o src/qpack-dec.o src/quic_cc_newreno.o \
|
||||
src/qcm_http.o src/qcm_trace.o src/quic_rules.o \
|
||||
src/qmux_http.o src/qmux_trace.o src/quic_rules.o \
|
||||
src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.o \
|
||||
src/h3_stats.o src/quic_stats.o src/qpack-enc.o \
|
||||
src/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o \
|
||||
src/quic_enc.o src/qcm_qmux.o src/xprt_qmux.o \
|
||||
src/quic_enc.o src/mux_quic_qstrm.o src/xprt_qstrm.o \
|
||||
src/mpring.o
|
||||
endif
|
||||
|
||||
|
|
|
|||
2
VERDATE
2
VERDATE
|
|
@ -1,2 +1,2 @@
|
|||
$Format:%ci$
|
||||
2026/05/20
|
||||
2026/05/08
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
3.4-dev13
|
||||
3.4-dev11
|
||||
|
|
|
|||
|
|
@ -550,8 +550,6 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
|
|||
char valuesBuffer[1024];
|
||||
#endif
|
||||
|
||||
#if defined(FIFTYONEDEGREES_H_PATTERN_INCLUDED) || defined(FIFTYONEDEGREES_H_TRIE_INCLUDED) || defined(FIFTYONE_DEGREES_HASH_INCLUDED)
|
||||
|
||||
char no_data[] = "NoData"; /* response when no data could be found */
|
||||
struct buffer *temp = get_trash_chunk();
|
||||
int i = 0, found;
|
||||
|
|
@ -638,7 +636,6 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
|
|||
smp->data.u.str.area = temp->area;
|
||||
smp->data.u.str.data = temp->data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sets the sample data as a constant string. This ensures that the
|
||||
* string will be processed correctly.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Configuration Manual
|
||||
----------------------
|
||||
version 3.4
|
||||
2026/05/20
|
||||
2026/05/08
|
||||
|
||||
|
||||
This document covers the configuration language as implemented in the version
|
||||
|
|
@ -2001,7 +2001,6 @@ The following keywords are supported in the "global" section :
|
|||
- tune.sndbuf.client
|
||||
- tune.sndbuf.frontend
|
||||
- tune.sndbuf.server
|
||||
- tune.streams-elasticity
|
||||
- tune.stick-counters
|
||||
- tune.ssl.cachesize
|
||||
- tune.ssl.capture-buffer-size
|
||||
|
|
@ -2126,28 +2125,13 @@ ca-base <dir>
|
|||
directives. Absolute locations specified in "ca-file", "ca-verify-file" and
|
||||
"crl-file" prevail and ignore "ca-base".
|
||||
|
||||
chroot { <jail dir> | auto }
|
||||
chroot <jail dir>
|
||||
Changes current directory to <jail dir> and performs a chroot() there before
|
||||
dropping privileges. This increases the security level in case an unknown
|
||||
vulnerability would be exploited, since it would make it very hard for the
|
||||
attacker to exploit the system. It is important to ensure that <jail dir>
|
||||
is both empty and non-writable to anyone. When the process is started with
|
||||
superuser privileges, the chroot() is performed directly. On Linux, when
|
||||
started unprivileged, haproxy attempts to perform it from inside a new
|
||||
user namespace created with unshare(CLONE_NEWUSER); if that mechanism is
|
||||
unavailable the chroot() will fail with the usual error.
|
||||
|
||||
As a special case, <jail dir> may be set to "auto", in which case haproxy
|
||||
creates an anonymous temporary directory, unlinks it, and chroots into it.
|
||||
The resulting jail has no name in the filesystem and is empty and read-only,
|
||||
removing the need to prepare a dedicated jail directory.
|
||||
|
||||
When starting with superuser privileges, a warning will be displayed if no
|
||||
chroot is used, in order to encourage users to always use the mechanism. If
|
||||
for any reason there is a compelling reason not to use chroot (e.g. access to
|
||||
a server via a UNIX socket with an unconvenient path), it remains possible to
|
||||
silence the warning by adding an explicit "chroot /", which has the benefit
|
||||
of being visible in a configuration.
|
||||
attacker to exploit the system. This only works when the process is started
|
||||
with superuser privileges. It is important to ensure that <jail_dir> is both
|
||||
empty and non-writable to anyone.
|
||||
|
||||
close-spread-time <time>
|
||||
Define a time window during which idle connections and active connections
|
||||
|
|
@ -3329,7 +3313,7 @@ setenv <name> <value>
|
|||
the configuration file sees the new value. See also "presetenv", "resetenv",
|
||||
and "unsetenv".
|
||||
|
||||
shm-stats-file <name>
|
||||
shm-stats-file <name> [ EXPERIMENTAL ]
|
||||
When this directive is set, it enables the use of shared memory for storing
|
||||
stats counters. <name> is used as argument to shm_open() to open the shared
|
||||
memory at a unique location. It also means that the directive is only
|
||||
|
|
@ -3345,7 +3329,7 @@ shm-stats-file <name>
|
|||
|
||||
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
|
||||
|
||||
shm-stats-file-max-objects <number>
|
||||
shm-stats-file-max-objects <number> [ EXPERIMENTAL ]
|
||||
This setting defines the maximum number of objects the shared memory used
|
||||
for shared counters will be able to store per thread group. It is directly
|
||||
related to the maximum memory size of the shm and is used to "premap" the
|
||||
|
|
@ -5321,26 +5305,17 @@ tune.quic.frontend.stream-data-ratio <0..100, in percent> (deprecated)
|
|||
|
||||
tune.quic.be.stream.max-concurrent <number>
|
||||
tune.quic.fe.stream.max-concurrent <number>
|
||||
On frontend side, this is used as the value for the advertised
|
||||
initial_max_streams_bidi transport parameter. This is enforced as the maximum
|
||||
number of bidirectional streams that the remote peer will be authorized to
|
||||
open concurrently during the connection lifetime. This effectively limits the
|
||||
number of concurrent HTTP/3 client requests.
|
||||
Sets the QUIC initial_max_streams_bidi transport parameter either on frontend
|
||||
or backend side. This is the maximum number of bidirectional streams that the
|
||||
remote peer will be authorized to open concurrently during the connection
|
||||
lifetime. On frontend side, this limits the number of concurrent HTTP/3
|
||||
client requests.
|
||||
|
||||
The default value is 100. Note that if you reduces it, it can restrict the
|
||||
buffering capabilities of streams on receive, which would result in poor
|
||||
upload throughput. It can be corrected by increasing the QUIC stream rxbuf
|
||||
connection setting.
|
||||
|
||||
On backend side, this is enforced locally by haproxy to limit the number of
|
||||
concurrent requests multiplexed over a single connection. This may be further
|
||||
restricted by the peer flow control. It may be necessary to reduce the
|
||||
default value of 100 to improve a site's responsiveness at the expense of a
|
||||
higher number of opened backend connections. Similarly to the frontend side,
|
||||
this setting also directly impacts the Rx buffering capability, this time
|
||||
though limiting the HTTP download capacity. QUIC stream rxbuf setting can be
|
||||
increased when dealing mostly with HTTP responses larger than "tune.bufsize".
|
||||
|
||||
See also: "tune.quic.be.stream.rxbuf", "tune.quic.fe.stream.rxbuf",
|
||||
"tune.quic.be.stream.data-ratio", "tune.quic.fe.stream.data-ratio"
|
||||
|
||||
|
|
@ -5714,49 +5689,6 @@ tune.ssl.ssl-ctx-cache-size <number>
|
|||
dynamically is expensive, they are cached. The default cache size is set to
|
||||
1000 entries.
|
||||
|
||||
tune.streams-elasticity <number>
|
||||
Defines a target percentage of streams per frontend connection relative to
|
||||
the maximum number of concurrent connections (maxconn) when all connections
|
||||
are established. This metric applies to multiplexed protocols like HTTP/2 or
|
||||
QUIC, where each connection may receive multiple streams. At least one is
|
||||
always guaranteed, so the percentage must be at least 100%. During connection
|
||||
setup, HAProxy dynamically advertises additional streams up to the configured
|
||||
limit, maintaining the target ratio. At connection establishment, every
|
||||
frontend connection receives at least one stream; extra streams are assigned
|
||||
based on the target percentage and configured stream limits. This ensures
|
||||
efficient stream allocation under varying load conditions (more streams at
|
||||
low loads, fewer at high loads).
|
||||
|
||||
Highly dynamic sites with many objects per page benefit from high ratios,
|
||||
enabling many streams per connection. Sites using fewer streams on average
|
||||
(WebSocket, application code) may prefer small ratios closer to 120 or 150
|
||||
(20 to 50% more streams than connections) preventing excessive stream counts
|
||||
under sustained loads.
|
||||
|
||||
The default value is 0, meaning no enforcement at this level, so only H2 and
|
||||
QUIC configurations apply (with the default setting of 100 streams per
|
||||
connection, this corresponds to 10000%). This remains the recommended setting
|
||||
for small deployments (maxconn around a thousand). Moderately sized setups
|
||||
(few thousands to tens of thousands connections) typically set the ratio
|
||||
between 1000 and 5000, allowing 10 to 50 streams per connection at full load.
|
||||
Large-scale deployments (hundreds of thousands to millions connections) might
|
||||
use lower values (120 to 200) to support 1.2 to 2 streams per connection on
|
||||
average at full load.
|
||||
|
||||
Contrary to HTTP/2, QUIC is capable to dynamically adjust the number of
|
||||
concurrent streams during the connection lifetime. However, QUIC flow control
|
||||
is stricter than HTTP/2, thus it is preferable when using it to specify
|
||||
values big enough to prevent extra latency on the connection. There is also a
|
||||
limitation for QUIC listeners with enabled 0-RTT. In this case, the initial
|
||||
value advertised to the peer will ignore stream elasticity and instead rely
|
||||
solely on the "tune.quic.fe.stream.max-concurrent" setting. However, the
|
||||
stream elasticity principle will still be effective past this initial
|
||||
annoucement during the connection lifetime.
|
||||
|
||||
Monitoring the total number of active streams on backends, including queues,
|
||||
provides a practical indicator of a sustainable target load and helps avoid
|
||||
over-provisioning.
|
||||
|
||||
tune.stick-counters <number>
|
||||
Sets the number of stick-counters that may be tracked at the same time by a
|
||||
connection or a request via "track-sc*" actions in "tcp-request" or
|
||||
|
|
@ -8294,10 +8226,7 @@ hash-type <method> <function> <modifier>
|
|||
|
||||
none don't hash the key, the key will be used as a hash, this can be
|
||||
useful to manually hash the key using a converter for that purpose
|
||||
and let haproxy use the result directly. The operation will
|
||||
convert the key to a string if it is not already, and parse it as
|
||||
an integer whose value will be used as the key. Some input key
|
||||
types might not be relevant here (e.g. IP addresses).
|
||||
and let haproxy use the result directly.
|
||||
|
||||
<modifier> indicates an optional method applied after hashing the key :
|
||||
|
||||
|
|
@ -18884,21 +18813,6 @@ hash-key <key>
|
|||
better only use values comprised between 1 and this value to
|
||||
avoid overlap.
|
||||
|
||||
id32 The node keys will be derived from the server's numeric
|
||||
identifier as set from "id" or which defaults to its position
|
||||
in the server list, but the full 32 bits of the ID will be
|
||||
used so that there is no collision. This one is not scaled
|
||||
like "id" is, so it is recommended to either always use it
|
||||
with a hash function (see "hash-key") or with explicitly
|
||||
assigned ID values that are evenly distributed over the 32-bit
|
||||
space.
|
||||
|
||||
guid The node keys will be derived from the server's guid, when
|
||||
available, otherwise they will fall back on "id". The benefit
|
||||
is that it does not depend on ordering at all, only on an
|
||||
internal stable identifier that can be replicated across many
|
||||
load balancers.
|
||||
|
||||
addr The node keys will be derived from the server's address, when
|
||||
available, or else fall back on "id".
|
||||
|
||||
|
|
@ -18928,13 +18842,9 @@ healthcheck <name>
|
|||
id <value>
|
||||
May be used in the following contexts: tcp, http, log
|
||||
|
||||
Set a persistent ID for the server. This ID must be a 32-bit positive number
|
||||
and unique for the proxy. An unused ID will automatically be assigned if
|
||||
unset. The first assigned value will be 1. This ID is currently only returned
|
||||
in statistics, and is used to place LB nodes when using consistent hash
|
||||
algorithms when "hash-key" is set to "id" (the default). In this case, only
|
||||
the 28 lowest bits of the value are used (i.e. (id % 268435356)), so better
|
||||
only use values comprised between 1 and this value to avoid overlap.
|
||||
Set a persistent ID for the server. This ID must be positive and unique for
|
||||
the proxy. An unused ID will automatically be assigned if unset. The first
|
||||
assigned value will be 1. This ID is currently only returned in statistics.
|
||||
|
||||
idle-ping <delay>
|
||||
May be used in the following contexts: tcp, http, log
|
||||
|
|
@ -19028,7 +18938,7 @@ downinter <delay>
|
|||
"inter" setting will have a very limited effect as it will not be able to
|
||||
reduce the time spent in the queue.
|
||||
|
||||
init-state { fully-up | up | down | fully-down | none }
|
||||
init-state { fully-up | up | down | fully-down }
|
||||
May be used in the following contexts: tcp, http
|
||||
|
||||
May be used in sections : defaults | frontend | listen | backend
|
||||
|
|
@ -19036,25 +18946,20 @@ init-state { fully-up | up | down | fully-down | none }
|
|||
|
||||
The "init-state" option sets the initial state of the server:
|
||||
- when set to 'fully-up', the server is considered immediately available
|
||||
and, if health checks are enabled for this server, it will be turned to
|
||||
the DOWN state when ALL health checks fail.
|
||||
- when set to 'up', the server is considered immediately available and, if
|
||||
health checks are enabled for this server, it will be turned to the DOWN
|
||||
state immediately if the next health check fails.
|
||||
- when set to 'down', the server initially is considered unavailable and,
|
||||
if health checks are enabled for this server, it can be turned to the UP
|
||||
state if the next health check succeeds.
|
||||
and can turn to the DOWN state when ALL health checks fail.
|
||||
- when set to 'up' (the default), the server is considered immediately
|
||||
available and will initiate a health check that can turn it to the DOWN
|
||||
state immediately if it fails.
|
||||
- when set to 'down', the server initially is considered unavailable and
|
||||
will initiate a health check that can turn it to the UP state immediately
|
||||
if it succeeds.
|
||||
- when set to 'fully-down', the server is initially considered unavailable
|
||||
and, if health checks are enabled for this server, it will turned to the
|
||||
UP state when ALL health checks succeed.
|
||||
- when set to 'none' (the default value), init-state management is
|
||||
disabled. It can be used to restore the default behavior when this
|
||||
parameter was inherited from a 'default-server' directive.
|
||||
and can turn to the UP state when ALL health checks succeed.
|
||||
|
||||
The server's init-state is considered when the HAProxy instance is
|
||||
(re)started, a new server is detected (for example via service discovery /
|
||||
DNS resolution), a dynamic server is inlived, a server exits maintenance,
|
||||
etc. This directive cannot be used when the server is tracking another one.
|
||||
etc.
|
||||
|
||||
Examples:
|
||||
# pass client traffic ONLY to Redis "master" node
|
||||
|
|
@ -20250,11 +20155,7 @@ a cache of previous answers, an answer will be considered obsolete after
|
|||
|
||||
|
||||
resolvers <resolvers id>
|
||||
Creates a new name server list labeled <resolvers id>. As mentioned above,
|
||||
the special name "default" always exists and will be automatically created if
|
||||
not explicitly declared; this will be the one internal services such as
|
||||
httpclient rely on. Declaring a "default" entry will affect how such services
|
||||
perform their name resolution.
|
||||
Creates a new name server list labeled <resolvers id>
|
||||
|
||||
A resolvers section accept the following parameters:
|
||||
|
||||
|
|
@ -21210,8 +21111,6 @@ param(name[,delim]) string string
|
|||
port_only string integer
|
||||
protobuf(field_number[,field_type]) binary binary
|
||||
regsub(regex,subst[,flags]) string string
|
||||
reverse string string
|
||||
reverse_dom string string
|
||||
rfc7239_field(field) string string
|
||||
rfc7239_is_valid string boolean
|
||||
rfc7239_n2nn string address / str
|
||||
|
|
@ -22709,58 +22608,6 @@ regsub(<regex>,<subst>[,<flags>])
|
|||
http-request redirect location %[url,'regsub("(foo|bar)([0-9]+)?","\2\1",i)']
|
||||
http-request redirect location %[url,regsub(\"(foo|bar)([0-9]+)?\",\"\2\1\",i)]
|
||||
|
||||
reverse
|
||||
Reverses the input string byte by byte.
|
||||
|
||||
This converter is encoding-agnostic and reverses bytes, not characters; it is
|
||||
not suitable for reversing human text encoded as UTF-8.
|
||||
|
||||
This can turn suffix lookups on the original string into prefix lookups on
|
||||
the reversed string, allowing the use of indexed prefix matchers such as
|
||||
"map_beg" on large maps.
|
||||
|
||||
Examples:
|
||||
"example.com" -> "moc.elpmaxe"
|
||||
"ab cd" -> "dc ba"
|
||||
|
||||
# Given a map file where each key contains a reversed hostname:
|
||||
# moc.elpmaxe.ppa app1
|
||||
# moc.elpmaxe.bd dbcluster
|
||||
# Pick a backend based on the domain suffix of the Host header:
|
||||
use_backend %[req.hdr(host),lower,reverse,map_beg(/etc/haproxy/hosts.map,default)]
|
||||
|
||||
reverse_dom
|
||||
Converts a string containing an FQDN-like hostname into its reversed-label
|
||||
form. A single trailing dot on the input is ignored. Empty labels cause the
|
||||
converter to fail.
|
||||
|
||||
This converter does not lowercase its input and does not strip any port.
|
||||
It is meant to be combined with existing converters such as "lower" or
|
||||
"host_only" when needed.
|
||||
|
||||
The trailing-dot policy is intentionally left to the caller. This allows
|
||||
callers to decide whether they want to match the apex too or only
|
||||
subdomains.
|
||||
|
||||
The reversed-label form is useful for large domain maps because it turns
|
||||
domain suffix lookups into prefix lookups, allowing the use of indexed prefix
|
||||
matchers such as "map_beg".
|
||||
|
||||
Examples:
|
||||
"example.com" -> "com.example"
|
||||
"mail.example.com" -> "com.example.mail"
|
||||
"example.com." -> "com.example"
|
||||
|
||||
# match only subdomains of example.net, not the apex
|
||||
acl example_net_sub req.hdr(Host),host_only,reverse_dom -m beg net.example.
|
||||
|
||||
# match only the apex
|
||||
acl example_net_apex req.hdr(Host),host_only,reverse_dom -i net.example
|
||||
|
||||
# exact-or-subdomain prefix lookup using an explicit dotted form
|
||||
http-request set-var(txn.rev_host) req.hdr(Host),host_only,reverse_dom,concat(.)
|
||||
use_backend %[var(txn.rev_host),map_beg(/etc/haproxy/domains.map)]
|
||||
|
||||
rfc7239_field(<field>)
|
||||
Extracts a single field/parameter from RFC 7239 compliant header value input.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,229 +0,0 @@
|
|||
HAPROXY CORE PRINCIPLES
|
||||
|
||||
0. RULE ZERO: EXCEPTIONS AND JUSTIFICATION
|
||||
- These rules are mandatory; violations are bugs unless explicitly justified.
|
||||
- A violation is acceptable if accompanied by a comment explaining WHY the
|
||||
standard approach was insufficient (e.g., "Performance-critical bypass").
|
||||
- Reviews should flag unjustified violations but accept commented ones.
|
||||
|
||||
1. PROJECT ORGANIZATION
|
||||
- header files all under "include/", and split between haproxy/<file>-t.h for
|
||||
type definitions (types, enums, structures), and haproxy/<file>.h for static
|
||||
definitions and exported symbols. A few imported libs under include/import.
|
||||
- C source files in src/.
|
||||
- some API doc in doc/internals/api/ (not always up to date, check date or
|
||||
version at the top).
|
||||
|
||||
2. ENVIRONMENT AND DATA TYPES
|
||||
- The project targets 32/64-bit POSIX systems (little or big endian).
|
||||
- Char is signed or unsigned 8-bit, short signed 16-bit, int signed 32-bit.
|
||||
- Long and pointers always match the native word size. Long long is 64-bit.
|
||||
- Aliases: uchar (unsigned char), uint (unsigned int), ulong (unsigned long),
|
||||
ushort (unsigned short), ullong (unsigned long long), llong (long long),
|
||||
schar (signed char).
|
||||
- size_t always same size as long but often declared as uint on 32-bit and
|
||||
ulong on 64-bit. Do not use in printf() without a cast (ulong with "%lu").
|
||||
- Main platforms are x86_64 and aarch64 with high thread counts (>=64).
|
||||
- Unaligned accesses are permitted for archs that support them; portable
|
||||
wrappers in net_helper.h (read_u32(), write_u32() etc).
|
||||
- signed integer wrapping well-defined via -fwrapv.
|
||||
- arch-specific asm() statements OK as long as equivalent C-code exists for
|
||||
generic archs.
|
||||
- Pointer arithmetics used a lot via container_of(), offset_of(), and void*
|
||||
casts.
|
||||
- Floating point not used.
|
||||
|
||||
3. MEMORY MANAGEMENT AND POOLS
|
||||
- Pools are used for runtime allocation; malloc/free are for boot code only.
|
||||
- pool_alloc() semantics match malloc(); the return must always be tested.
|
||||
- pool_alloc() and malloc() are not interchangeable / compatible.
|
||||
- pool_free() semantics match free(); it is a no-op on NULL.
|
||||
- pool_free() makes the pointer invalid immediately; it must not be touched
|
||||
or passed to pool_free() again.
|
||||
- Memory allocated from one pool must be released to the same pool.
|
||||
- ha_free() calls free() and sets the pointer to NULL before returning.
|
||||
- my_realloc2() frees the original pointer if the allocation fails.
|
||||
- never leave dangling pointers in structs after free().
|
||||
|
||||
4. BUFFER INVARIANTS (struct buffer)
|
||||
- Buffers are 4-word inline structs used for data in transit (wrapping,
|
||||
sliding window).
|
||||
- Members: area (storage), size (capacity), head (offset), data (count).
|
||||
- The area pointer is allowed to be NULL when size is zero.
|
||||
- always true: 0<=data<=size; always true when size>0: 0<=head<size.
|
||||
- contents start at <head>, for <data> bytes, and may wrap at the end of the
|
||||
storage area (area+size).
|
||||
- API (b_*, in buf.h and dynbuf.h) supports empty or unallocated buffers.
|
||||
- idempotent functions b_alloc() and b_free() use pools to manage the
|
||||
storage area and check <size> to know if alloc/free still needed.
|
||||
- a non-contiguous version exists (ncbuf, ncbmbuf), allowing holes anywhere
|
||||
in data. The former mandates holes of at least 8 bytes. The second relies
|
||||
on a bitmap of populated places.
|
||||
- another string API exists, "ist", representing a pointer and a length in a
|
||||
struct that is returned by inline functions and macros. It is described in
|
||||
doc/internals/api/ist.txt
|
||||
- buffers can switch to and from HTX, which is an internal representation of
|
||||
HTTP elements, with an API supporting header addition/modification/removal,
|
||||
start-line manipulation, data appending/consumption etc. HTX functions are
|
||||
all prefixed with "htx_". Between htx_from_buf() and htx_to_buf(), only the
|
||||
HTX API may be used, not the b_* API.
|
||||
|
||||
5. DATA MANIPULATION (CHUNKS, TRASH, LISTS, TREES)
|
||||
- Chunks use the buffer API but are NOT allowed to wrap.
|
||||
- Chunks are used for linear operations like chunk_printf().
|
||||
- Trash is a thread-local temporary buffer; scope stays within the caller.
|
||||
- trash always the same size as a buffer (global.tune.bufsize).
|
||||
- get_trash_chunk() provides up to 3 rotating thread-local trash chunks (with
|
||||
a scope spanning from the call to the next function call).
|
||||
- For longer lived trash chunks, alloc_trash_chunk() is available but must be
|
||||
released using free_trash_chunk() on leaving.
|
||||
- standard doubly-linked lists (struct list) are provided via macros LIST_*.
|
||||
- LIST_INIT() must be used on new heads and elements. LIST_DELETE() only
|
||||
removes the element and does not reinitialize it, so the idempotent
|
||||
LIST_DEL_INIT() is generally preferred. Iterators like list_for_each_* are
|
||||
available, some safe against item removal. See doc/internals/api/list.txt
|
||||
for details (grep -i "^list_" to list available macros).
|
||||
- thread-safe doubly-linked lists (struct mt_list) are provided via macros
|
||||
mt_list_*. They work like lists and use compatible storage, though they may
|
||||
not be mixed. See doc/internals/api/mt_list.txt (grep -i "^mt_list_" to
|
||||
list available operations).
|
||||
- elastic binary trees (ebtree) are used for fast access (O(logN) operations,
|
||||
O(1) deletion). Idempotent deletion. Main functions are lookup, insert,
|
||||
delete, first, next, with type-based prefix eb{32,64,st,mb,pt}_*().
|
||||
- compact elastic binary trees (cebtree) are used for read-mostly focusing on
|
||||
space savings (O(logN) operations, but higher cost than ebtree). Same ops
|
||||
as ebtree, with type-based prefix ceb{32,u32,64,u64,s,is}_*.
|
||||
|
||||
6. THREAD SYNCHRONIZATION
|
||||
- Threads are started at boot (one per CPU) and persist for the process life,
|
||||
arranged in thread groups (tg) by cache locality.
|
||||
- Each thread has its own polling loop and scheduler. Total parallelism.
|
||||
- thread_isolate()/thread_release() for total thread isolation (very heavy).
|
||||
- "tid" always current thread number, "th_ctx" always current thread's context,
|
||||
"ti" current thread info.
|
||||
- "tgid" always current tg number, "tg_ctx" current tg context.
|
||||
- HA_ATOMIC_* for atomic operations on integers and pointers (includes load
|
||||
and store). DWCAS available on some platforms but requires an equivalent
|
||||
for other ones.
|
||||
- The _HA_ATOMIC_* version (leading underscore) do not use barriers so these
|
||||
must be explicit (__ha_barrier_*).
|
||||
- Atomic loops must use CPU relaxation or exponential back-off.
|
||||
- For multiple changes at once, threads may use spinlocks (HA_SPIN_LOCK()/
|
||||
HA_SPIN_UNLOCK/HA_SPIN_TRYLOCK), and upgradable RW locks (HA_RWLOCK_*) if
|
||||
read accesses dominate.
|
||||
- No sleeping locks (mutex etc), only spinning/rwlocks/atomic loops.
|
||||
|
||||
7. SCHEDULING AND LATENCY
|
||||
- Latency is critical.
|
||||
- No runtime filesystem access, no blocking calls, no long loops.
|
||||
- Complex processing must be split into small steps; the task must yield.
|
||||
- CPUs are not dedicated to haproxy, high risk of a thread being interrupted
|
||||
by another process if it works too long, catastrophic if it happens with a
|
||||
lock held.
|
||||
- A watchdog kills the process if a task hogs a CPU for > few milliseconds.
|
||||
- Tasks vs Tasklets: Tasks have tree storage (rq) and timers (wq); tasklets
|
||||
use list elements instead of rq and are smaller (no wq). Only task.c/h may
|
||||
distinguish rq vs list access.
|
||||
- Tasks are aliased to tasklet while they are running (hence why some
|
||||
functions cast task to tasklets and conversely to access certain fields).
|
||||
- inter-thread task/tasklet wakeups always safe using the task_* API.
|
||||
- task/tasklet->state field must always be accessed atomically.
|
||||
|
||||
8. ARCHITECTURAL LAYERS (MUX AND STREAMS)
|
||||
- Naming: Lower layer (multiplexed), attached to the connection uses suffix
|
||||
'c' (h1c, h2c, qcc, muxc); Upper layer (demultiplexed/application, often a
|
||||
stream) uses suffix 's' (h1s, h2s, qcs, muxs).
|
||||
- Application layer stream (struct stream) has two stream connectors (stconn):
|
||||
front (scf) and back (scb). Responsible for processing requests/responses,
|
||||
deciding which server to route it, finding a backend connection or creating
|
||||
one, and exchanging data between the two sides.
|
||||
- Stream connectors link to a muxs or applet via a stream endpoint descriptor
|
||||
(sedesc/sd), and exchange data via buffers, which for an HTTP muxs are HTX
|
||||
buffers containing HTX blocks.
|
||||
- The sd carries the shared context between layers.
|
||||
- When a stream detaches from a mux, a new sd is allocated for the stream and
|
||||
the mux keeps its previous sd: stconn and muxs both always have a valid sd.
|
||||
- Front connections/streams are tied to the creator thread forever.
|
||||
- Idle back connections can be stolen via mux->takeover(), but become
|
||||
thread-bound once a stream attaches. => all streams of a mux are on the
|
||||
same thread.
|
||||
- session vs connection vs stream: connection is transport; session lasts for
|
||||
the client connection's life; stream are request/response pairs.
|
||||
- applets carry a context specific to the service being executed or the CLI
|
||||
command in appctx->svcctx, and this one is always zeroed before the handler
|
||||
is first called.
|
||||
|
||||
9. FUNCTION RETURN CONVENTIONS
|
||||
- Boolean style: Functions named as actions/sentences return 0 (failure) or
|
||||
non-zero (success).
|
||||
- Integer style: some syscall-like functions return <0 (error) or >=0 (success).
|
||||
- Tri-state style, e.g. counts: <0 (error), 0 (no progress), >0 (success).
|
||||
|
||||
10. DIAGNOSTICS AND SAFETY
|
||||
- When DEBUG_STRICT is set, ABORT_NOW() crashes the program immediately, and
|
||||
BUG_ON(cond[,msg]) crashes the program if the condition is true.
|
||||
- COUNT_IF() / CHECK_IF() only track if a condition occurs (non-fatal).
|
||||
- Glitches are counters for uncommon events used to detect hostile behavior.
|
||||
- strcpy(), strcat() and sprintf() are totally forbidden (the program will
|
||||
not build).
|
||||
|
||||
11. BASIC CODING STYLE
|
||||
- Linux Kernel-like, but uses tabs for indent, spaces for alignment. Function
|
||||
definitions have their opening brace on a new line, never on the same line.
|
||||
- All local variables must be declared at the beginning of the function
|
||||
block, before any executable statements (gnu89-like).
|
||||
- Avoid variable shadowing in code blocks.
|
||||
- Beware of local static and global variables.
|
||||
- Use const arguments whenever possible.
|
||||
- Avoid static storage when persistence is not needed.
|
||||
- Macros in uppercase unless they're used to wrap functions which then get a
|
||||
leading underscore.
|
||||
- Explicitly compare functions returning non-zero with 0 (e.g. strcmp) unless
|
||||
they explicitly return a boolean (e.g. isalnum) or a pointer (e.g. strchr).
|
||||
- Unsigned int comparisons to zero never use >0 but !=0 to avoid signedness
|
||||
mistakes.
|
||||
- turn non-zero integer to boolean using "!" or "!!".
|
||||
|
||||
12. BUILD AND TEST
|
||||
- Preferred build command:
|
||||
$ make -j$(nproc) TARGET=linux-glibc OPT_CFLAGS='-std=gnu89 -Os' \
|
||||
USE_OPENSSL=1 USE_QUIC_OPENSSL_COMPAT=1 USE_QUIC=1 USE_LUA=1
|
||||
- Individual files can be tested by passing src/file.o as a make argument.
|
||||
- Compiler warnings are not permitted for new code.
|
||||
|
||||
13. COMMIT MESSAGES AND DOCUMENTATION
|
||||
- Commit messages must follow the project's strict format below. Do not try
|
||||
to learn better from previous commits, which might be wrong during reviews.
|
||||
- Structure: <TAG>: <location>: <subject> (max ~70 chars), then blank line,
|
||||
then description.
|
||||
- Tags:
|
||||
- CLEANUP: spelling fixes, refactoring, no new code nor functional change.
|
||||
- MINOR: new feature or low-impact change, may be backported if needed.
|
||||
- MEDIUM: new feature or change with moderate severity/impact/risk.
|
||||
- MAJOR: new feature or change with important severity/impact/risk.
|
||||
- OPTIM: Performance improvements, may always be reverted if it breaks.
|
||||
- DOC: Documentation updates or fixes.
|
||||
- BUG/<severity>: Fixes a bug. Specify if regression or long-standing.
|
||||
Valid severities are MINOR (low impact), MEDIUM (perf/stability risk
|
||||
in uncommon configs, MAJOR (most configs), CRITICAL (stability risk
|
||||
without workaround).
|
||||
- Regressions: Find original commit via `git blame`; designate using
|
||||
`git log -1 --format='%h ("%s")'` and version via `git describe --tags`.
|
||||
- Location: subsystem (stream, tasks, mux-h2, qpack etc).
|
||||
- Description: Explain technical "WHY", "HOW", and technical impact. Explain
|
||||
how to trigger the bug for developer testing.
|
||||
- Backports: only for fixes, mention versions ("Must be backported to 3.0").
|
||||
- Style: No generic messages like "fix(xxx): blah". Be technically precise.
|
||||
- Do not mix spelling fixes in comments (not important) with other changes.
|
||||
However it's preferred to have a single commit for many typo fixes at once.
|
||||
- Spelling mistakes in user-visible parts (doc, logs, traces, error messages)
|
||||
must be in their own commit (may need backport).
|
||||
- One commit per bug.
|
||||
- Example:
|
||||
BUG/MEDIUM: sample: fix null pointer dereference in h1_parse_line
|
||||
|
||||
When parsing malformed headers, the line buffer was not initialized.
|
||||
This caused a crash on certain edge cases. Let's fix this by always
|
||||
initializing the line buffer when first calling the parser. This was
|
||||
brought by commit 04c9e8f5 ("MINOR: add h1_parse_line") in latest -dev
|
||||
so no backport is needed.
|
||||
|
|
@ -3095,40 +3095,37 @@ show events [<sink>] [-w] [-n] [-0]
|
|||
delimited by a line feed character ('\n' or 10 or 0x0A). It is possible to
|
||||
change this to the NUL character ('\0' or 0) by passing the "-0" argument.
|
||||
|
||||
show fd [-!plcfbsd]* [[<tgid>]/[<fd>] | <fd>]
|
||||
show fd [-!plcfbsd]* [<fd>]
|
||||
Dump the list of either all open file descriptors or just the one number <fd>
|
||||
if specified. The form "<tgid>/<fd>" is also accepted, where either side may
|
||||
be empty as a wildcard ("/<fd>" for fd <fd> across thread groups, "<tgid>/"
|
||||
for all fds of <tgid>). The <tgid> is currently parsed but ignored, pending
|
||||
future support for per-thread-group fd tables. A set of flags may optionally
|
||||
be passed to restrict the dump only to certain FD types or to omit certain FD
|
||||
types. When '-' or '!' are encountered, the selection is inverted for the
|
||||
following characters in the same argument. The inversion is reset before each
|
||||
argument word delimited by white spaces. Selectable FD types include 'p' for
|
||||
pipes, 'l' for listeners, 'c' for connections (any type), 'f' for frontend
|
||||
connections, 'b' for backend connections (any type), 's' for connections to
|
||||
servers, 'd' for connections to the "dispatch" address or the backend's
|
||||
transparent address. With this, 'b' is a shortcut for 'sd' and 'c' for 'fb' or
|
||||
'fsd'. 'c!f' is equivalent to 'b' ("any connections except frontend
|
||||
connections" are indeed backend connections). This is only aimed at developers
|
||||
who need to observe internal states in order to debug complex issues such as
|
||||
abnormal CPU usages. One fd is reported per lines, and for each of them, its
|
||||
state in the poller using upper case letters for enabled flags and lower case
|
||||
for disabled flags, using "P" for "polled", "R" for "ready", "A" for "active",
|
||||
the events status using "H" for "hangup", "E" for "error", "O" for "output",
|
||||
"P" for "priority" and "I" for "input", a few other flags like "N" for "new"
|
||||
(just added into the fd cache), "U" for "updated" (received an update in the
|
||||
fd cache), "L" for "linger_risk", "C" for "cloned", then the cached entry
|
||||
position, the pointer to the internal owner, the pointer to the I/O callback
|
||||
and its name when known. When the owner is a connection, the connection flags,
|
||||
and the target are reported (frontend, proxy or server). When the owner is a
|
||||
listener, the listener's state and its frontend are reported. There is no
|
||||
point in using this command without a good knowledge of the internals. It's
|
||||
worth noting that the output format may evolve over time so this output must
|
||||
not be parsed by tools designed to be durable. Some internal structure states
|
||||
may look suspicious to the function listing them, in this case the output line
|
||||
will be suffixed with an exclamation mark ('!'). This may help find a starting
|
||||
point when trying to diagnose an incident.
|
||||
if specified. A set of flags may optionally be passed to restrict the dump
|
||||
only to certain FD types or to omit certain FD types. When '-' or '!' are
|
||||
encountered, the selection is inverted for the following characters in the
|
||||
same argument. The inversion is reset before each argument word delimited by
|
||||
white spaces. Selectable FD types include 'p' for pipes, 'l' for listeners,
|
||||
'c' for connections (any type), 'f' for frontend connections, 'b' for backend
|
||||
connections (any type), 's' for connections to servers, 'd' for connections
|
||||
to the "dispatch" address or the backend's transparent address. With this,
|
||||
'b' is a shortcut for 'sd' and 'c' for 'fb' or 'fsd'. 'c!f' is equivalent to
|
||||
'b' ("any connections except frontend connections" are indeed backend
|
||||
connections). This is only aimed at developers who need to observe internal
|
||||
states in order to debug complex issues such as abnormal CPU usages. One fd
|
||||
is reported per lines, and for each of them, its state in the poller using
|
||||
upper case letters for enabled flags and lower case for disabled flags, using
|
||||
"P" for "polled", "R" for "ready", "A" for "active", the events status using
|
||||
"H" for "hangup", "E" for "error", "O" for "output", "P" for "priority" and
|
||||
"I" for "input", a few other flags like "N" for "new" (just added into the fd
|
||||
cache), "U" for "updated" (received an update in the fd cache), "L" for
|
||||
"linger_risk", "C" for "cloned", then the cached entry position, the pointer
|
||||
to the internal owner, the pointer to the I/O callback and its name when
|
||||
known. When the owner is a connection, the connection flags, and the target
|
||||
are reported (frontend, proxy or server). When the owner is a listener, the
|
||||
listener's state and its frontend are reported. There is no point in using
|
||||
this command without a good knowledge of the internals. It's worth noting
|
||||
that the output format may evolve over time so this output must not be parsed
|
||||
by tools designed to be durable. Some internal structure states may look
|
||||
suspicious to the function listing them, in this case the output line will be
|
||||
suffixed with an exclamation mark ('!'). This may help find a starting point
|
||||
when trying to diagnose an incident.
|
||||
|
||||
show info [typed|json] [desc] [float]
|
||||
Dump info about haproxy status on current process. If "typed" is passed as an
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
2026/04/27 Willy Tarreau
|
||||
2020/03/05 Willy Tarreau
|
||||
HAProxy Technologies
|
||||
The PROXY protocol
|
||||
Versions 1 & 2
|
||||
|
|
@ -31,7 +31,6 @@ Revision history
|
|||
2025/09/09 - added SSL-related TLVs for key exchange group and signature
|
||||
scheme (Steven Collison)
|
||||
2026/01/15 - added SSL client certificate TLV (Simon Ser)
|
||||
2026/04/27 - clarified UDP usage (Valaphee)
|
||||
|
||||
1. Background
|
||||
|
||||
|
|
@ -176,11 +175,6 @@ The receiver may apply a short timeout and decide to abort the connection if
|
|||
the protocol header is not seen within a few seconds (at least 3 seconds to
|
||||
cover a TCP retransmit).
|
||||
|
||||
For UDP, the PROXY protocol header and the proxied UDP payload MUST be sent in
|
||||
the same datagram. The sender MUST NOT split the PROXY protocol header across
|
||||
multiple UDP datagrams, and the receiver MUST parse the header independently
|
||||
for each received datagram.
|
||||
|
||||
The receiver MUST be configured to only receive the protocol described in this
|
||||
specification and MUST not try to guess whether the protocol header is present
|
||||
or not. This means that the protocol explicitly prevents port sharing between
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ traces
|
|||
trace applet verbosity complete start now
|
||||
trace h3 start now
|
||||
trace quic start now
|
||||
trace qcm start now
|
||||
trace qmux start now
|
||||
trace peers start now
|
||||
.endif
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
extern struct userlist *userlist;
|
||||
|
||||
struct userlist *auth_find_userlist(char *name);
|
||||
unsigned int auth_resolve_groups(struct userlist *l, char *groups);
|
||||
int userlist_postinit();
|
||||
void userlist_free(struct userlist *ul);
|
||||
struct pattern *pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ struct lbprm_per_tgrp {
|
|||
* The other ones might take it themselves if needed.
|
||||
*/
|
||||
struct lb_ops {
|
||||
struct list link;
|
||||
int (*proxy_init)(struct proxy *); /* set up per-proxy LB state at config time; <0=fail */
|
||||
void (*update_server_eweight)(struct server *); /* to be called after eweight change // srvlock */
|
||||
void (*set_server_status_up)(struct server *); /* to be called after status changes to UP // srvlock */
|
||||
|
|
@ -167,11 +166,6 @@ struct lb_ops {
|
|||
void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */
|
||||
void (*server_deinit)(struct server *); /* to be called when we're destroying the server */
|
||||
int (*server_init)(struct server *); /* initialize a freshly added server (runtime); <0=fail. */
|
||||
uint32_t algo_prop; /* load balancing algorithm lookup and properties */
|
||||
struct {
|
||||
uint32_t mask;
|
||||
uint32_t match;
|
||||
} map[VAR_ARRAY];
|
||||
};
|
||||
|
||||
/* LB parameters for all algorithms */
|
||||
|
|
|
|||
|
|
@ -30,10 +30,6 @@
|
|||
#include <haproxy/stream-t.h>
|
||||
#include <haproxy/time.h>
|
||||
|
||||
extern struct list lb_ops_list;
|
||||
|
||||
void lb_ops_register(struct lb_ops *ops);
|
||||
|
||||
struct server *get_server_sh(struct proxy *px, const char *addr, int len, const struct server *avoid);
|
||||
struct server *get_server_uh(struct proxy *px, char *uri, int uri_len, const struct server *avoid);
|
||||
struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len, const struct server *avoid);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
#define CF_WAKE_ONCE 0x10000000 /* pretend there is activity on this channel (one-shoot) */
|
||||
#define CF_FLT_ANALYZE 0x20000000 /* at least one filter is still analyzing this channel */
|
||||
/* unused 0x40000000 */
|
||||
/* unuse 0x40000000 */
|
||||
#define CF_ISRESP 0x80000000 /* 0 = request channel, 1 = response channel */
|
||||
|
||||
/* Masks which define input events for stream analysers */
|
||||
|
|
@ -252,30 +252,27 @@ struct channel {
|
|||
* without waking the parent up. The special value CHN_INFINITE_FORWARD is
|
||||
* never decreased nor increased.
|
||||
*
|
||||
* The channel's consumed data count (b_data(chn->buf)) says how many bytes may
|
||||
* be consumed from the visible buffer. This is updated by any buffer_write()
|
||||
* as well as any data forwarded through the visible buffer. Since the
|
||||
* ->to_forward attribute applies to data beyond what's already been accounted
|
||||
* for, an analyser will not see a buffer which has a non-null ->to_forward
|
||||
* with additional unprocessed data. A producer is responsible for raising the
|
||||
* consumed count by min(to_forward, available_data) when it injects data into
|
||||
* the buffer.
|
||||
* The buf->o parameter says how many bytes may be consumed from the visible
|
||||
* buffer. This parameter is updated by any buffer_write() as well as any data
|
||||
* forwarded through the visible buffer. Since the ->to_forward attribute
|
||||
* applies to data after buf->p, an analyser will not see a buffer which has a
|
||||
* non-null ->to_forward with buf->i > 0. A producer is responsible for raising
|
||||
* buf->o by min(to_forward, buf->i) when it injects data into the buffer.
|
||||
*
|
||||
* The consumer is responsible for advancing the consumed count (via
|
||||
* b_ack()) when it sends data from the visible buffer, and for updating
|
||||
* ->pipe->data when it sends data from the invisible buffer.
|
||||
* The consumer is responsible for decreasing ->buf->o when it sends data
|
||||
* from the visible buffer, and ->pipe->data when it sends data from the
|
||||
* invisible buffer.
|
||||
*
|
||||
* A real-world example consists in part in an HTTP response waiting in a
|
||||
* buffer to be forwarded. We know the header length (300) and the amount of
|
||||
* data to forward (content-length=9000). The buffer already contains 1000
|
||||
* bytes of data after the 300 bytes of headers. Thus the caller will set
|
||||
* the consumed count to 300 indicating that it explicitly wants to send those
|
||||
* data, and set ->to_forward to 9000 (content-length). This value must be
|
||||
* normalised immediately after updating ->to_forward : since there are already
|
||||
* 1300 bytes in the buffer, 300 of which are already counted in the consumed
|
||||
* count, and that size is smaller than ->to_forward, we must update the
|
||||
* consumed count to 1300 to flush the whole buffer, and reduce ->to_forward to
|
||||
* 8000. After that, the producer may
|
||||
* buf->o to 300 indicating that it explicitly wants to send those data, and
|
||||
* set ->to_forward to 9000 (content-length). This value must be normalised
|
||||
* immediately after updating ->to_forward : since there are already 1300 bytes
|
||||
* in the buffer, 300 of which are already counted in buf->o, and that size
|
||||
* is smaller than ->to_forward, we must update buf->o to 1300 to flush the
|
||||
* whole buffer, and reduce ->to_forward to 8000. After that, the producer may
|
||||
* try to feed the additional data through the invisible buffer using a
|
||||
* platform-specific method such as splice().
|
||||
*
|
||||
|
|
@ -294,16 +291,15 @@ struct channel {
|
|||
* buf->size - global.maxrewrite + ->to_forward.
|
||||
*
|
||||
* A buffer may contain up to 5 areas :
|
||||
* - the data already consumed (acknowledged). These data are located between
|
||||
* b_lim(b) and b_head(b) ;
|
||||
* - the data available to process and possibly transform. These data start at
|
||||
* b_head(b) and may be up to b_data(b) bytes long.
|
||||
* - the data to preserve. They start at b_head(b) and stop at
|
||||
* b_lim(b) + b_data(b). The limit between the two solely depends on the
|
||||
* protocol being analysed.
|
||||
* - the data waiting to be sent. These data are located between buf->p-o and
|
||||
* buf->p ;
|
||||
* - the data to process and possibly transform. These data start at
|
||||
* buf->p and may be up to ->i bytes long.
|
||||
* - the data to preserve. They start at ->p and stop at ->p+i. The limit
|
||||
* between the two solely depends on the protocol being analysed.
|
||||
* - the spare area : it is the remainder of the buffer, which can be used to
|
||||
* store new incoming data. It starts at b_lim(b) + b_data(b) and is up to
|
||||
* b->size - b_data(b) long. It may be limited by global.maxrewrite.
|
||||
* store new incoming data. It starts at ->p+i and is up to ->size-i-o long.
|
||||
* It may be limited by global.maxrewrite.
|
||||
* - the reserved area : this is the area which must not be filled and is
|
||||
* reserved for possible rewrites ; it is up to global.maxrewrite bytes
|
||||
* long.
|
||||
|
|
|
|||
|
|
@ -808,7 +808,7 @@ static inline size_t channel_data(const struct channel *chn)
|
|||
return (IS_HTX_STRM(chn_strm(chn)) ? htx_used_space(htxbuf(&chn->buf)) : c_data(chn));
|
||||
}
|
||||
|
||||
/* Returns the amount of input data in a channel, taking the HTX streams into
|
||||
/* Returns the amount of input data in a channel, taking he HTX streams into
|
||||
* account. This function relies on channel_data().
|
||||
*/
|
||||
static inline size_t channel_input_data(const struct channel *chn)
|
||||
|
|
@ -816,6 +816,12 @@ static inline size_t channel_input_data(const struct channel *chn)
|
|||
return channel_data(chn) - co_data(chn);
|
||||
}
|
||||
|
||||
/* Returns 1 if the channel is empty, taking he HTX streams into account */
|
||||
static inline size_t channel_empty(const struct channel *chn)
|
||||
{
|
||||
return (IS_HTX_STRM(chn) ? htx_is_empty(htxbuf(&chn->buf)) : c_empty(chn));
|
||||
}
|
||||
|
||||
/* Check channel's last_read date against the idle timeer to verify the producer
|
||||
* is still streaming data or not
|
||||
*/
|
||||
|
|
@ -855,7 +861,7 @@ static inline void channel_check_xfer(struct channel *chn, size_t xferred)
|
|||
chn->flags &= ~(CF_STREAMER | CF_STREAMER_FAST);
|
||||
}
|
||||
else if (chn->xfer_small >= 2) {
|
||||
/* if the buffer has been at least half full times,
|
||||
/* if the buffer has been at least half full twchne,
|
||||
* we receive faster than we send, so at least it
|
||||
* is not a "fast streamer".
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -583,12 +583,10 @@
|
|||
* for such array declarations. But it's not the case for clang and other
|
||||
* compilers.
|
||||
*/
|
||||
#ifndef __nonstring
|
||||
# if __has_attribute(nonstring)
|
||||
# define __nonstring __attribute__ ((nonstring))
|
||||
# else
|
||||
# define __nonstring
|
||||
# endif
|
||||
#if __has_attribute(nonstring)
|
||||
#define __nonstring __attribute__ ((nonstring))
|
||||
#else
|
||||
#define __nonstring
|
||||
#endif
|
||||
|
||||
#endif /* _HAPROXY_COMPILER_H */
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ struct comp_ctx {
|
|||
struct slz_stream strm;
|
||||
const void *direct_ptr; /* NULL or pointer to beginning of data */
|
||||
int direct_len; /* length of direct_ptr if not NULL */
|
||||
struct buffer queued; /* if not null, data already queued */
|
||||
struct buffer queued; /* if not NULL, data already queued */
|
||||
#elif defined(USE_ZLIB)
|
||||
z_stream strm; /* zlib stream */
|
||||
void *zlib_deflate_state;
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ enum {
|
|||
|
||||
CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */
|
||||
|
||||
CO_FL_QMUX_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
|
||||
CO_FL_QMUX_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
|
||||
CO_FL_QSTRM_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
|
||||
CO_FL_QSTRM_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
|
||||
|
||||
/* These flags indicate whether the Control and Transport layers are initialized */
|
||||
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */
|
||||
|
|
@ -179,8 +179,6 @@ enum {
|
|||
/* below we have all handshake flags grouped into one */
|
||||
CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP | CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV,
|
||||
CO_FL_WAIT_XPRT = CO_FL_WAIT_L4_CONN | CO_FL_HANDSHAKE | CO_FL_WAIT_L6_CONN,
|
||||
/* handshake running on top of a layer6 */
|
||||
CO_FL_WAIT_XPRT_L6 = CO_FL_QMUX_SEND | CO_FL_QMUX_RECV,
|
||||
|
||||
CO_FL_SSL_WAIT_HS = 0x08000000, /* wait for an SSL handshake to complete */
|
||||
|
||||
|
|
@ -215,7 +213,7 @@ static forceinline char *conn_show_flags(char *buf, size_t len, const char *deli
|
|||
/* flags */
|
||||
_(CO_FL_SAFE_LIST, _(CO_FL_IDLE_LIST, _(CO_FL_CTRL_READY,
|
||||
_(CO_FL_REVERSED, _(CO_FL_ACT_REVERSING, _(CO_FL_OPT_MARK, _(CO_FL_OPT_TOS,
|
||||
_(CO_FL_QMUX_SEND, _(CO_FL_QMUX_RECV,
|
||||
_(CO_FL_QSTRM_SEND, _(CO_FL_QSTRM_RECV,
|
||||
_(CO_FL_XPRT_READY, _(CO_FL_WANT_DRAIN, _(CO_FL_WAIT_ROOM, _(CO_FL_SSL_NO_CACHED_INFO, _(CO_FL_EARLY_SSL_HS,
|
||||
_(CO_FL_EARLY_DATA, _(CO_FL_SOCKS4_SEND, _(CO_FL_SOCKS4_RECV, _(CO_FL_SOCK_RD_SH,
|
||||
_(CO_FL_SOCK_WR_SH, _(CO_FL_ERROR, _(CO_FL_FDLESS, _(CO_FL_WAIT_L4_CONN,
|
||||
|
|
@ -287,7 +285,7 @@ enum {
|
|||
|
||||
CO_ER_SSL_FATAL, /* SSL fatal error during a SSL_read or SSL_write */
|
||||
|
||||
CO_ER_QMUX, /* QMux transport parameter exchange failure */
|
||||
CO_ER_QSTRM, /* QMux transport parameter exchange failure */
|
||||
|
||||
CO_ER_REVERSE, /* Error during reverse connect */
|
||||
|
||||
|
|
@ -351,7 +349,7 @@ enum {
|
|||
XPRT_SSL = 1,
|
||||
XPRT_HANDSHAKE = 2,
|
||||
XPRT_QUIC = 3,
|
||||
XPRT_QMUX = 4,
|
||||
XPRT_QSTRM = 4,
|
||||
XPRT_ENTRIES /* must be last one */
|
||||
};
|
||||
|
||||
|
|
@ -675,12 +673,11 @@ struct connection {
|
|||
};
|
||||
|
||||
struct mux_proto_list {
|
||||
const struct ist mux_proto; /* Mux protocol, to be used with the "proto" directive */
|
||||
const struct ist token; /* token name and length. Empty is catch-all */
|
||||
enum proto_proxy_mode mode;
|
||||
enum proto_proxy_side side;
|
||||
const struct mux_ops *mux;
|
||||
const char *alpn; /* Default alpn to set by default when the mux protocol is forced (optional, in binary form) */
|
||||
int init_xprt;
|
||||
struct list list;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ int conn_create_mux(struct connection *conn, int *closed_connection);
|
|||
int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake);
|
||||
int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
||||
struct ist mux_proto, int mode);
|
||||
const struct mux_proto_list *conn_select_mux_fe(const struct connection *conn);
|
||||
int conn_install_mux_fe(struct connection *conn, void *ctx);
|
||||
|
||||
const struct mux_proto_list *conn_select_mux_be(const struct connection *conn);
|
||||
int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess,
|
||||
const struct mux_ops *force_mux_ops);
|
||||
int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *sess);
|
||||
|
|
@ -114,7 +111,6 @@ int conn_reverse(struct connection *conn);
|
|||
const char *conn_err_code_name(struct connection *c);
|
||||
const char *conn_err_code_str(struct connection *c);
|
||||
int xprt_add_hs(struct connection *conn);
|
||||
int xprt_add_l6hs(struct connection *conn, int xprt);
|
||||
void register_mux_proto(struct mux_proto_list *list);
|
||||
|
||||
static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type);
|
||||
|
|
@ -500,64 +496,6 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Calculates the approximate number of streams permitted for an already
|
||||
* established frontend connection based on the number of active connections
|
||||
* (including this one), the number of already committed streams in the current
|
||||
* thread group, the limit, and the desired limit (a ratio of which will be
|
||||
* applied as the budget permits). May return 0 for no limit. The minimum value
|
||||
* when a limit is set will be 1 as a minimum.
|
||||
*/
|
||||
static inline uint conn_calc_max_streams(uint desired)
|
||||
{
|
||||
uint per_conn_left;
|
||||
uint avg_per_conn;
|
||||
uint conn_curr;
|
||||
int conn_left;
|
||||
uint extra;
|
||||
uint curr;
|
||||
|
||||
/* check for infinite */
|
||||
if (!global.tune.streams_elasticity)
|
||||
return 0;
|
||||
|
||||
/* check for none (0% overcommit) */
|
||||
if (global.tune.streams_elasticity == 100)
|
||||
return 1;
|
||||
|
||||
if (desired <= 1)
|
||||
return 1;
|
||||
|
||||
conn_curr = _HA_ATOMIC_LOAD(&actconn) - 1;
|
||||
conn_left = global.hardmaxconn - conn_curr;
|
||||
if (conn_left <= 0)
|
||||
return 1;
|
||||
|
||||
/* the limit is per process, we're working per group. Since we're
|
||||
* counting extra streams max, we subtract 100% from elasticity.
|
||||
*/
|
||||
extra = (((ullong)global.hardmaxconn * (global.tune.streams_elasticity - 100) / 100));
|
||||
curr = _HA_ATOMIC_LOAD(&tg_ctx->committed_extra_streams) * global.nbtgroups;
|
||||
if (curr >= extra)
|
||||
return 1;
|
||||
|
||||
/* this is the average per conn left that we can allocate */
|
||||
per_conn_left = ((extra - curr) + conn_left - 1) / conn_left;
|
||||
|
||||
/* OK so we know we can still allocate (extra - curr) streams per
|
||||
* tgroup, that will be shared across conn_left connections, but ought
|
||||
* to be fairly shared between all conn_curr ones. This allows to
|
||||
* provide at least up to <desired> as long as we leave enough for all
|
||||
* remaining connections left.
|
||||
*/
|
||||
avg_per_conn = ((ullong)(extra - curr) * (desired - 1)) / extra;
|
||||
|
||||
/* both values are permitted since they respect the global limit,
|
||||
* so let's deliver the best option to better serve first conns
|
||||
* so that the limit degrades smoothly with the number of conns.
|
||||
*/
|
||||
return 1 + MAX(per_conn_left, avg_per_conn);
|
||||
}
|
||||
|
||||
/* Retrieves any valid stream connector from this connection, preferably the first
|
||||
* valid one. The purpose is to be able to figure one other end of a private
|
||||
* connection for purposes like source binding or proxy protocol header
|
||||
|
|
@ -653,7 +591,7 @@ static inline struct mux_proto_list *get_mux_proto(const struct ist proto)
|
|||
struct mux_proto_list *item;
|
||||
|
||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||
if (isteq(proto, item->mux_proto))
|
||||
if (isteq(proto, item->token))
|
||||
return item;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -672,7 +610,6 @@ void list_mux_proto(FILE *out);
|
|||
*/
|
||||
static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
||||
const struct ist mux_proto,
|
||||
const struct ist alpn,
|
||||
int proto_side, int proto_is_quic, int proto_mode)
|
||||
{
|
||||
struct mux_proto_list *item;
|
||||
|
|
@ -681,14 +618,10 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
|||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||
if (!(item->side & proto_side) || !(item->mode & proto_mode) || ((proto_is_quic != 0) != ((item->mux->flags & MX_FL_FRAMED) != 0)))
|
||||
continue;
|
||||
if (istlen(mux_proto) && isteq(mux_proto, item->mux_proto)) {
|
||||
if (istlen(mux_proto) && isteq(mux_proto, item->token)) {
|
||||
return item;
|
||||
}
|
||||
else if (istlen(alpn) && item->alpn &&
|
||||
strlen(item->alpn) == istlen(alpn) + 1 &&
|
||||
!memcmp(alpn.ptr, item->alpn + 1, istlen(alpn)))
|
||||
return item;
|
||||
else if (!istlen(item->mux_proto)) {
|
||||
else if (!istlen(item->token)) {
|
||||
if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode))
|
||||
fallback = item;
|
||||
}
|
||||
|
|
@ -705,12 +638,11 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
|||
*/
|
||||
static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
|
||||
const struct ist mux_proto,
|
||||
const struct ist alpn,
|
||||
int proto_side, int proto_mode)
|
||||
{
|
||||
const struct mux_proto_list *item;
|
||||
|
||||
item = conn_get_best_mux_entry(mux_proto, alpn, proto_side, proto_is_quic(conn->ctrl), proto_mode);
|
||||
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
|
||||
|
||||
return item ? item->mux : NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
#define DEF_MAX_THREADS_PER_GROUP 16
|
||||
#endif
|
||||
|
||||
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 16 times
|
||||
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 4 times
|
||||
* long bits if more tgroups are enabled.
|
||||
*/
|
||||
#ifndef MAX_THREADS
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* include/haproxy/dgram.h
|
||||
* include/haproxy/proto_dgram.h
|
||||
* This file provides functions related to DGRAM processing.
|
||||
*
|
||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ static inline int b_may_alloc_for_crit(uint crit)
|
|||
return 0;
|
||||
|
||||
/* If the emergency buffers are too low, we won't try to allocate a
|
||||
* buffer either so that we speed up their release. As a corollary, it
|
||||
* buffer either so that we speed up their release. As a corrolary, it
|
||||
* means that we're always allowed to try to fall back to an emergency
|
||||
* buffer if pool_alloc() fails. The minimum number of available
|
||||
* emergency buffers for an allocation depends on the queue:
|
||||
|
|
@ -138,7 +138,7 @@ static inline char *__b_get_emergency_buf(void)
|
|||
/* Ensures that <buf> is allocated, or allocates it. If no memory is available,
|
||||
* ((char *)1) is assigned instead with a zero size. The allocated buffer is
|
||||
* returned, or NULL in case no memory is available. Since buffers only contain
|
||||
* user data, poisoning is always disabled as it brings no benefit and impacts
|
||||
* user data, poisonning is always disabled as it brings no benefit and impacts
|
||||
* performance. Due to the difficult buffer_wait management, they are not
|
||||
* subject to forced allocation failures either. If other waiters are present
|
||||
* at higher criticality levels, we refrain from allocating.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* include/haproxy/filters-t.h
|
||||
* include/haproxy/filteers-t.h
|
||||
* This file defines everything related to stream filters.
|
||||
*
|
||||
* Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>
|
||||
|
|
|
|||
|
|
@ -216,7 +216,6 @@ struct global {
|
|||
uint max_checks_per_thread; /* if >0, no more than this concurrent checks per thread */
|
||||
uint ring_queues; /* if >0, #ring queues, otherwise equals #thread groups */
|
||||
uint cli_max_payload_sz; /* The max payload size for the CLI */
|
||||
int streams_elasticity; /* percent of advertised streams to connection; 0=no limit */
|
||||
enum threadgroup_takeover tg_takeover; /* Policy for threadgroup takeover */
|
||||
} tune;
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ enum h1m_state {
|
|||
#define H1_MF_UPG_WEBSOCKET 0x00008000 // Set for a Websocket upgrade handshake
|
||||
#define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked"
|
||||
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
|
||||
/* unused: 0x00040000 */
|
||||
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
|
||||
#define H1_MF_NOT_HTTP 0x00080000 // Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted)
|
||||
/* Mask to use to reset H1M flags when we restart headers parsing.
|
||||
*
|
||||
|
|
@ -160,7 +160,7 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
|
|||
|
||||
int h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value);
|
||||
void h1_parse_connection_header(struct h1m *h1m, struct ist *value);
|
||||
void h1_parse_upgrade_header(struct h1m *h1m, struct ist *value);
|
||||
void h1_parse_upgrade_header(struct h1m *h1m, struct ist value);
|
||||
|
||||
void h1_generate_random_ws_input_key(char key_out[25]);
|
||||
void h1_calculate_ws_output_key(const char *key, char *result);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ struct httpclient {
|
|||
struct buffer buf; /* input buffer, raw HTTP */
|
||||
} res;
|
||||
struct {
|
||||
/* callbacks used to send the request, */
|
||||
/* callbacks used to send the request, */
|
||||
void (*req_payload)(struct httpclient *hc); /* send a payload */
|
||||
|
||||
/* callbacks used to receive the response, if not set, the IO
|
||||
|
|
@ -28,7 +28,7 @@ struct httpclient {
|
|||
void (*res_end)(struct httpclient *hc); /* end of the response */
|
||||
} ops;
|
||||
struct sockaddr_storage *dst; /* destination address */
|
||||
struct appctx *appctx; /* HTTP client appctx */
|
||||
struct appctx *appctx; /* HTTPclient appctx */
|
||||
int timeout_server; /* server timeout in ms */
|
||||
void *caller; /* ptr of the caller */
|
||||
unsigned int flags; /* other flags */
|
||||
|
|
@ -50,7 +50,7 @@ struct httpclient {
|
|||
#define HTTPCLIENT_FS_ENDED 0x00020000 /* the httpclient is stopped */
|
||||
|
||||
/* options */
|
||||
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must use an absolute URI */
|
||||
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must be use an absolute URI */
|
||||
#define HTTPCLIENT_O_RES_HTX 0x00000002 /* response is stored in HTX */
|
||||
|
||||
/* States of the HTTP Client Appctx */
|
||||
|
|
@ -65,4 +65,4 @@ enum {
|
|||
|
||||
#define HTTPCLIENT_USERAGENT "HAProxy"
|
||||
|
||||
#endif /* !_HAPROXY_HTTPCLIENT_T_H */
|
||||
#endif /* ! _HAPROXY_HTTCLIENT__T_H */
|
||||
|
|
|
|||
|
|
@ -38,4 +38,4 @@ static inline int httpclient_started(struct httpclient *hc)
|
|||
return !!(hc->flags & HTTPCLIENT_FS_STARTED);
|
||||
}
|
||||
|
||||
#endif /* !_HAPROXY_HTTPCLIENT_H */
|
||||
#endif /* ! _HAPROXY_HTTCLIENT_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* include/haproxy/http_htx.h
|
||||
* include/haproxy/http_htx-t.h
|
||||
* This file defines function prototypes for HTTP manipulation using the
|
||||
* internal representation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
* | HTX | PAYLOADS ==> | | <== HTX_BLKs |
|
||||
* +-----+---------------+------------------------------+--------------+
|
||||
* ^
|
||||
* blocks[] (the beginning of the blocks array)
|
||||
* blocks[] (the beginning of the bocks array)
|
||||
*
|
||||
*
|
||||
* The blocks part remains linear and sorted. You may think about it as an array
|
||||
|
|
@ -84,7 +84,7 @@
|
|||
* At the end, if payload wrapping or blocks defragmentation is not enough, some
|
||||
* free space may be get back with a full defragmentation. This way, the holes in
|
||||
* the middle are not reusable but count in the available free space. The only
|
||||
* way to reuse this lost space is to fully defragment the HTX message.
|
||||
* way to reuse this lost space is to fully defragmenate the HTX message.
|
||||
*
|
||||
* - * -
|
||||
*
|
||||
|
|
@ -113,10 +113,11 @@
|
|||
* - 0000 = request start-line
|
||||
* - 0001 = response start-line
|
||||
* - 0010 = header
|
||||
* - 0011 = end-of-headers
|
||||
* - 0100 = data
|
||||
* - 0101 = trailer
|
||||
* - 0110 = end-of-trailers
|
||||
* - 0011 = pseudo-header ou "special" header
|
||||
* - 0100 = end-of-headers
|
||||
* - 0101 = data
|
||||
* - 0110 = trailer
|
||||
* - 0111 = end-of-trailers
|
||||
* ...
|
||||
* - 1111 = unused
|
||||
*
|
||||
|
|
@ -127,7 +128,7 @@
|
|||
*/
|
||||
#define HTX_SL_F_NONE 0x00000000
|
||||
#define HTX_SL_F_IS_RESP 0x00000001 /* It is the response start-line (unset means the request one) */
|
||||
#define HTX_SL_F_XFER_LEN 0x00000002 /* The message xfer size can be determined */
|
||||
#define HTX_SL_F_XFER_LEN 0x00000002 /* The message xfer size can be dertermined */
|
||||
#define HTX_SL_F_XFER_ENC 0x00000004 /* The transfer-encoding header was found in message */
|
||||
#define HTX_SL_F_CLEN 0x00000008 /* The content-length header was found in message */
|
||||
#define HTX_SL_F_CHNK 0x00000010 /* The message payload is chunked */
|
||||
|
|
@ -139,7 +140,7 @@
|
|||
#define HTX_SL_F_HAS_AUTHORITY 0x00000400 /* The request authority is explicitly specified */
|
||||
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
|
||||
#define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
|
||||
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyless (only for request) */
|
||||
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
|
||||
#define HTX_SL_F_NOT_HTTP 0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
|
||||
|
||||
/* This function is used to report flags in debugging tools. Please reflect
|
||||
|
|
|
|||
|
|
@ -65,9 +65,7 @@ struct buffer *htx_copy_to_large_buffer(struct buffer *dst, struct buffer *src);
|
|||
#define HTX_XFER_DEFAULT 0x00000000 /* Default XFER: no partial xfer / remove blocks from source */
|
||||
#define HTX_XFER_KEEP_SRC_BLKS 0x00000001 /* Don't remove xfer blocks from source messages during xfer */
|
||||
#define HTX_XFER_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
|
||||
#define HTX_XFER_HDRS_ONLY 0x00000004 /* Only Transfer header blocks (start-line, header and EOH) */
|
||||
#define HTX_XFER_NO_METADATA 0x00000008 /* <count> don't include meta-data, only payload */
|
||||
|
||||
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfer header blocks (start-line, header and EOH) */
|
||||
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
|
||||
|
||||
/* Functions and macros to get parts of the start-line or length of these
|
||||
|
|
|
|||
|
|
@ -76,56 +76,6 @@ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* returns non-zero if a*b would overflow an unsigned long, otherwise sets the
|
||||
* result into res and returns 0.
|
||||
*/
|
||||
static inline int mulul_overflow(unsigned long a, unsigned long b, unsigned long *res)
|
||||
{
|
||||
/* __builtin_mul_overflow() is gcc >= 5 or clang >= 3.4 */
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
|
||||
(defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
|
||||
return __builtin_mul_overflow(a, b, res);
|
||||
#else
|
||||
/* portable method involving a division */
|
||||
if (a && b && a > (~(ulong)0) / b)
|
||||
return 1;
|
||||
*res = a * b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* returns non-zero if a*b would overflow a size_t, otherwise sets the
|
||||
* result into res and returns 0.
|
||||
*/
|
||||
static inline int mulsz_overflow(size_t a, size_t b, size_t *res)
|
||||
{
|
||||
/* __builtin_mul_overflow() is gcc >= 5 or clang >= 3.4 */
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
|
||||
(defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
|
||||
return __builtin_mul_overflow(a, b, res);
|
||||
#else
|
||||
/* portable method involving a division */
|
||||
if (a && b && a > (~(size_t)0) / b)
|
||||
return 1;
|
||||
*res = a * b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Computes the size of an array of m*n bytes, taking overflows into account.
|
||||
* If the multiply would overflow, returns the largest possible size_t so that
|
||||
* any call to malloc() or equivalent would fail. Otherwise returns the size.
|
||||
* Note that this implies that even 1*max would not be permitted either.
|
||||
*/
|
||||
static inline size_t array_size_or_fail(size_t m, size_t n)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (unlikely(mulsz_overflow(m, n, &size)))
|
||||
return DISGUISE(~(size_t)0);
|
||||
return size;
|
||||
}
|
||||
|
||||
/* rotate left a 64-bit integer by <bits:[0-5]> bits */
|
||||
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ struct server;
|
|||
struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
||||
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid);
|
||||
|
||||
extern const struct lb_ops lb_chash_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_CHASH_H */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
||||
|
||||
extern const struct lb_ops lb_fas_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_FAS_H */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
||||
|
||||
extern const struct lb_ops lb_fwlc_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_FWLC_H */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
||||
|
||||
extern const struct lb_ops lb_fwrr_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_FWRR_H */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
|
||||
struct server *map_get_server_hash(struct proxy *px, unsigned int hash);
|
||||
|
||||
extern const struct lb_ops lb_map_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_MAP_H */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -29,4 +29,6 @@
|
|||
|
||||
struct server *ss_get_server(struct proxy *px);
|
||||
|
||||
extern const struct lb_ops lb_ss_ops;
|
||||
|
||||
#endif /* _HAPROXY_LB_SS_H */
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ struct connack {
|
|||
} user_props[MQTT_PROP_USER_PROPERTY_ENTRIES];
|
||||
uint8_t wildcard_subscription_available;
|
||||
uint8_t subscription_identifiers_available;
|
||||
uint8_t shared_subscription_available;
|
||||
uint8_t shared_subsription_available;
|
||||
uint16_t server_keepalive;
|
||||
struct ist response_information;
|
||||
struct ist server_reference;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ struct qcc {
|
|||
struct list frms; /* prepared frames related to flow-control */
|
||||
|
||||
uint64_t ms_bidi_init; /* max initial sub-ID of bidi stream allowed for the peer */
|
||||
uint64_t ms_bidi_rel; /* max relative sub-ID of bidi stream allowed for the peer */
|
||||
uint64_t ms_bidi; /* max sub-ID of bidi stream allowed for the peer */
|
||||
uint64_t cl_bidi_r; /* total count of closed remote bidi stream since last MAX_STREAMS emission */
|
||||
|
||||
|
|
@ -90,12 +89,12 @@ struct qcc {
|
|||
struct quic_pacer pacer; /* engine used to pace emission */
|
||||
int paced_sent_ctr; /* counter for when emission is interrupted due to pacing */
|
||||
};
|
||||
/* qmux */
|
||||
struct buffer qmux_buf;
|
||||
/* qstrm */
|
||||
struct buffer qstrm_buf;
|
||||
};
|
||||
} tx;
|
||||
struct {
|
||||
struct buffer qmux_buf;
|
||||
struct buffer qstrm_buf;
|
||||
uint64_t rlen; /* last record length read */
|
||||
} rx;
|
||||
|
||||
|
|
@ -180,7 +179,7 @@ struct qcs {
|
|||
struct {
|
||||
union {
|
||||
struct qc_stream_desc *stream; /* quic */
|
||||
struct buffer qmux_buf; /* qmux */
|
||||
struct buffer qstrm_buf; /* qstrm */
|
||||
};
|
||||
struct quic_fctl fc; /* stream flow control applied on sending */
|
||||
struct quic_frame *msd_frm; /* MAX_STREAM_DATA frame prepared */
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <haproxy/connection.h>
|
||||
#include <haproxy/list.h>
|
||||
#include <haproxy/mux_quic-t.h>
|
||||
#include <haproxy/quic_tune.h>
|
||||
#include <haproxy/stconn.h>
|
||||
|
||||
#include <haproxy/h3.h>
|
||||
|
|
@ -54,7 +53,7 @@ int qcc_recv_max_streams(struct qcc *qcc, uint64_t max, int bidi);
|
|||
int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t final_size);
|
||||
int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err);
|
||||
|
||||
static inline int qcm_stream_rx_bufsz(void)
|
||||
static inline int qmux_stream_rx_bufsz(void)
|
||||
{
|
||||
return global.tune.bufsize - NCB_RESERVED_SZ;
|
||||
}
|
||||
|
|
@ -129,9 +128,6 @@ static inline void qcs_wait_http_req(struct qcs *qcs)
|
|||
BUG_ON_HOT(qcs->flags & QC_SF_HREQ_RECV);
|
||||
qcs->flags |= QC_SF_HREQ_RECV;
|
||||
++qcc->nb_hreq;
|
||||
|
||||
/* On BE side avail_streams cb should prevent opening of too many concurrent streams. */
|
||||
BUG_ON(conn_is_back(qcc->conn) && qcc->nb_hreq > quic_tune.be.stream_max_concurrent);
|
||||
}
|
||||
|
||||
void qcc_show_quic(struct qcc *qcc);
|
||||
|
|
|
|||
10
include/haproxy/mux_quic_qstrm.h
Normal file
10
include/haproxy/mux_quic_qstrm.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _HAPROXY_MUX_QUIC_QSTRM_H
|
||||
#define _HAPROXY_MUX_QUIC_QSTRM_H
|
||||
|
||||
#include <haproxy/mux_quic.h>
|
||||
|
||||
int qcc_qstrm_recv(struct qcc *qcc);
|
||||
|
||||
int qcc_qstrm_send_frames(struct qcc *qcc, struct list *frms);
|
||||
|
||||
#endif /* _HAPROXY_MUX_QUIC_QSTRM_H */
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
/* The principle is to be able to change the type of a pointer by pointing
|
||||
* it directly to an object type. The object type indicates the format of the
|
||||
* structure holding the type, and this is used to retrieve the pointer to the
|
||||
* structure holing the type, and this is used to retrieve the pointer to the
|
||||
* beginning of the structure. Doing so saves us from having to maintain both
|
||||
* a pointer and a type for elements such as connections which can point to
|
||||
* various types of objects.
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ int protocol_resume_all(void);
|
|||
int protocol_enable_all(void);
|
||||
|
||||
/* returns the protocol associated to family <family> with proto_type among the
|
||||
* supported protocol types, and index <alt> (0 or 1) selecting between the two
|
||||
* possible entries per (family, proto_type), or NULL if not found.
|
||||
* supported protocol types, and ctrl_type of either SOCK_STREAM or SOCK_DGRAM
|
||||
* depending on the requested values, or NULL if not found.
|
||||
*/
|
||||
static inline struct protocol *protocol_lookup(int family, enum proto_type proto_type, int alt)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ void proxy_capture_error(struct proxy *proxy, int is_back,
|
|||
void (*show)(struct buffer *, const struct error_snapshot *));
|
||||
void proxy_adjust_all_maxconn(void);
|
||||
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
|
||||
struct proxy *cli_find_backend(struct appctx *appctx, const char *arg);
|
||||
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
|
||||
int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
|
||||
void free_stick_rules(struct list *rules);
|
||||
void free_server_rules(struct list *srules);
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef _HAPROXY_QCM_QMUX_H
|
||||
#define _HAPROXY_QCM_QMUX_H
|
||||
|
||||
#include <haproxy/mux_quic.h>
|
||||
|
||||
int qcc_qmux_recv(struct qcc *qcc);
|
||||
|
||||
int qcc_qmux_send_frames(struct qcc *qcc, struct list *frms);
|
||||
|
||||
#endif /* _HAPROXY_QCM_QMUX_H */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _HAPROXY_QCM_HTTP_H
|
||||
#define _HAPROXY_QCM_HTTP_H
|
||||
#ifndef _HAPROXY_MUX_QUIC_HTTP_H
|
||||
#define _HAPROXY_MUX_QUIC_HTTP_H
|
||||
|
||||
#ifdef USE_QUIC
|
||||
|
||||
|
|
@ -17,4 +17,4 @@ size_t qcs_http_reset_buf(struct qcs *qcs, struct buffer *buf, size_t count);
|
|||
|
||||
#endif /* USE_QUIC */
|
||||
|
||||
#endif /* _HAPROXY_QCM_HTTP_H */
|
||||
#endif /* _HAPROXY_MUX_QUIC_HTTP_H */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _HAPROXY_QCM_TRACE_H
|
||||
#define _HAPROXY_QCM_TRACE_H
|
||||
#ifndef _HAPROXY_QMUX_TRACE_H
|
||||
#define _HAPROXY_QMUX_TRACE_H
|
||||
|
||||
#ifdef USE_QUIC
|
||||
|
||||
|
|
@ -10,10 +10,10 @@
|
|||
struct qcc;
|
||||
struct qcs;
|
||||
|
||||
extern struct trace_source trace_qcm;
|
||||
#define TRACE_SOURCE &trace_qcm
|
||||
extern struct trace_source trace_qmux;
|
||||
#define TRACE_SOURCE &trace_qmux
|
||||
|
||||
static const struct trace_event qcm_trace_events[] = {
|
||||
static const struct trace_event qmux_trace_events[] = {
|
||||
#define QMUX_EV_QCC_NEW (1ULL << 0)
|
||||
{ .mask = QMUX_EV_QCC_NEW , .name = "qcc_new", .desc = "new QUIC connection" },
|
||||
#define QMUX_EV_QCC_RECV (1ULL << 1)
|
||||
|
|
@ -72,9 +72,9 @@ struct qcs_build_stream_trace_arg {
|
|||
uint64_t offset;
|
||||
};
|
||||
|
||||
void qcm_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
|
||||
void qcm_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
|
||||
void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
|
||||
void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
|
||||
|
||||
#endif /* USE_QUIC */
|
||||
|
||||
#endif /* _HAPROXY_QCM_TRACE_H */
|
||||
#endif /* _HAPROXY_QMUX_TRACE_H */
|
||||
|
|
@ -42,7 +42,7 @@ struct pendconn {
|
|||
};
|
||||
|
||||
struct queue {
|
||||
struct eb_root head; /* queued pendconns */
|
||||
struct eb_root head; /* queued pendconnds */
|
||||
struct proxy *px; /* the proxy we're waiting for, never NULL in queue */
|
||||
struct server *sv; /* the server we are waiting for, may be NULL if don't care */
|
||||
__decl_thread(HA_SPINLOCK_T lock); /* for manipulations in the tree */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* include/haproxy/resolvers-t.h
|
||||
* include/haproxy/dns-t.h
|
||||
* This file provides structures and types for DNS.
|
||||
*
|
||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||
|
|
@ -114,7 +114,7 @@ struct resolv_answer_item {
|
|||
char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
|
||||
int16_t type; /* question type */
|
||||
int16_t class; /* query class */
|
||||
uint32_t ttl; /* response TTL */
|
||||
int32_t ttl; /* response TTL */
|
||||
int16_t priority; /* SRV type priority */
|
||||
uint16_t weight; /* SRV type weight */
|
||||
uint16_t port; /* SRV type port */
|
||||
|
|
@ -281,7 +281,7 @@ enum {
|
|||
* matching preference was found.
|
||||
*/
|
||||
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
|
||||
* OR provided IP found and preference is not matched and an IP
|
||||
* OR provided IP found and preference is not match and an IP
|
||||
* matching preference was found.
|
||||
*/
|
||||
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* include/haproxy/resolvers.h
|
||||
* include/haproxy/dns.h
|
||||
* This file provides functions related to DNS protocol
|
||||
*
|
||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||
|
|
|
|||
|
|
@ -111,8 +111,7 @@ enum srv_initaddr {
|
|||
* at start up time.
|
||||
*/
|
||||
enum srv_init_state {
|
||||
SRV_INIT_STATE_NONE = 0,
|
||||
SRV_INIT_STATE_FULLY_DOWN, /* the server should initially be considered DOWN until it passes all health checks. Please keep set to zero. */
|
||||
SRV_INIT_STATE_FULLY_DOWN = 0, /* the server should initially be considered DOWN until it passes all health checks. Please keep set to zero. */
|
||||
SRV_INIT_STATE_DOWN, /* the server should initially be considered DOWN until it passes one health check. */
|
||||
SRV_INIT_STATE_UP, /* the server should initially be considered UP, but will go DOWN if it fails one health check. */
|
||||
SRV_INIT_STATE_FULLY_UP, /* the server should initially be considered UP, but will go DOWN if it fails all health checks. */
|
||||
|
|
@ -249,9 +248,7 @@ struct pid_list {
|
|||
|
||||
/* srv methods of computing chash keys */
|
||||
enum srv_hash_key {
|
||||
SRV_HASH_KEY_ID = 0, /* derived from server puid, 28 LSB used */
|
||||
SRV_HASH_KEY_ID32, /* derived from server puid, 32 bits used */
|
||||
SRV_HASH_KEY_GUID, /* derived from server guid */
|
||||
SRV_HASH_KEY_ID = 0, /* derived from server puid */
|
||||
SRV_HASH_KEY_ADDR, /* derived from server address */
|
||||
SRV_HASH_KEY_ADDR_PORT /* derived from server address and port */
|
||||
};
|
||||
|
|
@ -329,7 +326,6 @@ enum renegotiate_mode {
|
|||
struct path_parameters {
|
||||
__decl_thread(HA_RWLOCK_T param_lock);
|
||||
char nego_alpn[MAX_ALPN_SIZE];
|
||||
int64_t srv_hash;
|
||||
#ifdef USE_QUIC
|
||||
struct quic_early_transport_params tps;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -278,35 +278,6 @@ static inline void srv_adm_set_ready(struct server *s)
|
|||
srv_clr_admin_flag(s, SRV_ADMF_FMAINT);
|
||||
}
|
||||
|
||||
static inline void srv_set_init_state(struct server *srv)
|
||||
{
|
||||
/* no init-state configured or the server is already disabled: don't eval init-state */
|
||||
if (srv->init_state == SRV_INIT_STATE_NONE ||
|
||||
srv->next_admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT))
|
||||
return;
|
||||
|
||||
if (srv->init_state == SRV_INIT_STATE_FULLY_UP) {
|
||||
/* initially UP, when all checks fail to bring server DOWN */
|
||||
srv->next_state = SRV_ST_RUNNING;
|
||||
srv->check.health = srv->check.rise + srv->check.fall - 1;
|
||||
}
|
||||
else if (srv->init_state == SRV_INIT_STATE_UP) {
|
||||
/* initially UP, when one check fails check brings server DOWN */
|
||||
srv->next_state = SRV_ST_RUNNING;
|
||||
srv->check.health = srv->check.rise;
|
||||
}
|
||||
else if (srv->init_state == SRV_INIT_STATE_DOWN) {
|
||||
/* initially DOWN, when one check is successful bring server UP */
|
||||
srv->next_state = SRV_ST_STOPPED;
|
||||
srv->check.health = srv->check.rise - 1;
|
||||
}
|
||||
else if (srv->init_state == SRV_INIT_STATE_FULLY_DOWN) {
|
||||
/* initially DOWN, when all checks are successful bring server UP */
|
||||
srv->next_state = SRV_ST_STOPPED;
|
||||
srv->check.health = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* appends an initaddr method to the existing list. Returns 0 on failure. */
|
||||
static inline int srv_append_initaddr(unsigned int *list, enum srv_initaddr addr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ struct certificate_ocsp {
|
|||
int refcount_store; /* Number of ckch_store that reference this certificate_ocsp */
|
||||
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
|
||||
struct buffer response;
|
||||
unsigned long expire;
|
||||
long expire;
|
||||
X509 *issuer;
|
||||
STACK_OF(X509) *chain;
|
||||
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
|
||||
|
|
|
|||
|
|
@ -736,6 +736,7 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
|
|||
when = tick_first(when, task->expire);
|
||||
|
||||
task->expire = when;
|
||||
task_drop_running(task, 0);
|
||||
if (!task_in_wq(task) || tick_is_lt(task->expire, task->wq.key)) {
|
||||
if (likely(caller)) {
|
||||
caller = HA_ATOMIC_XCHG(&task->caller, caller);
|
||||
|
|
@ -746,7 +747,6 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
|
|||
}
|
||||
__task_queue(task, &tg_ctx->timers);
|
||||
}
|
||||
task_drop_running(task, 0);
|
||||
HA_RWLOCK_WRUNLOCK(TASK_WQ_LOCK, &wq_lock);
|
||||
} else
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ struct tgroup_ctx {
|
|||
struct eb_root timers; /* wait queue (sorted timers tree, global, accessed under wq_lock) */
|
||||
|
||||
uint niced_tasks; /* number of niced tasks in this group's run queues */
|
||||
uint committed_extra_streams; /* sum of extra front streams committed by muxes in this group */
|
||||
|
||||
/* pad to cache line (64B) */
|
||||
char __pad[0]; /* unused except to check remaining room */
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@ static inline int get_addr_len(const struct sockaddr_storage *addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* set port in network byte order (use htons() before calling) */
|
||||
/* set port in host byte order */
|
||||
static inline int set_net_port(struct sockaddr_storage *addr, int port)
|
||||
{
|
||||
switch (addr->ss_family) {
|
||||
|
|
@ -840,7 +840,7 @@ static inline int set_net_port(struct sockaddr_storage *addr, int port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* set port in host byte order */
|
||||
/* set port in network byte order */
|
||||
static inline int set_host_port(struct sockaddr_storage *addr, int port)
|
||||
{
|
||||
switch (addr->ss_family) {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,6 @@ struct trace_ctx {
|
|||
struct trace_source {
|
||||
/* source definition */
|
||||
const struct ist name;
|
||||
const struct ist alias;
|
||||
const char *desc;
|
||||
const struct trace_event *known_events;
|
||||
struct list source_link; // element in list of known trace sources
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@
|
|||
#define _TRC_LOC(f,l) __TRC_LOC(f, ":", l)
|
||||
#define __TRC_LOC(f,c,l) f c #l
|
||||
|
||||
#if defined(USE_TRACE)
|
||||
|
||||
/* truncate a macro arg list to exactly 5 args and replace missing ones with NULL.
|
||||
* The first one (a0) is always ignored.
|
||||
*/
|
||||
|
|
@ -141,23 +139,8 @@
|
|||
&trace_no_cb, ist2(_msg, _msg_len)); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define TRACE_ENABLED(level, mask, args...) 0
|
||||
# define TRACE(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_ERROR(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_USER(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_DATA(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_PROTO(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_STATE(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_DEVEL(msg, mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_ENTER(mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_LEAVE(mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_POINT(mask, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_PRINTF(level, args...) do { /* do nothing */ } while(0)
|
||||
# define TRACE_PRINTF_LOC(level, args...) do { /* do nothing */ } while(0)
|
||||
#endif
|
||||
|
||||
#if defined (USE_TRACE) && (defined(DEBUG_DEV) || defined(DEBUG_FULL))
|
||||
#if defined(DEBUG_DEV) || defined(DEBUG_FULL)
|
||||
# define DBG_TRACE(msg, mask, args...) TRACE(msg, mask, ##args)
|
||||
# define DBG_TRACE_ERROR(msg, mask, args...) TRACE_ERROR(msg, mask, ##args)
|
||||
# define DBG_TRACE_USER(msg, mask, args...) TRACE_USER(msg, mask, ##args)
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _HAPROXY_XPRT_QMUX_H
|
||||
#define _HAPROXY_XPRT_QMUX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct buffer;
|
||||
struct quic_transport_params;
|
||||
|
||||
const struct quic_transport_params *xprt_qmux_lparams(const void *context);
|
||||
const struct quic_transport_params *xprt_qmux_rparams(const void *context);
|
||||
|
||||
size_t xprt_qmux_xfer_rxbuf(void *context, struct buffer *out);
|
||||
|
||||
#endif /* _HAPROXY_XPRT_QMUX_H */
|
||||
9
include/haproxy/xprt_qstrm.h
Normal file
9
include/haproxy/xprt_qstrm.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _HAPROXY_XPRT_QSTRM_H
|
||||
#define _HAPROXY_XPRT_QSTRM_H
|
||||
|
||||
const struct quic_transport_params *xprt_qstrm_lparams(const void *context);
|
||||
const struct quic_transport_params *xprt_qstrm_rparams(const void *context);
|
||||
|
||||
size_t xprt_qstrm_xfer_rxbuf(const void *context, struct buffer *out);
|
||||
|
||||
#endif /* _HAPROXY_XPRT_QSTRM_H */
|
||||
|
|
@ -29,7 +29,7 @@ syslog S3 -level notice {
|
|||
|
||||
syslog S4 -level notice {
|
||||
recv
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 failed.+reason: Layer4 connection problem.+info: \"ECONNREFUSED returned by OS.*\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 failed.+reason: Layer4 connection problem.+info: \"Connection refused\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
|
||||
} -start
|
||||
|
||||
server s1 {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ feature ignore_unknown_macro
|
|||
|
||||
syslog S1 -level notice {
|
||||
recv
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*ECONNREFUSED returned by OS.* at step 2 of tcp-check.*connect port 1"
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*Connection refused at step 2 of tcp-check.*connect port 1"
|
||||
} -start
|
||||
|
||||
syslog S2 -level notice {
|
||||
recv
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*ECONNREFUSED returned by OS.* at step 1 of tcp-check.*connect port 1"
|
||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*Connection refused at step 1 of tcp-check.*connect port 1"
|
||||
} -start
|
||||
|
||||
server s1 {
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
varnishtest "reverse converter test"
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
server s1 {
|
||||
rxreq
|
||||
txresp -hdr "Connection: close"
|
||||
} -repeat 4 -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
global
|
||||
.if feature(THREAD)
|
||||
thread-groups 1
|
||||
.endif
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
|
||||
http-request return status 200 hdr X-Reverse "%[str(example.com),reverse]" hdr X-Reverse2 "%[str(ab cd),reverse]" hdr X-Reverse3 "%[str(example.com),reverse,concat(.)]" hdr X-Reverse4 "%[str(),reverse]"
|
||||
|
||||
default_backend be
|
||||
|
||||
backend be
|
||||
server s1 ${s1_addr}:${s1_port}
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_fe_sock} {
|
||||
txreq -url "/"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-reverse == "moc.elpmaxe"
|
||||
expect resp.http.x-reverse2 == "dc ba"
|
||||
expect resp.http.x-reverse3 == "moc.elpmaxe."
|
||||
expect resp.http.x-reverse4 == "<undef>"
|
||||
} -run
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
com.example. example
|
||||
com.example.mail. mail
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
varnishtest "reverse_dom converter test"
|
||||
|
||||
feature ignore_unknown_macro
|
||||
|
||||
server s1 {
|
||||
rxreq
|
||||
txresp -hdr "Connection: close"
|
||||
} -repeat 8 -start
|
||||
|
||||
haproxy h1 -conf {
|
||||
global
|
||||
.if feature(THREAD)
|
||||
thread-groups 1
|
||||
.endif
|
||||
|
||||
defaults
|
||||
mode http
|
||||
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
frontend fe
|
||||
bind "fd@${fe}"
|
||||
|
||||
http-request set-var(txn.rev_const) str(MaIl.EXAMPLE.com),reverse_dom
|
||||
http-request set-var(txn.rev_host) req.hdr(Host),host_only,reverse_dom if { req.hdr(Host) -m found }
|
||||
http-request set-var(txn.rev_host_dot) var(txn.rev_host),concat(.) if { var(txn.rev_host) -m found }
|
||||
http-request set-var(txn.route) var(txn.rev_host_dot),map_beg(${testdir}/reverse_dom.map,miss) if { var(txn.rev_host_dot) -m found }
|
||||
http-request set-var(txn.sub_only) str(no)
|
||||
http-request set-var(txn.sub_only) str(yes) if { var(txn.rev_host) -m beg com.example. }
|
||||
|
||||
http-request return status 200 hdr X-Rev-Const "%[var(txn.rev_const)]" hdr X-Rev-Host "%[var(txn.rev_host)]" hdr X-Route "%[var(txn.route)]" hdr X-Sub-Only "%[var(txn.sub_only)]"
|
||||
|
||||
default_backend be
|
||||
|
||||
backend be
|
||||
server s1 ${s1_addr}:${s1_port}
|
||||
} -start
|
||||
|
||||
client c1 -connect ${h1_fe_sock} {
|
||||
txreq -url "/" -hdr "Host: example.com"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-const == "com.EXAMPLE.MaIl"
|
||||
expect resp.http.x-rev-host == "com.example"
|
||||
expect resp.http.x-route == "example"
|
||||
expect resp.http.x-sub-only == "no"
|
||||
|
||||
txreq -url "/" -hdr "Host: mail.example.com"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "com.example.mail"
|
||||
expect resp.http.x-route == "mail"
|
||||
expect resp.http.x-sub-only == "yes"
|
||||
|
||||
txreq -url "/" -hdr "Host: example.com."
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "com.example"
|
||||
expect resp.http.x-route == "example"
|
||||
expect resp.http.x-sub-only == "no"
|
||||
|
||||
txreq -url "/" -hdr "Host: localhost"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "localhost"
|
||||
expect resp.http.x-route == "miss"
|
||||
expect resp.http.x-sub-only == "no"
|
||||
|
||||
txreq -url "/" -hdr "Host: badexample.com"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "com.badexample"
|
||||
expect resp.http.x-route == "miss"
|
||||
expect resp.http.x-sub-only == "no"
|
||||
|
||||
txreq -url "/" -hdr "Host: foo..bar"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "<undef>"
|
||||
expect resp.http.x-route == "<undef>"
|
||||
|
||||
txreq -url "/" -hdr "Host: .example.com"
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "<undef>"
|
||||
expect resp.http.x-route == "<undef>"
|
||||
|
||||
txreq -url "/" -hdr "Host: ."
|
||||
rxresp
|
||||
expect resp.status == 200
|
||||
expect resp.http.x-rev-host == "<undef>"
|
||||
expect resp.http.x-route == "<undef>"
|
||||
} -run
|
||||
|
|
@ -146,7 +146,7 @@ client c1 -connect ${hap_fe1_sock} {
|
|||
} -run
|
||||
|
||||
# missing websocket key
|
||||
client c2_1 -connect ${hap_fe1_sock} {
|
||||
client c2 -connect ${hap_fe1_sock} {
|
||||
txreq \
|
||||
-req "GET" \
|
||||
-url "/" \
|
||||
|
|
@ -158,19 +158,6 @@ client c2_1 -connect ${hap_fe1_sock} {
|
|||
expect resp.status == 400
|
||||
} -run
|
||||
|
||||
client c2_2 -connect ${hap_fe1_sock} {
|
||||
txreq \
|
||||
-req "GET" \
|
||||
-url "/" \
|
||||
-hdr "host: 127.0.0.1" \
|
||||
-hdr "connection: upgrade" \
|
||||
-hdr "upgrade: proto1, websocket, proto2" \
|
||||
-hdr "upgrade: proto3"
|
||||
|
||||
rxresp
|
||||
expect resp.status == 400
|
||||
} -run
|
||||
|
||||
# missing key on server side
|
||||
client c3 -connect ${hap_fe2_sock} {
|
||||
txreq \
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ client c1 -connect ${h1_feS_sock} {
|
|||
|
||||
haproxy h1 -cli {
|
||||
# non existent backend
|
||||
send "add backend be from def"
|
||||
send "experimental-mode on; add backend be from def"
|
||||
expect ~ "Mode is required"
|
||||
|
||||
send "add backend be from def_http"
|
||||
send "experimental-mode on; add backend be from def_http"
|
||||
expect ~ "New backend registered."
|
||||
|
||||
send "add server be/srv ${hsrv_fe_addr}:${hsrv_fe_port}"
|
||||
|
|
|
|||
|
|
@ -40,29 +40,29 @@ haproxy h1 -conf {
|
|||
} -start
|
||||
|
||||
haproxy h1 -cli {
|
||||
send "del backend other"
|
||||
send "experimental-mode on; del backend other"
|
||||
expect ~ "No such backend."
|
||||
|
||||
send "del backend li"
|
||||
send "experimental-mode on; del backend li"
|
||||
expect ~ "Cannot delete a listen section."
|
||||
|
||||
send "del backend be_ref"
|
||||
send "experimental-mode on; del backend be_ref"
|
||||
expect ~ "This proxy cannot be removed at runtime due to other configuration elements pointing to it."
|
||||
|
||||
send "show stat be 2 -1"
|
||||
expect ~ "be,BACKEND,"
|
||||
|
||||
send "del backend be"
|
||||
send "experimental-mode on; del backend be"
|
||||
expect ~ "Backend must be unpublished prior to its deletion."
|
||||
|
||||
send "unpublish backend be;"
|
||||
expect ~ ".*"
|
||||
send "del backend be"
|
||||
send "experimental-mode on; del backend be"
|
||||
expect ~ "Only a backend without server can be deleted."
|
||||
|
||||
send "del server be/s1"
|
||||
expect ~ ".*"
|
||||
send "del backend be"
|
||||
send "experimental-mode on; del backend be"
|
||||
expect ~ "Backend deleted."
|
||||
|
||||
send "show stat be 2 -1"
|
||||
|
|
@ -75,7 +75,7 @@ haproxy h1 -cli {
|
|||
|
||||
send "unpublish backend be_unnamed_def_ref;"
|
||||
expect ~ ".*"
|
||||
send "del backend be_unnamed_def_ref"
|
||||
send "experimental-mode on; del backend be_unnamed_def_ref"
|
||||
expect ~ "Backend deleted."
|
||||
|
||||
send "show stat be_unnamed_def_ref 2 -1"
|
||||
|
|
@ -83,6 +83,6 @@ haproxy h1 -cli {
|
|||
|
||||
send "unpublish backend be_unnamed_def_ref2;"
|
||||
expect ~ ".*"
|
||||
send "del backend be_unnamed_def_ref2"
|
||||
send "experimental-mode on; del backend be_unnamed_def_ref2"
|
||||
expect ~ "Backend deleted."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
#REGTEST_TYPE=bug
|
||||
varnishtest "Test for ECDSA/RSA selection and crt-list filters"
|
||||
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8)'"
|
||||
# QUIC backend are not supported with USE_QUIC_OPENSSL_COMPAT
|
||||
feature cmd "$HAPROXY_PROGRAM -cc 'feature(QUIC) && !feature(QUIC_OPENSSL_COMPAT) && !feature(OPENSSL_WOLFSSL)'"
|
||||
feature cmd "$HAPROXY_PROGRAM -cc 'feature(QUIC)'"
|
||||
# Note that USE_OPENSSL is always set if USE_QUIC is set
|
||||
# Same conditions as for ssl/tls13_ssl_crt-list_filters.vtc about TLS library versions
|
||||
feature cmd "$HAPROXY_PROGRAM -cc 'ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1) || feature(OPENSSL_AWSLC)'"
|
||||
|
||||
# This test checks if the multiple certificate types works correctly with the
|
||||
# SNI, and that the negative filters are correctly excluded
|
||||
#
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ haproxy h2 -conf {
|
|||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||
|
||||
resolvers systemdns
|
||||
nameserver dns1 127.0.0.1:53
|
||||
parse-resolv-conf
|
||||
|
||||
frontend myfrontend
|
||||
bind "fd@${my_fe}"
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ haproxy h1 -conf {
|
|||
thread-groups 1
|
||||
.endif
|
||||
|
||||
.if feature(QUIC_OPENSSL_COMPAT)
|
||||
limited-quic
|
||||
.endif
|
||||
|
||||
stats socket "${tmpdir}/h1/stats" level admin
|
||||
issuers-chain-path "${testdir}/certs/issuers-chain-path/ca/"
|
||||
crt-base "${testdir}/certs/issuers-chain-path"
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ haproxy h5 -cli {
|
|||
shell {
|
||||
ocsp_resp_file="${tmpdir}.ocsp_resp.der"
|
||||
|
||||
echo "show ssl ocsp-response base64 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h5/stats" - | sed -e 's/.\{72\}/&\n/g' | openssl base64 -d | tee "${tmpdir}/with-o64" > $ocsp_resp_file
|
||||
echo "show ssl ocsp-response base64 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015" | socat "${tmpdir}/h5/stats" - | sed -e 's/.\{72\}/&\n/g' | openssl base64 -d | tee /tmp/with-o64 > $ocsp_resp_file
|
||||
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
|
|
|
|||
|
|
@ -215,7 +215,6 @@ fi
|
|||
echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}"
|
||||
echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
|
||||
echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest"
|
||||
echo " OpenTelemetry : https://github.com/haproxytech/haproxy-opentelemetry"
|
||||
echo " Pending bugs : https://www.haproxy.org/l/pending-bugs"
|
||||
echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs"
|
||||
echo " Code reports : https://www.haproxy.org/l/code-reports"
|
||||
|
|
|
|||
10
src/acme.c
10
src/acme.c
|
|
@ -1562,16 +1562,6 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
|||
key = ctx->store->data->key;
|
||||
ctx->store->data->key = NULL;
|
||||
|
||||
/* OpenSSL's BIO_new_mem_buf() expects a NUL-terminated string when
|
||||
* passed -1. The httpclient buffer lacks this, so manually terminate
|
||||
* it here to prevent an out-of-bounds heap read during PEM parsing.
|
||||
*/
|
||||
if (b_room(&hc->res.buf) < 1) {
|
||||
memprintf(errmsg, "ACME certificate response has no room for NUL terminator");
|
||||
goto error;
|
||||
}
|
||||
hc->res.buf.area[hc->res.buf.data] = '\0';
|
||||
|
||||
/* XXX: might need a function dedicated to this, which does not read a private key */
|
||||
if (ssl_sock_load_pem_into_ckch(ctx->store->path, hc->res.buf.area, ctx->store->data , errmsg) != 0)
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -539,6 +539,9 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
|||
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC))
|
||||
goto end;
|
||||
|
||||
if (!count)
|
||||
goto end;
|
||||
|
||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||
TRACE_STATE("waiting for appctx outbuf allocation", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
|
||||
goto end;
|
||||
|
|
@ -547,8 +550,7 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
|||
if (flags & CO_RFL_BUF_FLUSH)
|
||||
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
||||
|
||||
if (count)
|
||||
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
||||
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
||||
if (ret)
|
||||
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
||||
|
||||
|
|
@ -606,7 +608,7 @@ size_t appctx_htx_snd_buf(struct appctx *appctx, struct buffer *buf, size_t coun
|
|||
goto end;
|
||||
}
|
||||
|
||||
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_NO_METADATA);
|
||||
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_DEFAULT);
|
||||
if (htx_is_empty(buf_htx)) {
|
||||
appctx_htx->flags |= (buf_htx->flags & HTX_FL_EOM);
|
||||
}
|
||||
|
|
|
|||
26
src/auth.c
26
src/auth.c
|
|
@ -129,7 +129,7 @@ int userlist_postinit()
|
|||
for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
|
||||
struct auth_groups *ag;
|
||||
struct auth_users *curuser;
|
||||
struct auth_groups_list *grl, *tmp;
|
||||
struct auth_groups_list *grl;
|
||||
|
||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
||||
char *group = NULL;
|
||||
|
|
@ -152,7 +152,7 @@ int userlist_postinit()
|
|||
groups = groups->next;
|
||||
free(grl);
|
||||
}
|
||||
goto free_groups;
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
/* Add this group at the group userlist. */
|
||||
|
|
@ -165,7 +165,7 @@ int userlist_postinit()
|
|||
groups = groups->next;
|
||||
free(grl);
|
||||
}
|
||||
goto free_groups;
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
grl->group = ag;
|
||||
|
|
@ -192,7 +192,7 @@ int userlist_postinit()
|
|||
if (!curuser) {
|
||||
ha_alert("userlist '%s': no such user '%s' specified in group '%s'\n",
|
||||
curuserlist->name, user, ag->name);
|
||||
goto free_groups;
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
/* Add this group at the group userlist. */
|
||||
|
|
@ -200,7 +200,7 @@ int userlist_postinit()
|
|||
if (!grl) {
|
||||
ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
|
||||
curuserlist->name);
|
||||
goto free_groups;
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
grl->group = ag;
|
||||
|
|
@ -211,22 +211,6 @@ int userlist_postinit()
|
|||
ha_free(&ag->groupusers);
|
||||
}
|
||||
|
||||
goto next_userlist;
|
||||
|
||||
free_groups:
|
||||
/* Free already-assigned groups for all users in this userlist. */
|
||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
||||
grl = curuser->u.groups;
|
||||
while (grl) {
|
||||
tmp = grl;
|
||||
grl = grl->next;
|
||||
free(tmp);
|
||||
}
|
||||
curuser->u.groups = NULL;
|
||||
}
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
|
||||
next_userlist:;
|
||||
#ifdef DEBUG_AUTH
|
||||
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
||||
struct auth_groups_list *agl;
|
||||
|
|
|
|||
|
|
@ -64,13 +64,6 @@
|
|||
|
||||
#define TRACE_SOURCE &trace_strm
|
||||
|
||||
struct list lb_ops_list = LIST_HEAD_INIT(lb_ops_list);
|
||||
|
||||
void lb_ops_register(struct lb_ops *ops)
|
||||
{
|
||||
LIST_APPEND(&lb_ops_list, &ops->link);
|
||||
}
|
||||
|
||||
/* helper function to invoke the correct hash method */
|
||||
unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len)
|
||||
{
|
||||
|
|
@ -87,7 +80,7 @@ unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len
|
|||
hash = hash_crc32(key, len);
|
||||
break;
|
||||
case BE_LB_HFCN_NONE:
|
||||
/* use key as a hash. It MUST be in string format */
|
||||
/* use key as a hash */
|
||||
{
|
||||
const char *_key = key;
|
||||
|
||||
|
|
@ -370,11 +363,11 @@ struct server *get_server_ph_post(struct stream *s, const struct server *avoid)
|
|||
len -= plen + 1;
|
||||
|
||||
while (len && *end != '&') {
|
||||
if (unlikely(!HTTP_IS_TOKEN(*end))) {
|
||||
if (unlikely(!HTTP_IS_TOKEN(*p))) {
|
||||
/* if in a POST, body must be URI encoded or it's not a URI.
|
||||
* Do not interpret any possible binary data as a parameter.
|
||||
*/
|
||||
if (likely(HTTP_IS_LWS(*end))) /* eol, uncertain uri len */
|
||||
if (likely(HTTP_IS_LWS(*p))) /* eol, uncertain uri len */
|
||||
break;
|
||||
return NULL; /* oh, no; this is not uri-encoded.
|
||||
* This body does not contain parameters.
|
||||
|
|
@ -545,14 +538,7 @@ struct server *get_server_expr(struct stream *s, const struct server *avoid)
|
|||
if (px->lbprm.tot_used == 1)
|
||||
goto hash_done;
|
||||
|
||||
/* Note that if the hash-type doesn't hash the key, we must provide it
|
||||
* as a string representing a number as it will be parsed by read_int64().
|
||||
* Otherwise it's binary. The difference happens on samples returing
|
||||
* ints (e.g. rand()) as well as IP addresses, which, when turned to
|
||||
* binary, are just binary-encoded and cannot be parsed.
|
||||
*/
|
||||
smp = sample_fetch_as_type(px, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, px->lbprm.expr,
|
||||
((px->lbprm.algo & BE_LB_HASH_FUNC) == BE_LB_HFCN_NONE) ? SMP_T_STR : SMP_T_BIN);
|
||||
smp = sample_fetch_as_type(px, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, px->lbprm.expr, SMP_T_BIN);
|
||||
if (!smp)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1818,10 +1804,7 @@ int connect_server(struct stream *s)
|
|||
{
|
||||
struct connection *cli_conn = objt_conn(strm_orig(s));
|
||||
struct connection *srv_conn = NULL;
|
||||
const struct mux_proto_list *mux_proto = NULL;
|
||||
struct server *srv;
|
||||
struct ist name = IST_NULL;
|
||||
struct sample *name_smp;
|
||||
int reuse_mode;
|
||||
int reuse __maybe_unused = 0;
|
||||
int may_use_early_data __maybe_unused = 1; // are we allowed to use early data ?
|
||||
|
|
@ -1843,17 +1826,6 @@ int connect_server(struct stream *s)
|
|||
if (err != SRV_STATUS_OK)
|
||||
return SF_ERR_INTERNAL;
|
||||
|
||||
if (srv && srv->pool_conn_name_expr) {
|
||||
name_smp = sample_fetch_as_type(s->be, s->sess, s,
|
||||
SMP_OPT_DIR_REQ | SMP_OPT_FINAL,
|
||||
srv->pool_conn_name_expr, SMP_T_STR);
|
||||
if (name_smp) {
|
||||
name = ist2(name_smp->data.u.str.area,
|
||||
name_smp->data.u.str.data);
|
||||
}
|
||||
}
|
||||
hash = be_calculate_conn_hash(srv, s, s->sess, bind_addr, s->scb->dst, name);
|
||||
|
||||
if (!be_supports_conn_reuse(s->be))
|
||||
goto skip_reuse;
|
||||
|
||||
|
|
@ -1865,7 +1837,20 @@ int connect_server(struct stream *s)
|
|||
}
|
||||
else {
|
||||
const int not_first_req = s->txn.http && s->txn.http->flags & TX_NOT_FIRST;
|
||||
struct ist name = IST_NULL;
|
||||
struct sample *name_smp;
|
||||
|
||||
if (srv && srv->pool_conn_name_expr) {
|
||||
name_smp = sample_fetch_as_type(s->be, s->sess, s,
|
||||
SMP_OPT_DIR_REQ | SMP_OPT_FINAL,
|
||||
srv->pool_conn_name_expr, SMP_T_STR);
|
||||
if (name_smp) {
|
||||
name = ist2(name_smp->data.u.str.area,
|
||||
name_smp->data.u.str.data);
|
||||
}
|
||||
}
|
||||
|
||||
hash = be_calculate_conn_hash(srv, s, s->sess, bind_addr, s->scb->dst, name);
|
||||
err = be_reuse_connection(hash, s->sess, s->be, srv, s->scb,
|
||||
s->target, not_first_req);
|
||||
if (err == SF_ERR_INTERNAL)
|
||||
|
|
@ -2087,7 +2072,7 @@ int connect_server(struct stream *s)
|
|||
if (IS_HTX_STRM(s) && srv->use_ssl &&
|
||||
(srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str)) {
|
||||
HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
||||
if (srv->path_params.srv_hash != hash || srv->path_params.nego_alpn[0] == 0)
|
||||
if (srv->path_params.nego_alpn[0] == 0)
|
||||
may_start_mux_now = 0;
|
||||
HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
||||
}
|
||||
|
|
@ -2138,11 +2123,9 @@ int connect_server(struct stream *s)
|
|||
srv_conn->flags |= CO_FL_SOCKS4;
|
||||
}
|
||||
|
||||
if (may_start_mux_now) {
|
||||
/* Delay MUX init if an XPRT handshake is required prior. */
|
||||
mux_proto = conn_select_mux_be(srv_conn);
|
||||
if (mux_proto && mux_proto->init_xprt)
|
||||
may_start_mux_now = 0;
|
||||
if (srv && srv->mux_proto && isteq(srv->mux_proto->token, ist("qmux"))) {
|
||||
srv_conn->flags |= (CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND);
|
||||
may_start_mux_now = 0;
|
||||
}
|
||||
|
||||
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
|
||||
|
|
@ -2252,13 +2235,6 @@ int connect_server(struct stream *s)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (mux_proto && mux_proto->init_xprt) {
|
||||
/* Add handshake layer prior to MUX init if required. Does nothing if SSL layer is active though. */
|
||||
if (xprt_add_l6hs(srv_conn, mux_proto->init_xprt)) {
|
||||
conn_full_close(srv_conn);
|
||||
return SF_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that the mux may have been created, we can start the xprt.
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ size_t b_getdelim(const struct buffer *buf, size_t offset, size_t count,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Gets one text line out of a buffer.
|
||||
/* Gets one text line out of aa buffer.
|
||||
* Return values :
|
||||
* >0 : number of bytes read. Includes the \n if present before len or end.
|
||||
* =0 : no '\n' before end found. <str> is left undefined.
|
||||
|
|
@ -243,7 +243,7 @@ void b_slow_realign(struct buffer *b, char *swap, size_t output)
|
|||
/* b_slow_realign_ofs() : this function realigns a possibly wrapping buffer
|
||||
* setting its new head at <ofs>. Depending of the <ofs> value, the resulting
|
||||
* buffer may also wrap. A temporary swap area at least as large as b->size must
|
||||
* be provided in <swap>. It's up to the caller to ensure <ofs> is not larger
|
||||
* be provided in <swap>. It's up to the caller to ensuze <ofs> is not larger
|
||||
* than b->size.
|
||||
*/
|
||||
void b_slow_realign_ofs(struct buffer *b, char *swap, size_t ofs)
|
||||
|
|
|
|||
19
src/cache.c
19
src/cache.c
|
|
@ -1801,6 +1801,8 @@ static void http_cache_io_handler(struct appctx *appctx)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
res_htx = htx_from_buf(&appctx->outbuf);
|
||||
|
||||
len = first->len - sizeof(*cache_ptr) - ctx->sent;
|
||||
res_htx = htx_from_buf(&appctx->outbuf);
|
||||
|
||||
|
|
@ -1948,10 +1950,7 @@ static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_ru
|
|||
return 1;
|
||||
|
||||
err:
|
||||
if (cconf) {
|
||||
free(cconf->c.name);
|
||||
free(cconf);
|
||||
}
|
||||
free(cconf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2180,17 +2179,7 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
|
|||
sec_entry = get_secondary_entry(cache_tree, res,
|
||||
s->txn.http->cache_secondary_hash,
|
||||
0);
|
||||
if (!sec_entry) {
|
||||
/* Secondary key miss: release the retained primary entry
|
||||
* and reattach the detached row before returning.
|
||||
*/
|
||||
release_entry(cache_tree, res, 0);
|
||||
shctx_wrlock(shctx);
|
||||
if (detached)
|
||||
shctx_row_reattach(shctx, entry_block);
|
||||
shctx_wrunlock(shctx);
|
||||
}
|
||||
else if (sec_entry != res) {
|
||||
if (sec_entry && sec_entry != res) {
|
||||
/* The wrong row was added to the hot list. */
|
||||
release_entry(cache_tree, res, 0);
|
||||
retain_entry(sec_entry);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void cfg_free_cond_term(struct cfg_cond_term *term)
|
|||
* cfg_free_cond_term(). An error will be set in <err> on error, and only
|
||||
* in this case. In this case the first bad character will be reported in
|
||||
* <errptr>. <maxdepth> corresponds to the maximum recursion depth permitted,
|
||||
* it is decremented on each recursive call and the parsing will fail upon
|
||||
* it is decremented on each recursive call and the parsing will fail one
|
||||
* reaching <= 0.
|
||||
*/
|
||||
int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr, int maxdepth)
|
||||
|
|
@ -190,7 +190,7 @@ static int cfg_eval_cond_enabled(const char *str)
|
|||
else if (strcmp(str, "EPOLL") == 0)
|
||||
return !!(global.tune.options & GTUNE_USE_EPOLL);
|
||||
else if (strcmp(str, "KQUEUE") == 0)
|
||||
return !!(global.tune.options & GTUNE_USE_KQUEUE);
|
||||
return !!(global.tune.options & GTUNE_USE_EPOLL);
|
||||
else if (strcmp(str, "EVPORTS") == 0)
|
||||
return !!(global.tune.options & GTUNE_USE_EVPORTS);
|
||||
else if (strcmp(str, "SPLICE") == 0)
|
||||
|
|
@ -370,11 +370,11 @@ void cfg_free_cond_expr(struct cfg_cond_expr *expr)
|
|||
* success. <expr> is filled with the parsed info, and <text> is updated on
|
||||
* success to point to the first unparsed character, or is left untouched
|
||||
* on failure. On success, the caller will have to free all lower-level
|
||||
* allocated structs using cfg_free_cond_and(). An error will be set in
|
||||
* allocated structs using cfg_free_cond_expr(). An error will be set in
|
||||
* <err> on error, and only in this case. In this case the first bad
|
||||
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
||||
* maximum recursion depth permitted, it is decremented on each recursive
|
||||
* call and the parsing will fail upon reaching <= 0.
|
||||
* call and the parsing will fail one reaching <= 0.
|
||||
*/
|
||||
int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr, int maxdepth)
|
||||
{
|
||||
|
|
@ -438,7 +438,7 @@ int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Parse an indirect input text as a possible config condition expression.
|
||||
/* Parse an indirect input text as a possible config condition term.
|
||||
* Returns <0 on parsing error, 0 if the parser is desynchronized, or >0 on
|
||||
* success. <expr> is filled with the parsed info, and <text> is updated on
|
||||
* success to point to the first unparsed character, or is left untouched
|
||||
|
|
@ -447,7 +447,7 @@ int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err
|
|||
* <err> on error, and only in this case. In this case the first bad
|
||||
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
||||
* maximum recursion depth permitted, it is decremented on each recursive call
|
||||
* and the parsing will fail upon reaching <= 0.
|
||||
* and the parsing will fail one reaching <= 0.
|
||||
*/
|
||||
int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr, int maxdepth)
|
||||
{
|
||||
|
|
@ -511,7 +511,7 @@ int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **e
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* evaluate a sub-expression on a .if/.elif line. The expression is valid and
|
||||
/* evaluate an sub-expression on a .if/.elif line. The expression is valid and
|
||||
* was already parsed in <expr>. Returns -1 on error (in which case err is
|
||||
* filled with a message, and only in this case), 0 if the condition is false,
|
||||
* 1 if it's true.
|
||||
|
|
@ -544,7 +544,7 @@ int cfg_eval_cond_expr(struct cfg_cond_expr *expr, char **err)
|
|||
}
|
||||
|
||||
/* evaluate a condition on a .if/.elif line. The condition is already tokenized
|
||||
* in <args>. Returns -1 on error (in which case err is filled with a message,
|
||||
* in <err>. Returns -1 on error (in which case err is filled with a message,
|
||||
* and only in this case), 0 if the condition is false, 1 if it's true. If
|
||||
* <errptr> is not NULL, it's set to the first invalid character on error.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1444,16 +1444,6 @@ static int cfg_parse_global_tune_opts(char **args, int section_type,
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[0], "tune.streams-elasticity") == 0) {
|
||||
char *stop;
|
||||
|
||||
global.tune.streams_elasticity = strtol(args[1], &stop, 10);
|
||||
if (!*args[1] || *stop ||
|
||||
(global.tune.streams_elasticity && global.tune.streams_elasticity < 100)) {
|
||||
memprintf(err, "'%s' expects 0 or a positive percentage value of 100 or above", args[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[0], "tune.takeover-other-tg-connections") == 0) {
|
||||
if (*(args[1]) == 0) {
|
||||
memprintf(err, "'%s' expects 'none', 'restricted', or 'full'", args[0]);
|
||||
|
|
@ -1629,6 +1619,11 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
|||
struct proxy *curpx, const struct proxy *defpx,
|
||||
const char *file, int line, char **err)
|
||||
{
|
||||
if (!experimental_directives_allowed) {
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (global.shm_stats_file != NULL) {
|
||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||
return -1;
|
||||
|
|
@ -1639,6 +1634,7 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
|||
return -1;
|
||||
}
|
||||
|
||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
||||
global.shm_stats_file = strdup(args[1]);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1647,6 +1643,11 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
|||
struct proxy *curpx, const struct proxy *defpx,
|
||||
const char *file, int line, char **err)
|
||||
{
|
||||
if (!experimental_directives_allowed) {
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (shm_stats_file_max_objects != -1) {
|
||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||
return -1;
|
||||
|
|
@ -1657,6 +1658,7 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
|||
return -1;
|
||||
}
|
||||
|
||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
||||
shm_stats_file_max_objects = atoi(args[1]);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1901,7 +1903,6 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
|||
{ CFG_GLOBAL, "tune.runqueue-depth", cfg_parse_global_tune_opts },
|
||||
{ CFG_GLOBAL, "tune.sndbuf.client", cfg_parse_global_tune_opts },
|
||||
{ CFG_GLOBAL, "tune.sndbuf.server", cfg_parse_global_tune_opts },
|
||||
{ CFG_GLOBAL, "tune.streams-elasticity", cfg_parse_global_tune_opts },
|
||||
{ CFG_GLOBAL, "tune.takeover-other-tg-connections", cfg_parse_global_tune_opts },
|
||||
{ CFG_GLOBAL, "unsetenv", cfg_parse_global_env_opts, KWF_DISCOVERY },
|
||||
{ CFG_GLOBAL, "zero-warning", cfg_parse_global_mode, KWF_DISCOVERY },
|
||||
|
|
|
|||
|
|
@ -3262,14 +3262,12 @@ stats_error_parsing:
|
|||
/* prepare error message just in case */
|
||||
rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, curr_defproxy, file, linenum, &errmsg);
|
||||
if (rc < 0) {
|
||||
if (errmsg)
|
||||
ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
else if (rc > 0) {
|
||||
if (errmsg)
|
||||
ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
err_code |= ERR_WARN;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1495,7 +1495,7 @@ static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px
|
|||
goto fail;
|
||||
}
|
||||
|
||||
keys_ref->tlskeys = malloc(array_size_or_fail(TLS_TICKETS_NO, sizeof(union tls_sess_key)));
|
||||
keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
|
||||
if (!keys_ref->tlskeys) {
|
||||
memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -1394,7 +1394,7 @@ int parse_cfg(const struct cfgfile *cfg)
|
|||
global.cfg_curr_line = 0;
|
||||
global.cfg_curr_file = file;
|
||||
|
||||
if ((thisline = malloc(array_size_or_fail(sizeof(*thisline), linesize))) == NULL) {
|
||||
if ((thisline = malloc(sizeof(*thisline) * linesize)) == NULL) {
|
||||
ha_alert("Out of memory trying to allocate a buffer for a configuration line.\n");
|
||||
err_code = -1;
|
||||
goto err;
|
||||
|
|
@ -1442,7 +1442,7 @@ next_line:
|
|||
char *newline;
|
||||
int newlinesize = linesize * 2;
|
||||
|
||||
newline = realloc(thisline, array_size_or_fail(sizeof(*thisline), newlinesize));
|
||||
newline = realloc(thisline, sizeof(*thisline) * newlinesize);
|
||||
if (newline == NULL) {
|
||||
ha_alert("parsing [%s:%d]: line too long, cannot allocate memory.\n",
|
||||
file, linenum);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ unsigned long long __channel_forward(struct channel *chn, unsigned long long byt
|
|||
if (!budget)
|
||||
return forwarded;
|
||||
|
||||
/* Now we must ensure chn->to_forward stays below CHN_INFINITE_FORWARD,
|
||||
/* Now we must ensure chn->to_forward sats below CHN_INFINITE_FORWARD,
|
||||
* which also implies it won't overflow. It's less operations in 64-bit.
|
||||
*/
|
||||
bytes = (unsigned long long)chn->to_forward + budget;
|
||||
|
|
@ -105,7 +105,7 @@ int co_inject(struct channel *chn, const char *msg, int len)
|
|||
* controls. The chn->o and to_forward pointers are updated. If the channel
|
||||
* input is closed, -2 is returned. If there is not enough room left in the
|
||||
* buffer, -1 is returned. Otherwise the number of bytes copied is returned
|
||||
* (1). Channel flag CF_READ_EVENT is set if some data can be transferred.
|
||||
* (1). Channel flag READ_PARTIAL is updated if some data can be transferred.
|
||||
*/
|
||||
int ci_putchr(struct channel *chn, char c)
|
||||
{
|
||||
|
|
@ -134,7 +134,7 @@ int ci_putchr(struct channel *chn, char c)
|
|||
* input is closed, -2 is returned. If the block is too large for this buffer,
|
||||
* -3 is returned. If there is not enough room left in the buffer, -1 is
|
||||
* returned. Otherwise the number of bytes copied is returned (0 being a valid
|
||||
* number). Channel flag CF_READ_EVENT is set if some data can be
|
||||
* number). Channel flag READ_PARTIAL is updated if some data can be
|
||||
* transferred.
|
||||
*/
|
||||
int ci_putblk(struct channel *chn, const char *blk, int len)
|
||||
|
|
|
|||
|
|
@ -812,7 +812,7 @@ void chk_report_conn_err(struct check *check, int errno_bck, int expired)
|
|||
}
|
||||
|
||||
errno = unclean_errno(errno_bck);
|
||||
if (conn && !errno)
|
||||
if (conn && errno)
|
||||
retrieve_errno_from_socket(conn);
|
||||
|
||||
TRACE_ENTER(CHK_EV_HCHK_END|CHK_EV_HCHK_ERR, check, 0, 0, (size_t[]){expired});
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ struct buffer *get_small_trash_chunk(void)
|
|||
}
|
||||
|
||||
/* Returns a trash chunk accordingly to the requested size. This function may
|
||||
* fail if the requested size is too big or if the large chunks are not
|
||||
* fail if the requested size is too big or if the large chubks are not
|
||||
* configured.
|
||||
*/
|
||||
struct buffer *get_trash_chunk_sz(size_t size)
|
||||
|
|
|
|||
37
src/cli.c
37
src/cli.c
|
|
@ -1151,13 +1151,8 @@ int cli_parse_cmdline(struct appctx *appctx)
|
|||
*/
|
||||
if (len-1 == strlen(appctx->cli_ctx.payload_pat)) {
|
||||
if (strncmp(str, appctx->cli_ctx.payload_pat, len-1) == 0) {
|
||||
/* end of payload was reached, rewind before the previous \n, if any, and replace it by a \0
|
||||
* Otherwise, the payload is empty, just
|
||||
*/
|
||||
if (b_data(buf) > len)
|
||||
b_sub(buf, len+1);
|
||||
else
|
||||
b_sub(buf, len);
|
||||
/* end of payload was reached, rewind before the previous \n and replace it by a \0 */
|
||||
b_sub(buf, strlen(appctx->cli_ctx.payload_pat) + 2);
|
||||
*b_tail(buf) = '\0';
|
||||
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
||||
}
|
||||
|
|
@ -1884,26 +1879,28 @@ static int cli_parse_show_fd(char **args, char *payload, struct appctx *appctx,
|
|||
/* We allow the forms "<tgid>/" and "/<fd>" where the missing
|
||||
* value is considered a wildcard. So the first form means
|
||||
* "show me all the fds belonging to <tgid>", while the second
|
||||
* one means "show the fd <fd> for each thread group". Note
|
||||
* that the tgid is parsed but ignored for now - this code
|
||||
* will require changes once we split fd tables.
|
||||
* one means "show the fd <fd> for each thread group".
|
||||
*/
|
||||
if (c == args[2]) {
|
||||
if (c == args[2])
|
||||
ctx->tgid = -1;
|
||||
} else {
|
||||
else
|
||||
ctx->tgid = atoi(args[2]);
|
||||
if (ctx->tgid <= 0 || ctx->tgid > MAX_TGROUPS)
|
||||
return cli_err(appctx, "Invalid TGID.\n");
|
||||
}
|
||||
if (ctx->tgid > MAX_TGROUPS)
|
||||
return cli_err(appctx, "Invalid TGID.\n");
|
||||
c++;
|
||||
if (*c) {
|
||||
if (!*c)
|
||||
ctx->fd = -1;
|
||||
else
|
||||
ctx->fd = atoi(c);
|
||||
ctx->show_one = 1;
|
||||
}
|
||||
} else {
|
||||
ctx->fd = atoi(args[2]);
|
||||
ctx->show_one = 1;
|
||||
}
|
||||
|
||||
/* This will need to change when we implement split fd tables. We
|
||||
* completely ignore the tgid for now.
|
||||
*/
|
||||
if (ctx->fd != -1)
|
||||
ctx->show_one = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -2548,7 +2545,7 @@ static int _getsocks(char **args, char *payload, struct appctx *appctx, void *pr
|
|||
/* We will send sockets MAX_SEND_FD per MAX_SEND_FD, allocate a
|
||||
* buffer big enough to store the socket information.
|
||||
*/
|
||||
tmpbuf = malloc(array_size_or_fail(MAX_SEND_FD, (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int))));
|
||||
tmpbuf = malloc(MAX_SEND_FD * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int)));
|
||||
if (tmpbuf == NULL) {
|
||||
ha_warning("Failed to allocate memory to transfer socket information\n");
|
||||
goto out;
|
||||
|
|
|
|||
151
src/connection.c
151
src/connection.c
|
|
@ -196,7 +196,7 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
|
|||
* information to create one, typically from the ALPN. If we're
|
||||
* done with the handshake, attempt to create one.
|
||||
*/
|
||||
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_WAIT_XPRT_L6))) {
|
||||
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND))) {
|
||||
ret = conn_create_mux(conn, NULL);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
|
@ -282,7 +282,6 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
|||
struct ist mux_proto, int mode)
|
||||
{
|
||||
struct bind_conf *bind_conf = __objt_listener(conn->target)->bind_conf;
|
||||
struct ist alpn = IST_NULL;
|
||||
const struct mux_ops *old_mux, *new_mux;
|
||||
void *old_mux_ctx;
|
||||
const char *alpn_str = NULL;
|
||||
|
|
@ -290,9 +289,9 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
|||
|
||||
if (!mux_proto.len) {
|
||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
mux_proto = ist2(alpn_str, alpn_len);
|
||||
}
|
||||
new_mux = conn_get_best_mux(conn, mux_proto, alpn, PROTO_SIDE_FE, mode);
|
||||
new_mux = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
|
||||
old_mux = conn->mux;
|
||||
|
||||
/* No mux found */
|
||||
|
|
@ -319,29 +318,6 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the mux_proto_list entry compatible with <conn> frontend connection
|
||||
* or NULL if nothing eligible.
|
||||
* TODO duplicate code to merge with conn_install_mux_fe().
|
||||
*/
|
||||
const struct mux_proto_list *conn_select_mux_fe(const struct connection *conn)
|
||||
{
|
||||
struct bind_conf *bind_conf;
|
||||
const char *alpn_str = NULL;
|
||||
struct ist alpn;
|
||||
int alpn_len = 0, mode;
|
||||
|
||||
bind_conf = __objt_listener(conn->target)->bind_conf;
|
||||
|
||||
if (bind_conf->mux_proto)
|
||||
return bind_conf->mux_proto;
|
||||
|
||||
mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode);
|
||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
return conn_get_best_mux_entry(IST_NULL, alpn, PROTO_SIDE_FE,
|
||||
proto_is_quic(conn->ctrl), mode);
|
||||
}
|
||||
|
||||
/* installs the best mux for incoming connection <conn> using the upper context
|
||||
* <ctx>. If the mux protocol is forced, we use it to find the best
|
||||
* mux. Otherwise we use the ALPN name, if any. Returns < 0 on error.
|
||||
|
|
@ -354,14 +330,14 @@ int conn_install_mux_fe(struct connection *conn, void *ctx)
|
|||
if (bind_conf->mux_proto)
|
||||
mux_ops = bind_conf->mux_proto->mux;
|
||||
else {
|
||||
struct ist alpn;
|
||||
struct ist mux_proto;
|
||||
const char *alpn_str = NULL;
|
||||
int alpn_len = 0;
|
||||
int mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode);
|
||||
|
||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_FE, mode);
|
||||
mux_proto = ist2(alpn_str, alpn_len);
|
||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
|
||||
if (!mux_ops)
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -377,66 +353,6 @@ int conn_install_mux_fe(struct connection *conn, void *ctx)
|
|||
return conn_install_mux(conn, mux_ops, ctx, bind_conf->frontend, conn->owner);
|
||||
}
|
||||
|
||||
/* Returns the mux_proto_list entry compatible with <conn> backend connection
|
||||
* or NULL if nothing eligible.
|
||||
* TODO duplicate code to merge with conn_install_mux_be/chk().
|
||||
*/
|
||||
const struct mux_proto_list *conn_select_mux_be(const struct connection *conn)
|
||||
{
|
||||
struct session *sess;
|
||||
struct server *srv;
|
||||
struct proxy *prx;
|
||||
struct check *check;
|
||||
struct ist alpn;
|
||||
const char *alpn_str = NULL;
|
||||
int alpn_len = 0, mode;
|
||||
|
||||
sess = conn->owner;
|
||||
if (sess && obj_type(sess->origin) == OBJ_TYPE_CHECK) {
|
||||
check = __objt_check(sess->origin);
|
||||
if (check->mux_proto)
|
||||
return check->mux_proto;
|
||||
|
||||
mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
|
||||
|
||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
|
||||
return conn_get_best_mux_entry(IST_NULL, alpn, PROTO_SIDE_BE,
|
||||
proto_is_quic(conn->ctrl), mode);
|
||||
}
|
||||
else {
|
||||
srv = objt_server(conn->target);
|
||||
prx = objt_proxy(conn->target);
|
||||
if (srv)
|
||||
prx = srv->proxy;
|
||||
|
||||
if (!prx) {
|
||||
/* Target should either be a server or a proxy.
|
||||
* USE a full a BUG_ON() once considered definitive.
|
||||
*/
|
||||
BUG_ON_HOT(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mode = conn_pr_mode_to_proto_mode(prx->mode);
|
||||
|
||||
if (srv && srv->mux_proto)
|
||||
return srv->mux_proto;
|
||||
|
||||
if (!conn_get_alpn(conn, &alpn_str, &alpn_len)) {
|
||||
if (srv && srv->path_params.nego_alpn[0]) {
|
||||
alpn_str = srv->path_params.nego_alpn;
|
||||
alpn_len = strlen(alpn_str);
|
||||
}
|
||||
}
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
|
||||
return conn_get_best_mux_entry(IST_NULL, alpn, PROTO_SIDE_BE,
|
||||
proto_is_quic(conn->ctrl), mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* installs the best mux for outgoing connection <conn> using the upper context
|
||||
* <ctx>. If the server mux protocol is forced, we use it to find the best mux.
|
||||
* It's also possible to specify an alternative mux protocol <force_mux_ops>,
|
||||
|
|
@ -464,20 +380,20 @@ int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess
|
|||
mux_ops = force_mux_ops;
|
||||
}
|
||||
else {
|
||||
struct ist alpn;
|
||||
struct ist mux_proto;
|
||||
const char *alpn_str = NULL;
|
||||
int alpn_len = 0;
|
||||
int mode = conn_pr_mode_to_proto_mode(prx->mode);
|
||||
|
||||
if (!conn_get_alpn(conn, &alpn_str, &alpn_len)) {
|
||||
if (srv && srv->path_params.srv_hash == conn->hash_node.key && srv->path_params.nego_alpn[0]) {
|
||||
if (srv && srv->path_params.nego_alpn[0]) {
|
||||
alpn_str = srv->path_params.nego_alpn;
|
||||
alpn_len = strlen(alpn_str);
|
||||
}
|
||||
}
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
mux_proto = ist2(alpn_str, alpn_len);
|
||||
|
||||
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
|
||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
|
||||
if (!mux_ops)
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -518,15 +434,15 @@ int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *ses
|
|||
if (check->mux_proto)
|
||||
mux_ops = check->mux_proto->mux;
|
||||
else {
|
||||
struct ist alpn;
|
||||
struct ist mux_proto;
|
||||
const char *alpn_str = NULL;
|
||||
int alpn_len = 0;
|
||||
int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
|
||||
|
||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||
alpn = ist2(alpn_str, alpn_len);
|
||||
mux_proto = ist2(alpn_str, alpn_len);
|
||||
|
||||
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
|
||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
|
||||
if (!mux_ops)
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -847,43 +763,6 @@ int xprt_add_hs(struct connection *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Activates an <xprt> layer on top of <conn> connection. This handshake layer
|
||||
* should be designed to work on top of the layer 6. If SSL is active and its
|
||||
* handshake still in progress, this function does nothing.
|
||||
*
|
||||
* Returns 0 on success else a negative error code.
|
||||
*/
|
||||
int xprt_add_l6hs(struct connection *conn, int xprt)
|
||||
{
|
||||
const struct xprt_ops *ops = xprt_get(xprt);
|
||||
void *ops_ctx = NULL;
|
||||
|
||||
/* Only QMux is supported as handshake on top of layer6 for now. */
|
||||
BUG_ON(xprt != XPRT_QMUX);
|
||||
|
||||
if (conn->flags & CO_FL_ERROR)
|
||||
return -1;
|
||||
|
||||
/* Do nothing if SSL is in used but handshake still in progress. In
|
||||
* this case, xprt layer will be added on handshake completion.
|
||||
*/
|
||||
if (conn->xprt == xprt_get(XPRT_SSL) &&
|
||||
(conn->flags & CO_FL_WAIT_L6_CONN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ops->init(conn, &ops_ctx))
|
||||
return -1;
|
||||
|
||||
ops->add_xprt(conn, ops_ctx, conn->xprt_ctx, conn->xprt, NULL, NULL);
|
||||
conn->xprt = ops;
|
||||
conn->xprt_ctx = ops_ctx;
|
||||
/* Reset XPRT READY flag before the next conn_xprt_start(). */
|
||||
conn->flags &= ~CO_FL_XPRT_READY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns a short name for an error, typically the same as the enum name
|
||||
* without the "CO_ER_" prefix, or an empty string for no error (better eye
|
||||
* catching in logs). This is more compact for some debug cases.
|
||||
|
|
@ -1009,7 +888,7 @@ const char *conn_err_code_str(struct connection *c)
|
|||
|
||||
case CO_ER_SSL_FATAL: return "SSL fatal error";
|
||||
|
||||
case CO_ER_QMUX: return "Error during QMux transport parameters initial exchange";
|
||||
case CO_ER_QSTRM: return "Error during QMux transport parameters initial exchange";
|
||||
|
||||
case CO_ER_REVERSE: return "Reverse connect failure";
|
||||
|
||||
|
|
@ -2112,7 +1991,7 @@ void list_mux_proto(FILE *out)
|
|||
fprintf(out, "Available multiplexer protocols :\n"
|
||||
"(protocols marked as <default> cannot be specified using 'proto' keyword)\n");
|
||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||
proto = item->mux_proto;
|
||||
proto = item->token;
|
||||
|
||||
if (item->mode == PROTO_MODE_ANY)
|
||||
mode = "TCP|HTTP";
|
||||
|
|
|
|||
|
|
@ -983,7 +983,7 @@ void cpu_compose_clusters(void)
|
|||
/* renumber clusters and assign unassigned ones at the same
|
||||
* time. For this, we'll compare pkg/die/llc with the last
|
||||
* CPU's and verify if we need to create a new cluster ID.
|
||||
* Note that some platforms don't report cache. The local value
|
||||
* Note that some platforms don't report cache. The locao value
|
||||
* is local to the pkg+node combination so that we reset it
|
||||
* when changing, contrary to the global one which grows.
|
||||
*/
|
||||
|
|
@ -2402,7 +2402,7 @@ static int cpu_topo_alloc(void)
|
|||
ha_cpu_clusters[cpu].idx = cpu;
|
||||
}
|
||||
|
||||
/* pre-initialize the configured CPU sets */
|
||||
/* pre-inizialize the configured CPU sets */
|
||||
ha_cpuset_zero(&cpu_set_cfg.drop_cpus);
|
||||
ha_cpuset_zero(&cpu_set_cfg.only_cpus);
|
||||
ha_cpuset_zero(&cpu_set_cfg.drop_nodes);
|
||||
|
|
|
|||
13
src/cpuset.c
13
src/cpuset.c
|
|
@ -27,8 +27,6 @@ int ha_cpuset_set(struct hap_cpuset *set, int cpu)
|
|||
#elif defined(CPUSET_USE_ULONG)
|
||||
set->cpuset |= (0x1 << cpu);
|
||||
return 0;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -44,8 +42,6 @@ int ha_cpuset_clr(struct hap_cpuset *set, int cpu)
|
|||
#elif defined(CPUSET_USE_ULONG)
|
||||
set->cpuset &= ~(0x1 << cpu);
|
||||
return 0;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -100,8 +96,6 @@ int ha_cpuset_count(const struct hap_cpuset *set)
|
|||
|
||||
#elif defined(CPUSET_USE_ULONG)
|
||||
return my_popcountl(set->cpuset);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -126,8 +120,6 @@ int ha_cpuset_ffs(const struct hap_cpuset *set)
|
|||
return 0;
|
||||
|
||||
return my_ffsl(set->cpuset);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +148,6 @@ int ha_cpuset_isequal(const struct hap_cpuset *dst, const struct hap_cpuset *src
|
|||
|
||||
#elif defined(CPUSET_USE_ULONG)
|
||||
return dst->cpuset == src->cpuset;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -168,8 +158,7 @@ int ha_cpuset_size()
|
|||
|
||||
#elif defined(CPUSET_USE_ULONG)
|
||||
return LONGBITS;
|
||||
#else
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1357,7 +1357,8 @@ static int debug_parse_cli_write(char **args, char *payload, struct appctx *appc
|
|||
/*
|
||||
* debug dev stream [strm=<ptr>] [strm.f[{+-=}<flags>]] [txn.f[{+-=}<flags>]] \
|
||||
* [req.f[{+-=}<flags>]] [res.f[{+-=}<flags>]] \
|
||||
* [scf.s[=<state>]] [scb.s[=<state>]]
|
||||
* [sif.f[{+-=<flags>]] [sib.f[{+-=<flags>]] \
|
||||
* [sif.s[=<state>]] [sib.s[=<state>]]
|
||||
*/
|
||||
static int debug_parse_cli_stream(char **args, char *payload, struct appctx *appctx, void *private)
|
||||
{
|
||||
|
|
@ -1627,7 +1628,7 @@ static struct task *debug_delay_inj_task(struct task *t, void *ctx, unsigned int
|
|||
*/
|
||||
static int debug_parse_delay_inj(char **args, char *payload, struct appctx *appctx, void *private)
|
||||
{
|
||||
unsigned long *tctx; // [0] = inter, [1] = nbwakeups
|
||||
unsigned long *tctx; // [0] = inter, [2] = count
|
||||
struct task *task;
|
||||
|
||||
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
|
||||
|
|
|
|||
31
src/dict.c
31
src/dict.c
|
|
@ -59,7 +59,7 @@ static void free_dict_entry(struct dict_entry *de)
|
|||
}
|
||||
|
||||
/*
|
||||
* Simple function to lookup dictionary entries with <s> as key.
|
||||
* Simple function to lookup dictionary entries with <s> as value.
|
||||
*/
|
||||
static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
||||
{
|
||||
|
|
@ -75,21 +75,20 @@ static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
|||
}
|
||||
|
||||
/*
|
||||
* Insert an entry in <d> dictionary with <s> as key.
|
||||
* Insert an entry in <d> dictionary with <s> as value. *
|
||||
*/
|
||||
struct dict_entry *dict_insert(struct dict *d, char *s)
|
||||
{
|
||||
struct dict_entry *de, *tree_de;
|
||||
struct dict_entry *de;
|
||||
struct ebpt_node *n;
|
||||
|
||||
HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
|
||||
de = __dict_lookup(d, s);
|
||||
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
if (de) {
|
||||
HA_ATOMIC_INC(&de->refcount);
|
||||
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
return de;
|
||||
}
|
||||
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
|
||||
de = new_dict_entry(s);
|
||||
if (!de)
|
||||
|
|
@ -97,18 +96,13 @@ struct dict_entry *dict_insert(struct dict *d, char *s)
|
|||
|
||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||
n = ebis_insert(&d->values, &de->value);
|
||||
tree_de = container_of(n, struct dict_entry, value);
|
||||
if (tree_de == de)
|
||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
else {
|
||||
/* another entry was already there, we'll return it, kill
|
||||
* ours and bump the other's refcount before returning it.
|
||||
*/
|
||||
HA_ATOMIC_INC(&tree_de->refcount);
|
||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
if (n != &de->value) {
|
||||
free_dict_entry(de);
|
||||
de = container_of(n, struct dict_entry, value);
|
||||
}
|
||||
return tree_de;
|
||||
|
||||
return de;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -122,11 +116,10 @@ void dict_entry_unref(struct dict *d, struct dict_entry *de)
|
|||
if (!de)
|
||||
return;
|
||||
|
||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) {
|
||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||
ebpt_delete(&de->value);
|
||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||
|
||||
|
|
|
|||
19
src/dns.c
19
src/dns.c
|
|
@ -194,7 +194,7 @@ int dns_send_nameserver(struct dns_nameserver *ns, void *buf, size_t len)
|
|||
struct ist myist;
|
||||
|
||||
myist = ist2(buf, len);
|
||||
ret = dns_ring_write(ns->stream->ring_req, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
|
||||
ret = dns_ring_write(ns->stream->ring_req, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
|
||||
if (!ret) {
|
||||
ns->counters->snd_error++;
|
||||
return -1;
|
||||
|
|
@ -215,7 +215,7 @@ void dns_session_free(struct dns_session *);
|
|||
*/
|
||||
ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t size)
|
||||
{
|
||||
ssize_t ret = -1;
|
||||
ssize_t ret = -1;
|
||||
|
||||
if (ns->dgram) {
|
||||
struct dgram_conn *dgram = &ns->dgram->conn;
|
||||
|
|
@ -475,6 +475,7 @@ int dns_dgram_init(struct dns_nameserver *ns, struct sockaddr_storage *sk)
|
|||
dgram->conn.t.sock.fd = -1;
|
||||
dgram->conn.addr.to = *sk;
|
||||
HA_SPIN_INIT(&dgram->conn.lock);
|
||||
ns->dgram = dgram;
|
||||
|
||||
dgram->ofs_req = ~0; /* init ring offset */
|
||||
dgram->ring_req = dns_ring_new(2*DNS_TCP_MSG_RING_MAX_SIZE);
|
||||
|
|
@ -489,7 +490,6 @@ int dns_dgram_init(struct dns_nameserver *ns, struct sockaddr_storage *sk)
|
|||
ha_alert("nameserver sets too many watchers > 255 on ring. This is a bug and should not happen.\n");
|
||||
goto out;
|
||||
}
|
||||
ns->dgram = dgram;
|
||||
return 0;
|
||||
out:
|
||||
dns_ring_free(dgram->ring_req);
|
||||
|
|
@ -913,7 +913,6 @@ static int dns_session_init(struct appctx *appctx)
|
|||
return 0;
|
||||
|
||||
error:
|
||||
sockaddr_free(&addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -1346,8 +1345,8 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
|||
{
|
||||
struct dns_stream_server *dss = NULL;
|
||||
|
||||
dss = calloc(1, sizeof(*dss));
|
||||
if (!dss) {
|
||||
dss = calloc(1, sizeof(*dss));
|
||||
if (!dss) {
|
||||
ha_alert("memory allocation error initializing dns tcp server '%s'.\n", srv->id);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1363,7 +1362,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
|||
}
|
||||
/* Create the task associated to the resolver target handling conns */
|
||||
if ((dss->task_req = task_new_anywhere()) == NULL) {
|
||||
ha_alert("memory allocation error initializing req task for dns tcp server '%s'.\n", srv->id);
|
||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1380,7 +1379,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
|||
|
||||
/* Create the task associated to the resolver target handling conns */
|
||||
if ((dss->task_rsp = task_new_anywhere()) == NULL) {
|
||||
ha_alert("memory allocation error initializing rsp task for dns tcp server '%s'.\n", srv->id);
|
||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1390,7 +1389,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
|||
|
||||
/* Create the task associated to the resolver target handling conns */
|
||||
if ((dss->task_idle = task_new_anywhere()) == NULL) {
|
||||
ha_alert("memory allocation error initializing idle task for dns tcp server '%s'.\n", srv->id);
|
||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1426,7 +1425,7 @@ int init_dns_buffers()
|
|||
if (!dns_msg_trash)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void deinit_dns_buffers()
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static void usermsgs_put(const struct ist *msg)
|
|||
{
|
||||
/* Allocate the buffer if not already done. */
|
||||
if (unlikely(b_is_null(&usermsgs_buf))) {
|
||||
usermsgs_buf.area = malloc(array_size_or_fail(USER_MESSAGES_BUFSIZE, sizeof(char)));
|
||||
usermsgs_buf.area = malloc(USER_MESSAGES_BUFSIZE * sizeof(char));
|
||||
if (usermsgs_buf.area)
|
||||
usermsgs_buf.size = USER_MESSAGES_BUFSIZE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ int prepare_external_check(struct check *check)
|
|||
case PR_MODE_CLI: svmode = "cli"; break;
|
||||
case PR_MODE_SYSLOG: svmode = "syslog"; break;
|
||||
case PR_MODE_PEERS: svmode = "peers"; break;
|
||||
case PR_MODE_HTTP: svmode = (s->mux_proto) ? s->mux_proto->mux_proto.ptr : "h1"; break;
|
||||
case PR_MODE_HTTP: svmode = (s->mux_proto) ? s->mux_proto->token.ptr : "h1"; break;
|
||||
case PR_MODE_TCP: svmode = "tcp"; break;
|
||||
case PR_MODE_SPOP: svmode = "spop"; break;
|
||||
/* all valid cases must be enumerated above, below is to avoid a warning */
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ static int cfg_fcgi_apps_postparser()
|
|||
px->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_DEL;
|
||||
|
||||
for (srv = px->srv; srv; srv = srv->next) {
|
||||
if (srv->mux_proto && isteq(srv->mux_proto->mux_proto, ist("fcgi"))) {
|
||||
if (srv->mux_proto && isteq(srv->mux_proto->token, ist("fcgi"))) {
|
||||
nb_fcgi_srv++;
|
||||
if (fcgi_conf)
|
||||
continue;
|
||||
|
|
|
|||
2
src/fd.c
2
src/fd.c
|
|
@ -1166,7 +1166,7 @@ int init_pollers()
|
|||
struct poller *bp;
|
||||
|
||||
/* always provide an aligned fdtab */
|
||||
if ((fdtab = ha_aligned_zalloc(64, array_size_or_fail(global.maxsock, sizeof(*fdtab)))) == NULL) {
|
||||
if ((fdtab = ha_aligned_zalloc(64, global.maxsock * sizeof(*fdtab))) == NULL) {
|
||||
ha_alert("Not enough memory to allocate %d entries for fdtab!\n", global.maxsock);
|
||||
goto fail_tab;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue