mirror of
https://github.com/haproxy/haproxy.git
synced 2026-05-25 10:42:14 -04:00
Compare commits
180 commits
v3.4-dev11
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32fc35ef09 | ||
|
|
6bb8cb51e6 | ||
|
|
8fe8d5fbe3 | ||
|
|
b78b023d55 | ||
|
|
7d182a2ed5 | ||
|
|
c0e302fe79 | ||
|
|
478e7e52cb | ||
|
|
8e1d33a648 | ||
|
|
49d6306de3 | ||
|
|
01ebb668a4 | ||
|
|
340cc86efb | ||
|
|
f62d020140 | ||
|
|
bbef74fb21 | ||
|
|
608951844e | ||
|
|
f9088a5d75 | ||
|
|
007d5946b4 | ||
|
|
4db85fc53e | ||
|
|
41bb1c24f6 | ||
|
|
9091cfa617 | ||
|
|
57b526e022 | ||
|
|
2644f9ddf9 | ||
|
|
7cab3a3c3a | ||
|
|
04b9215a2e | ||
|
|
75f72c2eb9 | ||
|
|
1ed4ef6659 | ||
|
|
3fab21ea42 | ||
|
|
f9d4d659a4 | ||
|
|
c0aa91a202 | ||
|
|
e2c3cd9eb7 | ||
|
|
6717531053 | ||
|
|
812962d110 | ||
|
|
8fe8f78473 | ||
|
|
cdeb2aa4ef | ||
|
|
9e6e0fd149 | ||
|
|
e98595e4e5 | ||
|
|
413f6f9a1f | ||
|
|
3475a5bb9f | ||
|
|
050e06dd66 | ||
|
|
bcf768f157 | ||
|
|
897c5ddb8c | ||
|
|
f5477c8d45 | ||
|
|
b62ba7592a | ||
|
|
3e25104a9c | ||
|
|
482b6763a3 | ||
|
|
2a87629052 | ||
|
|
56e7f8ef31 | ||
|
|
99d48c3aec | ||
|
|
47a61eb86d | ||
|
|
b7c607e207 | ||
|
|
05e65489cb | ||
|
|
b9acb4415f | ||
|
|
3c35e7f137 | ||
|
|
d142c7f421 | ||
|
|
8dd31dcd07 | ||
|
|
f521581922 | ||
|
|
de3f245df0 | ||
|
|
e139dd90e3 | ||
|
|
89f3975acc | ||
|
|
d21ec4c707 | ||
|
|
e4adba6e64 | ||
|
|
33c8270903 | ||
|
|
ad3562fea1 | ||
|
|
641fe4f119 | ||
|
|
2d2980408f | ||
|
|
7004bb3b8c | ||
|
|
a59e6e5efd | ||
|
|
cb5d98c495 | ||
|
|
f2bf3483ba | ||
|
|
f2b152c95e | ||
|
|
e30bcfe6cd | ||
|
|
879c78c909 | ||
|
|
356f1ab5d7 | ||
|
|
86ffbaa0f5 | ||
|
|
6aab6d4e98 | ||
|
|
022681eca2 | ||
|
|
50354f929d | ||
|
|
6f6bf3fecc | ||
|
|
1279bd80e9 | ||
|
|
b74b5289c8 | ||
|
|
8dd49dfaba | ||
|
|
c53256adbc | ||
|
|
18c5cd6674 | ||
|
|
b786eaf1b1 | ||
|
|
307294b30a | ||
|
|
0284be5456 | ||
|
|
11bad01760 | ||
|
|
b59fe471a5 | ||
|
|
29b9da7821 | ||
|
|
d4a4be6c34 | ||
|
|
bbc41785d9 | ||
|
|
3b825d2745 | ||
|
|
3da2b63274 | ||
|
|
fdb569c2ea | ||
|
|
fd31df765f | ||
|
|
b44d60eb42 | ||
|
|
015933794e | ||
|
|
4519906c70 | ||
|
|
2f88b4bc4b | ||
|
|
9ebb00e673 | ||
|
|
3460626148 | ||
|
|
6cbcb4f9db | ||
|
|
677fdfe126 | ||
|
|
b15e9b1b29 | ||
|
|
0c8c9b1c2a | ||
|
|
bed842390f | ||
|
|
569f1e2f37 | ||
|
|
493dc352ad | ||
|
|
8aa99dfc74 | ||
|
|
5b468a0820 | ||
|
|
6c663a9374 | ||
|
|
2a43a1306b | ||
|
|
b6bd6f5b9a | ||
|
|
ace19fd638 | ||
|
|
bb5c18ab74 | ||
|
|
fefce297ab | ||
|
|
bcb4f9cd4a | ||
|
|
da4a4976d7 | ||
|
|
4a499938d0 | ||
|
|
b08cf94ae2 | ||
|
|
68f6522add | ||
|
|
61aa17aec8 | ||
|
|
6e9b9196bd | ||
|
|
f4edcdf4de | ||
|
|
f3fc68e3a2 | ||
|
|
c090e51502 | ||
|
|
8e1b46f8d7 | ||
|
|
19a3c29d3c | ||
|
|
1bb879cb3f | ||
|
|
96b72fd461 | ||
|
|
57ab169747 | ||
|
|
e68d4c9c36 | ||
|
|
1a9ab14efc | ||
|
|
545351f2c1 | ||
|
|
af3560fa0a | ||
|
|
7e2f0fa178 | ||
|
|
b24260ec94 | ||
|
|
de6a26e3c8 | ||
|
|
31a3e16e16 | ||
|
|
a9f38c19b4 | ||
|
|
4f9b8574d2 | ||
|
|
f9e9ab8c90 | ||
|
|
ae614e24c3 | ||
|
|
80fd275773 | ||
|
|
d9a7ff9b6c | ||
|
|
e0144843a4 | ||
|
|
58f3e191e8 | ||
|
|
648b5b6e50 | ||
|
|
57c3e4b4e2 | ||
|
|
82d723dd8e | ||
|
|
aa2c7034e1 | ||
|
|
241cfb2483 | ||
|
|
e32cc2e805 | ||
|
|
4eb6e8daa3 | ||
|
|
827defccda | ||
|
|
adb9a5f82f | ||
|
|
e4e614022b | ||
|
|
e9cc913e3c | ||
|
|
fa9cefd277 | ||
|
|
be2851f304 | ||
|
|
e2ab156fa2 | ||
|
|
57878f3b5c | ||
|
|
448cc829e5 | ||
|
|
128c654aac | ||
|
|
5830cf3ccf | ||
|
|
2dfbc311a8 | ||
|
|
fdfecc5589 | ||
|
|
0995c914bd | ||
|
|
cbdbc96e36 | ||
|
|
8941cc5f6d | ||
|
|
15c5226bd3 | ||
|
|
009c32d863 | ||
|
|
d7f8a25db1 | ||
|
|
af067e17fb | ||
|
|
3df1fbc6b9 | ||
|
|
87a4f6d47e | ||
|
|
731fc033dd | ||
|
|
dd36c84a7b | ||
|
|
7f17512d18 | ||
|
|
2a1599297b | ||
|
|
efb36c0daf |
170 changed files with 2621 additions and 951 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
|
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
|
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
|
"critical fixes only" status, which means that they will rarely receive a fix
|
||||||
but if that a critital issue affects them, a release will be made, with or
|
but if that a critical issue affects them, a release will be made, with or
|
||||||
without any other fix. Once a version is not supported anymore, it will not
|
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
|
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
|
recent branch. Please note that even when an upgrade is needed, a great care is
|
||||||
|
|
|
||||||
144
CHANGELOG
144
CHANGELOG
|
|
@ -1,6 +1,150 @@
|
||||||
ChangeLog :
|
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
|
2026/05/08 : 3.4-dev11
|
||||||
- BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
|
- BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
|
||||||
- BUG/MINOR: acme: skip auth/challenge steps when newOrder returns a certificate
|
- 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
|
may want to retry with "gmake" which is the name commonly used for GNU make
|
||||||
on BSD systems.
|
on BSD systems.
|
||||||
|
|
||||||
- GCC >= 4.7 (up to 15 tested). Older versions are no longer supported due to
|
- GCC >= 4.7 (up to 16 tested). Older versions are no longer supported due to
|
||||||
the latest mt_list update which only uses c11-like atomics. Newer versions
|
the latest mt_list update which only uses c11-like atomics. Newer versions
|
||||||
may sometimes break due to compiler regressions or behaviour changes. The
|
may sometimes break due to compiler regressions or behaviour changes. The
|
||||||
version shipped with your operating system is very likely to work with no
|
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
|
trouble. Clang >= 3.0 is also known to work as an alternative solution, and
|
||||||
versions up to 19 were successfully tested. Recent versions may emit a bit
|
versions up to 21 were successfully tested. Recent versions may emit a bit
|
||||||
more warnings that are worth reporting as they may reveal real bugs. TCC
|
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
|
(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
|
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
|
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
|
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 3.6. It is recommended to use
|
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
|
||||||
at least OpenSSL 1.1.1 to have support for all SSL keywords and configuration
|
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,
|
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
|
and each of the branches above receives its own fixes, without forcing you to
|
||||||
|
|
|
||||||
10
Makefile
10
Makefile
|
|
@ -44,6 +44,7 @@
|
||||||
# USE_CLOSEFROM : enable use of closefrom() on *bsd, solaris. Automatic.
|
# USE_CLOSEFROM : enable use of closefrom() on *bsd, solaris. Automatic.
|
||||||
# USE_PRCTL : enable use of prctl(). Automatic.
|
# USE_PRCTL : enable use of prctl(). Automatic.
|
||||||
# USE_PROCCTL : enable use of procctl(). 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_ZLIB : enable zlib library support and disable SLZ
|
||||||
# USE_SLZ : enable slz library instead of zlib (default=enabled)
|
# USE_SLZ : enable slz library instead of zlib (default=enabled)
|
||||||
# USE_CPU_AFFINITY : enable pinning processes to CPU on Linux. Automatic.
|
# USE_CPU_AFFINITY : enable pinning processes to CPU on Linux. Automatic.
|
||||||
|
|
@ -343,7 +344,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER USE_POLL \
|
||||||
USE_TPROXY USE_LINUX_TPROXY USE_LINUX_CAP \
|
USE_TPROXY USE_LINUX_TPROXY USE_LINUX_CAP \
|
||||||
USE_LINUX_SPLICE USE_LIBCRYPT USE_CRYPT_H USE_ENGINE \
|
USE_LINUX_SPLICE USE_LIBCRYPT USE_CRYPT_H USE_ENGINE \
|
||||||
USE_GETADDRINFO USE_OPENSSL USE_OPENSSL_WOLFSSL USE_OPENSSL_AWSLC \
|
USE_GETADDRINFO USE_OPENSSL USE_OPENSSL_WOLFSSL USE_OPENSSL_AWSLC \
|
||||||
USE_ECH \
|
USE_ECH USE_TRACE \
|
||||||
USE_SSL USE_LUA USE_ACCEPT4 USE_CLOSEFROM USE_ZLIB USE_SLZ \
|
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_CPU_AFFINITY USE_TFO USE_NS USE_DL USE_RT USE_LIBATOMIC \
|
||||||
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
|
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
|
||||||
|
|
@ -366,6 +367,9 @@ $(warn_unknown_options)
|
||||||
# on the make command line.
|
# on the make command line.
|
||||||
USE_POLL = default
|
USE_POLL = default
|
||||||
|
|
||||||
|
# traces are always enabled
|
||||||
|
USE_TRACE = default
|
||||||
|
|
||||||
# SLZ is always supported unless explicitly disabled by passing USE_SLZ=""
|
# SLZ is always supported unless explicitly disabled by passing USE_SLZ=""
|
||||||
# or disabled by enabling ZLIB using USE_ZLIB=1
|
# or disabled by enabling ZLIB using USE_ZLIB=1
|
||||||
ifeq ($(USE_ZLIB:0=),)
|
ifeq ($(USE_ZLIB:0=),)
|
||||||
|
|
@ -667,11 +671,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/quic_cc_bbr.o src/quic_retry.o \
|
||||||
src/cfgparse-quic.o src/xprt_quic.o src/quic_token.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/quic_ack.o src/qpack-dec.o src/quic_cc_newreno.o \
|
||||||
src/qmux_http.o src/qmux_trace.o src/quic_rules.o \
|
src/qcm_http.o src/qcm_trace.o src/quic_rules.o \
|
||||||
src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.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/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/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o \
|
||||||
src/quic_enc.o src/mux_quic_qstrm.o src/xprt_qstrm.o \
|
src/quic_enc.o src/qcm_qmux.o src/xprt_qmux.o \
|
||||||
src/mpring.o
|
src/mpring.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
||||||
2
VERDATE
2
VERDATE
|
|
@ -1,2 +1,2 @@
|
||||||
$Format:%ci$
|
$Format:%ci$
|
||||||
2026/05/08
|
2026/05/20
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
3.4-dev11
|
3.4-dev13
|
||||||
|
|
|
||||||
|
|
@ -550,6 +550,8 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
|
||||||
char valuesBuffer[1024];
|
char valuesBuffer[1024];
|
||||||
#endif
|
#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 */
|
char no_data[] = "NoData"; /* response when no data could be found */
|
||||||
struct buffer *temp = get_trash_chunk();
|
struct buffer *temp = get_trash_chunk();
|
||||||
int i = 0, found;
|
int i = 0, found;
|
||||||
|
|
@ -636,6 +638,7 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
|
||||||
smp->data.u.str.area = temp->area;
|
smp->data.u.str.area = temp->area;
|
||||||
smp->data.u.str.data = temp->data;
|
smp->data.u.str.data = temp->data;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sets the sample data as a constant string. This ensures that the
|
/* Sets the sample data as a constant string. This ensures that the
|
||||||
* string will be processed correctly.
|
* string will be processed correctly.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Configuration Manual
|
Configuration Manual
|
||||||
----------------------
|
----------------------
|
||||||
version 3.4
|
version 3.4
|
||||||
2026/05/08
|
2026/05/20
|
||||||
|
|
||||||
|
|
||||||
This document covers the configuration language as implemented in the version
|
This document covers the configuration language as implemented in the version
|
||||||
|
|
@ -2001,6 +2001,7 @@ The following keywords are supported in the "global" section :
|
||||||
- tune.sndbuf.client
|
- tune.sndbuf.client
|
||||||
- tune.sndbuf.frontend
|
- tune.sndbuf.frontend
|
||||||
- tune.sndbuf.server
|
- tune.sndbuf.server
|
||||||
|
- tune.streams-elasticity
|
||||||
- tune.stick-counters
|
- tune.stick-counters
|
||||||
- tune.ssl.cachesize
|
- tune.ssl.cachesize
|
||||||
- tune.ssl.capture-buffer-size
|
- tune.ssl.capture-buffer-size
|
||||||
|
|
@ -2125,13 +2126,28 @@ ca-base <dir>
|
||||||
directives. Absolute locations specified in "ca-file", "ca-verify-file" and
|
directives. Absolute locations specified in "ca-file", "ca-verify-file" and
|
||||||
"crl-file" prevail and ignore "ca-base".
|
"crl-file" prevail and ignore "ca-base".
|
||||||
|
|
||||||
chroot <jail dir>
|
chroot { <jail dir> | auto }
|
||||||
Changes current directory to <jail dir> and performs a chroot() there before
|
Changes current directory to <jail dir> and performs a chroot() there before
|
||||||
dropping privileges. This increases the security level in case an unknown
|
dropping privileges. This increases the security level in case an unknown
|
||||||
vulnerability would be exploited, since it would make it very hard for the
|
vulnerability would be exploited, since it would make it very hard for the
|
||||||
attacker to exploit the system. This only works when the process is started
|
attacker to exploit the system. It is important to ensure that <jail dir>
|
||||||
with superuser privileges. It is important to ensure that <jail_dir> is both
|
is both empty and non-writable to anyone. When the process is started with
|
||||||
empty and non-writable to anyone.
|
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.
|
||||||
|
|
||||||
close-spread-time <time>
|
close-spread-time <time>
|
||||||
Define a time window during which idle connections and active connections
|
Define a time window during which idle connections and active connections
|
||||||
|
|
@ -3313,7 +3329,7 @@ setenv <name> <value>
|
||||||
the configuration file sees the new value. See also "presetenv", "resetenv",
|
the configuration file sees the new value. See also "presetenv", "resetenv",
|
||||||
and "unsetenv".
|
and "unsetenv".
|
||||||
|
|
||||||
shm-stats-file <name> [ EXPERIMENTAL ]
|
shm-stats-file <name>
|
||||||
When this directive is set, it enables the use of shared memory for storing
|
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
|
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
|
memory at a unique location. It also means that the directive is only
|
||||||
|
|
@ -3329,7 +3345,7 @@ shm-stats-file <name> [ EXPERIMENTAL ]
|
||||||
|
|
||||||
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
|
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
|
||||||
|
|
||||||
shm-stats-file-max-objects <number> [ EXPERIMENTAL ]
|
shm-stats-file-max-objects <number>
|
||||||
This setting defines the maximum number of objects the shared memory used
|
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
|
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
|
related to the maximum memory size of the shm and is used to "premap" the
|
||||||
|
|
@ -5305,17 +5321,26 @@ tune.quic.frontend.stream-data-ratio <0..100, in percent> (deprecated)
|
||||||
|
|
||||||
tune.quic.be.stream.max-concurrent <number>
|
tune.quic.be.stream.max-concurrent <number>
|
||||||
tune.quic.fe.stream.max-concurrent <number>
|
tune.quic.fe.stream.max-concurrent <number>
|
||||||
Sets the QUIC initial_max_streams_bidi transport parameter either on frontend
|
On frontend side, this is used as the value for the advertised
|
||||||
or backend side. This is the maximum number of bidirectional streams that the
|
initial_max_streams_bidi transport parameter. This is enforced as the maximum
|
||||||
remote peer will be authorized to open concurrently during the connection
|
number of bidirectional streams that the remote peer will be authorized to
|
||||||
lifetime. On frontend side, this limits the number of concurrent HTTP/3
|
open concurrently during the connection lifetime. This effectively limits the
|
||||||
client requests.
|
number of concurrent HTTP/3 client requests.
|
||||||
|
|
||||||
The default value is 100. Note that if you reduces it, it can restrict the
|
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
|
buffering capabilities of streams on receive, which would result in poor
|
||||||
upload throughput. It can be corrected by increasing the QUIC stream rxbuf
|
upload throughput. It can be corrected by increasing the QUIC stream rxbuf
|
||||||
connection setting.
|
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",
|
See also: "tune.quic.be.stream.rxbuf", "tune.quic.fe.stream.rxbuf",
|
||||||
"tune.quic.be.stream.data-ratio", "tune.quic.fe.stream.data-ratio"
|
"tune.quic.be.stream.data-ratio", "tune.quic.fe.stream.data-ratio"
|
||||||
|
|
||||||
|
|
@ -5689,6 +5714,49 @@ tune.ssl.ssl-ctx-cache-size <number>
|
||||||
dynamically is expensive, they are cached. The default cache size is set to
|
dynamically is expensive, they are cached. The default cache size is set to
|
||||||
1000 entries.
|
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>
|
tune.stick-counters <number>
|
||||||
Sets the number of stick-counters that may be tracked at the same time by a
|
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
|
connection or a request via "track-sc*" actions in "tcp-request" or
|
||||||
|
|
@ -8226,7 +8294,10 @@ hash-type <method> <function> <modifier>
|
||||||
|
|
||||||
none don't hash the key, the key will be used as a hash, this can be
|
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
|
useful to manually hash the key using a converter for that purpose
|
||||||
and let haproxy use the result directly.
|
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).
|
||||||
|
|
||||||
<modifier> indicates an optional method applied after hashing the key :
|
<modifier> indicates an optional method applied after hashing the key :
|
||||||
|
|
||||||
|
|
@ -18813,6 +18884,21 @@ hash-key <key>
|
||||||
better only use values comprised between 1 and this value to
|
better only use values comprised between 1 and this value to
|
||||||
avoid overlap.
|
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
|
addr The node keys will be derived from the server's address, when
|
||||||
available, or else fall back on "id".
|
available, or else fall back on "id".
|
||||||
|
|
||||||
|
|
@ -18842,9 +18928,13 @@ healthcheck <name>
|
||||||
id <value>
|
id <value>
|
||||||
May be used in the following contexts: tcp, http, log
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
Set a persistent ID for the server. This ID must be positive and unique for
|
Set a persistent ID for the server. This ID must be a 32-bit positive number
|
||||||
the proxy. An unused ID will automatically be assigned if unset. The first
|
and unique for the proxy. An unused ID will automatically be assigned if
|
||||||
assigned value will be 1. This ID is currently only returned in statistics.
|
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.
|
||||||
|
|
||||||
idle-ping <delay>
|
idle-ping <delay>
|
||||||
May be used in the following contexts: tcp, http, log
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
@ -18938,7 +19028,7 @@ downinter <delay>
|
||||||
"inter" setting will have a very limited effect as it will not be able to
|
"inter" setting will have a very limited effect as it will not be able to
|
||||||
reduce the time spent in the queue.
|
reduce the time spent in the queue.
|
||||||
|
|
||||||
init-state { fully-up | up | down | fully-down }
|
init-state { fully-up | up | down | fully-down | none }
|
||||||
May be used in the following contexts: tcp, http
|
May be used in the following contexts: tcp, http
|
||||||
|
|
||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
|
|
@ -18946,20 +19036,25 @@ init-state { fully-up | up | down | fully-down }
|
||||||
|
|
||||||
The "init-state" option sets the initial state of the server:
|
The "init-state" option sets the initial state of the server:
|
||||||
- when set to 'fully-up', the server is considered immediately available
|
- when set to 'fully-up', the server is considered immediately available
|
||||||
and can turn to the DOWN state when ALL health checks fail.
|
and, if health checks are enabled for this server, it will be turned to
|
||||||
- when set to 'up' (the default), the server is considered immediately
|
the DOWN state when ALL health checks fail.
|
||||||
available and will initiate a health check that can turn it to the DOWN
|
- when set to 'up', the server is considered immediately available and, if
|
||||||
state immediately if it fails.
|
health checks are enabled for this server, it will be turned to the DOWN
|
||||||
- when set to 'down', the server initially is considered unavailable and
|
state immediately if the next health check fails.
|
||||||
will initiate a health check that can turn it to the UP state immediately
|
- when set to 'down', the server initially is considered unavailable and,
|
||||||
if it succeeds.
|
if health checks are enabled for this server, it can be turned to the UP
|
||||||
|
state if the next health check succeeds.
|
||||||
- when set to 'fully-down', the server is initially considered unavailable
|
- when set to 'fully-down', the server is initially considered unavailable
|
||||||
and can turn to the UP state when ALL health checks succeed.
|
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.
|
||||||
|
|
||||||
The server's init-state is considered when the HAProxy instance is
|
The server's init-state is considered when the HAProxy instance is
|
||||||
(re)started, a new server is detected (for example via service discovery /
|
(re)started, a new server is detected (for example via service discovery /
|
||||||
DNS resolution), a dynamic server is inlived, a server exits maintenance,
|
DNS resolution), a dynamic server is inlived, a server exits maintenance,
|
||||||
etc.
|
etc. This directive cannot be used when the server is tracking another one.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
# pass client traffic ONLY to Redis "master" node
|
# pass client traffic ONLY to Redis "master" node
|
||||||
|
|
@ -20155,7 +20250,11 @@ a cache of previous answers, an answer will be considered obsolete after
|
||||||
|
|
||||||
|
|
||||||
resolvers <resolvers id>
|
resolvers <resolvers id>
|
||||||
Creates a new name server list labeled <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.
|
||||||
|
|
||||||
A resolvers section accept the following parameters:
|
A resolvers section accept the following parameters:
|
||||||
|
|
||||||
|
|
@ -21111,6 +21210,8 @@ param(name[,delim]) string string
|
||||||
port_only string integer
|
port_only string integer
|
||||||
protobuf(field_number[,field_type]) binary binary
|
protobuf(field_number[,field_type]) binary binary
|
||||||
regsub(regex,subst[,flags]) string string
|
regsub(regex,subst[,flags]) string string
|
||||||
|
reverse string string
|
||||||
|
reverse_dom string string
|
||||||
rfc7239_field(field) string string
|
rfc7239_field(field) string string
|
||||||
rfc7239_is_valid string boolean
|
rfc7239_is_valid string boolean
|
||||||
rfc7239_n2nn string address / str
|
rfc7239_n2nn string address / str
|
||||||
|
|
@ -22608,6 +22709,58 @@ 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)']
|
||||||
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>)
|
rfc7239_field(<field>)
|
||||||
Extracts a single field/parameter from RFC 7239 compliant header value input.
|
Extracts a single field/parameter from RFC 7239 compliant header value input.
|
||||||
|
|
||||||
|
|
|
||||||
229
doc/internals/core-principles.txt
Normal file
229
doc/internals/core-principles.txt
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
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,37 +3095,40 @@ show events [<sink>] [-w] [-n] [-0]
|
||||||
delimited by a line feed character ('\n' or 10 or 0x0A). It is possible to
|
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.
|
change this to the NUL character ('\0' or 0) by passing the "-0" argument.
|
||||||
|
|
||||||
show fd [-!plcfbsd]* [<fd>]
|
show fd [-!plcfbsd]* [[<tgid>]/[<fd>] | <fd>]
|
||||||
Dump the list of either all open file descriptors or just the one number <fd>
|
Dump the list of either all open file descriptors or just the one number <fd>
|
||||||
if specified. A set of flags may optionally be passed to restrict the dump
|
if specified. The form "<tgid>/<fd>" is also accepted, where either side may
|
||||||
only to certain FD types or to omit certain FD types. When '-' or '!' are
|
be empty as a wildcard ("/<fd>" for fd <fd> across thread groups, "<tgid>/"
|
||||||
encountered, the selection is inverted for the following characters in the
|
for all fds of <tgid>). The <tgid> is currently parsed but ignored, pending
|
||||||
same argument. The inversion is reset before each argument word delimited by
|
future support for per-thread-group fd tables. A set of flags may optionally
|
||||||
white spaces. Selectable FD types include 'p' for pipes, 'l' for listeners,
|
be passed to restrict the dump only to certain FD types or to omit certain FD
|
||||||
'c' for connections (any type), 'f' for frontend connections, 'b' for backend
|
types. When '-' or '!' are encountered, the selection is inverted for the
|
||||||
connections (any type), 's' for connections to servers, 'd' for connections
|
following characters in the same argument. The inversion is reset before each
|
||||||
to the "dispatch" address or the backend's transparent address. With this,
|
argument word delimited by white spaces. Selectable FD types include 'p' for
|
||||||
'b' is a shortcut for 'sd' and 'c' for 'fb' or 'fsd'. 'c!f' is equivalent to
|
pipes, 'l' for listeners, 'c' for connections (any type), 'f' for frontend
|
||||||
'b' ("any connections except frontend connections" are indeed backend
|
connections, 'b' for backend connections (any type), 's' for connections to
|
||||||
connections). This is only aimed at developers who need to observe internal
|
servers, 'd' for connections to the "dispatch" address or the backend's
|
||||||
states in order to debug complex issues such as abnormal CPU usages. One fd
|
transparent address. With this, 'b' is a shortcut for 'sd' and 'c' for 'fb' or
|
||||||
is reported per lines, and for each of them, its state in the poller using
|
'fsd'. 'c!f' is equivalent to 'b' ("any connections except frontend
|
||||||
upper case letters for enabled flags and lower case for disabled flags, using
|
connections" are indeed backend connections). This is only aimed at developers
|
||||||
"P" for "polled", "R" for "ready", "A" for "active", the events status using
|
who need to observe internal states in order to debug complex issues such as
|
||||||
"H" for "hangup", "E" for "error", "O" for "output", "P" for "priority" and
|
abnormal CPU usages. One fd is reported per lines, and for each of them, its
|
||||||
"I" for "input", a few other flags like "N" for "new" (just added into the fd
|
state in the poller using upper case letters for enabled flags and lower case
|
||||||
cache), "U" for "updated" (received an update in the fd cache), "L" for
|
for disabled flags, using "P" for "polled", "R" for "ready", "A" for "active",
|
||||||
"linger_risk", "C" for "cloned", then the cached entry position, the pointer
|
the events status using "H" for "hangup", "E" for "error", "O" for "output",
|
||||||
to the internal owner, the pointer to the I/O callback and its name when
|
"P" for "priority" and "I" for "input", a few other flags like "N" for "new"
|
||||||
known. When the owner is a connection, the connection flags, and the target
|
(just added into the fd cache), "U" for "updated" (received an update in the
|
||||||
are reported (frontend, proxy or server). When the owner is a listener, the
|
fd cache), "L" for "linger_risk", "C" for "cloned", then the cached entry
|
||||||
listener's state and its frontend are reported. There is no point in using
|
position, the pointer to the internal owner, the pointer to the I/O callback
|
||||||
this command without a good knowledge of the internals. It's worth noting
|
and its name when known. When the owner is a connection, the connection flags,
|
||||||
that the output format may evolve over time so this output must not be parsed
|
and the target are reported (frontend, proxy or server). When the owner is a
|
||||||
by tools designed to be durable. Some internal structure states may look
|
listener, the listener's state and its frontend are reported. There is no
|
||||||
suspicious to the function listing them, in this case the output line will be
|
point in using this command without a good knowledge of the internals. It's
|
||||||
suffixed with an exclamation mark ('!'). This may help find a starting point
|
worth noting that the output format may evolve over time so this output must
|
||||||
when trying to diagnose an incident.
|
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]
|
show info [typed|json] [desc] [float]
|
||||||
Dump info about haproxy status on current process. If "typed" is passed as an
|
Dump info about haproxy status on current process. If "typed" is passed as an
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
2020/03/05 Willy Tarreau
|
2026/04/27 Willy Tarreau
|
||||||
HAProxy Technologies
|
HAProxy Technologies
|
||||||
The PROXY protocol
|
The PROXY protocol
|
||||||
Versions 1 & 2
|
Versions 1 & 2
|
||||||
|
|
@ -31,6 +31,7 @@ Revision history
|
||||||
2025/09/09 - added SSL-related TLVs for key exchange group and signature
|
2025/09/09 - added SSL-related TLVs for key exchange group and signature
|
||||||
scheme (Steven Collison)
|
scheme (Steven Collison)
|
||||||
2026/01/15 - added SSL client certificate TLV (Simon Ser)
|
2026/01/15 - added SSL client certificate TLV (Simon Ser)
|
||||||
|
2026/04/27 - clarified UDP usage (Valaphee)
|
||||||
|
|
||||||
1. Background
|
1. Background
|
||||||
|
|
||||||
|
|
@ -175,6 +176,11 @@ 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
|
the protocol header is not seen within a few seconds (at least 3 seconds to
|
||||||
cover a TCP retransmit).
|
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
|
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
|
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
|
or not. This means that the protocol explicitly prevents port sharing between
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@ traces
|
||||||
trace applet verbosity complete start now
|
trace applet verbosity complete start now
|
||||||
trace h3 start now
|
trace h3 start now
|
||||||
trace quic start now
|
trace quic start now
|
||||||
trace qmux start now
|
trace qcm start now
|
||||||
trace peers start now
|
trace peers start now
|
||||||
.endif
|
.endif
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
extern struct userlist *userlist;
|
extern struct userlist *userlist;
|
||||||
|
|
||||||
struct userlist *auth_find_userlist(char *name);
|
struct userlist *auth_find_userlist(char *name);
|
||||||
unsigned int auth_resolve_groups(struct userlist *l, char *groups);
|
|
||||||
int userlist_postinit();
|
int userlist_postinit();
|
||||||
void userlist_free(struct userlist *ul);
|
void userlist_free(struct userlist *ul);
|
||||||
struct pattern *pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill);
|
struct pattern *pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill);
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ struct lbprm_per_tgrp {
|
||||||
* The other ones might take it themselves if needed.
|
* The other ones might take it themselves if needed.
|
||||||
*/
|
*/
|
||||||
struct lb_ops {
|
struct lb_ops {
|
||||||
|
struct list link;
|
||||||
int (*proxy_init)(struct proxy *); /* set up per-proxy LB state at config time; <0=fail */
|
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 (*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 */
|
void (*set_server_status_up)(struct server *); /* to be called after status changes to UP // srvlock */
|
||||||
|
|
@ -166,6 +167,11 @@ struct lb_ops {
|
||||||
void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */
|
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 */
|
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. */
|
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 */
|
/* LB parameters for all algorithms */
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@
|
||||||
#include <haproxy/stream-t.h>
|
#include <haproxy/stream-t.h>
|
||||||
#include <haproxy/time.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_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_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);
|
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_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 */
|
#define CF_FLT_ANALYZE 0x20000000 /* at least one filter is still analyzing this channel */
|
||||||
/* unuse 0x40000000 */
|
/* unused 0x40000000 */
|
||||||
#define CF_ISRESP 0x80000000 /* 0 = request channel, 1 = response channel */
|
#define CF_ISRESP 0x80000000 /* 0 = request channel, 1 = response channel */
|
||||||
|
|
||||||
/* Masks which define input events for stream analysers */
|
/* Masks which define input events for stream analysers */
|
||||||
|
|
@ -252,27 +252,30 @@ struct channel {
|
||||||
* without waking the parent up. The special value CHN_INFINITE_FORWARD is
|
* without waking the parent up. The special value CHN_INFINITE_FORWARD is
|
||||||
* never decreased nor increased.
|
* never decreased nor increased.
|
||||||
*
|
*
|
||||||
* The buf->o parameter says how many bytes may be consumed from the visible
|
* The channel's consumed data count (b_data(chn->buf)) says how many bytes may
|
||||||
* buffer. This parameter is updated by any buffer_write() as well as any data
|
* be consumed from the visible buffer. This is updated by any buffer_write()
|
||||||
* forwarded through the visible buffer. Since the ->to_forward attribute
|
* as well as any data forwarded through the visible buffer. Since the
|
||||||
* applies to data after buf->p, an analyser will not see a buffer which has a
|
* ->to_forward attribute applies to data beyond what's already been accounted
|
||||||
* non-null ->to_forward with buf->i > 0. A producer is responsible for raising
|
* for, an analyser will not see a buffer which has a non-null ->to_forward
|
||||||
* buf->o by min(to_forward, buf->i) when it injects data into the buffer.
|
* 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 consumer is responsible for decreasing ->buf->o when it sends data
|
* The consumer is responsible for advancing the consumed count (via
|
||||||
* from the visible buffer, and ->pipe->data when it sends data from the
|
* b_ack()) when it sends data from the visible buffer, and for updating
|
||||||
* invisible buffer.
|
* ->pipe->data when it sends data from the invisible buffer.
|
||||||
*
|
*
|
||||||
* A real-world example consists in part in an HTTP response waiting in a
|
* 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
|
* 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
|
* 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
|
* bytes of data after the 300 bytes of headers. Thus the caller will set
|
||||||
* buf->o to 300 indicating that it explicitly wants to send those data, and
|
* the consumed count to 300 indicating that it explicitly wants to send those
|
||||||
* set ->to_forward to 9000 (content-length). This value must be normalised
|
* data, and set ->to_forward to 9000 (content-length). This value must be
|
||||||
* immediately after updating ->to_forward : since there are already 1300 bytes
|
* normalised immediately after updating ->to_forward : since there are already
|
||||||
* in the buffer, 300 of which are already counted in buf->o, and that size
|
* 1300 bytes in the buffer, 300 of which are already counted in the consumed
|
||||||
* is smaller than ->to_forward, we must update buf->o to 1300 to flush the
|
* count, and that size is smaller than ->to_forward, we must update the
|
||||||
* whole buffer, and reduce ->to_forward to 8000. After that, the producer may
|
* consumed count 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
|
* try to feed the additional data through the invisible buffer using a
|
||||||
* platform-specific method such as splice().
|
* platform-specific method such as splice().
|
||||||
*
|
*
|
||||||
|
|
@ -291,15 +294,16 @@ struct channel {
|
||||||
* buf->size - global.maxrewrite + ->to_forward.
|
* buf->size - global.maxrewrite + ->to_forward.
|
||||||
*
|
*
|
||||||
* A buffer may contain up to 5 areas :
|
* A buffer may contain up to 5 areas :
|
||||||
* - the data waiting to be sent. These data are located between buf->p-o and
|
* - the data already consumed (acknowledged). These data are located between
|
||||||
* buf->p ;
|
* b_lim(b) and b_head(b) ;
|
||||||
* - the data to process and possibly transform. These data start at
|
* - the data available to process and possibly transform. These data start at
|
||||||
* buf->p and may be up to ->i bytes long.
|
* b_head(b) and may be up to b_data(b) bytes long.
|
||||||
* - the data to preserve. They start at ->p and stop at ->p+i. The limit
|
* - the data to preserve. They start at b_head(b) and stop at
|
||||||
* between the two solely depends on the protocol being analysed.
|
* b_lim(b) + b_data(b). 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
|
* - the spare area : it is the remainder of the buffer, which can be used to
|
||||||
* store new incoming data. It starts at ->p+i and is up to ->size-i-o long.
|
* store new incoming data. It starts at b_lim(b) + b_data(b) and is up to
|
||||||
* It may be limited by global.maxrewrite.
|
* b->size - b_data(b) long. It may be limited by global.maxrewrite.
|
||||||
* - the reserved area : this is the area which must not be filled and is
|
* - 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
|
* reserved for possible rewrites ; it is up to global.maxrewrite bytes
|
||||||
* long.
|
* 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));
|
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 he HTX streams into
|
/* Returns the amount of input data in a channel, taking the HTX streams into
|
||||||
* account. This function relies on channel_data().
|
* account. This function relies on channel_data().
|
||||||
*/
|
*/
|
||||||
static inline size_t channel_input_data(const struct channel *chn)
|
static inline size_t channel_input_data(const struct channel *chn)
|
||||||
|
|
@ -816,12 +816,6 @@ static inline size_t channel_input_data(const struct channel *chn)
|
||||||
return channel_data(chn) - co_data(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
|
/* Check channel's last_read date against the idle timeer to verify the producer
|
||||||
* is still streaming data or not
|
* is still streaming data or not
|
||||||
*/
|
*/
|
||||||
|
|
@ -861,7 +855,7 @@ static inline void channel_check_xfer(struct channel *chn, size_t xferred)
|
||||||
chn->flags &= ~(CF_STREAMER | CF_STREAMER_FAST);
|
chn->flags &= ~(CF_STREAMER | CF_STREAMER_FAST);
|
||||||
}
|
}
|
||||||
else if (chn->xfer_small >= 2) {
|
else if (chn->xfer_small >= 2) {
|
||||||
/* if the buffer has been at least half full twchne,
|
/* if the buffer has been at least half full times,
|
||||||
* we receive faster than we send, so at least it
|
* we receive faster than we send, so at least it
|
||||||
* is not a "fast streamer".
|
* is not a "fast streamer".
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -583,10 +583,12 @@
|
||||||
* for such array declarations. But it's not the case for clang and other
|
* for such array declarations. But it's not the case for clang and other
|
||||||
* compilers.
|
* compilers.
|
||||||
*/
|
*/
|
||||||
#if __has_attribute(nonstring)
|
#ifndef __nonstring
|
||||||
#define __nonstring __attribute__ ((nonstring))
|
# if __has_attribute(nonstring)
|
||||||
#else
|
# define __nonstring __attribute__ ((nonstring))
|
||||||
#define __nonstring
|
# else
|
||||||
|
# define __nonstring
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _HAPROXY_COMPILER_H */
|
#endif /* _HAPROXY_COMPILER_H */
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ struct comp_ctx {
|
||||||
struct slz_stream strm;
|
struct slz_stream strm;
|
||||||
const void *direct_ptr; /* NULL or pointer to beginning of data */
|
const void *direct_ptr; /* NULL or pointer to beginning of data */
|
||||||
int direct_len; /* length of direct_ptr if not NULL */
|
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)
|
#elif defined(USE_ZLIB)
|
||||||
z_stream strm; /* zlib stream */
|
z_stream strm; /* zlib stream */
|
||||||
void *zlib_deflate_state;
|
void *zlib_deflate_state;
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,8 @@ enum {
|
||||||
|
|
||||||
CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */
|
CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */
|
||||||
|
|
||||||
CO_FL_QSTRM_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
|
CO_FL_QMUX_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 */
|
CO_FL_QMUX_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 */
|
/* These flags indicate whether the Control and Transport layers are initialized */
|
||||||
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */
|
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */
|
||||||
|
|
@ -179,6 +179,8 @@ enum {
|
||||||
/* below we have all handshake flags grouped into one */
|
/* 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_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,
|
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 */
|
CO_FL_SSL_WAIT_HS = 0x08000000, /* wait for an SSL handshake to complete */
|
||||||
|
|
||||||
|
|
@ -213,7 +215,7 @@ static forceinline char *conn_show_flags(char *buf, size_t len, const char *deli
|
||||||
/* flags */
|
/* flags */
|
||||||
_(CO_FL_SAFE_LIST, _(CO_FL_IDLE_LIST, _(CO_FL_CTRL_READY,
|
_(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_REVERSED, _(CO_FL_ACT_REVERSING, _(CO_FL_OPT_MARK, _(CO_FL_OPT_TOS,
|
||||||
_(CO_FL_QSTRM_SEND, _(CO_FL_QSTRM_RECV,
|
_(CO_FL_QMUX_SEND, _(CO_FL_QMUX_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_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_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,
|
_(CO_FL_SOCK_WR_SH, _(CO_FL_ERROR, _(CO_FL_FDLESS, _(CO_FL_WAIT_L4_CONN,
|
||||||
|
|
@ -285,7 +287,7 @@ enum {
|
||||||
|
|
||||||
CO_ER_SSL_FATAL, /* SSL fatal error during a SSL_read or SSL_write */
|
CO_ER_SSL_FATAL, /* SSL fatal error during a SSL_read or SSL_write */
|
||||||
|
|
||||||
CO_ER_QSTRM, /* QMux transport parameter exchange failure */
|
CO_ER_QMUX, /* QMux transport parameter exchange failure */
|
||||||
|
|
||||||
CO_ER_REVERSE, /* Error during reverse connect */
|
CO_ER_REVERSE, /* Error during reverse connect */
|
||||||
|
|
||||||
|
|
@ -349,7 +351,7 @@ enum {
|
||||||
XPRT_SSL = 1,
|
XPRT_SSL = 1,
|
||||||
XPRT_HANDSHAKE = 2,
|
XPRT_HANDSHAKE = 2,
|
||||||
XPRT_QUIC = 3,
|
XPRT_QUIC = 3,
|
||||||
XPRT_QSTRM = 4,
|
XPRT_QMUX = 4,
|
||||||
XPRT_ENTRIES /* must be last one */
|
XPRT_ENTRIES /* must be last one */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -673,11 +675,12 @@ struct connection {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mux_proto_list {
|
struct mux_proto_list {
|
||||||
const struct ist token; /* token name and length. Empty is catch-all */
|
const struct ist mux_proto; /* Mux protocol, to be used with the "proto" directive */
|
||||||
enum proto_proxy_mode mode;
|
enum proto_proxy_mode mode;
|
||||||
enum proto_proxy_side side;
|
enum proto_proxy_side side;
|
||||||
const struct mux_ops *mux;
|
const struct mux_ops *mux;
|
||||||
const char *alpn; /* Default alpn to set by default when the mux protocol is forced (optional, in binary form) */
|
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;
|
struct list list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,10 @@ 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_notify_mux(struct connection *conn, int old_flags, int forced_wake);
|
||||||
int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
||||||
struct ist mux_proto, int mode);
|
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);
|
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,
|
int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess,
|
||||||
const struct mux_ops *force_mux_ops);
|
const struct mux_ops *force_mux_ops);
|
||||||
int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *sess);
|
int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *sess);
|
||||||
|
|
@ -111,6 +114,7 @@ int conn_reverse(struct connection *conn);
|
||||||
const char *conn_err_code_name(struct connection *c);
|
const char *conn_err_code_name(struct connection *c);
|
||||||
const char *conn_err_code_str(struct connection *c);
|
const char *conn_err_code_str(struct connection *c);
|
||||||
int xprt_add_hs(struct connection *conn);
|
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);
|
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);
|
static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type);
|
||||||
|
|
@ -496,6 +500,64 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
|
||||||
return ret;
|
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
|
/* 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
|
* 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
|
* connection for purposes like source binding or proxy protocol header
|
||||||
|
|
@ -591,7 +653,7 @@ static inline struct mux_proto_list *get_mux_proto(const struct ist proto)
|
||||||
struct mux_proto_list *item;
|
struct mux_proto_list *item;
|
||||||
|
|
||||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||||
if (isteq(proto, item->token))
|
if (isteq(proto, item->mux_proto))
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -610,6 +672,7 @@ void list_mux_proto(FILE *out);
|
||||||
*/
|
*/
|
||||||
static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
||||||
const struct ist mux_proto,
|
const struct ist mux_proto,
|
||||||
|
const struct ist alpn,
|
||||||
int proto_side, int proto_is_quic, int proto_mode)
|
int proto_side, int proto_is_quic, int proto_mode)
|
||||||
{
|
{
|
||||||
struct mux_proto_list *item;
|
struct mux_proto_list *item;
|
||||||
|
|
@ -618,10 +681,14 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
|
||||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
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)))
|
if (!(item->side & proto_side) || !(item->mode & proto_mode) || ((proto_is_quic != 0) != ((item->mux->flags & MX_FL_FRAMED) != 0)))
|
||||||
continue;
|
continue;
|
||||||
if (istlen(mux_proto) && isteq(mux_proto, item->token)) {
|
if (istlen(mux_proto) && isteq(mux_proto, item->mux_proto)) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
else if (!istlen(item->token)) {
|
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)) {
|
||||||
if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode))
|
if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode))
|
||||||
fallback = item;
|
fallback = item;
|
||||||
}
|
}
|
||||||
|
|
@ -638,11 +705,12 @@ 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,
|
static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
|
||||||
const struct ist mux_proto,
|
const struct ist mux_proto,
|
||||||
|
const struct ist alpn,
|
||||||
int proto_side, int proto_mode)
|
int proto_side, int proto_mode)
|
||||||
{
|
{
|
||||||
const struct mux_proto_list *item;
|
const struct mux_proto_list *item;
|
||||||
|
|
||||||
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
|
item = conn_get_best_mux_entry(mux_proto, alpn, proto_side, proto_is_quic(conn->ctrl), proto_mode);
|
||||||
|
|
||||||
return item ? item->mux : NULL;
|
return item ? item->mux : NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
#define DEF_MAX_THREADS_PER_GROUP 16
|
#define DEF_MAX_THREADS_PER_GROUP 16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 4 times
|
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 16 times
|
||||||
* long bits if more tgroups are enabled.
|
* long bits if more tgroups are enabled.
|
||||||
*/
|
*/
|
||||||
#ifndef MAX_THREADS
|
#ifndef MAX_THREADS
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/proto_dgram.h
|
* include/haproxy/dgram.h
|
||||||
* This file provides functions related to DGRAM processing.
|
* This file provides functions related to DGRAM processing.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ static inline int b_may_alloc_for_crit(uint crit)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the emergency buffers are too low, we won't try to allocate a
|
/* 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 corrolary, it
|
* buffer either so that we speed up their release. As a corollary, it
|
||||||
* means that we're always allowed to try to fall back to an emergency
|
* means that we're always allowed to try to fall back to an emergency
|
||||||
* buffer if pool_alloc() fails. The minimum number of available
|
* buffer if pool_alloc() fails. The minimum number of available
|
||||||
* emergency buffers for an allocation depends on the queue:
|
* 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,
|
/* 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
|
* ((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
|
* returned, or NULL in case no memory is available. Since buffers only contain
|
||||||
* user data, poisonning is always disabled as it brings no benefit and impacts
|
* user data, poisoning is always disabled as it brings no benefit and impacts
|
||||||
* performance. Due to the difficult buffer_wait management, they are not
|
* performance. Due to the difficult buffer_wait management, they are not
|
||||||
* subject to forced allocation failures either. If other waiters are present
|
* subject to forced allocation failures either. If other waiters are present
|
||||||
* at higher criticality levels, we refrain from allocating.
|
* at higher criticality levels, we refrain from allocating.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/filteers-t.h
|
* include/haproxy/filters-t.h
|
||||||
* This file defines everything related to stream filters.
|
* This file defines everything related to stream filters.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>
|
* Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,7 @@ struct global {
|
||||||
uint max_checks_per_thread; /* if >0, no more than this concurrent checks per thread */
|
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 ring_queues; /* if >0, #ring queues, otherwise equals #thread groups */
|
||||||
uint cli_max_payload_sz; /* The max payload size for the CLI */
|
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 */
|
enum threadgroup_takeover tg_takeover; /* Policy for threadgroup takeover */
|
||||||
} tune;
|
} tune;
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ enum h1m_state {
|
||||||
#define H1_MF_UPG_WEBSOCKET 0x00008000 // Set for a Websocket upgrade handshake
|
#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_CHUNKED 0x00010000 // T-E "chunked"
|
||||||
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
|
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
|
||||||
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
|
/* unused: 0x00040000 */
|
||||||
#define H1_MF_NOT_HTTP 0x00080000 // Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted)
|
#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.
|
/* 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);
|
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_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_generate_random_ws_input_key(char key_out[25]);
|
||||||
void h1_calculate_ws_output_key(const char *key, char *result);
|
void h1_calculate_ws_output_key(const char *key, char *result);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ struct httpclient {
|
||||||
struct buffer buf; /* input buffer, raw HTTP */
|
struct buffer buf; /* input buffer, raw HTTP */
|
||||||
} res;
|
} res;
|
||||||
struct {
|
struct {
|
||||||
/* callbacks used to send the request, */
|
/* callbacks used to send the request, */
|
||||||
void (*req_payload)(struct httpclient *hc); /* send a payload */
|
void (*req_payload)(struct httpclient *hc); /* send a payload */
|
||||||
|
|
||||||
/* callbacks used to receive the response, if not set, the IO
|
/* 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 */
|
void (*res_end)(struct httpclient *hc); /* end of the response */
|
||||||
} ops;
|
} ops;
|
||||||
struct sockaddr_storage *dst; /* destination address */
|
struct sockaddr_storage *dst; /* destination address */
|
||||||
struct appctx *appctx; /* HTTPclient appctx */
|
struct appctx *appctx; /* HTTP client appctx */
|
||||||
int timeout_server; /* server timeout in ms */
|
int timeout_server; /* server timeout in ms */
|
||||||
void *caller; /* ptr of the caller */
|
void *caller; /* ptr of the caller */
|
||||||
unsigned int flags; /* other flags */
|
unsigned int flags; /* other flags */
|
||||||
|
|
@ -50,7 +50,7 @@ struct httpclient {
|
||||||
#define HTTPCLIENT_FS_ENDED 0x00020000 /* the httpclient is stopped */
|
#define HTTPCLIENT_FS_ENDED 0x00020000 /* the httpclient is stopped */
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must be use an absolute URI */
|
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must use an absolute URI */
|
||||||
#define HTTPCLIENT_O_RES_HTX 0x00000002 /* response is stored in HTX */
|
#define HTTPCLIENT_O_RES_HTX 0x00000002 /* response is stored in HTX */
|
||||||
|
|
||||||
/* States of the HTTP Client Appctx */
|
/* States of the HTTP Client Appctx */
|
||||||
|
|
@ -65,4 +65,4 @@ enum {
|
||||||
|
|
||||||
#define HTTPCLIENT_USERAGENT "HAProxy"
|
#define HTTPCLIENT_USERAGENT "HAProxy"
|
||||||
|
|
||||||
#endif /* ! _HAPROXY_HTTCLIENT__T_H */
|
#endif /* !_HAPROXY_HTTPCLIENT_T_H */
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,4 @@ static inline int httpclient_started(struct httpclient *hc)
|
||||||
return !!(hc->flags & HTTPCLIENT_FS_STARTED);
|
return !!(hc->flags & HTTPCLIENT_FS_STARTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ! _HAPROXY_HTTCLIENT_H */
|
#endif /* !_HAPROXY_HTTPCLIENT_H */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/http_htx-t.h
|
* include/haproxy/http_htx.h
|
||||||
* This file defines function prototypes for HTTP manipulation using the
|
* This file defines function prototypes for HTTP manipulation using the
|
||||||
* internal representation.
|
* internal representation.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
* | HTX | PAYLOADS ==> | | <== HTX_BLKs |
|
* | HTX | PAYLOADS ==> | | <== HTX_BLKs |
|
||||||
* +-----+---------------+------------------------------+--------------+
|
* +-----+---------------+------------------------------+--------------+
|
||||||
* ^
|
* ^
|
||||||
* blocks[] (the beginning of the bocks array)
|
* blocks[] (the beginning of the blocks array)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* The blocks part remains linear and sorted. You may think about it as an 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
|
* 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
|
* 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
|
* the middle are not reusable but count in the available free space. The only
|
||||||
* way to reuse this lost space is to fully defragmenate the HTX message.
|
* way to reuse this lost space is to fully defragment the HTX message.
|
||||||
*
|
*
|
||||||
* - * -
|
* - * -
|
||||||
*
|
*
|
||||||
|
|
@ -113,11 +113,10 @@
|
||||||
* - 0000 = request start-line
|
* - 0000 = request start-line
|
||||||
* - 0001 = response start-line
|
* - 0001 = response start-line
|
||||||
* - 0010 = header
|
* - 0010 = header
|
||||||
* - 0011 = pseudo-header ou "special" header
|
* - 0011 = end-of-headers
|
||||||
* - 0100 = end-of-headers
|
* - 0100 = data
|
||||||
* - 0101 = data
|
* - 0101 = trailer
|
||||||
* - 0110 = trailer
|
* - 0110 = end-of-trailers
|
||||||
* - 0111 = end-of-trailers
|
|
||||||
* ...
|
* ...
|
||||||
* - 1111 = unused
|
* - 1111 = unused
|
||||||
*
|
*
|
||||||
|
|
@ -128,7 +127,7 @@
|
||||||
*/
|
*/
|
||||||
#define HTX_SL_F_NONE 0x00000000
|
#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_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 dertermined */
|
#define HTX_SL_F_XFER_LEN 0x00000002 /* The message xfer size can be determined */
|
||||||
#define HTX_SL_F_XFER_ENC 0x00000004 /* The transfer-encoding header was found in message */
|
#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_CLEN 0x00000008 /* The content-length header was found in message */
|
||||||
#define HTX_SL_F_CHNK 0x00000010 /* The message payload is chunked */
|
#define HTX_SL_F_CHNK 0x00000010 /* The message payload is chunked */
|
||||||
|
|
@ -140,7 +139,7 @@
|
||||||
#define HTX_SL_F_HAS_AUTHORITY 0x00000400 /* The request authority is explicitly specified */
|
#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_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_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
|
||||||
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
|
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyless (only for request) */
|
||||||
#define HTX_SL_F_NOT_HTTP 0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
|
#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
|
/* This function is used to report flags in debugging tools. Please reflect
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,9 @@ 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_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_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_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
|
||||||
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfer header blocks (start-line, header and EOH) */
|
#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 */
|
||||||
|
|
||||||
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
|
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
|
/* Functions and macros to get parts of the start-line or length of these
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,56 @@ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
|
||||||
return result;
|
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 */
|
/* rotate left a 64-bit integer by <bits:[0-5]> bits */
|
||||||
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
|
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,6 @@ struct server;
|
||||||
struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
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);
|
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 */
|
#endif /* _HAPROXY_LB_CHASH_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
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 */
|
#endif /* _HAPROXY_LB_FAS_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
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 */
|
#endif /* _HAPROXY_LB_FWLC_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid);
|
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 */
|
#endif /* _HAPROXY_LB_FWRR_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
|
struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
|
||||||
struct server *map_get_server_hash(struct proxy *px, unsigned int hash);
|
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 */
|
#endif /* _HAPROXY_LB_MAP_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,4 @@
|
||||||
|
|
||||||
struct server *ss_get_server(struct proxy *px);
|
struct server *ss_get_server(struct proxy *px);
|
||||||
|
|
||||||
extern const struct lb_ops lb_ss_ops;
|
|
||||||
|
|
||||||
#endif /* _HAPROXY_LB_SS_H */
|
#endif /* _HAPROXY_LB_SS_H */
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ struct connack {
|
||||||
} user_props[MQTT_PROP_USER_PROPERTY_ENTRIES];
|
} user_props[MQTT_PROP_USER_PROPERTY_ENTRIES];
|
||||||
uint8_t wildcard_subscription_available;
|
uint8_t wildcard_subscription_available;
|
||||||
uint8_t subscription_identifiers_available;
|
uint8_t subscription_identifiers_available;
|
||||||
uint8_t shared_subsription_available;
|
uint8_t shared_subscription_available;
|
||||||
uint16_t server_keepalive;
|
uint16_t server_keepalive;
|
||||||
struct ist response_information;
|
struct ist response_information;
|
||||||
struct ist server_reference;
|
struct ist server_reference;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ struct qcc {
|
||||||
struct list frms; /* prepared frames related to flow-control */
|
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_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 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 */
|
uint64_t cl_bidi_r; /* total count of closed remote bidi stream since last MAX_STREAMS emission */
|
||||||
|
|
||||||
|
|
@ -89,12 +90,12 @@ struct qcc {
|
||||||
struct quic_pacer pacer; /* engine used to pace emission */
|
struct quic_pacer pacer; /* engine used to pace emission */
|
||||||
int paced_sent_ctr; /* counter for when emission is interrupted due to pacing */
|
int paced_sent_ctr; /* counter for when emission is interrupted due to pacing */
|
||||||
};
|
};
|
||||||
/* qstrm */
|
/* qmux */
|
||||||
struct buffer qstrm_buf;
|
struct buffer qmux_buf;
|
||||||
};
|
};
|
||||||
} tx;
|
} tx;
|
||||||
struct {
|
struct {
|
||||||
struct buffer qstrm_buf;
|
struct buffer qmux_buf;
|
||||||
uint64_t rlen; /* last record length read */
|
uint64_t rlen; /* last record length read */
|
||||||
} rx;
|
} rx;
|
||||||
|
|
||||||
|
|
@ -179,7 +180,7 @@ struct qcs {
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
struct qc_stream_desc *stream; /* quic */
|
struct qc_stream_desc *stream; /* quic */
|
||||||
struct buffer qstrm_buf; /* qstrm */
|
struct buffer qmux_buf; /* qmux */
|
||||||
};
|
};
|
||||||
struct quic_fctl fc; /* stream flow control applied on sending */
|
struct quic_fctl fc; /* stream flow control applied on sending */
|
||||||
struct quic_frame *msd_frm; /* MAX_STREAM_DATA frame prepared */
|
struct quic_frame *msd_frm; /* MAX_STREAM_DATA frame prepared */
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <haproxy/connection.h>
|
#include <haproxy/connection.h>
|
||||||
#include <haproxy/list.h>
|
#include <haproxy/list.h>
|
||||||
#include <haproxy/mux_quic-t.h>
|
#include <haproxy/mux_quic-t.h>
|
||||||
|
#include <haproxy/quic_tune.h>
|
||||||
#include <haproxy/stconn.h>
|
#include <haproxy/stconn.h>
|
||||||
|
|
||||||
#include <haproxy/h3.h>
|
#include <haproxy/h3.h>
|
||||||
|
|
@ -53,7 +54,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_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);
|
int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err);
|
||||||
|
|
||||||
static inline int qmux_stream_rx_bufsz(void)
|
static inline int qcm_stream_rx_bufsz(void)
|
||||||
{
|
{
|
||||||
return global.tune.bufsize - NCB_RESERVED_SZ;
|
return global.tune.bufsize - NCB_RESERVED_SZ;
|
||||||
}
|
}
|
||||||
|
|
@ -128,6 +129,9 @@ static inline void qcs_wait_http_req(struct qcs *qcs)
|
||||||
BUG_ON_HOT(qcs->flags & QC_SF_HREQ_RECV);
|
BUG_ON_HOT(qcs->flags & QC_SF_HREQ_RECV);
|
||||||
qcs->flags |= QC_SF_HREQ_RECV;
|
qcs->flags |= QC_SF_HREQ_RECV;
|
||||||
++qcc->nb_hreq;
|
++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);
|
void qcc_show_quic(struct qcc *qcc);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
#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
|
/* 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
|
* it directly to an object type. The object type indicates the format of the
|
||||||
* structure holing the type, and this is used to retrieve the pointer to the
|
* structure holding 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
|
* 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
|
* a pointer and a type for elements such as connections which can point to
|
||||||
* various types of objects.
|
* various types of objects.
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ int protocol_resume_all(void);
|
||||||
int protocol_enable_all(void);
|
int protocol_enable_all(void);
|
||||||
|
|
||||||
/* returns the protocol associated to family <family> with proto_type among the
|
/* returns the protocol associated to family <family> with proto_type among the
|
||||||
* supported protocol types, and ctrl_type of either SOCK_STREAM or SOCK_DGRAM
|
* supported protocol types, and index <alt> (0 or 1) selecting between the two
|
||||||
* depending on the requested values, or NULL if not found.
|
* possible entries per (family, proto_type), or NULL if not found.
|
||||||
*/
|
*/
|
||||||
static inline struct protocol *protocol_lookup(int family, enum proto_type proto_type, int alt)
|
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 (*show)(struct buffer *, const struct error_snapshot *));
|
||||||
void proxy_adjust_all_maxconn(void);
|
void proxy_adjust_all_maxconn(void);
|
||||||
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
|
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
|
||||||
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
|
struct proxy *cli_find_backend(struct appctx *appctx, const char *arg);
|
||||||
int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
|
int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
|
||||||
void free_stick_rules(struct list *rules);
|
void free_stick_rules(struct list *rules);
|
||||||
void free_server_rules(struct list *srules);
|
void free_server_rules(struct list *srules);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _HAPROXY_MUX_QUIC_HTTP_H
|
#ifndef _HAPROXY_QCM_HTTP_H
|
||||||
#define _HAPROXY_MUX_QUIC_HTTP_H
|
#define _HAPROXY_QCM_HTTP_H
|
||||||
|
|
||||||
#ifdef USE_QUIC
|
#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 /* USE_QUIC */
|
||||||
|
|
||||||
#endif /* _HAPROXY_MUX_QUIC_HTTP_H */
|
#endif /* _HAPROXY_QCM_HTTP_H */
|
||||||
10
include/haproxy/qcm_qmux.h
Normal file
10
include/haproxy/qcm_qmux.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#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_QMUX_TRACE_H
|
#ifndef _HAPROXY_QCM_TRACE_H
|
||||||
#define _HAPROXY_QMUX_TRACE_H
|
#define _HAPROXY_QCM_TRACE_H
|
||||||
|
|
||||||
#ifdef USE_QUIC
|
#ifdef USE_QUIC
|
||||||
|
|
||||||
|
|
@ -10,10 +10,10 @@
|
||||||
struct qcc;
|
struct qcc;
|
||||||
struct qcs;
|
struct qcs;
|
||||||
|
|
||||||
extern struct trace_source trace_qmux;
|
extern struct trace_source trace_qcm;
|
||||||
#define TRACE_SOURCE &trace_qmux
|
#define TRACE_SOURCE &trace_qcm
|
||||||
|
|
||||||
static const struct trace_event qmux_trace_events[] = {
|
static const struct trace_event qcm_trace_events[] = {
|
||||||
#define QMUX_EV_QCC_NEW (1ULL << 0)
|
#define QMUX_EV_QCC_NEW (1ULL << 0)
|
||||||
{ .mask = QMUX_EV_QCC_NEW , .name = "qcc_new", .desc = "new QUIC connection" },
|
{ .mask = QMUX_EV_QCC_NEW , .name = "qcc_new", .desc = "new QUIC connection" },
|
||||||
#define QMUX_EV_QCC_RECV (1ULL << 1)
|
#define QMUX_EV_QCC_RECV (1ULL << 1)
|
||||||
|
|
@ -72,9 +72,9 @@ struct qcs_build_stream_trace_arg {
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
|
void qcm_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
|
||||||
void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
|
void qcm_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
|
|
||||||
#endif /* _HAPROXY_QMUX_TRACE_H */
|
#endif /* _HAPROXY_QCM_TRACE_H */
|
||||||
|
|
@ -42,7 +42,7 @@ struct pendconn {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct queue {
|
struct queue {
|
||||||
struct eb_root head; /* queued pendconnds */
|
struct eb_root head; /* queued pendconns */
|
||||||
struct proxy *px; /* the proxy we're waiting for, never NULL in queue */
|
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 */
|
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 */
|
__decl_thread(HA_SPINLOCK_T lock); /* for manipulations in the tree */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/dns-t.h
|
* include/haproxy/resolvers-t.h
|
||||||
* This file provides structures and types for DNS.
|
* This file provides structures and types for DNS.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
* 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 */
|
char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
|
||||||
int16_t type; /* question type */
|
int16_t type; /* question type */
|
||||||
int16_t class; /* query class */
|
int16_t class; /* query class */
|
||||||
int32_t ttl; /* response TTL */
|
uint32_t ttl; /* response TTL */
|
||||||
int16_t priority; /* SRV type priority */
|
int16_t priority; /* SRV type priority */
|
||||||
uint16_t weight; /* SRV type weight */
|
uint16_t weight; /* SRV type weight */
|
||||||
uint16_t port; /* SRV type port */
|
uint16_t port; /* SRV type port */
|
||||||
|
|
@ -281,7 +281,7 @@ enum {
|
||||||
* matching preference was found.
|
* matching preference was found.
|
||||||
*/
|
*/
|
||||||
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
|
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
|
||||||
* OR provided IP found and preference is not match and an IP
|
* OR provided IP found and preference is not matched and an IP
|
||||||
* matching preference was found.
|
* matching preference was found.
|
||||||
*/
|
*/
|
||||||
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */
|
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/dns.h
|
* include/haproxy/resolvers.h
|
||||||
* This file provides functions related to DNS protocol
|
* This file provides functions related to DNS protocol
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,8 @@ enum srv_initaddr {
|
||||||
* at start up time.
|
* at start up time.
|
||||||
*/
|
*/
|
||||||
enum srv_init_state {
|
enum srv_init_state {
|
||||||
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_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_DOWN, /* the server should initially be considered DOWN until it passes one health check. */
|
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_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. */
|
SRV_INIT_STATE_FULLY_UP, /* the server should initially be considered UP, but will go DOWN if it fails all health checks. */
|
||||||
|
|
@ -248,7 +249,9 @@ struct pid_list {
|
||||||
|
|
||||||
/* srv methods of computing chash keys */
|
/* srv methods of computing chash keys */
|
||||||
enum srv_hash_key {
|
enum srv_hash_key {
|
||||||
SRV_HASH_KEY_ID = 0, /* derived from server puid */
|
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_ADDR, /* derived from server address */
|
SRV_HASH_KEY_ADDR, /* derived from server address */
|
||||||
SRV_HASH_KEY_ADDR_PORT /* derived from server address and port */
|
SRV_HASH_KEY_ADDR_PORT /* derived from server address and port */
|
||||||
};
|
};
|
||||||
|
|
@ -326,6 +329,7 @@ enum renegotiate_mode {
|
||||||
struct path_parameters {
|
struct path_parameters {
|
||||||
__decl_thread(HA_RWLOCK_T param_lock);
|
__decl_thread(HA_RWLOCK_T param_lock);
|
||||||
char nego_alpn[MAX_ALPN_SIZE];
|
char nego_alpn[MAX_ALPN_SIZE];
|
||||||
|
int64_t srv_hash;
|
||||||
#ifdef USE_QUIC
|
#ifdef USE_QUIC
|
||||||
struct quic_early_transport_params tps;
|
struct quic_early_transport_params tps;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,35 @@ static inline void srv_adm_set_ready(struct server *s)
|
||||||
srv_clr_admin_flag(s, SRV_ADMF_FMAINT);
|
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. */
|
/* 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)
|
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_store; /* Number of ckch_store that reference this certificate_ocsp */
|
||||||
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
|
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
|
||||||
struct buffer response;
|
struct buffer response;
|
||||||
long expire;
|
unsigned long expire;
|
||||||
X509 *issuer;
|
X509 *issuer;
|
||||||
STACK_OF(X509) *chain;
|
STACK_OF(X509) *chain;
|
||||||
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
|
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
|
||||||
|
|
|
||||||
|
|
@ -736,7 +736,6 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
|
||||||
when = tick_first(when, task->expire);
|
when = tick_first(when, task->expire);
|
||||||
|
|
||||||
task->expire = when;
|
task->expire = when;
|
||||||
task_drop_running(task, 0);
|
|
||||||
if (!task_in_wq(task) || tick_is_lt(task->expire, task->wq.key)) {
|
if (!task_in_wq(task) || tick_is_lt(task->expire, task->wq.key)) {
|
||||||
if (likely(caller)) {
|
if (likely(caller)) {
|
||||||
caller = HA_ATOMIC_XCHG(&task->caller, caller);
|
caller = HA_ATOMIC_XCHG(&task->caller, caller);
|
||||||
|
|
@ -747,6 +746,7 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
|
||||||
}
|
}
|
||||||
__task_queue(task, &tg_ctx->timers);
|
__task_queue(task, &tg_ctx->timers);
|
||||||
}
|
}
|
||||||
|
task_drop_running(task, 0);
|
||||||
HA_RWLOCK_WRUNLOCK(TASK_WQ_LOCK, &wq_lock);
|
HA_RWLOCK_WRUNLOCK(TASK_WQ_LOCK, &wq_lock);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ struct tgroup_ctx {
|
||||||
struct eb_root timers; /* wait queue (sorted timers tree, global, accessed under wq_lock) */
|
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 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) */
|
/* pad to cache line (64B) */
|
||||||
char __pad[0]; /* unused except to check remaining room */
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set port in host byte order */
|
/* set port in network byte order (use htons() before calling) */
|
||||||
static inline int set_net_port(struct sockaddr_storage *addr, int port)
|
static inline int set_net_port(struct sockaddr_storage *addr, int port)
|
||||||
{
|
{
|
||||||
switch (addr->ss_family) {
|
switch (addr->ss_family) {
|
||||||
|
|
@ -840,7 +840,7 @@ static inline int set_net_port(struct sockaddr_storage *addr, int port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set port in network byte order */
|
/* set port in host byte order */
|
||||||
static inline int set_host_port(struct sockaddr_storage *addr, int port)
|
static inline int set_host_port(struct sockaddr_storage *addr, int port)
|
||||||
{
|
{
|
||||||
switch (addr->ss_family) {
|
switch (addr->ss_family) {
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ struct trace_ctx {
|
||||||
struct trace_source {
|
struct trace_source {
|
||||||
/* source definition */
|
/* source definition */
|
||||||
const struct ist name;
|
const struct ist name;
|
||||||
|
const struct ist alias;
|
||||||
const char *desc;
|
const char *desc;
|
||||||
const struct trace_event *known_events;
|
const struct trace_event *known_events;
|
||||||
struct list source_link; // element in list of known trace sources
|
struct list source_link; // element in list of known trace sources
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
#define _TRC_LOC(f,l) __TRC_LOC(f, ":", l)
|
#define _TRC_LOC(f,l) __TRC_LOC(f, ":", l)
|
||||||
#define __TRC_LOC(f,c,l) f c #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.
|
/* truncate a macro arg list to exactly 5 args and replace missing ones with NULL.
|
||||||
* The first one (a0) is always ignored.
|
* The first one (a0) is always ignored.
|
||||||
*/
|
*/
|
||||||
|
|
@ -139,8 +141,23 @@
|
||||||
&trace_no_cb, ist2(_msg, _msg_len)); \
|
&trace_no_cb, ist2(_msg, _msg_len)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} 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(DEBUG_DEV) || defined(DEBUG_FULL)
|
#if defined (USE_TRACE) && (defined(DEBUG_DEV) || defined(DEBUG_FULL))
|
||||||
# define DBG_TRACE(msg, mask, args...) TRACE(msg, mask, ##args)
|
# 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_ERROR(msg, mask, args...) TRACE_ERROR(msg, mask, ##args)
|
||||||
# define DBG_TRACE_USER(msg, mask, args...) TRACE_USER(msg, mask, ##args)
|
# define DBG_TRACE_USER(msg, mask, args...) TRACE_USER(msg, mask, ##args)
|
||||||
|
|
|
||||||
14
include/haproxy/xprt_qmux.h
Normal file
14
include/haproxy/xprt_qmux.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#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 */
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#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 {
|
syslog S4 -level notice {
|
||||||
recv
|
recv
|
||||||
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."
|
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."
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
server s1 {
|
server s1 {
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ feature ignore_unknown_macro
|
||||||
|
|
||||||
syslog S1 -level notice {
|
syslog S1 -level notice {
|
||||||
recv
|
recv
|
||||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*Connection refused at step 2 of tcp-check.*connect port 1"
|
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*ECONNREFUSED returned by OS.* at step 2 of tcp-check.*connect port 1"
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
syslog S2 -level notice {
|
syslog S2 -level notice {
|
||||||
recv
|
recv
|
||||||
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*Connection refused at step 1 of tcp-check.*connect port 1"
|
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*ECONNREFUSED returned by OS.* at step 1 of tcp-check.*connect port 1"
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
server s1 {
|
server s1 {
|
||||||
|
|
|
||||||
41
reg-tests/converter/reverse.vtc
Normal file
41
reg-tests/converter/reverse.vtc
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
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
|
||||||
2
reg-tests/converter/reverse_dom.map
Normal file
2
reg-tests/converter/reverse_dom.map
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
com.example. example
|
||||||
|
com.example.mail. mail
|
||||||
94
reg-tests/converter/reverse_dom.vtc
Normal file
94
reg-tests/converter/reverse_dom.vtc
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
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
|
} -run
|
||||||
|
|
||||||
# missing websocket key
|
# missing websocket key
|
||||||
client c2 -connect ${hap_fe1_sock} {
|
client c2_1 -connect ${hap_fe1_sock} {
|
||||||
txreq \
|
txreq \
|
||||||
-req "GET" \
|
-req "GET" \
|
||||||
-url "/" \
|
-url "/" \
|
||||||
|
|
@ -158,6 +158,19 @@ client c2 -connect ${hap_fe1_sock} {
|
||||||
expect resp.status == 400
|
expect resp.status == 400
|
||||||
} -run
|
} -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
|
# missing key on server side
|
||||||
client c3 -connect ${hap_fe2_sock} {
|
client c3 -connect ${hap_fe2_sock} {
|
||||||
txreq \
|
txreq \
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ client c1 -connect ${h1_feS_sock} {
|
||||||
|
|
||||||
haproxy h1 -cli {
|
haproxy h1 -cli {
|
||||||
# non existent backend
|
# non existent backend
|
||||||
send "experimental-mode on; add backend be from def"
|
send "add backend be from def"
|
||||||
expect ~ "Mode is required"
|
expect ~ "Mode is required"
|
||||||
|
|
||||||
send "experimental-mode on; add backend be from def_http"
|
send "add backend be from def_http"
|
||||||
expect ~ "New backend registered."
|
expect ~ "New backend registered."
|
||||||
|
|
||||||
send "add server be/srv ${hsrv_fe_addr}:${hsrv_fe_port}"
|
send "add server be/srv ${hsrv_fe_addr}:${hsrv_fe_port}"
|
||||||
|
|
|
||||||
|
|
@ -40,29 +40,29 @@ haproxy h1 -conf {
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
haproxy h1 -cli {
|
haproxy h1 -cli {
|
||||||
send "experimental-mode on; del backend other"
|
send "del backend other"
|
||||||
expect ~ "No such backend."
|
expect ~ "No such backend."
|
||||||
|
|
||||||
send "experimental-mode on; del backend li"
|
send "del backend li"
|
||||||
expect ~ "Cannot delete a listen section."
|
expect ~ "Cannot delete a listen section."
|
||||||
|
|
||||||
send "experimental-mode on; del backend be_ref"
|
send "del backend be_ref"
|
||||||
expect ~ "This proxy cannot be removed at runtime due to other configuration elements pointing to it."
|
expect ~ "This proxy cannot be removed at runtime due to other configuration elements pointing to it."
|
||||||
|
|
||||||
send "show stat be 2 -1"
|
send "show stat be 2 -1"
|
||||||
expect ~ "be,BACKEND,"
|
expect ~ "be,BACKEND,"
|
||||||
|
|
||||||
send "experimental-mode on; del backend be"
|
send "del backend be"
|
||||||
expect ~ "Backend must be unpublished prior to its deletion."
|
expect ~ "Backend must be unpublished prior to its deletion."
|
||||||
|
|
||||||
send "unpublish backend be;"
|
send "unpublish backend be;"
|
||||||
expect ~ ".*"
|
expect ~ ".*"
|
||||||
send "experimental-mode on; del backend be"
|
send "del backend be"
|
||||||
expect ~ "Only a backend without server can be deleted."
|
expect ~ "Only a backend without server can be deleted."
|
||||||
|
|
||||||
send "del server be/s1"
|
send "del server be/s1"
|
||||||
expect ~ ".*"
|
expect ~ ".*"
|
||||||
send "experimental-mode on; del backend be"
|
send "del backend be"
|
||||||
expect ~ "Backend deleted."
|
expect ~ "Backend deleted."
|
||||||
|
|
||||||
send "show stat be 2 -1"
|
send "show stat be 2 -1"
|
||||||
|
|
@ -75,7 +75,7 @@ haproxy h1 -cli {
|
||||||
|
|
||||||
send "unpublish backend be_unnamed_def_ref;"
|
send "unpublish backend be_unnamed_def_ref;"
|
||||||
expect ~ ".*"
|
expect ~ ".*"
|
||||||
send "experimental-mode on; del backend be_unnamed_def_ref"
|
send "del backend be_unnamed_def_ref"
|
||||||
expect ~ "Backend deleted."
|
expect ~ "Backend deleted."
|
||||||
|
|
||||||
send "show stat be_unnamed_def_ref 2 -1"
|
send "show stat be_unnamed_def_ref 2 -1"
|
||||||
|
|
@ -83,6 +83,6 @@ haproxy h1 -cli {
|
||||||
|
|
||||||
send "unpublish backend be_unnamed_def_ref2;"
|
send "unpublish backend be_unnamed_def_ref2;"
|
||||||
expect ~ ".*"
|
expect ~ ".*"
|
||||||
send "experimental-mode on; del backend be_unnamed_def_ref2"
|
send "del backend be_unnamed_def_ref2"
|
||||||
expect ~ "Backend deleted."
|
expect ~ "Backend deleted."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
#REGTEST_TYPE=bug
|
#REGTEST_TYPE=bug
|
||||||
varnishtest "Test for ECDSA/RSA selection and crt-list filters"
|
varnishtest "Test for ECDSA/RSA selection and crt-list filters"
|
||||||
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8)'"
|
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.8)'"
|
||||||
feature cmd "$HAPROXY_PROGRAM -cc 'feature(QUIC)'"
|
# QUIC backend are not supported with USE_QUIC_OPENSSL_COMPAT
|
||||||
|
feature cmd "$HAPROXY_PROGRAM -cc 'feature(QUIC) && !feature(QUIC_OPENSSL_COMPAT) && !feature(OPENSSL_WOLFSSL)'"
|
||||||
# Note that USE_OPENSSL is always set if USE_QUIC is set
|
# 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
|
# 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)'"
|
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
|
# This test checks if the multiple certificate types works correctly with the
|
||||||
# SNI, and that the negative filters are correctly excluded
|
# SNI, and that the negative filters are correctly excluded
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ haproxy h2 -conf {
|
||||||
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
|
||||||
|
|
||||||
resolvers systemdns
|
resolvers systemdns
|
||||||
parse-resolv-conf
|
nameserver dns1 127.0.0.1:53
|
||||||
|
|
||||||
frontend myfrontend
|
frontend myfrontend
|
||||||
bind "fd@${my_fe}"
|
bind "fd@${my_fe}"
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ haproxy h1 -conf {
|
||||||
thread-groups 1
|
thread-groups 1
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
.if feature(QUIC_OPENSSL_COMPAT)
|
||||||
|
limited-quic
|
||||||
|
.endif
|
||||||
|
|
||||||
stats socket "${tmpdir}/h1/stats" level admin
|
stats socket "${tmpdir}/h1/stats" level admin
|
||||||
issuers-chain-path "${testdir}/certs/issuers-chain-path/ca/"
|
issuers-chain-path "${testdir}/certs/issuers-chain-path/ca/"
|
||||||
crt-base "${testdir}/certs/issuers-chain-path"
|
crt-base "${testdir}/certs/issuers-chain-path"
|
||||||
|
|
|
||||||
|
|
@ -407,7 +407,7 @@ haproxy h5 -cli {
|
||||||
shell {
|
shell {
|
||||||
ocsp_resp_file="${tmpdir}.ocsp_resp.der"
|
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 /tmp/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 "${tmpdir}/with-o64" > $ocsp_resp_file
|
||||||
|
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ]
|
||||||
then
|
then
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,7 @@ fi
|
||||||
echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}"
|
echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}"
|
||||||
echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
|
echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
|
||||||
echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest"
|
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 " Pending bugs : https://www.haproxy.org/l/pending-bugs"
|
||||||
echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs"
|
echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs"
|
||||||
echo " Code reports : https://www.haproxy.org/l/code-reports"
|
echo " Code reports : https://www.haproxy.org/l/code-reports"
|
||||||
|
|
|
||||||
10
src/acme.c
10
src/acme.c
|
|
@ -1562,6 +1562,16 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
key = ctx->store->data->key;
|
key = ctx->store->data->key;
|
||||||
ctx->store->data->key = NULL;
|
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 */
|
/* 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)
|
if (ssl_sock_load_pem_into_ckch(ctx->store->path, hc->res.buf.area, ctx->store->data , errmsg) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
||||||
|
|
@ -539,9 +539,6 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC))
|
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (!count)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||||
TRACE_STATE("waiting for appctx outbuf allocation", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
|
TRACE_STATE("waiting for appctx outbuf allocation", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
|
||||||
goto end;
|
goto end;
|
||||||
|
|
@ -550,7 +547,8 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
if (flags & CO_RFL_BUF_FLUSH)
|
if (flags & CO_RFL_BUF_FLUSH)
|
||||||
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
||||||
|
|
||||||
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
if (count)
|
||||||
|
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
||||||
if (ret)
|
if (ret)
|
||||||
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
||||||
|
|
||||||
|
|
@ -608,7 +606,7 @@ size_t appctx_htx_snd_buf(struct appctx *appctx, struct buffer *buf, size_t coun
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_DEFAULT);
|
htx_xfer(appctx_htx, buf_htx, count, HTX_XFER_NO_METADATA);
|
||||||
if (htx_is_empty(buf_htx)) {
|
if (htx_is_empty(buf_htx)) {
|
||||||
appctx_htx->flags |= (buf_htx->flags & HTX_FL_EOM);
|
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) {
|
for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
|
||||||
struct auth_groups *ag;
|
struct auth_groups *ag;
|
||||||
struct auth_users *curuser;
|
struct auth_users *curuser;
|
||||||
struct auth_groups_list *grl;
|
struct auth_groups_list *grl, *tmp;
|
||||||
|
|
||||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
||||||
char *group = NULL;
|
char *group = NULL;
|
||||||
|
|
@ -152,7 +152,7 @@ int userlist_postinit()
|
||||||
groups = groups->next;
|
groups = groups->next;
|
||||||
free(grl);
|
free(grl);
|
||||||
}
|
}
|
||||||
return ERR_ALERT | ERR_FATAL;
|
goto free_groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add this group at the group userlist. */
|
/* Add this group at the group userlist. */
|
||||||
|
|
@ -165,7 +165,7 @@ int userlist_postinit()
|
||||||
groups = groups->next;
|
groups = groups->next;
|
||||||
free(grl);
|
free(grl);
|
||||||
}
|
}
|
||||||
return ERR_ALERT | ERR_FATAL;
|
goto free_groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
grl->group = ag;
|
grl->group = ag;
|
||||||
|
|
@ -192,7 +192,7 @@ int userlist_postinit()
|
||||||
if (!curuser) {
|
if (!curuser) {
|
||||||
ha_alert("userlist '%s': no such user '%s' specified in group '%s'\n",
|
ha_alert("userlist '%s': no such user '%s' specified in group '%s'\n",
|
||||||
curuserlist->name, user, ag->name);
|
curuserlist->name, user, ag->name);
|
||||||
return ERR_ALERT | ERR_FATAL;
|
goto free_groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add this group at the group userlist. */
|
/* Add this group at the group userlist. */
|
||||||
|
|
@ -200,7 +200,7 @@ int userlist_postinit()
|
||||||
if (!grl) {
|
if (!grl) {
|
||||||
ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
|
ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
|
||||||
curuserlist->name);
|
curuserlist->name);
|
||||||
return ERR_ALERT | ERR_FATAL;
|
goto free_groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
grl->group = ag;
|
grl->group = ag;
|
||||||
|
|
@ -211,6 +211,22 @@ int userlist_postinit()
|
||||||
ha_free(&ag->groupusers);
|
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
|
#ifdef DEBUG_AUTH
|
||||||
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
||||||
struct auth_groups_list *agl;
|
struct auth_groups_list *agl;
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,13 @@
|
||||||
|
|
||||||
#define TRACE_SOURCE &trace_strm
|
#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 */
|
/* helper function to invoke the correct hash method */
|
||||||
unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len)
|
unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len)
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +87,7 @@ unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len
|
||||||
hash = hash_crc32(key, len);
|
hash = hash_crc32(key, len);
|
||||||
break;
|
break;
|
||||||
case BE_LB_HFCN_NONE:
|
case BE_LB_HFCN_NONE:
|
||||||
/* use key as a hash */
|
/* use key as a hash. It MUST be in string format */
|
||||||
{
|
{
|
||||||
const char *_key = key;
|
const char *_key = key;
|
||||||
|
|
||||||
|
|
@ -363,11 +370,11 @@ struct server *get_server_ph_post(struct stream *s, const struct server *avoid)
|
||||||
len -= plen + 1;
|
len -= plen + 1;
|
||||||
|
|
||||||
while (len && *end != '&') {
|
while (len && *end != '&') {
|
||||||
if (unlikely(!HTTP_IS_TOKEN(*p))) {
|
if (unlikely(!HTTP_IS_TOKEN(*end))) {
|
||||||
/* if in a POST, body must be URI encoded or it's not a URI.
|
/* 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.
|
* Do not interpret any possible binary data as a parameter.
|
||||||
*/
|
*/
|
||||||
if (likely(HTTP_IS_LWS(*p))) /* eol, uncertain uri len */
|
if (likely(HTTP_IS_LWS(*end))) /* eol, uncertain uri len */
|
||||||
break;
|
break;
|
||||||
return NULL; /* oh, no; this is not uri-encoded.
|
return NULL; /* oh, no; this is not uri-encoded.
|
||||||
* This body does not contain parameters.
|
* This body does not contain parameters.
|
||||||
|
|
@ -538,7 +545,14 @@ struct server *get_server_expr(struct stream *s, const struct server *avoid)
|
||||||
if (px->lbprm.tot_used == 1)
|
if (px->lbprm.tot_used == 1)
|
||||||
goto hash_done;
|
goto hash_done;
|
||||||
|
|
||||||
smp = sample_fetch_as_type(px, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, px->lbprm.expr, SMP_T_BIN);
|
/* 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);
|
||||||
if (!smp)
|
if (!smp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -1804,7 +1818,10 @@ int connect_server(struct stream *s)
|
||||||
{
|
{
|
||||||
struct connection *cli_conn = objt_conn(strm_orig(s));
|
struct connection *cli_conn = objt_conn(strm_orig(s));
|
||||||
struct connection *srv_conn = NULL;
|
struct connection *srv_conn = NULL;
|
||||||
|
const struct mux_proto_list *mux_proto = NULL;
|
||||||
struct server *srv;
|
struct server *srv;
|
||||||
|
struct ist name = IST_NULL;
|
||||||
|
struct sample *name_smp;
|
||||||
int reuse_mode;
|
int reuse_mode;
|
||||||
int reuse __maybe_unused = 0;
|
int reuse __maybe_unused = 0;
|
||||||
int may_use_early_data __maybe_unused = 1; // are we allowed to use early data ?
|
int may_use_early_data __maybe_unused = 1; // are we allowed to use early data ?
|
||||||
|
|
@ -1826,6 +1843,17 @@ int connect_server(struct stream *s)
|
||||||
if (err != SRV_STATUS_OK)
|
if (err != SRV_STATUS_OK)
|
||||||
return SF_ERR_INTERNAL;
|
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))
|
if (!be_supports_conn_reuse(s->be))
|
||||||
goto skip_reuse;
|
goto skip_reuse;
|
||||||
|
|
||||||
|
|
@ -1837,20 +1865,7 @@ int connect_server(struct stream *s)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const int not_first_req = s->txn.http && s->txn.http->flags & TX_NOT_FIRST;
|
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,
|
err = be_reuse_connection(hash, s->sess, s->be, srv, s->scb,
|
||||||
s->target, not_first_req);
|
s->target, not_first_req);
|
||||||
if (err == SF_ERR_INTERNAL)
|
if (err == SF_ERR_INTERNAL)
|
||||||
|
|
@ -2072,7 +2087,7 @@ int connect_server(struct stream *s)
|
||||||
if (IS_HTX_STRM(s) && srv->use_ssl &&
|
if (IS_HTX_STRM(s) && srv->use_ssl &&
|
||||||
(srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str)) {
|
(srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str)) {
|
||||||
HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
||||||
if (srv->path_params.nego_alpn[0] == 0)
|
if (srv->path_params.srv_hash != hash || srv->path_params.nego_alpn[0] == 0)
|
||||||
may_start_mux_now = 0;
|
may_start_mux_now = 0;
|
||||||
HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock);
|
||||||
}
|
}
|
||||||
|
|
@ -2123,9 +2138,11 @@ int connect_server(struct stream *s)
|
||||||
srv_conn->flags |= CO_FL_SOCKS4;
|
srv_conn->flags |= CO_FL_SOCKS4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srv && srv->mux_proto && isteq(srv->mux_proto->token, ist("qmux"))) {
|
if (may_start_mux_now) {
|
||||||
srv_conn->flags |= (CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND);
|
/* Delay MUX init if an XPRT handshake is required prior. */
|
||||||
may_start_mux_now = 0;
|
mux_proto = conn_select_mux_be(srv_conn);
|
||||||
|
if (mux_proto && mux_proto->init_xprt)
|
||||||
|
may_start_mux_now = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
|
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
|
||||||
|
|
@ -2235,6 +2252,13 @@ 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.
|
* 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets one text line out of aa buffer.
|
/* Gets one text line out of a buffer.
|
||||||
* Return values :
|
* Return values :
|
||||||
* >0 : number of bytes read. Includes the \n if present before len or end.
|
* >0 : number of bytes read. Includes the \n if present before len or end.
|
||||||
* =0 : no '\n' before end found. <str> is left undefined.
|
* =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
|
/* b_slow_realign_ofs() : this function realigns a possibly wrapping buffer
|
||||||
* setting its new head at <ofs>. Depending of the <ofs> value, the resulting
|
* 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
|
* 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 ensuze <ofs> is not larger
|
* be provided in <swap>. It's up to the caller to ensure <ofs> is not larger
|
||||||
* than b->size.
|
* than b->size.
|
||||||
*/
|
*/
|
||||||
void b_slow_realign_ofs(struct buffer *b, char *swap, size_t ofs)
|
void b_slow_realign_ofs(struct buffer *b, char *swap, size_t ofs)
|
||||||
|
|
|
||||||
19
src/cache.c
19
src/cache.c
|
|
@ -1801,8 +1801,6 @@ static void http_cache_io_handler(struct appctx *appctx)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
res_htx = htx_from_buf(&appctx->outbuf);
|
|
||||||
|
|
||||||
len = first->len - sizeof(*cache_ptr) - ctx->sent;
|
len = first->len - sizeof(*cache_ptr) - ctx->sent;
|
||||||
res_htx = htx_from_buf(&appctx->outbuf);
|
res_htx = htx_from_buf(&appctx->outbuf);
|
||||||
|
|
||||||
|
|
@ -1950,7 +1948,10 @@ static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_ru
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
free(cconf);
|
if (cconf) {
|
||||||
|
free(cconf->c.name);
|
||||||
|
free(cconf);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2179,7 +2180,17 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
|
||||||
sec_entry = get_secondary_entry(cache_tree, res,
|
sec_entry = get_secondary_entry(cache_tree, res,
|
||||||
s->txn.http->cache_secondary_hash,
|
s->txn.http->cache_secondary_hash,
|
||||||
0);
|
0);
|
||||||
if (sec_entry && sec_entry != res) {
|
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) {
|
||||||
/* The wrong row was added to the hot list. */
|
/* The wrong row was added to the hot list. */
|
||||||
release_entry(cache_tree, res, 0);
|
release_entry(cache_tree, res, 0);
|
||||||
retain_entry(sec_entry);
|
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
|
* 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
|
* in this case. In this case the first bad character will be reported in
|
||||||
* <errptr>. <maxdepth> corresponds to the maximum recursion depth permitted,
|
* <errptr>. <maxdepth> corresponds to the maximum recursion depth permitted,
|
||||||
* it is decremented on each recursive call and the parsing will fail one
|
* it is decremented on each recursive call and the parsing will fail upon
|
||||||
* reaching <= 0.
|
* reaching <= 0.
|
||||||
*/
|
*/
|
||||||
int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr, int maxdepth)
|
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)
|
else if (strcmp(str, "EPOLL") == 0)
|
||||||
return !!(global.tune.options & GTUNE_USE_EPOLL);
|
return !!(global.tune.options & GTUNE_USE_EPOLL);
|
||||||
else if (strcmp(str, "KQUEUE") == 0)
|
else if (strcmp(str, "KQUEUE") == 0)
|
||||||
return !!(global.tune.options & GTUNE_USE_EPOLL);
|
return !!(global.tune.options & GTUNE_USE_KQUEUE);
|
||||||
else if (strcmp(str, "EVPORTS") == 0)
|
else if (strcmp(str, "EVPORTS") == 0)
|
||||||
return !!(global.tune.options & GTUNE_USE_EVPORTS);
|
return !!(global.tune.options & GTUNE_USE_EVPORTS);
|
||||||
else if (strcmp(str, "SPLICE") == 0)
|
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. <expr> is filled with the parsed info, and <text> is updated on
|
||||||
* success to point to the first unparsed character, or is left untouched
|
* 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
|
* on failure. On success, the caller will have to free all lower-level
|
||||||
* allocated structs using cfg_free_cond_expr(). An error will be set in
|
* allocated structs using cfg_free_cond_and(). An error will be set in
|
||||||
* <err> on error, and only in this case. In this case the first bad
|
* <err> on error, and only in this case. In this case the first bad
|
||||||
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
||||||
* maximum recursion depth permitted, it is decremented on each recursive
|
* maximum recursion depth permitted, it is decremented on each recursive
|
||||||
* call and the parsing will fail one reaching <= 0.
|
* call and the parsing will fail upon reaching <= 0.
|
||||||
*/
|
*/
|
||||||
int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr, int maxdepth)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse an indirect input text as a possible config condition term.
|
/* Parse an indirect input text as a possible config condition expression.
|
||||||
* Returns <0 on parsing error, 0 if the parser is desynchronized, or >0 on
|
* 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. <expr> is filled with the parsed info, and <text> is updated on
|
||||||
* success to point to the first unparsed character, or is left untouched
|
* 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
|
* <err> on error, and only in this case. In this case the first bad
|
||||||
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
* character will be reported in <errptr>. <maxdepth> corresponds to the
|
||||||
* maximum recursion depth permitted, it is decremented on each recursive call
|
* maximum recursion depth permitted, it is decremented on each recursive call
|
||||||
* and the parsing will fail one reaching <= 0.
|
* and the parsing will fail upon reaching <= 0.
|
||||||
*/
|
*/
|
||||||
int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr, int maxdepth)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* evaluate an sub-expression on a .if/.elif line. The expression is valid and
|
/* evaluate a 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
|
* 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,
|
* filled with a message, and only in this case), 0 if the condition is false,
|
||||||
* 1 if it's true.
|
* 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
|
/* evaluate a condition on a .if/.elif line. The condition is already tokenized
|
||||||
* in <err>. Returns -1 on error (in which case err is filled with a message,
|
* in <args>. 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
|
* 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.
|
* <errptr> is not NULL, it's set to the first invalid character on error.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1444,6 +1444,16 @@ static int cfg_parse_global_tune_opts(char **args, int section_type,
|
||||||
return -1;
|
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) {
|
else if (strcmp(args[0], "tune.takeover-other-tg-connections") == 0) {
|
||||||
if (*(args[1]) == 0) {
|
if (*(args[1]) == 0) {
|
||||||
memprintf(err, "'%s' expects 'none', 'restricted', or 'full'", args[0]);
|
memprintf(err, "'%s' expects 'none', 'restricted', or 'full'", args[0]);
|
||||||
|
|
@ -1619,11 +1629,6 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
||||||
struct proxy *curpx, const struct proxy *defpx,
|
struct proxy *curpx, const struct proxy *defpx,
|
||||||
const char *file, int line, char **err)
|
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) {
|
if (global.shm_stats_file != NULL) {
|
||||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1634,7 +1639,6 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
|
||||||
global.shm_stats_file = strdup(args[1]);
|
global.shm_stats_file = strdup(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1643,11 +1647,6 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
||||||
struct proxy *curpx, const struct proxy *defpx,
|
struct proxy *curpx, const struct proxy *defpx,
|
||||||
const char *file, int line, char **err)
|
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) {
|
if (shm_stats_file_max_objects != -1) {
|
||||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1658,7 +1657,6 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
|
||||||
shm_stats_file_max_objects = atoi(args[1]);
|
shm_stats_file_max_objects = atoi(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1903,6 +1901,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||||
{ CFG_GLOBAL, "tune.runqueue-depth", cfg_parse_global_tune_opts },
|
{ CFG_GLOBAL, "tune.runqueue-depth", cfg_parse_global_tune_opts },
|
||||||
{ CFG_GLOBAL, "tune.sndbuf.client", 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.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, "tune.takeover-other-tg-connections", cfg_parse_global_tune_opts },
|
||||||
{ CFG_GLOBAL, "unsetenv", cfg_parse_global_env_opts, KWF_DISCOVERY },
|
{ CFG_GLOBAL, "unsetenv", cfg_parse_global_env_opts, KWF_DISCOVERY },
|
||||||
{ CFG_GLOBAL, "zero-warning", cfg_parse_global_mode, KWF_DISCOVERY },
|
{ CFG_GLOBAL, "zero-warning", cfg_parse_global_mode, KWF_DISCOVERY },
|
||||||
|
|
|
||||||
|
|
@ -3262,12 +3262,14 @@ stats_error_parsing:
|
||||||
/* prepare error message just in case */
|
/* prepare error message just in case */
|
||||||
rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, curr_defproxy, file, linenum, &errmsg);
|
rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, curr_defproxy, file, linenum, &errmsg);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
if (errmsg)
|
||||||
|
ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else if (rc > 0) {
|
else if (rc > 0) {
|
||||||
ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
if (errmsg)
|
||||||
|
ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||||
err_code |= ERR_WARN;
|
err_code |= ERR_WARN;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1495,7 +1495,7 @@ static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
|
keys_ref->tlskeys = malloc(array_size_or_fail(TLS_TICKETS_NO, sizeof(union tls_sess_key)));
|
||||||
if (!keys_ref->tlskeys) {
|
if (!keys_ref->tlskeys) {
|
||||||
memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
|
memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
||||||
|
|
@ -1394,7 +1394,7 @@ int parse_cfg(const struct cfgfile *cfg)
|
||||||
global.cfg_curr_line = 0;
|
global.cfg_curr_line = 0;
|
||||||
global.cfg_curr_file = file;
|
global.cfg_curr_file = file;
|
||||||
|
|
||||||
if ((thisline = malloc(sizeof(*thisline) * linesize)) == NULL) {
|
if ((thisline = malloc(array_size_or_fail(sizeof(*thisline), linesize))) == NULL) {
|
||||||
ha_alert("Out of memory trying to allocate a buffer for a configuration line.\n");
|
ha_alert("Out of memory trying to allocate a buffer for a configuration line.\n");
|
||||||
err_code = -1;
|
err_code = -1;
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -1442,7 +1442,7 @@ next_line:
|
||||||
char *newline;
|
char *newline;
|
||||||
int newlinesize = linesize * 2;
|
int newlinesize = linesize * 2;
|
||||||
|
|
||||||
newline = realloc(thisline, sizeof(*thisline) * newlinesize);
|
newline = realloc(thisline, array_size_or_fail(sizeof(*thisline), newlinesize));
|
||||||
if (newline == NULL) {
|
if (newline == NULL) {
|
||||||
ha_alert("parsing [%s:%d]: line too long, cannot allocate memory.\n",
|
ha_alert("parsing [%s:%d]: line too long, cannot allocate memory.\n",
|
||||||
file, linenum);
|
file, linenum);
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ unsigned long long __channel_forward(struct channel *chn, unsigned long long byt
|
||||||
if (!budget)
|
if (!budget)
|
||||||
return forwarded;
|
return forwarded;
|
||||||
|
|
||||||
/* Now we must ensure chn->to_forward sats below CHN_INFINITE_FORWARD,
|
/* Now we must ensure chn->to_forward stays below CHN_INFINITE_FORWARD,
|
||||||
* which also implies it won't overflow. It's less operations in 64-bit.
|
* which also implies it won't overflow. It's less operations in 64-bit.
|
||||||
*/
|
*/
|
||||||
bytes = (unsigned long long)chn->to_forward + budget;
|
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
|
* 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
|
* 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
|
* buffer, -1 is returned. Otherwise the number of bytes copied is returned
|
||||||
* (1). Channel flag READ_PARTIAL is updated if some data can be transferred.
|
* (1). Channel flag CF_READ_EVENT is set if some data can be transferred.
|
||||||
*/
|
*/
|
||||||
int ci_putchr(struct channel *chn, char c)
|
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,
|
* 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
|
* -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
|
* returned. Otherwise the number of bytes copied is returned (0 being a valid
|
||||||
* number). Channel flag READ_PARTIAL is updated if some data can be
|
* number). Channel flag CF_READ_EVENT is set if some data can be
|
||||||
* transferred.
|
* transferred.
|
||||||
*/
|
*/
|
||||||
int ci_putblk(struct channel *chn, const char *blk, int len)
|
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);
|
errno = unclean_errno(errno_bck);
|
||||||
if (conn && errno)
|
if (conn && !errno)
|
||||||
retrieve_errno_from_socket(conn);
|
retrieve_errno_from_socket(conn);
|
||||||
|
|
||||||
TRACE_ENTER(CHK_EV_HCHK_END|CHK_EV_HCHK_ERR, check, 0, 0, (size_t[]){expired});
|
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
|
/* Returns a trash chunk accordingly to the requested size. This function may
|
||||||
* fail if the requested size is too big or if the large chubks are not
|
* fail if the requested size is too big or if the large chunks are not
|
||||||
* configured.
|
* configured.
|
||||||
*/
|
*/
|
||||||
struct buffer *get_trash_chunk_sz(size_t size)
|
struct buffer *get_trash_chunk_sz(size_t size)
|
||||||
|
|
|
||||||
37
src/cli.c
37
src/cli.c
|
|
@ -1151,8 +1151,13 @@ int cli_parse_cmdline(struct appctx *appctx)
|
||||||
*/
|
*/
|
||||||
if (len-1 == strlen(appctx->cli_ctx.payload_pat)) {
|
if (len-1 == strlen(appctx->cli_ctx.payload_pat)) {
|
||||||
if (strncmp(str, appctx->cli_ctx.payload_pat, len-1) == 0) {
|
if (strncmp(str, appctx->cli_ctx.payload_pat, len-1) == 0) {
|
||||||
/* end of payload was reached, rewind before the previous \n and replace it by a \0 */
|
/* end of payload was reached, rewind before the previous \n, if any, and replace it by a \0
|
||||||
b_sub(buf, strlen(appctx->cli_ctx.payload_pat) + 2);
|
* Otherwise, the payload is empty, just
|
||||||
|
*/
|
||||||
|
if (b_data(buf) > len)
|
||||||
|
b_sub(buf, len+1);
|
||||||
|
else
|
||||||
|
b_sub(buf, len);
|
||||||
*b_tail(buf) = '\0';
|
*b_tail(buf) = '\0';
|
||||||
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
@ -1879,28 +1884,26 @@ static int cli_parse_show_fd(char **args, char *payload, struct appctx *appctx,
|
||||||
/* We allow the forms "<tgid>/" and "/<fd>" where the missing
|
/* We allow the forms "<tgid>/" and "/<fd>" where the missing
|
||||||
* value is considered a wildcard. So the first form means
|
* value is considered a wildcard. So the first form means
|
||||||
* "show me all the fds belonging to <tgid>", while the second
|
* "show me all the fds belonging to <tgid>", while the second
|
||||||
* one means "show the fd <fd> for each thread group".
|
* 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.
|
||||||
*/
|
*/
|
||||||
if (c == args[2])
|
if (c == args[2]) {
|
||||||
ctx->tgid = -1;
|
ctx->tgid = -1;
|
||||||
else
|
} else {
|
||||||
ctx->tgid = atoi(args[2]);
|
ctx->tgid = atoi(args[2]);
|
||||||
if (ctx->tgid > MAX_TGROUPS)
|
if (ctx->tgid <= 0 || ctx->tgid > MAX_TGROUPS)
|
||||||
return cli_err(appctx, "Invalid TGID.\n");
|
return cli_err(appctx, "Invalid TGID.\n");
|
||||||
|
}
|
||||||
c++;
|
c++;
|
||||||
if (!*c)
|
if (*c) {
|
||||||
ctx->fd = -1;
|
|
||||||
else
|
|
||||||
ctx->fd = atoi(c);
|
ctx->fd = atoi(c);
|
||||||
|
ctx->show_one = 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx->fd = atoi(args[2]);
|
ctx->fd = atoi(args[2]);
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
ctx->show_one = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2545,7 +2548,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
|
/* We will send sockets MAX_SEND_FD per MAX_SEND_FD, allocate a
|
||||||
* buffer big enough to store the socket information.
|
* buffer big enough to store the socket information.
|
||||||
*/
|
*/
|
||||||
tmpbuf = malloc(MAX_SEND_FD * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int)));
|
tmpbuf = malloc(array_size_or_fail(MAX_SEND_FD, (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int))));
|
||||||
if (tmpbuf == NULL) {
|
if (tmpbuf == NULL) {
|
||||||
ha_warning("Failed to allocate memory to transfer socket information\n");
|
ha_warning("Failed to allocate memory to transfer socket information\n");
|
||||||
goto out;
|
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
|
* information to create one, typically from the ALPN. If we're
|
||||||
* done with the handshake, attempt to create one.
|
* done with the handshake, attempt to create one.
|
||||||
*/
|
*/
|
||||||
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND))) {
|
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_WAIT_XPRT_L6))) {
|
||||||
ret = conn_create_mux(conn, NULL);
|
ret = conn_create_mux(conn, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -282,6 +282,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
||||||
struct ist mux_proto, int mode)
|
struct ist mux_proto, int mode)
|
||||||
{
|
{
|
||||||
struct bind_conf *bind_conf = __objt_listener(conn->target)->bind_conf;
|
struct bind_conf *bind_conf = __objt_listener(conn->target)->bind_conf;
|
||||||
|
struct ist alpn = IST_NULL;
|
||||||
const struct mux_ops *old_mux, *new_mux;
|
const struct mux_ops *old_mux, *new_mux;
|
||||||
void *old_mux_ctx;
|
void *old_mux_ctx;
|
||||||
const char *alpn_str = NULL;
|
const char *alpn_str = NULL;
|
||||||
|
|
@ -289,9 +290,9 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
||||||
|
|
||||||
if (!mux_proto.len) {
|
if (!mux_proto.len) {
|
||||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||||
mux_proto = ist2(alpn_str, alpn_len);
|
alpn = ist2(alpn_str, alpn_len);
|
||||||
}
|
}
|
||||||
new_mux = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
|
new_mux = conn_get_best_mux(conn, mux_proto, alpn, PROTO_SIDE_FE, mode);
|
||||||
old_mux = conn->mux;
|
old_mux = conn->mux;
|
||||||
|
|
||||||
/* No mux found */
|
/* No mux found */
|
||||||
|
|
@ -318,6 +319,29 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
|
||||||
return 0;
|
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
|
/* 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
|
* <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.
|
* mux. Otherwise we use the ALPN name, if any. Returns < 0 on error.
|
||||||
|
|
@ -330,14 +354,14 @@ int conn_install_mux_fe(struct connection *conn, void *ctx)
|
||||||
if (bind_conf->mux_proto)
|
if (bind_conf->mux_proto)
|
||||||
mux_ops = bind_conf->mux_proto->mux;
|
mux_ops = bind_conf->mux_proto->mux;
|
||||||
else {
|
else {
|
||||||
struct ist mux_proto;
|
struct ist alpn;
|
||||||
const char *alpn_str = NULL;
|
const char *alpn_str = NULL;
|
||||||
int alpn_len = 0;
|
int alpn_len = 0;
|
||||||
int mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode);
|
int mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode);
|
||||||
|
|
||||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||||
mux_proto = ist2(alpn_str, alpn_len);
|
alpn = ist2(alpn_str, alpn_len);
|
||||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
|
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_FE, mode);
|
||||||
if (!mux_ops)
|
if (!mux_ops)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -353,6 +377,66 @@ int conn_install_mux_fe(struct connection *conn, void *ctx)
|
||||||
return conn_install_mux(conn, mux_ops, ctx, bind_conf->frontend, conn->owner);
|
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
|
/* 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.
|
* <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>,
|
* It's also possible to specify an alternative mux protocol <force_mux_ops>,
|
||||||
|
|
@ -380,20 +464,20 @@ int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess
|
||||||
mux_ops = force_mux_ops;
|
mux_ops = force_mux_ops;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct ist mux_proto;
|
struct ist alpn;
|
||||||
const char *alpn_str = NULL;
|
const char *alpn_str = NULL;
|
||||||
int alpn_len = 0;
|
int alpn_len = 0;
|
||||||
int mode = conn_pr_mode_to_proto_mode(prx->mode);
|
int mode = conn_pr_mode_to_proto_mode(prx->mode);
|
||||||
|
|
||||||
if (!conn_get_alpn(conn, &alpn_str, &alpn_len)) {
|
if (!conn_get_alpn(conn, &alpn_str, &alpn_len)) {
|
||||||
if (srv && srv->path_params.nego_alpn[0]) {
|
if (srv && srv->path_params.srv_hash == conn->hash_node.key && srv->path_params.nego_alpn[0]) {
|
||||||
alpn_str = srv->path_params.nego_alpn;
|
alpn_str = srv->path_params.nego_alpn;
|
||||||
alpn_len = strlen(alpn_str);
|
alpn_len = strlen(alpn_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mux_proto = ist2(alpn_str, alpn_len);
|
alpn = ist2(alpn_str, alpn_len);
|
||||||
|
|
||||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
|
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
|
||||||
if (!mux_ops)
|
if (!mux_ops)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -434,15 +518,15 @@ int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *ses
|
||||||
if (check->mux_proto)
|
if (check->mux_proto)
|
||||||
mux_ops = check->mux_proto->mux;
|
mux_ops = check->mux_proto->mux;
|
||||||
else {
|
else {
|
||||||
struct ist mux_proto;
|
struct ist alpn;
|
||||||
const char *alpn_str = NULL;
|
const char *alpn_str = NULL;
|
||||||
int alpn_len = 0;
|
int alpn_len = 0;
|
||||||
int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
|
int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
|
||||||
|
|
||||||
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
conn_get_alpn(conn, &alpn_str, &alpn_len);
|
||||||
mux_proto = ist2(alpn_str, alpn_len);
|
alpn = ist2(alpn_str, alpn_len);
|
||||||
|
|
||||||
mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
|
mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
|
||||||
if (!mux_ops)
|
if (!mux_ops)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -763,6 +847,43 @@ int xprt_add_hs(struct connection *conn)
|
||||||
return 0;
|
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
|
/* 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
|
* 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.
|
* catching in logs). This is more compact for some debug cases.
|
||||||
|
|
@ -888,7 +1009,7 @@ const char *conn_err_code_str(struct connection *c)
|
||||||
|
|
||||||
case CO_ER_SSL_FATAL: return "SSL fatal error";
|
case CO_ER_SSL_FATAL: return "SSL fatal error";
|
||||||
|
|
||||||
case CO_ER_QSTRM: return "Error during QMux transport parameters initial exchange";
|
case CO_ER_QMUX: return "Error during QMux transport parameters initial exchange";
|
||||||
|
|
||||||
case CO_ER_REVERSE: return "Reverse connect failure";
|
case CO_ER_REVERSE: return "Reverse connect failure";
|
||||||
|
|
||||||
|
|
@ -1991,7 +2112,7 @@ void list_mux_proto(FILE *out)
|
||||||
fprintf(out, "Available multiplexer protocols :\n"
|
fprintf(out, "Available multiplexer protocols :\n"
|
||||||
"(protocols marked as <default> cannot be specified using 'proto' keyword)\n");
|
"(protocols marked as <default> cannot be specified using 'proto' keyword)\n");
|
||||||
list_for_each_entry(item, &mux_proto_list.list, list) {
|
list_for_each_entry(item, &mux_proto_list.list, list) {
|
||||||
proto = item->token;
|
proto = item->mux_proto;
|
||||||
|
|
||||||
if (item->mode == PROTO_MODE_ANY)
|
if (item->mode == PROTO_MODE_ANY)
|
||||||
mode = "TCP|HTTP";
|
mode = "TCP|HTTP";
|
||||||
|
|
|
||||||
|
|
@ -983,7 +983,7 @@ void cpu_compose_clusters(void)
|
||||||
/* renumber clusters and assign unassigned ones at the same
|
/* renumber clusters and assign unassigned ones at the same
|
||||||
* time. For this, we'll compare pkg/die/llc with the last
|
* 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.
|
* CPU's and verify if we need to create a new cluster ID.
|
||||||
* Note that some platforms don't report cache. The locao value
|
* Note that some platforms don't report cache. The local value
|
||||||
* is local to the pkg+node combination so that we reset it
|
* is local to the pkg+node combination so that we reset it
|
||||||
* when changing, contrary to the global one which grows.
|
* 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;
|
ha_cpu_clusters[cpu].idx = cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pre-inizialize the configured CPU sets */
|
/* pre-initialize the configured CPU sets */
|
||||||
ha_cpuset_zero(&cpu_set_cfg.drop_cpus);
|
ha_cpuset_zero(&cpu_set_cfg.drop_cpus);
|
||||||
ha_cpuset_zero(&cpu_set_cfg.only_cpus);
|
ha_cpuset_zero(&cpu_set_cfg.only_cpus);
|
||||||
ha_cpuset_zero(&cpu_set_cfg.drop_nodes);
|
ha_cpuset_zero(&cpu_set_cfg.drop_nodes);
|
||||||
|
|
|
||||||
13
src/cpuset.c
13
src/cpuset.c
|
|
@ -27,6 +27,8 @@ int ha_cpuset_set(struct hap_cpuset *set, int cpu)
|
||||||
#elif defined(CPUSET_USE_ULONG)
|
#elif defined(CPUSET_USE_ULONG)
|
||||||
set->cpuset |= (0x1 << cpu);
|
set->cpuset |= (0x1 << cpu);
|
||||||
return 0;
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,6 +44,8 @@ int ha_cpuset_clr(struct hap_cpuset *set, int cpu)
|
||||||
#elif defined(CPUSET_USE_ULONG)
|
#elif defined(CPUSET_USE_ULONG)
|
||||||
set->cpuset &= ~(0x1 << cpu);
|
set->cpuset &= ~(0x1 << cpu);
|
||||||
return 0;
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,6 +100,8 @@ int ha_cpuset_count(const struct hap_cpuset *set)
|
||||||
|
|
||||||
#elif defined(CPUSET_USE_ULONG)
|
#elif defined(CPUSET_USE_ULONG)
|
||||||
return my_popcountl(set->cpuset);
|
return my_popcountl(set->cpuset);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +126,8 @@ int ha_cpuset_ffs(const struct hap_cpuset *set)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return my_ffsl(set->cpuset);
|
return my_ffsl(set->cpuset);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,6 +156,8 @@ int ha_cpuset_isequal(const struct hap_cpuset *dst, const struct hap_cpuset *src
|
||||||
|
|
||||||
#elif defined(CPUSET_USE_ULONG)
|
#elif defined(CPUSET_USE_ULONG)
|
||||||
return dst->cpuset == src->cpuset;
|
return dst->cpuset == src->cpuset;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,7 +168,8 @@ int ha_cpuset_size()
|
||||||
|
|
||||||
#elif defined(CPUSET_USE_ULONG)
|
#elif defined(CPUSET_USE_ULONG)
|
||||||
return LONGBITS;
|
return LONGBITS;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1357,8 +1357,7 @@ static int debug_parse_cli_write(char **args, char *payload, struct appctx *appc
|
||||||
/*
|
/*
|
||||||
* debug dev stream [strm=<ptr>] [strm.f[{+-=}<flags>]] [txn.f[{+-=}<flags>]] \
|
* debug dev stream [strm=<ptr>] [strm.f[{+-=}<flags>]] [txn.f[{+-=}<flags>]] \
|
||||||
* [req.f[{+-=}<flags>]] [res.f[{+-=}<flags>]] \
|
* [req.f[{+-=}<flags>]] [res.f[{+-=}<flags>]] \
|
||||||
* [sif.f[{+-=<flags>]] [sib.f[{+-=<flags>]] \
|
* [scf.s[=<state>]] [scb.s[=<state>]]
|
||||||
* [sif.s[=<state>]] [sib.s[=<state>]]
|
|
||||||
*/
|
*/
|
||||||
static int debug_parse_cli_stream(char **args, char *payload, struct appctx *appctx, void *private)
|
static int debug_parse_cli_stream(char **args, char *payload, struct appctx *appctx, void *private)
|
||||||
{
|
{
|
||||||
|
|
@ -1628,7 +1627,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)
|
static int debug_parse_delay_inj(char **args, char *payload, struct appctx *appctx, void *private)
|
||||||
{
|
{
|
||||||
unsigned long *tctx; // [0] = inter, [2] = count
|
unsigned long *tctx; // [0] = inter, [1] = nbwakeups
|
||||||
struct task *task;
|
struct task *task;
|
||||||
|
|
||||||
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
|
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 value.
|
* Simple function to lookup dictionary entries with <s> as key.
|
||||||
*/
|
*/
|
||||||
static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
||||||
{
|
{
|
||||||
|
|
@ -75,20 +75,21 @@ static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert an entry in <d> dictionary with <s> as value. *
|
* Insert an entry in <d> dictionary with <s> as key.
|
||||||
*/
|
*/
|
||||||
struct dict_entry *dict_insert(struct dict *d, char *s)
|
struct dict_entry *dict_insert(struct dict *d, char *s)
|
||||||
{
|
{
|
||||||
struct dict_entry *de;
|
struct dict_entry *de, *tree_de;
|
||||||
struct ebpt_node *n;
|
struct ebpt_node *n;
|
||||||
|
|
||||||
HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
|
||||||
de = __dict_lookup(d, s);
|
de = __dict_lookup(d, s);
|
||||||
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
|
||||||
if (de) {
|
if (de) {
|
||||||
HA_ATOMIC_INC(&de->refcount);
|
HA_ATOMIC_INC(&de->refcount);
|
||||||
|
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
return de;
|
return de;
|
||||||
}
|
}
|
||||||
|
HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
|
||||||
de = new_dict_entry(s);
|
de = new_dict_entry(s);
|
||||||
if (!de)
|
if (!de)
|
||||||
|
|
@ -96,13 +97,18 @@ struct dict_entry *dict_insert(struct dict *d, char *s)
|
||||||
|
|
||||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||||
n = ebis_insert(&d->values, &de->value);
|
n = ebis_insert(&d->values, &de->value);
|
||||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
tree_de = container_of(n, struct dict_entry, value);
|
||||||
if (n != &de->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);
|
||||||
free_dict_entry(de);
|
free_dict_entry(de);
|
||||||
de = container_of(n, struct dict_entry, value);
|
|
||||||
}
|
}
|
||||||
|
return tree_de;
|
||||||
return de;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -116,10 +122,11 @@ void dict_entry_unref(struct dict *d, struct dict_entry *de)
|
||||||
if (!de)
|
if (!de)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) {
|
||||||
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
ebpt_delete(&de->value);
|
ebpt_delete(&de->value);
|
||||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
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;
|
struct ist myist;
|
||||||
|
|
||||||
myist = ist2(buf, len);
|
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) {
|
if (!ret) {
|
||||||
ns->counters->snd_error++;
|
ns->counters->snd_error++;
|
||||||
return -1;
|
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 dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t size)
|
||||||
{
|
{
|
||||||
ssize_t ret = -1;
|
ssize_t ret = -1;
|
||||||
|
|
||||||
if (ns->dgram) {
|
if (ns->dgram) {
|
||||||
struct dgram_conn *dgram = &ns->dgram->conn;
|
struct dgram_conn *dgram = &ns->dgram->conn;
|
||||||
|
|
@ -475,7 +475,6 @@ int dns_dgram_init(struct dns_nameserver *ns, struct sockaddr_storage *sk)
|
||||||
dgram->conn.t.sock.fd = -1;
|
dgram->conn.t.sock.fd = -1;
|
||||||
dgram->conn.addr.to = *sk;
|
dgram->conn.addr.to = *sk;
|
||||||
HA_SPIN_INIT(&dgram->conn.lock);
|
HA_SPIN_INIT(&dgram->conn.lock);
|
||||||
ns->dgram = dgram;
|
|
||||||
|
|
||||||
dgram->ofs_req = ~0; /* init ring offset */
|
dgram->ofs_req = ~0; /* init ring offset */
|
||||||
dgram->ring_req = dns_ring_new(2*DNS_TCP_MSG_RING_MAX_SIZE);
|
dgram->ring_req = dns_ring_new(2*DNS_TCP_MSG_RING_MAX_SIZE);
|
||||||
|
|
@ -490,6 +489,7 @@ 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");
|
ha_alert("nameserver sets too many watchers > 255 on ring. This is a bug and should not happen.\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ns->dgram = dgram;
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
dns_ring_free(dgram->ring_req);
|
dns_ring_free(dgram->ring_req);
|
||||||
|
|
@ -913,6 +913,7 @@ static int dns_session_init(struct appctx *appctx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
sockaddr_free(&addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1345,8 +1346,8 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
||||||
{
|
{
|
||||||
struct dns_stream_server *dss = NULL;
|
struct dns_stream_server *dss = NULL;
|
||||||
|
|
||||||
dss = calloc(1, sizeof(*dss));
|
dss = calloc(1, sizeof(*dss));
|
||||||
if (!dss) {
|
if (!dss) {
|
||||||
ha_alert("memory allocation error initializing dns tcp server '%s'.\n", srv->id);
|
ha_alert("memory allocation error initializing dns tcp server '%s'.\n", srv->id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -1362,7 +1363,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
||||||
}
|
}
|
||||||
/* Create the task associated to the resolver target handling conns */
|
/* Create the task associated to the resolver target handling conns */
|
||||||
if ((dss->task_req = task_new_anywhere()) == NULL) {
|
if ((dss->task_req = task_new_anywhere()) == NULL) {
|
||||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
ha_alert("memory allocation error initializing req task for dns tcp server '%s'.\n", srv->id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1379,7 +1380,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
||||||
|
|
||||||
/* Create the task associated to the resolver target handling conns */
|
/* Create the task associated to the resolver target handling conns */
|
||||||
if ((dss->task_rsp = task_new_anywhere()) == NULL) {
|
if ((dss->task_rsp = task_new_anywhere()) == NULL) {
|
||||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
ha_alert("memory allocation error initializing rsp task for dns tcp server '%s'.\n", srv->id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1389,7 +1390,7 @@ int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
|
||||||
|
|
||||||
/* Create the task associated to the resolver target handling conns */
|
/* Create the task associated to the resolver target handling conns */
|
||||||
if ((dss->task_idle = task_new_anywhere()) == NULL) {
|
if ((dss->task_idle = task_new_anywhere()) == NULL) {
|
||||||
ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
|
ha_alert("memory allocation error initializing idle task for dns tcp server '%s'.\n", srv->id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1425,7 +1426,7 @@ int init_dns_buffers()
|
||||||
if (!dns_msg_trash)
|
if (!dns_msg_trash)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinit_dns_buffers()
|
void deinit_dns_buffers()
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ static void usermsgs_put(const struct ist *msg)
|
||||||
{
|
{
|
||||||
/* Allocate the buffer if not already done. */
|
/* Allocate the buffer if not already done. */
|
||||||
if (unlikely(b_is_null(&usermsgs_buf))) {
|
if (unlikely(b_is_null(&usermsgs_buf))) {
|
||||||
usermsgs_buf.area = malloc(USER_MESSAGES_BUFSIZE * sizeof(char));
|
usermsgs_buf.area = malloc(array_size_or_fail(USER_MESSAGES_BUFSIZE, sizeof(char)));
|
||||||
if (usermsgs_buf.area)
|
if (usermsgs_buf.area)
|
||||||
usermsgs_buf.size = USER_MESSAGES_BUFSIZE;
|
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_CLI: svmode = "cli"; break;
|
||||||
case PR_MODE_SYSLOG: svmode = "syslog"; break;
|
case PR_MODE_SYSLOG: svmode = "syslog"; break;
|
||||||
case PR_MODE_PEERS: svmode = "peers"; break;
|
case PR_MODE_PEERS: svmode = "peers"; break;
|
||||||
case PR_MODE_HTTP: svmode = (s->mux_proto) ? s->mux_proto->token.ptr : "h1"; break;
|
case PR_MODE_HTTP: svmode = (s->mux_proto) ? s->mux_proto->mux_proto.ptr : "h1"; break;
|
||||||
case PR_MODE_TCP: svmode = "tcp"; break;
|
case PR_MODE_TCP: svmode = "tcp"; break;
|
||||||
case PR_MODE_SPOP: svmode = "spop"; break;
|
case PR_MODE_SPOP: svmode = "spop"; break;
|
||||||
/* all valid cases must be enumerated above, below is to avoid a warning */
|
/* 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;
|
px->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_DEL;
|
||||||
|
|
||||||
for (srv = px->srv; srv; srv = srv->next) {
|
for (srv = px->srv; srv; srv = srv->next) {
|
||||||
if (srv->mux_proto && isteq(srv->mux_proto->token, ist("fcgi"))) {
|
if (srv->mux_proto && isteq(srv->mux_proto->mux_proto, ist("fcgi"))) {
|
||||||
nb_fcgi_srv++;
|
nb_fcgi_srv++;
|
||||||
if (fcgi_conf)
|
if (fcgi_conf)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
2
src/fd.c
2
src/fd.c
|
|
@ -1166,7 +1166,7 @@ int init_pollers()
|
||||||
struct poller *bp;
|
struct poller *bp;
|
||||||
|
|
||||||
/* always provide an aligned fdtab */
|
/* always provide an aligned fdtab */
|
||||||
if ((fdtab = ha_aligned_zalloc(64, global.maxsock * sizeof(*fdtab))) == NULL) {
|
if ((fdtab = ha_aligned_zalloc(64, array_size_or_fail(global.maxsock, sizeof(*fdtab)))) == NULL) {
|
||||||
ha_alert("Not enough memory to allocate %d entries for fdtab!\n", global.maxsock);
|
ha_alert("Not enough memory to allocate %d entries for fdtab!\n", global.maxsock);
|
||||||
goto fail_tab;
|
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