2006-06-25 20:48:02 -04:00
/*
* Proxy variables and functions .
*
2009-03-05 17:48:25 -05:00
* Copyright 2000 - 2009 Willy Tarreau < w @ 1 wt . eu >
2006-06-25 20:48:02 -04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
# include <unistd.h>
2007-11-30 12:38:35 -05:00
# include <string.h>
2006-06-25 20:48:02 -04:00
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/stat.h>
2025-07-15 05:47:54 -04:00
# include <import/cebis_tree.h>
2020-06-09 03:07:15 -04:00
# include <import/eb32tree.h>
2021-03-24 11:13:20 -04:00
# include <haproxy/acl.h>
2020-05-27 06:58:42 -04:00
# include <haproxy/api.h>
2022-05-03 05:24:24 -04:00
# include <haproxy/applet.h>
2025-12-18 03:51:27 -05:00
# include <haproxy/backend.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/capture-t.h>
2020-06-04 18:00:29 -04:00
# include <haproxy/cfgparse.h>
2020-06-04 14:19:54 -04:00
# include <haproxy/cli.h>
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
# include <haproxy/counters.h>
2020-05-27 10:10:29 -04:00
# include <haproxy/errors.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/fd.h>
2020-06-04 15:29:29 -04:00
# include <haproxy/filters.h>
2026-01-30 10:31:04 -05:00
# include <haproxy/frontend.h>
2020-06-04 11:05:57 -04:00
# include <haproxy/global.h>
2024-03-26 10:26:43 -04:00
# include <haproxy/guid.h>
2020-06-04 15:21:03 -04:00
# include <haproxy/http_ana.h>
2021-02-12 02:49:47 -05:00
# include <haproxy/http_htx.h>
2022-12-28 09:37:57 -05:00
# include <haproxy/http_ext.h>
2023-05-11 04:30:27 -04:00
# include <haproxy/http_rules.h>
2024-06-17 12:39:19 -04:00
# include <haproxy/mailers.h>
2020-06-04 08:58:24 -04:00
# include <haproxy/listener.h>
2026-01-30 10:31:04 -05:00
# include <haproxy/lb_chash.h>
# include <haproxy/lb_fas.h>
# include <haproxy/lb_fwlc.h>
# include <haproxy/lb_fwrr.h>
# include <haproxy/lb_map.h>
# include <haproxy/lb_ss.h>
2020-06-04 16:01:04 -04:00
# include <haproxy/log.h>
2020-06-04 05:29:21 -04:00
# include <haproxy/obj_type-t.h>
2026-02-09 07:36:59 -05:00
# include <haproxy/openssl-compat.h> /* required for TLSEXT_TYPE_application_layer_protocol_negotiation */
2020-06-04 12:38:21 -04:00
# include <haproxy/peers.h>
2020-06-02 03:38:52 -04:00
# include <haproxy/pool.h>
2020-10-07 10:52:43 -04:00
# include <haproxy/protocol.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/proto_tcp.h>
2020-06-04 16:29:18 -04:00
# include <haproxy/proxy.h>
2022-05-27 03:25:10 -04:00
# include <haproxy/sc_strm.h>
2022-05-21 17:58:40 -04:00
# include <haproxy/quic_tp.h>
2026-01-30 10:31:04 -05:00
# include <haproxy/quic_tune.h>
2020-06-04 17:20:13 -04:00
# include <haproxy/server-t.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/signal.h>
2025-12-18 03:51:27 -05:00
# include <haproxy/stats.h>
2022-05-27 03:47:12 -04:00
# include <haproxy/stconn.h>
2020-06-04 17:46:14 -04:00
# include <haproxy/stream.h>
2020-06-04 11:25:40 -04:00
# include <haproxy/task.h>
2021-02-12 02:49:47 -05:00
# include <haproxy/tcpcheck.h>
2025-12-17 04:57:40 -05:00
# include <haproxy/thread.h>
2020-06-01 05:05:15 -04:00
# include <haproxy/time.h>
2021-05-08 07:02:07 -04:00
# include <haproxy/tools.h>
2024-11-13 13:54:32 -05:00
# include <haproxy/uri_auth.h>
2006-06-25 20:48:02 -04:00
2011-07-25 10:33:49 -04:00
int listeners ; /* # of proxy listeners, set by cfgparse */
2025-05-09 10:02:09 -04:00
struct proxy * proxies_list = NULL ; /* list of main proxies */
struct list proxies = LIST_HEAD_INIT ( proxies ) ; /* list of all proxies */
2025-08-23 13:57:29 -04:00
struct ceb_root * used_proxy_id = NULL ; /* list of proxy IDs in use */
2025-07-15 05:47:54 -04:00
struct ceb_root * proxy_by_name = NULL ; /* tree of proxies sorted by name */
struct ceb_root * defproxy_by_name = NULL ; /* tree of default proxies sorted by name (dups possible) */
2026-01-20 08:33:46 -05:00
struct list defaults_list = LIST_HEAD_INIT ( defaults_list ) ; /* list of all defaults proxies */
2010-12-12 08:00:34 -05:00
unsigned int error_snapshot_id = 0 ; /* global ID assigned to each error then incremented */
2006-06-25 20:48:02 -04:00
2025-12-23 10:15:47 -05:00
unsigned int dynpx_next_id = 0 ; /* lowest ID assigned to dynamic proxies */
2022-05-05 11:00:20 -04:00
/* CLI context used during "show servers {state|conn}" */
struct show_srv_ctx {
struct proxy * px ; /* current proxy to dump or NULL */
struct server * sv ; /* current server to dump or NULL */
uint only_pxid ; /* dump only this proxy ID when explicit */
int show_conn ; /* non-zero = "conn" otherwise "state" */
2022-05-05 13:26:18 -04:00
enum {
SHOW_SRV_HEAD = 0 ,
SHOW_SRV_LIST ,
} state ;
2022-05-05 11:00:20 -04:00
} ;
2018-11-11 09:40:36 -05:00
/* proxy->options */
const struct cfg_opt cfg_opts [ ] =
{
2025-10-08 02:34:43 -04:00
{ " abortonclose " , PR_O_ABRT_CLOSE , PR_CAP_BE | PR_CAP_FE , 0 , 0 } ,
2018-11-11 09:40:36 -05:00
{ " allbackups " , PR_O_USE_ALL_BK , PR_CAP_BE , 0 , 0 } ,
{ " checkcache " , PR_O_CHK_CACHE , PR_CAP_BE , 0 , PR_MODE_HTTP } ,
{ " clitcpka " , PR_O_TCP_CLI_KA , PR_CAP_FE , 0 , 0 } ,
{ " contstats " , PR_O_CONTSTATS , PR_CAP_FE , 0 , 0 } ,
{ " dontlognull " , PR_O_NULLNOLOG , PR_CAP_FE , 0 , 0 } ,
{ " http-buffer-request " , PR_O_WREQ_BODY , PR_CAP_FE | PR_CAP_BE , 0 , PR_MODE_HTTP } ,
2025-04-15 09:36:19 -04:00
{ " http-drop-request-trailers " , PR_O_HTTP_DROP_REQ_TRLS , PR_CAP_BE , 0 , PR_MODE_HTTP } ,
{ " http-drop-response-trailers " , PR_O_HTTP_DROP_RES_TRLS , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
2018-11-11 09:40:36 -05:00
{ " http-ignore-probes " , PR_O_IGNORE_PRB , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
MINOR: proxy: add option idle-close-on-response
Avoid closing idle connections if a soft stop is in progress.
By default, idle connections will be closed during a soft stop. In some
environments, a client talking to the proxy may have prepared some idle
connections in order to send requests later. If there is no proper retry
on write errors, this can result in errors while haproxy is reloading.
Even though a proper implementation should retry on connection/write
errors, this option was introduced to support back compat with haproxy <
v2.4. Indeed before v2.4, we were waiting for a last request to be able
to add a "connection: close" header and advice the client to close the
connection.
In a real life example, this behavior was seen in AWS using the ALB in
front of a haproxy. The end result was ALB sending 502 during haproxy
reloads.
This patch was tested on haproxy v2.4, with a regular reload on the
process, and a constant trend of requests coming in. Before the patch,
we see regular 502 returned to the client; when activating the option,
the 502 disappear.
This patch should help fixing github issue #1506.
In order to unblock some v2.3 to v2.4 migraton, this patch should be
backported up to v2.4 branch.
Signed-off-by: William Dauchy <wdauchy@gmail.com>
[wt: minor edits to the doc to mention other options to care about]
Signed-off-by: Willy Tarreau <w@1wt.eu>
2022-01-05 16:53:24 -05:00
{ " idle-close-on-response " , PR_O_IDLE_CLOSE_RESP , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
2018-11-11 09:40:36 -05:00
{ " prefer-last-server " , PR_O_PREF_LAST , PR_CAP_BE , 0 , PR_MODE_HTTP } ,
{ " logasap " , PR_O_LOGASAP , PR_CAP_FE , 0 , 0 } ,
{ " nolinger " , PR_O_TCP_NOLING , PR_CAP_FE | PR_CAP_BE , 0 , 0 } ,
{ " persist " , PR_O_PERSIST , PR_CAP_BE , 0 , 0 } ,
{ " srvtcpka " , PR_O_TCP_SRV_KA , PR_CAP_BE , 0 , 0 } ,
2019-05-22 13:24:06 -04:00
# ifdef USE_TPROXY
2018-11-11 09:40:36 -05:00
{ " transparent " , PR_O_TRANSP , PR_CAP_BE , 0 , 0 } ,
# else
{ " transparent " , 0 , 0 , 0 , 0 } ,
# endif
{ NULL , 0 , 0 , 0 , 0 }
} ;
/* proxy->options2 */
const struct cfg_opt cfg_opts2 [ ] =
{
2019-05-22 13:24:06 -04:00
# ifdef USE_LINUX_SPLICE
2018-11-11 09:40:36 -05:00
{ " splice-request " , PR_O2_SPLIC_REQ , PR_CAP_FE | PR_CAP_BE , 0 , 0 } ,
{ " splice-response " , PR_O2_SPLIC_RTR , PR_CAP_FE | PR_CAP_BE , 0 , 0 } ,
{ " splice-auto " , PR_O2_SPLIC_AUT , PR_CAP_FE | PR_CAP_BE , 0 , 0 } ,
# else
{ " splice-request " , 0 , 0 , 0 , 0 } ,
{ " splice-response " , 0 , 0 , 0 , 0 } ,
{ " splice-auto " , 0 , 0 , 0 , 0 } ,
# endif
2024-09-12 03:33:32 -04:00
{ " accept-unsafe-violations-in-http-request " , PR_O2_REQBUG_OK , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
{ " accept-unsafe-violations-in-http-response " , PR_O2_RSPBUG_OK , PR_CAP_BE , 0 , PR_MODE_HTTP } ,
2018-11-11 09:40:36 -05:00
{ " dontlog-normal " , PR_O2_NOLOGNORM , PR_CAP_FE , 0 , 0 } ,
{ " log-separate-errors " , PR_O2_LOGERRORS , PR_CAP_FE , 0 , 0 } ,
{ " log-health-checks " , PR_O2_LOGHCHKS , PR_CAP_BE , 0 , 0 } ,
{ " socket-stats " , PR_O2_SOCKSTAT , PR_CAP_FE , 0 , 0 } ,
{ " tcp-smart-accept " , PR_O2_SMARTACC , PR_CAP_FE , 0 , 0 } ,
{ " tcp-smart-connect " , PR_O2_SMARTCON , PR_CAP_BE , 0 , 0 } ,
{ " independent-streams " , PR_O2_INDEPSTR , PR_CAP_FE | PR_CAP_BE , 0 , 0 } ,
{ " http-use-proxy-header " , PR_O2_USE_PXHDR , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
{ " http-pretend-keepalive " , PR_O2_FAKE_KA , PR_CAP_BE , 0 , PR_MODE_HTTP } ,
{ " http-no-delay " , PR_O2_NODELAY , PR_CAP_FE | PR_CAP_BE , 0 , PR_MODE_HTTP } ,
MEDIUM: mux-h1: Add the support of headers adjustment for bogus HTTP/1 apps
There is no standard case for HTTP header names because, as stated in the
RFC7230, they are case-insensitive. So applications must handle them in a
case-insensitive manner. But some bogus applications erroneously rely on the
case used by most browsers. This problem becomes critical with HTTP/2
because all header names must be exchanged in lowercase. And HAProxy uses the
same convention. All header names are sent in lowercase to clients and servers,
regardless of the HTTP version.
This design choice is linked to the HTX implementation. So, for previous
versions (2.0 and 1.9), a workaround is to disable the HTX mode to fall
back to the legacy HTTP mode.
Since the legacy HTTP mode was removed, some users reported interoperability
issues because their application was not able anymore to handle HTTP/1 message
received from HAProxy. So, we've decided to add a way to change the case of some
headers before sending them. It is now possible to define a "mapping" between a
lowercase header name and a version supported by the bogus application. To do
so, you must use the global directives "h1-case-adjust" and
"h1-case-adjust-file". Then options "h1-case-adjust-bogus-client" and
"h1-case-adjust-bogus-server" may be used in proxy sections to enable the
conversion. See the configuration manual for more info.
Of course, our advice is to urgently upgrade these applications for
interoperability concerns and because they may be vulnerable to various types of
content smuggling attacks. But, if your are really forced to use an unmaintained
bogus application, you may use these directive, at your own risks.
If it is relevant, this feature may be backported to 2.0.
2019-07-22 10:18:24 -04:00
2022-09-06 04:09:40 -04:00
{ " h1-case-adjust-bogus-client " , PR_O2_H1_ADJ_BUGCLI , PR_CAP_FE , 0 , 0 } ,
{ " h1-case-adjust-bogus-server " , PR_O2_H1_ADJ_BUGSRV , PR_CAP_BE , 0 , 0 } ,
2020-06-02 11:33:56 -04:00
{ " disable-h2-upgrade " , PR_O2_NO_H2_UPGRADE , PR_CAP_FE , 0 , PR_MODE_HTTP } ,
2018-11-11 09:40:36 -05:00
{ NULL , 0 , 0 , 0 }
} ;
2025-03-07 04:55:31 -05:00
/* proxy->options3 */
const struct cfg_opt cfg_opts3 [ ] =
{
2025-03-07 05:00:59 -05:00
{ " assume-rfc6587-ntf " , PR_O3_ASSUME_RFC6587_NTF , PR_CAP_FE , 0 , PR_MODE_SYSLOG } ,
{ " dont-parse-log " , PR_O3_DONTPARSELOG , PR_CAP_FE , 0 , PR_MODE_SYSLOG } ,
2025-03-07 04:55:31 -05:00
{ NULL , 0 , 0 , 0 }
} ;
2023-08-08 05:37:59 -04:00
/* Helper function to resolve a single sticking rule after config parsing.
* Returns 1 for success and 0 for failure
*/
int resolve_stick_rule ( struct proxy * curproxy , struct sticking_rule * mrule )
{
struct stktable * target ;
if ( mrule - > table . name )
target = stktable_find_by_name ( mrule - > table . name ) ;
else
target = curproxy - > table ;
if ( ! target ) {
ha_alert ( " Proxy '%s': unable to find stick-table '%s'. \n " ,
curproxy - > id , mrule - > table . name ? mrule - > table . name : curproxy - > id ) ;
return 0 ;
}
else if ( ! stktable_compatible_sample ( mrule - > expr , target - > type ) ) {
ha_alert ( " Proxy '%s': type of fetch not usable with type of stick-table '%s'. \n " ,
curproxy - > id , mrule - > table . name ? mrule - > table . name : curproxy - > id ) ;
return 0 ;
}
/* success */
ha_free ( & mrule - > table . name ) ;
mrule - > table . t = target ;
stktable_alloc_data_type ( target , STKTABLE_DT_SERVER_ID , NULL , NULL ) ;
stktable_alloc_data_type ( target , STKTABLE_DT_SERVER_KEY , NULL , NULL ) ;
if ( ! in_proxies_list ( target - > proxies_list , curproxy ) ) {
curproxy - > next_stkt_ref = target - > proxies_list ;
target - > proxies_list = curproxy ;
}
return 1 ;
}
2023-11-16 05:29:58 -05:00
void free_stick_rules ( struct list * rules )
2021-03-24 11:13:20 -04:00
{
struct sticking_rule * rule , * ruleb ;
list_for_each_entry_safe ( rule , ruleb , rules , list ) {
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & rule - > list ) ;
2021-03-24 11:13:20 -04:00
free_acl_cond ( rule - > cond ) ;
release_sample_expr ( rule - > expr ) ;
free ( rule ) ;
}
}
2023-11-23 10:27:45 -05:00
void free_server_rules ( struct list * srules )
{
struct server_rule * srule , * sruleb ;
list_for_each_entry_safe ( srule , sruleb , srules , list ) {
LIST_DELETE ( & srule - > list ) ;
free_acl_cond ( srule - > cond ) ;
2024-02-23 09:57:21 -05:00
lf_expr_deinit ( & srule - > expr ) ;
2023-11-23 10:27:45 -05:00
free ( srule - > file ) ;
free ( srule ) ;
}
}
2024-06-10 13:31:19 -04:00
/* Frees proxy members that are common to all proxy types (either regular or
* default ones ) for a proxy that ' s about to be destroyed .
* This is a subset of the complete proxy or default proxy deinit code .
*/
static inline void proxy_free_common ( struct proxy * px )
{
struct acl * acl , * aclb ;
struct logger * log , * logb ;
BUG/MEDIUM: proxy: fix UAF with {tcp,http}checks logformat expressions
When parsing a logformat expression using parse_logformat_string(), the
caller passes the proxy under which the expression is found as argument.
This information allows the logformat expression API to check if the
expression is compatible with the proxy settings.
Since 7a21c3a ("MAJOR: log: implement proper postparsing for logformat
expressions"), the proxy compatibilty checks are postponed after the proxy
is fully parsed to ensure proxy properties are fully resolved for checks
consistency.
The way it works, is that each time parse_logformat_string() is called for
a given expression and proxy, it schedules the expression for postchecking
by appending the expression to the list of pending expression checks on
the proxy (lf_checks struct). Then, when the proxy is called with the
REGISTER_POST_PROXY_CHECK() hook, it iterates over unchecked expressions
and performs the check, then it removes the expression from its list.
However, I overlooked a special case: if a logformat expression is used
on a proxy that is disabled or a default proxy:
REGISTER_POST_PROXY_CHECK() hook is never called. Because of that, lf
expressions may still point to the proxy after the proxy is freed.
For most logformat expressions, this isn't an issue because they are
stored within the proxy itself, but this isn't the case with
{tcp,http}checks logformat expressions: during deinit() sequence, all
proxies are first cleaned up, and only then shared checks are freed.
Because of that, the below config will trigger UAF since 7a21c3a:
uaf.conf:
listen dummy
bind localhost:2222
backend testback
disabled
mode http
option httpchk
http-check send hdr test "test"
http-check expect status 200
haproxy -f uaf.conf -c:
==152096== Invalid write of size 8
==152096== at 0x21C317: lf_expr_deinit (log.c:3491)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:84)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:79)
==152096== by 0x2334A3: free_tcpcheck_http_hdrs (tcpcheck.c:98)
==152096== by 0x23365A: free_tcpcheck.part.0 (tcpcheck.c:130)
==152096== by 0x2338B1: free_tcpcheck (tcpcheck.c:108)
==152096== by 0x2338B1: deinit_tcpchecks (tcpcheck.c:3780)
==152096== by 0x2CF9A4: deinit (haproxy.c:2949)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
==152096== Address 0x52a8df8 is 6,968 bytes inside a block of size 7,168 free'd
==152096== at 0x484B27F: free (vg_replace_malloc.c:872)
==152096== by 0x2CF8AD: deinit (haproxy.c:2906)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
To fix the issue, let's ensure in proxy_free_common() that no unchecked
expressions may still point to the proxy after the proxy is freed by
purging the list (DEL_INIT is used to reset list items).
Special thanks to GH user @mhameed who filed a comprehensive issue with
all the relevant information required to reproduce the bug (see GH #2597),
after having first reported the issue on the alpine project bug tracker.
2024-06-10 14:21:02 -04:00
struct lf_expr * lf , * lfb ;
2024-06-10 13:31:19 -04:00
2025-04-19 04:21:19 -04:00
/* note that the node's key points to p->id */
2025-07-15 05:47:54 -04:00
cebis_item_delete ( ( px - > cap & PR_CAP_DEF ) ? & defproxy_by_name : & proxy_by_name , conf . name_node , id , px ) ;
2024-06-10 13:31:19 -04:00
ha_free ( & px - > id ) ;
2025-05-09 10:02:09 -04:00
LIST_DEL_INIT ( & px - > global_list ) ;
2024-09-19 09:35:11 -04:00
drop_file_name ( & px - > conf . file ) ;
2025-07-22 11:15:02 -04:00
counters_fe_shared_drop ( & px - > fe_counters . shared ) ;
counters_be_shared_drop ( & px - > be_counters . shared ) ;
2024-06-10 13:31:19 -04:00
ha_free ( & px - > check_command ) ;
ha_free ( & px - > check_path ) ;
ha_free ( & px - > cookie_name ) ;
ha_free ( & px - > rdp_cookie_name ) ;
ha_free ( & px - > dyncookie_key ) ;
ha_free ( & px - > cookie_domain ) ;
ha_free ( & px - > cookie_attrs ) ;
ha_free ( & px - > lbprm . arg_str ) ;
ha_free ( & px - > capture_name ) ;
istfree ( & px - > monitor_uri ) ;
ha_free ( & px - > conn_src . iface_name ) ;
# if defined(CONFIG_HAP_TRANSPARENT)
ha_free ( & px - > conn_src . bind_hdr_name ) ;
# endif
istfree ( & px - > server_id_hdr_name ) ;
istfree ( & px - > header_unique_id ) ;
http_ext_clean ( px ) ;
list_for_each_entry_safe ( acl , aclb , & px - > acl , list ) {
LIST_DELETE ( & acl - > list ) ;
prune_acl ( acl ) ;
free ( acl ) ;
}
free_act_rules ( & px - > tcp_req . inspect_rules ) ;
free_act_rules ( & px - > tcp_rep . inspect_rules ) ;
free_act_rules ( & px - > tcp_req . l4_rules ) ;
free_act_rules ( & px - > tcp_req . l5_rules ) ;
free_act_rules ( & px - > http_req_rules ) ;
free_act_rules ( & px - > http_res_rules ) ;
free_act_rules ( & px - > http_after_res_rules ) ;
2024-07-18 12:25:43 -04:00
# ifdef USE_QUIC
free_act_rules ( & px - > quic_init_rules ) ;
# endif
2024-06-10 13:31:19 -04:00
lf_expr_deinit ( & px - > logformat ) ;
lf_expr_deinit ( & px - > logformat_sd ) ;
lf_expr_deinit ( & px - > logformat_error ) ;
lf_expr_deinit ( & px - > format_unique_id ) ;
list_for_each_entry_safe ( log , logb , & px - > loggers , list ) {
LIST_DEL_INIT ( & log - > list ) ;
free_logger ( log ) ;
}
BUG/MEDIUM: proxy: fix UAF with {tcp,http}checks logformat expressions
When parsing a logformat expression using parse_logformat_string(), the
caller passes the proxy under which the expression is found as argument.
This information allows the logformat expression API to check if the
expression is compatible with the proxy settings.
Since 7a21c3a ("MAJOR: log: implement proper postparsing for logformat
expressions"), the proxy compatibilty checks are postponed after the proxy
is fully parsed to ensure proxy properties are fully resolved for checks
consistency.
The way it works, is that each time parse_logformat_string() is called for
a given expression and proxy, it schedules the expression for postchecking
by appending the expression to the list of pending expression checks on
the proxy (lf_checks struct). Then, when the proxy is called with the
REGISTER_POST_PROXY_CHECK() hook, it iterates over unchecked expressions
and performs the check, then it removes the expression from its list.
However, I overlooked a special case: if a logformat expression is used
on a proxy that is disabled or a default proxy:
REGISTER_POST_PROXY_CHECK() hook is never called. Because of that, lf
expressions may still point to the proxy after the proxy is freed.
For most logformat expressions, this isn't an issue because they are
stored within the proxy itself, but this isn't the case with
{tcp,http}checks logformat expressions: during deinit() sequence, all
proxies are first cleaned up, and only then shared checks are freed.
Because of that, the below config will trigger UAF since 7a21c3a:
uaf.conf:
listen dummy
bind localhost:2222
backend testback
disabled
mode http
option httpchk
http-check send hdr test "test"
http-check expect status 200
haproxy -f uaf.conf -c:
==152096== Invalid write of size 8
==152096== at 0x21C317: lf_expr_deinit (log.c:3491)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:84)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:79)
==152096== by 0x2334A3: free_tcpcheck_http_hdrs (tcpcheck.c:98)
==152096== by 0x23365A: free_tcpcheck.part.0 (tcpcheck.c:130)
==152096== by 0x2338B1: free_tcpcheck (tcpcheck.c:108)
==152096== by 0x2338B1: deinit_tcpchecks (tcpcheck.c:3780)
==152096== by 0x2CF9A4: deinit (haproxy.c:2949)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
==152096== Address 0x52a8df8 is 6,968 bytes inside a block of size 7,168 free'd
==152096== at 0x484B27F: free (vg_replace_malloc.c:872)
==152096== by 0x2CF8AD: deinit (haproxy.c:2906)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
To fix the issue, let's ensure in proxy_free_common() that no unchecked
expressions may still point to the proxy after the proxy is freed by
purging the list (DEL_INIT is used to reset list items).
Special thanks to GH user @mhameed who filed a comprehensive issue with
all the relevant information required to reproduce the bug (see GH #2597),
after having first reported the issue on the alpine project bug tracker.
2024-06-10 14:21:02 -04:00
/* ensure that remaining lf_expr that were not postchecked (ie: disabled
2024-06-11 04:52:37 -04:00
* proxy ) don ' t keep a reference on the proxy which is about to be freed .
BUG/MEDIUM: proxy: fix UAF with {tcp,http}checks logformat expressions
When parsing a logformat expression using parse_logformat_string(), the
caller passes the proxy under which the expression is found as argument.
This information allows the logformat expression API to check if the
expression is compatible with the proxy settings.
Since 7a21c3a ("MAJOR: log: implement proper postparsing for logformat
expressions"), the proxy compatibilty checks are postponed after the proxy
is fully parsed to ensure proxy properties are fully resolved for checks
consistency.
The way it works, is that each time parse_logformat_string() is called for
a given expression and proxy, it schedules the expression for postchecking
by appending the expression to the list of pending expression checks on
the proxy (lf_checks struct). Then, when the proxy is called with the
REGISTER_POST_PROXY_CHECK() hook, it iterates over unchecked expressions
and performs the check, then it removes the expression from its list.
However, I overlooked a special case: if a logformat expression is used
on a proxy that is disabled or a default proxy:
REGISTER_POST_PROXY_CHECK() hook is never called. Because of that, lf
expressions may still point to the proxy after the proxy is freed.
For most logformat expressions, this isn't an issue because they are
stored within the proxy itself, but this isn't the case with
{tcp,http}checks logformat expressions: during deinit() sequence, all
proxies are first cleaned up, and only then shared checks are freed.
Because of that, the below config will trigger UAF since 7a21c3a:
uaf.conf:
listen dummy
bind localhost:2222
backend testback
disabled
mode http
option httpchk
http-check send hdr test "test"
http-check expect status 200
haproxy -f uaf.conf -c:
==152096== Invalid write of size 8
==152096== at 0x21C317: lf_expr_deinit (log.c:3491)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:84)
==152096== by 0x2334A3: free_tcpcheck_http_hdr (tcpcheck.c:79)
==152096== by 0x2334A3: free_tcpcheck_http_hdrs (tcpcheck.c:98)
==152096== by 0x23365A: free_tcpcheck.part.0 (tcpcheck.c:130)
==152096== by 0x2338B1: free_tcpcheck (tcpcheck.c:108)
==152096== by 0x2338B1: deinit_tcpchecks (tcpcheck.c:3780)
==152096== by 0x2CF9A4: deinit (haproxy.c:2949)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
==152096== Address 0x52a8df8 is 6,968 bytes inside a block of size 7,168 free'd
==152096== at 0x484B27F: free (vg_replace_malloc.c:872)
==152096== by 0x2CF8AD: deinit (haproxy.c:2906)
==152096== by 0x2D0065: deinit_and_exit (haproxy.c:3052)
==152096== by 0x169BC0: main (haproxy.c:3996)
To fix the issue, let's ensure in proxy_free_common() that no unchecked
expressions may still point to the proxy after the proxy is freed by
purging the list (DEL_INIT is used to reset list items).
Special thanks to GH user @mhameed who filed a comprehensive issue with
all the relevant information required to reproduce the bug (see GH #2597),
after having first reported the issue on the alpine project bug tracker.
2024-06-10 14:21:02 -04:00
*/
list_for_each_entry_safe ( lf , lfb , & px - > conf . lf_checks , list )
LIST_DEL_INIT ( & lf - > list ) ;
2024-06-10 13:31:19 -04:00
chunk_destroy ( & px - > log_tag ) ;
2024-06-17 12:53:48 -04:00
free_email_alert ( px ) ;
2024-11-13 13:54:32 -05:00
stats_uri_auth_drop ( px - > uri_auth ) ;
px - > uri_auth = NULL ;
2024-06-10 13:31:19 -04:00
}
2025-04-10 04:37:33 -04:00
/* deinit all <p> proxy members, but doesn't touch to the parent pointer
* itself
*/
void deinit_proxy ( struct proxy * p )
2021-03-24 11:13:20 -04:00
{
2021-08-25 09:03:46 -04:00
struct server * s ;
2021-03-24 11:13:20 -04:00
struct cap_hdr * h , * h_next ;
struct listener * l , * l_next ;
struct bind_conf * bind_conf , * bind_back ;
struct acl_cond * cond , * condb ;
struct switching_rule * rule , * ruleb ;
struct redirect_rule * rdr , * rdrb ;
struct proxy_deinit_fct * pxdf ;
struct server_deinit_fct * srvdf ;
2021-08-20 04:16:37 -04:00
if ( ! p )
return ;
2024-06-10 13:31:19 -04:00
proxy_free_common ( p ) ;
/* regular proxy specific cleanup */
2022-04-25 04:25:34 -04:00
release_sample_expr ( p - > lbprm . expr ) ;
2021-03-24 11:13:20 -04:00
free ( p - > server_state_file_name ) ;
free ( p - > invalid_rep ) ;
free ( p - > invalid_req ) ;
if ( ( p - > lbprm . algo & BE_LB_LKUP ) = = BE_LB_LKUP_MAP )
free ( p - > lbprm . map . srv ) ;
list_for_each_entry_safe ( cond , condb , & p - > mon_fail_cond , list ) {
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & cond - > list ) ;
2023-05-11 06:29:51 -04:00
free_acl_cond ( cond ) ;
2021-03-24 11:13:20 -04:00
}
2024-03-26 10:26:43 -04:00
guid_remove ( & p - > guid ) ;
2021-03-24 11:13:20 -04:00
EXTRA_COUNTERS_FREE ( p - > extra_counters_fe ) ;
EXTRA_COUNTERS_FREE ( p - > extra_counters_be ) ;
2026-01-14 05:19:13 -05:00
list_for_each_entry_safe ( rule , ruleb , & p - > persist_rules , list ) {
LIST_DELETE ( & rule - > list ) ;
free_acl_cond ( rule - > cond ) ;
free ( rule ) ;
}
2023-11-23 10:27:45 -05:00
free_server_rules ( & p - > server_rules ) ;
2021-03-24 11:13:20 -04:00
list_for_each_entry_safe ( rule , ruleb , & p - > switching_rules , list ) {
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & rule - > list ) ;
2023-05-11 06:29:51 -04:00
free_acl_cond ( rule - > cond ) ;
2024-03-13 11:29:38 -04:00
if ( rule - > dynamic )
2024-02-23 09:57:21 -05:00
lf_expr_deinit ( & rule - > be . expr ) ;
2021-03-24 11:13:20 -04:00
free ( rule - > file ) ;
free ( rule ) ;
}
list_for_each_entry_safe ( rdr , rdrb , & p - > redirect_rules , list ) {
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & rdr - > list ) ;
2023-05-11 04:30:27 -04:00
http_free_redirect_rule ( rdr ) ;
2021-03-24 11:13:20 -04:00
}
free_stick_rules ( & p - > storersp_rules ) ;
free_stick_rules ( & p - > sticking_rules ) ;
h = p - > req_cap ;
while ( h ) {
2022-04-25 08:30:58 -04:00
if ( p - > defpx & & h = = p - > defpx - > req_cap )
break ;
2021-03-24 11:13:20 -04:00
h_next = h - > next ;
free ( h - > name ) ;
pool_destroy ( h - > pool ) ;
free ( h ) ;
h = h_next ;
} /* end while(h) */
h = p - > rsp_cap ;
while ( h ) {
2022-04-25 08:30:58 -04:00
if ( p - > defpx & & h = = p - > defpx - > rsp_cap )
break ;
2021-03-24 11:13:20 -04:00
h_next = h - > next ;
free ( h - > name ) ;
pool_destroy ( h - > pool ) ;
free ( h ) ;
h = h_next ;
} /* end while(h) */
s = p - > srv ;
while ( s ) {
list_for_each_entry ( srvdf , & server_deinit_list , list )
srvdf - > fct ( s ) ;
2025-05-12 10:09:15 -04:00
if ( p - > lbprm . server_deinit )
p - > lbprm . server_deinit ( s ) ;
2021-08-25 09:34:53 -04:00
s = srv_drop ( s ) ;
2021-03-24 11:13:20 -04:00
} /* end while(s) */
2023-06-01 06:07:43 -04:00
/* also free default-server parameters since some of them might have
* been dynamically allocated ( e . g . : config hints , cookies , ssl . . )
*/
2025-07-10 10:16:24 -04:00
if ( p - > defsrv ) {
srv_free_params ( p - > defsrv ) ;
2025-08-13 05:52:59 -04:00
srv_free ( & p - > defsrv ) ;
2025-07-10 10:16:24 -04:00
}
2023-06-01 06:07:43 -04:00
2025-03-25 12:24:46 -04:00
if ( p - > lbprm . proxy_deinit )
p - > lbprm . proxy_deinit ( p ) ;
2021-03-24 11:13:20 -04:00
list_for_each_entry_safe ( l , l_next , & p - > conf . listeners , by_fe ) {
2024-04-02 04:44:08 -04:00
guid_remove ( & l - > guid ) ;
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & l - > by_fe ) ;
LIST_DELETE ( & l - > by_bind ) ;
2021-03-24 11:13:20 -04:00
free ( l - > name ) ;
2025-05-26 01:38:11 -04:00
free ( l - > label ) ;
2022-01-25 10:21:47 -05:00
free ( l - > per_thr ) ;
2025-04-08 12:16:38 -04:00
if ( l - > counters ) {
2025-07-22 11:15:02 -04:00
counters_fe_shared_drop ( & l - > counters - > shared ) ;
2025-04-08 12:16:38 -04:00
free ( l - > counters ) ;
}
2023-11-21 05:10:34 -05:00
task_destroy ( l - > rx . rhttp . task ) ;
2021-03-24 11:13:20 -04:00
EXTRA_COUNTERS_FREE ( l - > extra_counters ) ;
free ( l ) ;
}
/* Release unused SSL configs. */
list_for_each_entry_safe ( bind_conf , bind_back , & p - > conf . bind , by_fe ) {
if ( bind_conf - > xprt - > destroy_bind_conf )
bind_conf - > xprt - > destroy_bind_conf ( bind_conf ) ;
free ( bind_conf - > file ) ;
free ( bind_conf - > arg ) ;
2023-06-01 04:58:44 -04:00
free ( bind_conf - > settings . interface ) ;
2021-04-21 01:32:39 -04:00
LIST_DELETE ( & bind_conf - > by_fe ) ;
2024-04-02 04:44:08 -04:00
free ( bind_conf - > guid_prefix ) ;
2023-11-21 05:10:34 -05:00
free ( bind_conf - > rhttp_srvname ) ;
2025-07-03 09:16:47 -04:00
free ( bind_conf - > tcp_md5sig ) ;
2025-09-17 11:03:42 -04:00
free ( bind_conf - > cc_algo ) ;
2021-03-24 11:13:20 -04:00
free ( bind_conf ) ;
}
flt_deinit ( p ) ;
list_for_each_entry ( pxdf , & proxy_deinit_list , list )
pxdf - > fct ( p ) ;
free ( p - > desc ) ;
2023-01-09 05:09:03 -05:00
2021-03-24 11:13:20 -04:00
task_destroy ( p - > task ) ;
pool_destroy ( p - > req_cap_pool ) ;
pool_destroy ( p - > rsp_cap_pool ) ;
2023-11-16 10:18:14 -05:00
2023-11-16 10:17:12 -05:00
stktable_deinit ( p - > table ) ;
2023-11-16 10:18:14 -05:00
ha_free ( & p - > table ) ;
2025-01-15 10:10:43 -05:00
ha_free ( & p - > per_tgrp ) ;
2021-03-24 11:13:20 -04:00
HA_RWLOCK_DESTROY ( & p - > lbprm . lock ) ;
HA_RWLOCK_DESTROY ( & p - > lock ) ;
2022-04-25 08:30:58 -04:00
proxy_unref_defaults ( p ) ;
2025-04-10 04:37:33 -04:00
}
/* deinit and free <p> proxy */
void free_proxy ( struct proxy * p )
{
deinit_proxy ( p ) ;
2021-03-24 11:13:20 -04:00
ha_free ( & p ) ;
}
2006-12-29 08:19:17 -05:00
/*
2007-11-04 01:04:43 -05:00
* This function returns a string containing a name describing capabilities to
* report comprehensible error messages . Specifically , it will return the words
2021-02-12 03:43:33 -05:00
* " frontend " , " backend " when appropriate , " defaults " if it corresponds to a
* defaults section , or " proxy " for all other cases including the proxies
* declared in " listen " mode .
2006-12-29 08:19:17 -05:00
*/
2007-11-04 01:04:43 -05:00
const char * proxy_cap_str ( int cap )
2006-12-29 08:19:17 -05:00
{
2021-02-12 03:43:33 -05:00
if ( cap & PR_CAP_DEF )
return " defaults " ;
2007-11-04 01:04:43 -05:00
if ( ( cap & PR_CAP_LISTEN ) ! = PR_CAP_LISTEN ) {
if ( cap & PR_CAP_FE )
return " frontend " ;
else if ( cap & PR_CAP_BE )
return " backend " ;
}
return " proxy " ;
2006-12-29 08:19:17 -05:00
}
2007-11-03 18:41:58 -04:00
/*
* This function returns a string containing the mode of the proxy in a format
* suitable for error messages .
*/
const char * proxy_mode_str ( int mode ) {
if ( mode = = PR_MODE_TCP )
return " tcp " ;
else if ( mode = = PR_MODE_HTTP )
return " http " ;
2018-10-26 08:47:40 -04:00
else if ( mode = = PR_MODE_CLI )
return " cli " ;
2022-03-08 05:50:59 -05:00
else if ( mode = = PR_MODE_SYSLOG )
return " syslog " ;
else if ( mode = = PR_MODE_PEERS )
return " peers " ;
2024-07-04 03:58:12 -04:00
else if ( mode = = PR_MODE_SPOP )
return " spop " ;
2007-11-03 18:41:58 -04:00
else
return " unknown " ;
}
2026-01-12 08:47:51 -05:00
/* Convert <mode> string into proxy mode type. PR_MODES is returned for unknown values. */
enum pr_mode str_to_proxy_mode ( const char * mode )
{
if ( strcmp ( mode , " http " ) = = 0 )
return PR_MODE_HTTP ;
else if ( strcmp ( mode , " tcp " ) = = 0 )
return PR_MODE_TCP ;
else if ( strcmp ( mode , " log " ) = = 0 )
return PR_MODE_SYSLOG ;
else if ( strcmp ( mode , " spop " ) = = 0 )
return PR_MODE_SPOP ;
return PR_MODES ;
}
2021-03-15 06:11:55 -04:00
/* try to find among known options the one that looks closest to <word> by
* counting transitions between letters , digits and other characters . Will
* return the best matching word if found , otherwise NULL . An optional array
* of extra words to compare may be passed in < extra > , but it must then be
* terminated by a NULL entry . If unused it may be NULL .
*/
const char * proxy_find_best_option ( const char * word , const char * * extra )
{
uint8_t word_sig [ 1024 ] ;
uint8_t list_sig [ 1024 ] ;
const char * best_ptr = NULL ;
int dist , best_dist = INT_MAX ;
int index ;
make_word_fingerprint ( word_sig , word ) ;
for ( index = 0 ; cfg_opts [ index ] . name ; index + + ) {
make_word_fingerprint ( list_sig , cfg_opts [ index ] . name ) ;
dist = word_fingerprint_distance ( word_sig , list_sig ) ;
if ( dist < best_dist ) {
best_dist = dist ;
best_ptr = cfg_opts [ index ] . name ;
}
}
for ( index = 0 ; cfg_opts2 [ index ] . name ; index + + ) {
make_word_fingerprint ( list_sig , cfg_opts2 [ index ] . name ) ;
dist = word_fingerprint_distance ( word_sig , list_sig ) ;
if ( dist < best_dist ) {
best_dist = dist ;
best_ptr = cfg_opts2 [ index ] . name ;
}
}
while ( extra & & * extra ) {
make_word_fingerprint ( list_sig , * extra ) ;
dist = word_fingerprint_distance ( word_sig , list_sig ) ;
if ( dist < best_dist ) {
best_dist = dist ;
best_ptr = * extra ;
}
extra + + ;
}
if ( best_dist > 2 * strlen ( word ) | | ( best_ptr & & best_dist > 2 * strlen ( best_ptr ) ) )
best_ptr = NULL ;
return best_ptr ;
}
2025-08-23 13:24:21 -04:00
/* This function returns the first unused proxy ID greater than or equal to
* < from > in used_proxy_id . Zero is returned if no spare one is found ( should
* never happen ) .
*/
uint proxy_get_next_id ( uint from )
{
2025-08-23 13:57:29 -04:00
const struct proxy * px ;
2025-08-23 13:24:21 -04:00
do {
2025-08-23 13:57:29 -04:00
px = ceb32_item_lookup_ge ( & used_proxy_id , conf . uuid_node , uuid , from , struct proxy ) ;
if ( ! px | | px - > uuid > from )
2025-08-23 13:24:21 -04:00
return from ; /* available */
from + + ;
} while ( from ) ;
return from ;
}
2007-12-02 19:30:13 -05:00
/* This function parses a "timeout" statement in a proxy section. It returns
* - 1 if there is any error , 1 for a warning , otherwise zero . If it does not
2012-05-08 13:47:01 -04:00
* return zero , it will write an error or warning message into a preallocated
* buffer returned at < err > . The trailing is not be written . The function must
* be called with < args > pointing to the first command line word , with < proxy >
* pointing to the proxy being parsed , and < defpx > to the default proxy or NULL .
* As a special case for compatibility with older configs , it also accepts
* " {cli|srv|con}timeout " in args [ 0 ] .
2007-12-02 19:30:13 -05:00
*/
2008-07-09 14:34:27 -04:00
static int proxy_parse_timeout ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2012-09-18 14:02:48 -04:00
char * * err )
2007-12-02 19:30:13 -05:00
{
unsigned timeout ;
int retval , cap ;
const char * res , * name ;
2008-07-06 18:09:58 -04:00
int * tv = NULL ;
2021-03-09 03:53:46 -05:00
const int * td = NULL ;
2007-12-02 19:30:13 -05:00
retval = 0 ;
2008-07-09 14:34:27 -04:00
/* simply skip "timeout" but remain compatible with old form */
if ( strcmp ( args [ 0 ] , " timeout " ) = = 0 )
args + + ;
2007-12-02 19:30:13 -05:00
name = args [ 0 ] ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( strcmp ( args [ 0 ] , " client " ) = = 0 ) {
2007-12-02 19:30:13 -05:00
name = " client " ;
2007-12-02 19:38:36 -05:00
tv = & proxy - > timeout . client ;
td = & defpx - > timeout . client ;
2007-12-02 19:30:13 -05:00
cap = PR_CAP_FE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " tarpit " ) = = 0 ) {
2007-12-02 19:30:13 -05:00
tv = & proxy - > timeout . tarpit ;
td = & defpx - > timeout . tarpit ;
2008-01-06 07:40:03 -05:00
cap = PR_CAP_FE | PR_CAP_BE ;
2023-11-17 12:03:20 -05:00
} else if ( strcmp ( args [ 0 ] , " client-hs " ) = = 0 ) {
tv = & proxy - > timeout . client_hs ;
td = & defpx - > timeout . client_hs ;
2023-11-14 12:31:38 -05:00
cap = PR_CAP_FE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " http-keep-alive " ) = = 0 ) {
2010-01-10 08:46:16 -05:00
tv = & proxy - > timeout . httpka ;
td = & defpx - > timeout . httpka ;
cap = PR_CAP_FE | PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " http-request " ) = = 0 ) {
2008-01-06 07:24:40 -05:00
tv = & proxy - > timeout . httpreq ;
td = & defpx - > timeout . httpreq ;
2009-07-12 04:03:17 -04:00
cap = PR_CAP_FE | PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " server " ) = = 0 ) {
2007-12-02 19:30:13 -05:00
name = " server " ;
2007-12-02 19:38:36 -05:00
tv = & proxy - > timeout . server ;
td = & defpx - > timeout . server ;
2007-12-02 19:30:13 -05:00
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " connect " ) = = 0 ) {
2007-12-02 19:30:13 -05:00
name = " connect " ;
2007-12-02 19:38:36 -05:00
tv = & proxy - > timeout . connect ;
td = & defpx - > timeout . connect ;
2007-12-02 19:30:13 -05:00
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " check " ) = = 0 ) {
2008-01-20 19:54:06 -05:00
tv = & proxy - > timeout . check ;
td = & defpx - > timeout . check ;
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " queue " ) = = 0 ) {
2007-12-02 19:30:13 -05:00
tv = & proxy - > timeout . queue ;
td = & defpx - > timeout . queue ;
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " tunnel " ) = = 0 ) {
2012-05-12 06:50:00 -04:00
tv = & proxy - > timeout . tunnel ;
td = & defpx - > timeout . tunnel ;
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " client-fin " ) = = 0 ) {
2014-05-10 08:30:07 -04:00
tv = & proxy - > timeout . clientfin ;
td = & defpx - > timeout . clientfin ;
cap = PR_CAP_FE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " server-fin " ) = = 0 ) {
2014-05-10 08:30:07 -04:00
tv = & proxy - > timeout . serverfin ;
td = & defpx - > timeout . serverfin ;
cap = PR_CAP_BE ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " clitimeout " ) = = 0 ) {
2019-05-14 14:57:59 -04:00
memprintf ( err , " the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout client'. " , args [ 0 ] ) ;
return - 1 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " srvtimeout " ) = = 0 ) {
2019-05-14 14:57:59 -04:00
memprintf ( err , " the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout server'. " , args [ 0 ] ) ;
return - 1 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " contimeout " ) = = 0 ) {
2019-05-14 14:57:59 -04:00
memprintf ( err , " the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout connect'. " , args [ 0 ] ) ;
return - 1 ;
2007-12-02 19:30:13 -05:00
} else {
2012-05-08 13:47:01 -04:00
memprintf ( err ,
" 'timeout' supports 'client', 'server', 'connect', 'check', "
2023-11-14 12:31:38 -05:00
" 'queue', 'handshake', 'http-keep-alive', 'http-request', 'tunnel', 'tarpit', "
2014-05-10 08:30:07 -04:00
" 'client-fin' and 'server-fin' (got '%s') " ,
2012-05-08 13:47:01 -04:00
args [ 0 ] ) ;
2007-12-02 19:30:13 -05:00
return - 1 ;
}
if ( * args [ 1 ] = = 0 ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " 'timeout %s' expects an integer value (in milliseconds) " , name ) ;
2007-12-02 19:30:13 -05:00
return - 1 ;
}
res = parse_time_err ( args [ 1 ] , & timeout , TIME_UNIT_MS ) ;
2019-06-07 13:00:37 -04:00
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to 'timeout %s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , name ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to 'timeout %s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , name ) ;
return - 1 ;
}
else if ( res ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " unexpected character '%c' in 'timeout %s' " , * res , name ) ;
2007-12-02 19:30:13 -05:00
return - 1 ;
}
2024-11-18 13:47:59 -05:00
if ( warn_if_lower ( args [ 1 ] , 100 ) ) {
memprintf ( err , " 'timeout %s %u' in %s '%s' is suspiciously small for a value in milliseconds. Please use an explicit unit ('%ums') if that was the intent. " ,
name , timeout , proxy_type_str ( proxy ) , proxy - > id , timeout ) ;
retval = 1 ;
}
2007-12-02 19:30:13 -05:00
if ( ! ( proxy - > cap & cap ) ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " 'timeout %s' will be ignored because %s '%s' has no %s capability " ,
name , proxy_type_str ( proxy ) , proxy - > id ,
( cap & PR_CAP_BE ) ? " backend " : " frontend " ) ;
2007-12-02 19:30:13 -05:00
retval = 1 ;
}
2008-07-06 18:09:58 -04:00
else if ( defpx & & * tv ! = * td ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " overwriting 'timeout %s' which was already specified " , name ) ;
2007-12-02 19:30:13 -05:00
retval = 1 ;
}
2014-05-22 02:24:46 -04:00
if ( * args [ 2 ] ! = 0 ) {
memprintf ( err , " 'timeout %s' : unexpected extra argument '%s' after value '%s'. " , name , args [ 2 ] , args [ 1 ] ) ;
retval = - 1 ;
}
2008-07-06 18:09:58 -04:00
* tv = MS_TO_TICKS ( timeout ) ;
2007-12-02 19:30:13 -05:00
return retval ;
}
2009-03-05 17:48:25 -05:00
/* This function parses a "rate-limit" statement in a proxy section. It returns
* - 1 if there is any error , 1 for a warning , otherwise zero . If it does not
2012-05-08 13:47:01 -04:00
* return zero , it will write an error or warning message into a preallocated
* buffer returned at < err > . The function must be called with < args > pointing
* to the first command line word , with < proxy > pointing to the proxy being
* parsed , and < defpx > to the default proxy or NULL .
2009-03-05 17:48:25 -05:00
*/
static int proxy_parse_rate_limit ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2012-09-18 14:02:48 -04:00
char * * err )
2009-03-05 17:48:25 -05:00
{
2020-01-15 19:34:27 -05:00
int retval ;
2012-05-08 13:47:01 -04:00
char * res ;
2009-03-05 17:48:25 -05:00
unsigned int * tv = NULL ;
2021-03-09 03:53:46 -05:00
const unsigned int * td = NULL ;
2009-03-05 17:48:25 -05:00
unsigned int val ;
retval = 0 ;
2012-05-08 13:47:01 -04:00
if ( strcmp ( args [ 1 ] , " sessions " ) = = 0 ) {
2009-05-10 12:52:49 -04:00
tv = & proxy - > fe_sps_lim ;
td = & defpx - > fe_sps_lim ;
2012-05-08 13:47:01 -04:00
}
else {
memprintf ( err , " '%s' only supports 'sessions' (got '%s') " , args [ 0 ] , args [ 1 ] ) ;
2009-03-05 17:48:25 -05:00
return - 1 ;
}
2012-05-08 13:47:01 -04:00
if ( * args [ 2 ] = = 0 ) {
memprintf ( err , " '%s %s' expects expects an integer value (in sessions/second) " , args [ 0 ] , args [ 1 ] ) ;
2009-03-05 17:48:25 -05:00
return - 1 ;
}
2012-05-08 13:47:01 -04:00
val = strtoul ( args [ 2 ] , & res , 0 ) ;
2009-03-05 17:48:25 -05:00
if ( * res ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " '%s %s' : unexpected character '%c' in integer value '%s' " , args [ 0 ] , args [ 1 ] , * res , args [ 2 ] ) ;
2009-03-05 17:48:25 -05:00
return - 1 ;
}
2020-01-15 19:34:27 -05:00
if ( ! ( proxy - > cap & PR_CAP_FE ) ) {
memprintf ( err , " %s %s will be ignored because %s '%s' has no frontend capability " ,
args [ 0 ] , args [ 1 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
2009-03-05 17:48:25 -05:00
retval = 1 ;
}
else if ( defpx & & * tv ! = * td ) {
2012-05-08 13:47:01 -04:00
memprintf ( err , " overwriting %s %s which was already specified " , args [ 0 ] , args [ 1 ] ) ;
2009-03-05 17:48:25 -05:00
retval = 1 ;
}
* tv = val ;
return retval ;
}
2014-04-25 07:58:37 -04:00
/* This function parses a "max-keep-alive-queue" statement in a proxy section.
* It returns - 1 if there is any error , 1 for a warning , otherwise zero . If it
* does not return zero , it will write an error or warning message into a
* preallocated buffer returned at < err > . The function must be called with
* < args > pointing to the first command line word , with < proxy > pointing to
* the proxy being parsed , and < defpx > to the default proxy or NULL .
*/
static int proxy_parse_max_ka_queue ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2014-04-25 07:58:37 -04:00
char * * err )
{
int retval ;
char * res ;
unsigned int val ;
retval = 0 ;
if ( * args [ 1 ] = = 0 ) {
memprintf ( err , " '%s' expects expects an integer value (or -1 to disable) " , args [ 0 ] ) ;
return - 1 ;
}
val = strtol ( args [ 1 ] , & res , 0 ) ;
if ( * res ) {
memprintf ( err , " '%s' : unexpected character '%c' in integer value '%s' " , args [ 0 ] , * res , args [ 1 ] ) ;
return - 1 ;
}
if ( ! ( proxy - > cap & PR_CAP_BE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no backend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
/* we store <val+1> so that a user-facing value of -1 is stored as zero (default) */
proxy - > max_ka_queue = val + 1 ;
return retval ;
}
2015-05-26 11:44:32 -04:00
/* This function parses a "declare" statement in a proxy section. It returns -1
* if there is any error , 1 for warning , otherwise 0. If it does not return zero ,
* it will write an error or warning message into a preallocated buffer returned
* at < err > . The function must be called with < args > pointing to the first command
* line word , with < proxy > pointing to the proxy being parsed , and < defpx > to the
* default proxy or NULL .
*/
static int proxy_parse_declare ( char * * args , int section , struct proxy * curpx ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2015-05-26 11:44:32 -04:00
char * * err )
{
/* Capture keyword wannot be declared in a default proxy. */
if ( curpx = = defpx ) {
2018-11-15 14:50:44 -05:00
memprintf ( err , " '%s' not available in default section " , args [ 0 ] ) ;
2015-05-26 11:44:32 -04:00
return - 1 ;
}
2021-01-07 23:35:52 -05:00
/* Capture keyword is only available in frontend. */
2015-05-26 11:44:32 -04:00
if ( ! ( curpx - > cap & PR_CAP_FE ) ) {
2018-11-15 14:50:44 -05:00
memprintf ( err , " '%s' only available in frontend or listen section " , args [ 0 ] ) ;
2015-05-26 11:44:32 -04:00
return - 1 ;
}
/* Check mandatory second keyword. */
if ( ! args [ 1 ] | | ! * args [ 1 ] ) {
memprintf ( err , " '%s' needs a second keyword that specify the type of declaration ('capture') " , args [ 0 ] ) ;
return - 1 ;
}
2018-11-15 14:46:55 -05:00
/* Actually, declare is only available for declaring capture
2015-05-26 11:44:32 -04:00
* slot , but in the future it can declare maps or variables .
2018-11-15 14:46:55 -05:00
* So , this section permits to check and switch according with
2015-05-26 11:44:32 -04:00
* the second keyword .
*/
if ( strcmp ( args [ 1 ] , " capture " ) = = 0 ) {
char * error = NULL ;
long len ;
struct cap_hdr * hdr ;
/* Check the next keyword. */
if ( ! args [ 2 ] | | ! * args [ 2 ] | |
( strcmp ( args [ 2 ] , " response " ) ! = 0 & &
strcmp ( args [ 2 ] , " request " ) ! = 0 ) ) {
memprintf ( err , " '%s %s' requires a direction ('request' or 'response') " , args [ 0 ] , args [ 1 ] ) ;
return - 1 ;
}
/* Check the 'len' keyword. */
if ( ! args [ 3 ] | | ! * args [ 3 ] | | strcmp ( args [ 3 ] , " len " ) ! = 0 ) {
memprintf ( err , " '%s %s' requires a capture length ('len') " , args [ 0 ] , args [ 1 ] ) ;
return - 1 ;
}
/* Check the length value. */
if ( ! args [ 4 ] | | ! * args [ 4 ] ) {
memprintf ( err , " '%s %s': 'len' requires a numeric value that represents the "
" capture length " ,
args [ 0 ] , args [ 1 ] ) ;
return - 1 ;
}
/* convert the length value. */
len = strtol ( args [ 4 ] , & error , 10 ) ;
if ( * error ! = ' \0 ' ) {
memprintf ( err , " '%s %s': cannot parse the length '%s'. " ,
args [ 0 ] , args [ 1 ] , args [ 3 ] ) ;
return - 1 ;
}
/* check length. */
if ( len < = 0 ) {
memprintf ( err , " length must be > 0 " ) ;
return - 1 ;
}
/* register the capture. */
2016-04-03 07:48:43 -04:00
hdr = calloc ( 1 , sizeof ( * hdr ) ) ;
2021-05-12 12:04:46 -04:00
if ( ! hdr ) {
memprintf ( err , " proxy '%s': out of memory while registering a capture " , curpx - > id ) ;
return - 1 ;
}
2015-05-26 11:44:32 -04:00
hdr - > name = NULL ; /* not a header capture */
hdr - > namelen = 0 ;
hdr - > len = len ;
hdr - > pool = create_pool ( " caphdr " , hdr - > len + 1 , MEM_F_SHARED ) ;
2026-01-26 05:13:29 -05:00
if ( ! hdr - > pool ) {
memprintf ( err , " out of memory " ) ;
free ( hdr ) ;
return - 1 ;
}
2015-05-26 11:44:32 -04:00
if ( strcmp ( args [ 2 ] , " request " ) = = 0 ) {
hdr - > next = curpx - > req_cap ;
hdr - > index = curpx - > nb_req_cap + + ;
curpx - > req_cap = hdr ;
}
if ( strcmp ( args [ 2 ] , " response " ) = = 0 ) {
hdr - > next = curpx - > rsp_cap ;
hdr - > index = curpx - > nb_rsp_cap + + ;
curpx - > rsp_cap = hdr ;
}
return 0 ;
}
else {
memprintf ( err , " unknown declaration type '%s' (supports 'capture') " , args [ 1 ] ) ;
return - 1 ;
}
}
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
/* This function parses a "retry-on" statement */
static int
proxy_parse_retry_on ( char * * args , int section , struct proxy * curpx ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
char * * err )
{
int i ;
if ( ! ( * args [ 1 ] ) ) {
memprintf ( err , " '%s' needs at least one keyword to specify when to retry " , args [ 0 ] ) ;
return - 1 ;
}
if ( ! ( curpx - > cap & PR_CAP_BE ) ) {
memprintf ( err , " '%s' only available in backend or listen section " , args [ 0 ] ) ;
return - 1 ;
}
curpx - > retry_type = 0 ;
for ( i = 1 ; * ( args [ i ] ) ; i + + ) {
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( strcmp ( args [ i ] , " conn-failure " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_CONN_FAILED ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " empty-response " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_DISCONNECTED ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " response-timeout " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_TIMEOUT ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 401 " ) = = 0 )
2020-11-12 05:14:05 -05:00
curpx - > retry_type | = PR_RE_401 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 403 " ) = = 0 )
2020-11-12 05:14:05 -05:00
curpx - > retry_type | = PR_RE_403 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 404 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_404 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 408 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_408 ;
2024-11-28 05:45:51 -05:00
else if ( strcmp ( args [ i ] , " 421 " ) = = 0 )
curpx - > retry_type | = PR_RE_421 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 425 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_425 ;
2024-08-27 13:09:08 -04:00
else if ( strcmp ( args [ i ] , " 429 " ) = = 0 )
curpx - > retry_type | = PR_RE_429 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 500 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_500 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 501 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_501 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 502 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_502 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 503 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_503 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 504 " ) = = 0 )
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
curpx - > retry_type | = PR_RE_504 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " 0rtt-rejected " ) = = 0 )
2019-05-03 16:46:27 -04:00
curpx - > retry_type | = PR_RE_EARLY_ERROR ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " junk-response " ) = = 0 )
2019-05-03 17:01:47 -04:00
curpx - > retry_type | = PR_RE_JUNK_REQUEST ;
MINOR: streams: Introduce a new retry-on keyword, all-retryable-errors.
Add a new retry-on keyword, "all-retryable-errors", that activates retry
for all errors that are considered retryable.
This currently activates retry for "conn-failure", "empty-response",
"junk-respones", "response-timeout", "0rtt-rejected", "500", "502", "503" and
"504".
2019-05-10 12:05:40 -04:00
else if ( ! ( strcmp ( args [ i ] , " all-retryable-errors " ) ) )
curpx - > retry_type | = PR_RE_CONN_FAILED | PR_RE_DISCONNECTED |
PR_RE_TIMEOUT | PR_RE_500 | PR_RE_502 |
PR_RE_503 | PR_RE_504 | PR_RE_EARLY_ERROR |
PR_RE_JUNK_REQUEST ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ i ] , " none " ) = = 0 ) {
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
if ( i ! = 1 | | * args [ i + 1 ] ) {
memprintf ( err , " '%s' 'none' keyworld only usable alone " , args [ 0 ] ) ;
return - 1 ;
}
} else {
memprintf ( err , " '%s': unknown keyword '%s' " , args [ 0 ] , args [ i ] ) ;
return - 1 ;
}
}
return 0 ;
}
2025-03-21 06:27:21 -04:00
/* This function parses a "hash-preserve-affinity" statement */
static int
proxy_parse_hash_preserve_affinity ( char * * args , int section , struct proxy * curpx ,
const struct proxy * defpx , const char * file , int line ,
char * * err )
{
if ( ! ( * args [ 1 ] ) ) {
memprintf ( err , " '%s' needs a keyword to specify when to preserve hash affinity " , args [ 0 ] ) ;
return - 1 ;
}
if ( ! ( curpx - > cap & PR_CAP_BE ) ) {
memprintf ( err , " '%s' only available in backend or listen section " , args [ 0 ] ) ;
return - 1 ;
}
curpx - > options3 & = ~ PR_O3_HASHAFNTY_MASK ;
if ( strcmp ( args [ 1 ] , " always " ) = = 0 )
curpx - > options3 | = PR_O3_HASHAFNTY_ALWS ;
else if ( strcmp ( args [ 1 ] , " maxconn " ) = = 0 )
curpx - > options3 | = PR_O3_HASHAFNTY_MAXCONN ;
else if ( strcmp ( args [ 1 ] , " maxqueue " ) = = 0 )
curpx - > options3 | = PR_O3_HASHAFNTY_MAXQUEUE ;
else {
memprintf ( err , " '%s': unknown keyword '%s' " , args [ 0 ] , args [ 1 ] ) ;
return - 1 ;
}
return 0 ;
}
2020-07-08 23:58:51 -04:00
# ifdef TCP_KEEPCNT
2020-07-08 22:13:20 -04:00
/* This function parses "{cli|srv}tcpka-cnt" statements */
static int proxy_parse_tcpka_cnt ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2020-07-08 22:13:20 -04:00
char * * err )
{
int retval ;
char * res ;
unsigned int tcpka_cnt ;
retval = 0 ;
if ( * args [ 1 ] = = 0 ) {
memprintf ( err , " '%s' expects an integer value " , args [ 0 ] ) ;
return - 1 ;
}
tcpka_cnt = strtol ( args [ 1 ] , & res , 0 ) ;
if ( * res ) {
memprintf ( err , " '%s' : unexpected character '%c' in integer value '%s' " , args [ 0 ] , * res , args [ 1 ] ) ;
return - 1 ;
}
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( strcmp ( args [ 0 ] , " clitcpka-cnt " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_FE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no frontend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > clitcpka_cnt = tcpka_cnt ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " srvtcpka-cnt " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_BE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no backend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > srvtcpka_cnt = tcpka_cnt ;
} else {
/* unreachable */
memprintf ( err , " '%s': unknown keyword " , args [ 0 ] ) ;
return - 1 ;
}
return retval ;
}
2020-07-08 23:58:51 -04:00
# endif
2020-07-08 22:13:20 -04:00
2020-07-08 23:58:51 -04:00
# ifdef TCP_KEEPIDLE
2020-07-08 22:13:20 -04:00
/* This function parses "{cli|srv}tcpka-idle" statements */
static int proxy_parse_tcpka_idle ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2020-07-08 22:13:20 -04:00
char * * err )
{
int retval ;
const char * res ;
unsigned int tcpka_idle ;
retval = 0 ;
if ( * args [ 1 ] = = 0 ) {
memprintf ( err , " '%s' expects an integer value " , args [ 0 ] ) ;
return - 1 ;
}
res = parse_time_err ( args [ 1 ] , & tcpka_idle , TIME_UNIT_S ) ;
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res ) {
memprintf ( err , " unexpected character '%c' in argument to <%s>. \n " , * res , args [ 0 ] ) ;
return - 1 ;
}
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( strcmp ( args [ 0 ] , " clitcpka-idle " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_FE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no frontend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > clitcpka_idle = tcpka_idle ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " srvtcpka-idle " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_BE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no backend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > srvtcpka_idle = tcpka_idle ;
} else {
/* unreachable */
memprintf ( err , " '%s': unknown keyword " , args [ 0 ] ) ;
return - 1 ;
}
return retval ;
}
2020-07-08 23:58:51 -04:00
# endif
2020-07-08 22:13:20 -04:00
2020-07-08 23:58:51 -04:00
# ifdef TCP_KEEPINTVL
2020-07-08 22:13:20 -04:00
/* This function parses "{cli|srv}tcpka-intvl" statements */
static int proxy_parse_tcpka_intvl ( char * * args , int section , struct proxy * proxy ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2020-07-08 22:13:20 -04:00
char * * err )
{
int retval ;
const char * res ;
unsigned int tcpka_intvl ;
retval = 0 ;
if ( * args [ 1 ] = = 0 ) {
memprintf ( err , " '%s' expects an integer value " , args [ 0 ] ) ;
return - 1 ;
}
res = parse_time_err ( args [ 1 ] , & tcpka_intvl , TIME_UNIT_S ) ;
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res ) {
memprintf ( err , " unexpected character '%c' in argument to <%s>. \n " , * res , args [ 0 ] ) ;
return - 1 ;
}
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( strcmp ( args [ 0 ] , " clitcpka-intvl " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_FE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no frontend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > clitcpka_intvl = tcpka_intvl ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
} else if ( strcmp ( args [ 0 ] , " srvtcpka-intvl " ) = = 0 ) {
2020-07-08 22:13:20 -04:00
if ( ! ( proxy - > cap & PR_CAP_BE ) ) {
memprintf ( err , " %s will be ignored because %s '%s' has no backend capability " ,
args [ 0 ] , proxy_type_str ( proxy ) , proxy - > id ) ;
retval = 1 ;
}
proxy - > srvtcpka_intvl = tcpka_intvl ;
} else {
/* unreachable */
memprintf ( err , " '%s': unknown keyword " , args [ 0 ] ) ;
return - 1 ;
}
return retval ;
}
2020-07-08 23:58:51 -04:00
# endif
2020-07-08 22:13:20 -04:00
2026-01-07 08:15:14 -05:00
static int proxy_parse_force_be_switch ( char * * args , int section_type , struct proxy * curpx ,
const struct proxy * defpx , const char * file , int line ,
char * * err )
{
struct acl_cond * cond = NULL ;
struct persist_rule * rule ;
if ( curpx - > cap & PR_CAP_DEF ) {
memprintf ( err , " '%s' not allowed in 'defaults' section. " , args [ 0 ] ) ;
goto err ;
}
if ( ! ( curpx - > cap & PR_CAP_FE ) ) {
memprintf ( err , " '%s' only available in frontend or listen section. " , args [ 0 ] ) ;
goto err ;
}
if ( strcmp ( args [ 1 ] , " if " ) ! = 0 & & strcmp ( args [ 1 ] , " unless " ) ! = 0 ) {
memprintf ( err , " '%s' requires either 'if' or 'unless' followed by a condition. " , args [ 0 ] ) ;
goto err ;
}
if ( ! ( cond = build_acl_cond ( file , line , & curpx - > acl , curpx , ( const char * * ) args + 1 , err ) ) ) {
memprintf ( err , " '%s' : %s. " , args [ 0 ] , * err ) ;
goto err ;
}
if ( warnif_cond_conflicts ( cond , SMP_VAL_FE_REQ_CNT , err ) ) {
memprintf ( err , " '%s' : %s. " , args [ 0 ] , * err ) ;
goto err ;
}
rule = calloc ( 1 , sizeof ( * rule ) ) ;
if ( ! rule ) {
memprintf ( err , " '%s' : out of memory. " , args [ 0 ] ) ;
goto err ;
}
rule - > cond = cond ;
rule - > type = PERSIST_TYPE_BE_SWITCH ;
LIST_INIT ( & rule - > list ) ;
LIST_APPEND ( & curpx - > persist_rules , & rule - > list ) ;
return 0 ;
err :
free_acl_cond ( cond ) ;
return - 1 ;
}
2024-03-26 10:26:43 -04:00
static int proxy_parse_guid ( char * * args , int section_type , struct proxy * curpx ,
const struct proxy * defpx , const char * file , int line ,
char * * err )
{
const char * guid ;
char * guid_err = NULL ;
if ( curpx - > cap & PR_CAP_DEF ) {
ha_alert ( " parsing [%s:%d] : '%s' not allowed in 'defaults' section. \n " , file , line , args [ 0 ] ) ;
return - 1 ;
}
if ( ! * args [ 1 ] ) {
memprintf ( err , " '%s' : expects an argument " , args [ 0 ] ) ;
return - 1 ;
}
guid = args [ 1 ] ;
if ( guid_insert ( & curpx - > obj_type , guid , & guid_err ) ) {
memprintf ( err , " '%s': %s " , args [ 0 ] , guid_err ) ;
ha_free ( & guid_err ) ;
return - 1 ;
}
return 0 ;
}
2021-02-12 07:52:11 -05:00
/* This function inserts proxy <px> into the tree of known proxies (regular
* ones or defaults depending on px - > cap & PR_CAP_DEF ) . The proxy ' s name is
* used as the storing key so it must already have been initialized .
2014-03-15 02:22:35 -04:00
*/
void proxy_store_name ( struct proxy * px )
{
2025-07-15 05:47:54 -04:00
struct ceb_root * * root = ( px - > cap & PR_CAP_DEF ) ? & defproxy_by_name : & proxy_by_name ;
2021-02-12 07:52:11 -05:00
2025-07-15 05:47:54 -04:00
cebis_item_insert ( root , conf . name_node , id , px ) ;
2014-03-15 02:22:35 -04:00
}
2015-05-26 09:25:32 -04:00
/* Returns a pointer to the first proxy matching capabilities <cap> and id
* < id > . NULL is returned if no match is found . If < table > is non - zero , it
* only considers proxies having a table .
2011-08-02 05:25:54 -04:00
*/
2015-05-26 09:25:32 -04:00
struct proxy * proxy_find_by_id ( int id , int cap , int table )
2015-05-26 05:24:42 -04:00
{
2025-08-23 13:57:29 -04:00
struct proxy * px ;
2009-11-01 21:27:13 -05:00
2025-08-23 13:57:29 -04:00
for ( px = ceb32_item_lookup ( & used_proxy_id , conf . uuid_node , uuid , id , struct proxy ) ;
px ; px = ceb32_item_next_dup ( & used_proxy_id , conf . uuid_node , uuid , px ) ) {
2015-05-26 09:25:32 -04:00
if ( ( px - > cap & cap ) ! = cap )
continue ;
2014-03-15 02:43:51 -04:00
2019-03-14 02:07:41 -04:00
if ( table & & ( ! px - > table | | ! px - > table - > size ) )
2015-05-26 09:25:32 -04:00
continue ;
2014-03-15 02:43:51 -04:00
2015-05-26 09:25:32 -04:00
return px ;
}
return NULL ;
}
2014-03-15 02:43:51 -04:00
2015-05-26 09:25:32 -04:00
/* Returns a pointer to the first proxy matching either name <name>, or id
* < name > if < name > begins with a ' # ' . NULL is returned if no match is found .
2021-02-12 07:52:11 -05:00
* If < table > is non - zero , it only considers proxies having a table . The search
* is made into the regular proxies , unless < cap > has PR_CAP_DEF set in which
* case it ' s searched into the defproxy tree .
2015-05-26 09:25:32 -04:00
*/
struct proxy * proxy_find_by_name ( const char * name , int cap , int table )
{
struct proxy * curproxy ;
2015-05-26 05:24:42 -04:00
2021-02-12 07:52:11 -05:00
if ( * name = = ' # ' & & ! ( cap & PR_CAP_DEF ) ) {
2015-05-26 09:25:32 -04:00
curproxy = proxy_find_by_id ( atoi ( name + 1 ) , cap , table ) ;
if ( curproxy )
2015-05-26 05:35:41 -04:00
return curproxy ;
2009-11-01 21:27:13 -05:00
}
2014-03-15 02:43:51 -04:00
else {
2025-07-15 05:47:54 -04:00
struct ceb_root * * root ;
2014-03-15 02:43:51 -04:00
2021-02-12 07:52:11 -05:00
root = ( cap & PR_CAP_DEF ) ? & defproxy_by_name : & proxy_by_name ;
2025-07-15 05:47:54 -04:00
for ( curproxy = cebis_item_lookup ( root , conf . name_node , id , name , struct proxy ) ;
curproxy ; curproxy = cebis_item_next_dup ( root , conf . name_node , id , curproxy ) ) {
2014-03-15 02:43:51 -04:00
if ( ( curproxy - > cap & cap ) ! = cap )
continue ;
2009-11-01 21:27:13 -05:00
2019-03-14 02:07:41 -04:00
if ( table & & ( ! curproxy - > table | | ! curproxy - > table - > size ) )
2015-05-26 05:24:42 -04:00
continue ;
2015-05-26 05:35:41 -04:00
return curproxy ;
2014-03-15 02:43:51 -04:00
}
}
2015-05-26 05:35:41 -04:00
return NULL ;
2009-11-01 21:27:13 -05:00
}
2015-05-27 10:46:26 -04:00
/* Finds the best match for a proxy with capabilities <cap>, name <name> and id
* < id > . At most one of < id > or < name > may be different provided that < cap > is
* valid . Either < id > or < name > may be left unspecified ( 0 ) . The purpose is to
* find a proxy based on some information from a previous configuration , across
* reloads or during information exchange between peers .
*
* Names are looked up first if present , then IDs are compared if present . In
* case of an inexact match whatever is forced in the configuration has
* precedence in the following order :
* - 1 ) forced ID ( proves a renaming / change of proxy type )
* - 2 ) proxy name + type ( may indicate a move if ID differs )
* - 3 ) automatic ID + type ( may indicate a renaming )
*
* Depending on what is found , we can end up in the following situations :
*
* name id cap | possible causes
* - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - -
* - - - - - - | nothing found
* - - - - ok | nothing found
* - - ok - - | proxy deleted , ID points to next one
* - - ok ok | proxy renamed , or deleted with ID pointing to next one
* ok - - - - | proxy deleted , but other half with same name still here ( before )
* ok - - ok | proxy ' s ID changed ( proxy moved in the config file )
* ok ok - - | proxy deleted , but other half with same name still here ( after )
* ok ok ok | perfect match
*
* Upon return if < diff > is not NULL , it is zeroed then filled with up to 3 bits :
2015-07-03 05:03:33 -04:00
* - PR_FBM_MISMATCH_ID : proxy was found but ID differs
* ( and ID was not zero )
* - PR_FBM_MISMATCH_NAME : proxy was found by ID but name differs
* ( and name was not NULL )
* - PR_FBM_MISMATCH_PROXYTYPE : a proxy of different type was found with
* the same name and / or id
2015-05-27 10:46:26 -04:00
*
* Only a valid proxy is returned . If capabilities do not match , NULL is
* returned . The caller can check < diff > to report detailed warnings / errors ,
* and decide whether or not to use what was found .
*/
struct proxy * proxy_find_best_match ( int cap , const char * name , int id , int * diff )
{
struct proxy * byname ;
struct proxy * byid ;
if ( ! name & & ! id )
return NULL ;
if ( diff )
* diff = 0 ;
byname = byid = NULL ;
if ( name ) {
byname = proxy_find_by_name ( name , cap , 0 ) ;
if ( byname & & ( ! id | | byname - > uuid = = id ) )
return byname ;
}
2018-11-15 14:46:55 -05:00
/* remaining possibilities :
2015-05-27 10:46:26 -04:00
* - name not set
* - name set but not found
* - name found , but ID doesn ' t match .
*/
if ( id ) {
byid = proxy_find_by_id ( id , cap , 0 ) ;
if ( byid ) {
if ( byname ) {
/* id+type found, name+type found, but not all 3.
* ID wins only if forced , otherwise name wins .
*/
if ( byid - > options & PR_O_FORCED_ID ) {
if ( diff )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_NAME ;
2015-05-27 10:46:26 -04:00
return byid ;
}
else {
if ( diff )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_ID ;
2015-05-27 10:46:26 -04:00
return byname ;
}
}
2018-11-15 14:46:55 -05:00
/* remaining possibilities :
2015-05-27 10:46:26 -04:00
* - name not set
* - name set but not found
*/
if ( name & & diff )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_NAME ;
2015-05-27 10:46:26 -04:00
return byid ;
}
/* ID not found */
if ( byname ) {
if ( diff )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_ID ;
2015-05-27 10:46:26 -04:00
return byname ;
}
}
2018-11-15 14:46:55 -05:00
/* All remaining possibilities will lead to NULL. If we can report more
2015-05-27 10:46:26 -04:00
* detailed information to the caller about changed types and / or name ,
* we ' ll do it . For example , we could detect that " listen foo " was
* split into " frontend foo_ft " and " backend foo_bk " if IDs are forced .
* - name not set , ID not found
* - name not found , ID not set
* - name not found , ID not found
*/
if ( ! diff )
return NULL ;
if ( name ) {
byname = proxy_find_by_name ( name , 0 , 0 ) ;
if ( byname & & ( ! id | | byname - > uuid = = id ) )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_PROXYTYPE ;
2015-05-27 10:46:26 -04:00
}
if ( id ) {
byid = proxy_find_by_id ( id , 0 , 0 ) ;
if ( byid ) {
if ( ! name )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_PROXYTYPE ; /* only type changed */
2015-05-27 10:46:26 -04:00
else if ( byid - > options & PR_O_FORCED_ID )
2015-07-03 05:03:33 -04:00
* diff | = PR_FBM_MISMATCH_NAME | PR_FBM_MISMATCH_PROXYTYPE ; /* name and type changed */
2015-05-27 10:46:26 -04:00
/* otherwise it's a different proxy that was returned */
}
}
return NULL ;
}
2009-03-15 08:46:16 -04:00
/* This function checks that the designated proxy has no http directives
* enabled . It will output a warning if there are , and will fix some of them .
* It returns the number of fatal errors encountered . This should be called
* at the end of the configuration parsing if the proxy is not in http mode .
* The < file > argument is used to construct the error message .
*/
2009-06-22 09:48:36 -04:00
int proxy_cfg_ensure_no_http ( struct proxy * curproxy )
2009-03-15 08:46:16 -04:00
{
if ( curproxy - > cookie_name ! = NULL ) {
2021-06-04 12:22:08 -04:00
ha_warning ( " cookie will be ignored for %s '%s' (needs 'mode http'). \n " ,
2017-11-24 10:50:31 -05:00
proxy_type_str ( curproxy ) , curproxy - > id ) ;
2009-03-15 08:46:16 -04:00
}
2009-10-03 06:21:20 -04:00
if ( curproxy - > lbprm . algo & BE_LB_NEED_HTTP ) {
2009-03-15 08:46:16 -04:00
curproxy - > lbprm . algo & = ~ BE_LB_ALGO ;
curproxy - > lbprm . algo | = BE_LB_ALGO_RR ;
2021-06-04 12:22:08 -04:00
ha_warning ( " Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin. \n " ,
2017-11-24 10:50:31 -05:00
proxy_type_str ( curproxy ) , curproxy - > id ) ;
2009-03-15 08:46:16 -04:00
}
2024-08-13 14:25:38 -04:00
if ( curproxy - > logformat . str = = default_http_log_format ) {
2013-04-12 12:13:46 -04:00
/* Note: we don't change the directive's file:line number */
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
curproxy - > logformat . str = default_tcp_log_format ;
2017-11-24 10:50:31 -05:00
ha_warning ( " parsing [%s:%d] : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'. \n " ,
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
curproxy - > logformat . conf . file , curproxy - > logformat . conf . line ,
2017-11-24 10:50:31 -05:00
proxy_type_str ( curproxy ) , curproxy - > id ) ;
2012-05-31 13:30:26 -04:00
}
2024-08-13 14:25:38 -04:00
else if ( curproxy - > logformat . str = = clf_http_log_format ) {
/* Note: we don't change the directive's file:line number */
curproxy - > logformat . str = clf_tcp_log_format ;
ha_warning ( " parsing [%s:%d] : 'option httplog clf' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog clf'. \n " ,
curproxy - > logformat . conf . file , curproxy - > logformat . conf . line ,
proxy_type_str ( curproxy ) , curproxy - > id ) ;
}
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
else if ( curproxy - > logformat . str = = default_https_log_format ) {
2021-07-29 03:45:52 -04:00
/* Note: we don't change the directive's file:line number */
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
curproxy - > logformat . str = default_tcp_log_format ;
2021-07-29 03:45:52 -04:00
ha_warning ( " parsing [%s:%d] : 'option httpslog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'. \n " ,
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
curproxy - > logformat . conf . file , curproxy - > logformat . conf . line ,
2021-07-29 03:45:52 -04:00
proxy_type_str ( curproxy ) , curproxy - > id ) ;
}
2012-05-31 13:30:26 -04:00
2009-03-15 08:46:16 -04:00
return 0 ;
}
2023-11-15 06:18:52 -05:00
/* This function checks that the designated proxy has no log directives
* enabled . It will output a warning if there are , and will fix some of them .
* It returns the number of fatal errors encountered . This should be called
* at the end of the configuration parsing if the proxy is not in log mode .
* The < file > argument is used to construct the error message .
*/
int proxy_cfg_ensure_no_log ( struct proxy * curproxy )
{
if ( curproxy - > lbprm . algo & BE_LB_NEED_LOG ) {
curproxy - > lbprm . algo & = ~ BE_LB_ALGO ;
curproxy - > lbprm . algo | = BE_LB_ALGO_RR ;
ha_warning ( " Unusable balance algorithm for %s '%s' (needs 'mode log'). Falling back to round robin. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id ) ;
}
return 0 ;
}
2026-01-20 05:41:37 -05:00
/* Perform the most basic initialization of <p> proxy and define some common
* default parameters values . Any new proxy or peer should be initialized via
* this function .
2011-07-28 19:49:03 -04:00
*/
void init_new_proxy ( struct proxy * p )
{
memset ( p , 0 , sizeof ( struct proxy ) ) ;
2012-11-11 18:42:33 -05:00
p - > obj_type = OBJ_TYPE_PROXY ;
2025-05-09 10:02:09 -04:00
LIST_INIT ( & p - > global_list ) ;
2026-01-20 08:33:46 -05:00
LIST_INIT ( & p - > el ) ;
2011-07-28 19:49:03 -04:00
LIST_INIT ( & p - > acl ) ;
LIST_INIT ( & p - > http_req_rules ) ;
2013-06-11 10:06:12 -04:00
LIST_INIT ( & p - > http_res_rules ) ;
2020-01-22 03:26:35 -05:00
LIST_INIT ( & p - > http_after_res_rules ) ;
2011-07-28 19:49:03 -04:00
LIST_INIT ( & p - > redirect_rules ) ;
LIST_INIT ( & p - > mon_fail_cond ) ;
LIST_INIT ( & p - > switching_rules ) ;
2012-04-05 15:09:48 -04:00
LIST_INIT ( & p - > server_rules ) ;
2011-07-28 19:49:03 -04:00
LIST_INIT ( & p - > persist_rules ) ;
LIST_INIT ( & p - > sticking_rules ) ;
LIST_INIT ( & p - > storersp_rules ) ;
LIST_INIT ( & p - > tcp_req . inspect_rules ) ;
LIST_INIT ( & p - > tcp_rep . inspect_rules ) ;
LIST_INIT ( & p - > tcp_req . l4_rules ) ;
2016-10-21 10:37:51 -04:00
LIST_INIT ( & p - > tcp_req . l5_rules ) ;
2024-07-18 12:25:43 -04:00
# ifdef USE_QUIC
LIST_INIT ( & p - > quic_init_rules ) ;
# endif
2019-08-08 09:47:21 -04:00
MT_LIST_INIT ( & p - > listener_queue ) ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
LIST_INIT ( & p - > loggers ) ;
2012-09-13 11:54:29 -04:00
LIST_INIT ( & p - > conf . bind ) ;
2012-09-20 10:48:07 -04:00
LIST_INIT ( & p - > conf . listeners ) ;
2020-01-13 09:52:01 -05:00
LIST_INIT ( & p - > conf . errors ) ;
MAJOR: sample: maintain a per-proxy list of the fetch args to resolve
While ACL args were resolved after all the config was parsed, it was not the
case with sample fetch args because they're almost everywhere now.
The issue is that ACLs now solely rely on sample fetches, so their args
resolving doesn't work anymore. And many fetches involving a server, a
proxy or a userlist don't work at all.
The real issue is that at the bottom layers we have no information about
proxies, line numbers, even ACLs in order to report understandable errors,
and that at the top layers we have no visibility over the locations where
fetches are referenced (think log node).
After failing multiple unsatisfying solutions attempts, we now have a new
concept of args list. The principle is that every proxy has a list head
which contains a number of indications such as the config keyword, the
context where it's used, the file and line number, etc... and a list of
arguments. This list head is of the same type as the elements, so it
serves as a template for adding new elements. This way, it is filled from
top to bottom by the callers with the information they have (eg: line
numbers, ACL name, ...) and the lower layers just have to duplicate it and
add an element when they face an argument they cannot resolve yet.
Then at the end of the configuration parsing, a loop passes over each
proxy's list and resolves all the args in sequence. And this way there is
all necessary information to report verbose errors.
The first immediate benefit is that for the first time we got very precise
location of issues (arg number in a keyword in its context, ...). Second,
in order to do this we had to parse log-format and unique-id-format a bit
earlier, so that was a great opportunity for doing so when the directives
are encountered (unless it's a default section). This way, the recorded
line numbers for these args are the ones of the place where the log format
is declared, not the end of the file.
Userlists report slightly more information now. They're the only remaining
ones in the ACL resolving function.
2013-04-02 10:34:32 -04:00
LIST_INIT ( & p - > conf . args . list ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
LIST_INIT ( & p - > conf . lf_checks ) ;
2016-02-04 07:40:26 -05:00
LIST_INIT ( & p - > filter_configs ) ;
2020-04-02 12:05:11 -04:00
LIST_INIT ( & p - > tcpcheck_rules . preset_vars ) ;
2011-07-28 19:49:03 -04:00
MAJOR: leastconn; Revamp the way servers are ordered.
For leastconn, servers used to just be stored in an ebtree.
Each server would be one node.
Change that so that nodes contain multiple mt_lists. Each list
will contain servers that share the same key (typically meaning
they have the same number of connections). Using mt_lists means
that as long as tree elements already exist, moving a server from
one tree element to another does no longer require the lbprm write
lock.
We use multiple mt_lists to reduce the contention when moving
a server from one tree element to another. A list in the new
element will be chosen randomly.
We no longer remove a tree element as soon as they no longer
contain any server. Instead, we keep a list of all elements,
and when we need a new element, we look at that list only if it
contains a number of elements already, otherwise we'll allocate
a new one. Keeping nodes in the tree ensures that we very
rarely have to take the lbrpm write lock (as it only happens
when we're moving the server to a position for which no
element is currently in the tree).
The number of mt_lists used is defined as FWLC_NB_LISTS.
The number of tree elements we want to keep is defined as
FWLC_MIN_FREE_ENTRIES, both in defaults.h.
The value used were picked afrer experimentation, and
seems to be the best choice of performances vs memory
usage.
Doing that gives a good boost in performances when a lot of
servers are used.
With a configuration using 500 servers, before that patch,
about 830000 requests per second could be processed, with
that patch, about 1550000 requests per second are
processed, on an 64-cores AMD, using 1200 concurrent connections.
2025-03-26 12:16:48 -04:00
MT_LIST_INIT ( & p - > lbprm . lb_free_list ) ;
2025-08-24 05:12:49 -04:00
p - > conf . used_listener_id = NULL ;
2025-08-24 05:21:02 -04:00
p - > conf . used_server_id = NULL ;
2025-07-07 09:13:15 -04:00
p - > used_server_addr = NULL ;
2021-02-12 03:15:16 -05:00
2011-07-28 19:49:03 -04:00
/* Timeouts are defined as -1 */
proxy_reset_timeouts ( p ) ;
p - > tcp_rep . inspect_delay = TICK_ETERNITY ;
2012-10-04 02:47:34 -04:00
/* initial uuid is unassigned (-1) */
p - > uuid = - 1 ;
2017-06-02 09:33:24 -04:00
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
/* Default to only allow L4 retries */
p - > retry_type = PR_RE_CONN_FAILED ;
2026-02-11 08:43:58 -05:00
p - > stream_new_from_sc = stream_new ;
2024-03-26 10:26:43 -04:00
guid_init ( & p - > guid ) ;
2020-11-10 08:24:31 -05:00
p - > extra_counters_fe = NULL ;
p - > extra_counters_be = NULL ;
2020-10-20 11:24:27 -04:00
HA_RWLOCK_INIT ( & p - > lock ) ;
2023-11-13 03:17:05 -05:00
2026-01-20 05:41:37 -05:00
lf_expr_init ( & p - > logformat ) ;
lf_expr_init ( & p - > logformat_sd ) ;
lf_expr_init ( & p - > format_unique_id ) ;
lf_expr_init ( & p - > logformat_error ) ;
/* initialize parameters to common default values */
p - > mode = PR_MODE_TCP ;
p - > options | = PR_O_REUSE_SAFE ;
p - > max_out_conns = MAX_SRV_LIST ;
p - > email_alert . level = LOG_ALERT ;
p - > load_server_state_from_file = PR_SRV_STATE_FILE_UNSPEC ;
if ( ! ( p - > cap & PR_CAP_INT ) ) {
p - > maxconn = cfg_maxpconn ;
p - > conn_retries = CONN_RETRIES ;
}
else {
p - > options2 | = PR_O2_INDEPSTR ;
p - > timeout . connect = 5000 ;
}
2011-07-28 19:49:03 -04:00
}
2025-01-15 10:10:43 -05:00
/* Initialize per-thread proxy fields */
int proxy_init_per_thr ( struct proxy * px )
{
int i ;
2025-11-07 16:10:45 -05:00
px - > per_tgrp = ha_aligned_zalloc_typed ( global . nbtgroups , typeof ( * px - > per_tgrp ) ) ;
2025-01-15 10:10:43 -05:00
for ( i = 0 ; i < global . nbtgroups ; i + + )
queue_init ( & px - > per_tgrp [ i ] . queue , px , NULL ) ;
return 0 ;
}
2026-01-30 10:31:04 -05:00
int proxy_finalize ( struct proxy * px , int * err_code )
{
struct bind_conf * bind_conf ;
struct server * newsrv ;
struct switching_rule * rule ;
struct server_rule * srule ;
struct sticking_rule * mrule ;
struct logger * tmplogger ;
unsigned int next_id ;
int cfgerr = 0 ;
char * err = NULL ;
int i ;
/* check and reduce the bind-proc of each listener */
list_for_each_entry ( bind_conf , & px - > conf . bind , by_fe ) {
int mode = conn_pr_mode_to_proto_mode ( px - > mode ) ;
const struct mux_proto_list * mux_ent ;
int ret ;
/* Check the mux protocols, if any; before the check the ALPN */
if ( bind_conf - > xprt & & bind_conf - > xprt = = xprt_get ( XPRT_QUIC ) ) {
if ( ! bind_conf - > mux_proto ) {
/* No protocol was specified. If we're using QUIC at the transport
* layer , we ' ll instantiate it as a mux as well . If QUIC is not
* compiled in , this will remain NULL .
*/
bind_conf - > mux_proto = get_mux_proto ( ist ( " quic " ) ) ;
}
if ( bind_conf - > options & BC_O_ACC_PROXY ) {
ha_alert ( " Binding [%s:%d] for %s %s: QUIC protocol does not support PROXY protocol yet. "
" 'accept-proxy' option cannot be used with a QUIC listener. \n " ,
bind_conf - > file , bind_conf - > line ,
proxy_type_str ( px ) , px - > id ) ;
cfgerr + + ;
}
}
if ( bind_conf - > mux_proto ) {
/* it is possible that an incorrect mux was referenced
* due to the proxy ' s mode not being taken into account
* on first pass . Let ' s adjust it now .
*/
mux_ent = conn_get_best_mux_entry ( bind_conf - > mux_proto - > token , PROTO_SIDE_FE , mode ) ;
if ( ! mux_ent | | ! isteq ( mux_ent - > token , bind_conf - > mux_proto - > token ) ) {
ha_alert ( " %s '%s' : MUX protocol '%.*s' is not usable for 'bind %s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) bind_conf - > mux_proto - > token . len ,
bind_conf - > mux_proto - > token . ptr ,
bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
cfgerr + + ;
}
else {
if ( ( mux_ent - > mux - > flags & MX_FL_FRAMED ) & & ! ( bind_conf - > options & BC_O_USE_SOCK_DGRAM ) ) {
ha_alert ( " %s '%s' : frame-based MUX protocol '%.*s' is incompatible with stream transport of 'bind %s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) bind_conf - > mux_proto - > token . len ,
bind_conf - > mux_proto - > token . ptr ,
bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
cfgerr + + ;
}
else if ( ! ( mux_ent - > mux - > flags & MX_FL_FRAMED ) & & ! ( bind_conf - > options & BC_O_USE_SOCK_STREAM ) ) {
ha_alert ( " %s '%s' : stream-based MUX protocol '%.*s' is incompatible with framed transport of 'bind %s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) bind_conf - > mux_proto - > token . len ,
bind_conf - > mux_proto - > token . ptr ,
bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
cfgerr + + ;
}
}
/* update the mux */
bind_conf - > mux_proto = mux_ent ;
}
/* HTTP frontends with "h2" as ALPN/NPN will work in
* HTTP / 2 and absolutely require buffers 16 kB or larger .
*/
# ifdef USE_OPENSSL
/* no-alpn ? If so, it's the right moment to remove it */
if ( bind_conf - > ssl_conf . alpn_str & & ! bind_conf - > ssl_conf . alpn_len ) {
ha_free ( & bind_conf - > ssl_conf . alpn_str ) ;
}
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
else if ( ! bind_conf - > ssl_conf . alpn_str & & ! bind_conf - > ssl_conf . npn_str & &
( ( bind_conf - > options & BC_O_USE_SSL ) | | bind_conf - > xprt = = xprt_get ( XPRT_QUIC ) ) & &
px - > mode = = PR_MODE_HTTP & & global . tune . bufsize > = 16384 ) {
/* Neither ALPN nor NPN were explicitly set nor disabled, we're
* in HTTP mode with an SSL or QUIC listener , we can enable ALPN .
* Note that it ' s in binary form . First we try to set the ALPN from
* mux proto if set . Otherwise rely on the default ALPN .
*/
if ( bind_conf - > mux_proto & & bind_conf - > mux_proto - > alpn )
bind_conf - > ssl_conf . alpn_str = strdup ( bind_conf - > mux_proto - > alpn ) ;
else if ( bind_conf - > xprt = = xprt_get ( XPRT_QUIC ) )
bind_conf - > ssl_conf . alpn_str = strdup ( " \002 h3 " ) ;
else
bind_conf - > ssl_conf . alpn_str = strdup ( " \002 h2 \010 http/1.1 " ) ;
if ( ! bind_conf - > ssl_conf . alpn_str ) {
ha_alert ( " Proxy '%s': out of memory while trying to allocate a default alpn string in 'bind %s' at [%s:%d]. \n " ,
px - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
cfgerr + + ;
* err_code | = ERR_FATAL | ERR_ALERT ;
goto out ;
}
bind_conf - > ssl_conf . alpn_len = strlen ( bind_conf - > ssl_conf . alpn_str ) ;
}
# endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
if ( px - > mode = = PR_MODE_HTTP & & global . tune . bufsize < 16384 ) {
# ifdef OPENSSL_NPN_NEGOTIATED
/* check NPN */
if ( bind_conf - > ssl_conf . npn_str & & strstr ( bind_conf - > ssl_conf . npn_str , " \002 h2 " ) ) {
ha_alert ( " HTTP frontend '%s' enables HTTP/2 via NPN at [%s:%d], so global.tune.bufsize must be at least 16384 bytes (%d now). \n " ,
px - > id , bind_conf - > file , bind_conf - > line , global . tune . bufsize ) ;
cfgerr + + ;
}
# endif /* OPENSSL_NPN_NEGOTIATED */
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
/* check ALPN */
if ( bind_conf - > ssl_conf . alpn_str & & strstr ( bind_conf - > ssl_conf . alpn_str , " \002 h2 " ) ) {
ha_alert ( " HTTP frontend '%s' enables HTTP/2 via ALPN at [%s:%d], so global.tune.bufsize must be at least 16384 bytes (%d now). \n " ,
px - > id , bind_conf - > file , bind_conf - > line , global . tune . bufsize ) ;
cfgerr + + ;
}
# endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
} /* HTTP && bufsize < 16384 */
# endif /* USE_OPENSSL */
# ifdef USE_QUIC
if ( bind_conf - > xprt = = xprt_get ( XPRT_QUIC ) ) {
const struct quic_cc_algo * cc_algo = bind_conf - > quic_cc_algo ?
bind_conf - > quic_cc_algo : default_quic_cc_algo ;
if ( ! ( cc_algo - > flags & QUIC_CC_ALGO_FL_OPT_PACING ) & &
! ( quic_tune . fe . fb_opts & QUIC_TUNE_FB_TX_PACING ) ) {
ha_warning ( " Binding [%s:%d] for %s %s: using the selected congestion algorithm without pacing may cause slowdowns or high loss rates during transfers. \n " ,
bind_conf - > file , bind_conf - > line ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
}
# endif /* USE_QUIC */
/* finish the bind setup */
ret = bind_complete_thread_setup ( bind_conf , err_code ) ;
if ( ret ! = 0 ) {
cfgerr + = ret ;
if ( * err_code & ERR_FATAL )
goto out ;
}
if ( bind_generate_guid ( bind_conf ) ) {
cfgerr + + ;
* err_code | = ERR_FATAL | ERR_ALERT ;
goto out ;
}
}
switch ( px - > mode ) {
case PR_MODE_TCP :
cfgerr + = proxy_cfg_ensure_no_http ( px ) ;
cfgerr + = proxy_cfg_ensure_no_log ( px ) ;
break ;
case PR_MODE_HTTP :
cfgerr + = proxy_cfg_ensure_no_log ( px ) ;
px - > http_needed = 1 ;
break ;
case PR_MODE_CLI :
cfgerr + = proxy_cfg_ensure_no_http ( px ) ;
cfgerr + = proxy_cfg_ensure_no_log ( px ) ;
break ;
case PR_MODE_SYSLOG :
/* this mode is initialized as the classic tcp proxy */
cfgerr + = proxy_cfg_ensure_no_http ( px ) ;
break ;
case PR_MODE_SPOP :
cfgerr + = proxy_cfg_ensure_no_http ( px ) ;
cfgerr + = proxy_cfg_ensure_no_log ( px ) ;
break ;
case PR_MODE_PEERS :
case PR_MODES :
/* should not happen, bug gcc warn missing switch statement */
ha_alert ( " %s '%s' cannot initialize this proxy mode (peers) in this way. NOTE: PLEASE REPORT THIS TO DEVELOPERS AS YOU'RE NOT SUPPOSED TO BE ABLE TO CREATE A CONFIGURATION TRIGGERING THIS! \n " ,
proxy_type_str ( px ) , px - > id ) ;
cfgerr + + ;
break ;
}
if ( ! ( px - > cap & PR_CAP_INT ) & & ( px - > cap & PR_CAP_FE ) & & LIST_ISEMPTY ( & px - > conf . listeners ) ) {
ha_warning ( " %s '%s' has no 'bind' directive. Please declare it as a backend if this was intended. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( px - > cap & PR_CAP_BE ) {
if ( px - > lbprm . algo & BE_LB_KIND ) {
if ( px - > options & PR_O_TRANSP ) {
ha_alert ( " %s '%s' cannot use both transparent and balance mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
cfgerr + + ;
}
else if ( px - > options & PR_O_DISPATCH ) {
ha_warning ( " dispatch address of %s '%s' will be ignored in balance mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
}
else if ( ! ( px - > options & ( PR_O_TRANSP | PR_O_DISPATCH ) ) ) {
/* If no LB algo is set in a backend, and we're not in
* transparent mode , dispatch mode nor proxy mode , we
* want to use balance random by default .
*/
px - > lbprm . algo & = ~ BE_LB_ALGO ;
px - > lbprm . algo | = BE_LB_ALGO_RND ;
}
}
if ( px - > options & PR_O_DISPATCH )
px - > options & = ~ PR_O_TRANSP ;
else if ( px - > options & PR_O_TRANSP )
px - > options & = ~ PR_O_DISPATCH ;
if ( ( px - > tcpcheck_rules . flags & TCPCHK_RULES_UNUSED_HTTP_RS ) ) {
ha_warning ( " %s '%s' uses http-check rules without 'option httpchk', so the rules are ignored. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ( px - > options2 & PR_O2_CHK_ANY ) = = PR_O2_TCPCHK_CHK & &
( px - > tcpcheck_rules . flags & TCPCHK_RULES_PROTO_CHK ) ! = TCPCHK_RULES_HTTP_CHK ) {
if ( px - > options & PR_O_DISABLE404 ) {
ha_warning ( " '%s' will be ignored for %s '%s' (requires 'option httpchk'). \n " ,
" disable-on-404 " , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
px - > options & = ~ PR_O_DISABLE404 ;
}
if ( px - > options2 & PR_O2_CHK_SNDST ) {
ha_warning ( " '%s' will be ignored for %s '%s' (requires 'option httpchk'). \n " ,
" send-state " , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
px - > options2 & = ~ PR_O2_CHK_SNDST ;
}
}
if ( ( px - > options2 & PR_O2_CHK_ANY ) = = PR_O2_EXT_CHK ) {
if ( ! global . external_check ) {
ha_alert ( " Proxy '%s' : '%s' unable to find required 'global.external-check'. \n " ,
px - > id , " option external-check " ) ;
cfgerr + + ;
}
if ( ! px - > check_command ) {
ha_alert ( " Proxy '%s' : '%s' unable to find required 'external-check command'. \n " ,
px - > id , " option external-check " ) ;
cfgerr + + ;
}
if ( ! ( global . tune . options & GTUNE_INSECURE_FORK ) ) {
ha_warning ( " Proxy '%s' : 'insecure-fork-wanted' not enabled in the global section, '%s' will likely fail. \n " ,
px - > id , " option external-check " ) ;
* err_code | = ERR_WARN ;
}
}
if ( px - > email_alert . flags & PR_EMAIL_ALERT_SET ) {
if ( ! ( px - > email_alert . mailers . name & & px - > email_alert . from & & px - > email_alert . to ) ) {
ha_warning ( " 'email-alert' will be ignored for %s '%s' (the presence any of "
" 'email-alert from', 'email-alert level' 'email-alert mailers', "
" 'email-alert myhostname', or 'email-alert to' "
" requires each of 'email-alert from', 'email-alert mailers' and 'email-alert to' "
" to be present). \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
free_email_alert ( px ) ;
}
if ( ! px - > email_alert . myhostname )
px - > email_alert . myhostname = strdup ( hostname ) ;
}
if ( px - > check_command ) {
int clear = 0 ;
if ( ( px - > options2 & PR_O2_CHK_ANY ) ! = PR_O2_EXT_CHK ) {
ha_warning ( " '%s' will be ignored for %s '%s' (requires 'option external-check'). \n " ,
" external-check command " , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
clear = 1 ;
}
if ( px - > check_command [ 0 ] ! = ' / ' & & ! px - > check_path ) {
ha_alert ( " Proxy '%s': '%s' does not have a leading '/' and 'external-check path' is not set. \n " ,
px - > id , " external-check command " ) ;
cfgerr + + ;
}
if ( clear ) {
ha_free ( & px - > check_command ) ;
}
}
if ( px - > check_path ) {
if ( ( px - > options2 & PR_O2_CHK_ANY ) ! = PR_O2_EXT_CHK ) {
ha_warning ( " '%s' will be ignored for %s '%s' (requires 'option external-check'). \n " ,
" external-check path " , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
ha_free ( & px - > check_path ) ;
}
}
/* if a default backend was specified, let's find it */
if ( px - > defbe . name ) {
struct proxy * target ;
target = proxy_be_by_name ( px - > defbe . name ) ;
if ( ! target ) {
ha_alert ( " Proxy '%s': unable to find required default_backend: '%s'. \n " ,
px - > id , px - > defbe . name ) ;
cfgerr + + ;
} else if ( target = = px ) {
ha_alert ( " Proxy '%s': loop detected for default_backend: '%s'. \n " ,
px - > id , px - > defbe . name ) ;
cfgerr + + ;
} else if ( target - > mode ! = px - > mode & &
! ( px - > mode = = PR_MODE_TCP & & target - > mode = = PR_MODE_HTTP ) ) {
ha_alert ( " %s %s '%s' (%s:%d) tries to use incompatible %s %s '%s' (%s:%d) as its default backend (see 'mode'). \n " ,
proxy_mode_str ( px - > mode ) , proxy_type_str ( px ) , px - > id ,
px - > conf . file , px - > conf . line ,
proxy_mode_str ( target - > mode ) , proxy_type_str ( target ) , target - > id ,
target - > conf . file , target - > conf . line ) ;
cfgerr + + ;
} else {
free ( px - > defbe . name ) ;
px - > defbe . be = target ;
/* Emit a warning if this proxy also has some servers */
if ( px - > srv ) {
ha_warning ( " In proxy '%s', the 'default_backend' rule always has precedence over the servers, which will never be used. \n " ,
px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( target - > mode = = PR_MODE_HTTP ) {
/* at least one of the used backends will provoke an
* HTTP upgrade
*/
px - > options | = PR_O_HTTP_UPG ;
}
}
}
/* find the target proxy for 'use_backend' rules */
list_for_each_entry ( rule , & px - > switching_rules , list ) {
struct proxy * target ;
struct logformat_node * node ;
char * pxname ;
/* Try to parse the string as a log format expression. If the result
* of the parsing is only one entry containing a simple string , then
* it ' s a standard string corresponding to a static rule , thus the
* parsing is cancelled and be . name is restored to be resolved .
*/
pxname = rule - > be . name ;
lf_expr_init ( & rule - > be . expr ) ;
px - > conf . args . ctx = ARGC_UBK ;
px - > conf . args . file = rule - > file ;
px - > conf . args . line = rule - > line ;
err = NULL ;
if ( ! parse_logformat_string ( pxname , px , & rule - > be . expr , 0 , SMP_VAL_FE_HRQ_HDR , & err ) ) {
ha_alert ( " Parsing [%s:%d]: failed to parse use_backend rule '%s' : %s. \n " ,
rule - > file , rule - > line , pxname , err ) ;
free ( err ) ;
cfgerr + + ;
continue ;
}
node = LIST_NEXT ( & rule - > be . expr . nodes . list , struct logformat_node * , list ) ;
if ( ! lf_expr_isempty ( & rule - > be . expr ) ) {
if ( node - > type ! = LOG_FMT_TEXT | | node - > list . n ! = & rule - > be . expr . nodes . list ) {
rule - > dynamic = 1 ;
free ( pxname ) ;
/* backend is not yet known so we cannot assume its type,
* thus we should consider that at least one of the used
* backends may provoke HTTP upgrade
*/
px - > options | = PR_O_HTTP_UPG ;
continue ;
}
/* Only one element in the list, a simple string: free the expression and
* fall back to static rule
*/
lf_expr_deinit ( & rule - > be . expr ) ;
}
rule - > dynamic = 0 ;
rule - > be . name = pxname ;
target = proxy_be_by_name ( rule - > be . name ) ;
if ( ! target ) {
ha_alert ( " Proxy '%s': unable to find required use_backend: '%s'. \n " ,
px - > id , rule - > be . name ) ;
cfgerr + + ;
} else if ( target = = px ) {
ha_alert ( " Proxy '%s': loop detected for use_backend: '%s'. \n " ,
px - > id , rule - > be . name ) ;
cfgerr + + ;
} else if ( target - > mode ! = px - > mode & &
! ( px - > mode = = PR_MODE_TCP & & target - > mode = = PR_MODE_HTTP ) ) {
ha_alert ( " %s %s '%s' (%s:%d) tries to use incompatible %s %s '%s' (%s:%d) in a 'use_backend' rule (see 'mode'). \n " ,
proxy_mode_str ( px - > mode ) , proxy_type_str ( px ) , px - > id ,
px - > conf . file , px - > conf . line ,
proxy_mode_str ( target - > mode ) , proxy_type_str ( target ) , target - > id ,
target - > conf . file , target - > conf . line ) ;
cfgerr + + ;
} else {
ha_free ( & rule - > be . name ) ;
rule - > be . backend = target ;
if ( target - > mode = = PR_MODE_HTTP ) {
/* at least one of the used backends will provoke an
* HTTP upgrade
*/
px - > options | = PR_O_HTTP_UPG ;
}
}
* err_code | = warnif_tcp_http_cond ( px , rule - > cond ) ;
}
/* find the target server for 'use_server' rules */
list_for_each_entry ( srule , & px - > server_rules , list ) {
struct server * target ;
struct logformat_node * node ;
char * server_name ;
/* We try to parse the string as a log format expression. If the result of the parsing
* is only one entry containing a single string , then it ' s a standard string corresponding
* to a static rule , thus the parsing is cancelled and we fall back to setting srv . ptr .
*/
server_name = srule - > srv . name ;
lf_expr_init ( & srule - > expr ) ;
px - > conf . args . ctx = ARGC_USRV ;
err = NULL ;
if ( ! parse_logformat_string ( server_name , px , & srule - > expr , 0 , SMP_VAL_FE_HRQ_HDR , & err ) ) {
ha_alert ( " Parsing [%s:%d]; use-server rule failed to parse log-format '%s' : %s. \n " ,
srule - > file , srule - > line , server_name , err ) ;
free ( err ) ;
cfgerr + + ;
continue ;
}
node = LIST_NEXT ( & srule - > expr . nodes . list , struct logformat_node * , list ) ;
if ( ! lf_expr_isempty ( & srule - > expr ) ) {
if ( node - > type ! = LOG_FMT_TEXT | | node - > list . n ! = & srule - > expr . nodes . list ) {
srule - > dynamic = 1 ;
free ( server_name ) ;
continue ;
}
/* Only one element in the list, a simple string: free the expression and
* fall back to static rule
*/
lf_expr_deinit ( & srule - > expr ) ;
}
srule - > dynamic = 0 ;
srule - > srv . name = server_name ;
target = server_find_by_name ( px , srule - > srv . name ) ;
* err_code | = warnif_tcp_http_cond ( px , srule - > cond ) ;
if ( ! target ) {
ha_alert ( " %s '%s' : unable to find server '%s' referenced in a 'use-server' rule. \n " ,
proxy_type_str ( px ) , px - > id , srule - > srv . name ) ;
cfgerr + + ;
continue ;
}
ha_free ( & srule - > srv . name ) ;
srule - > srv . ptr = target ;
target - > flags | = SRV_F_NON_PURGEABLE ;
}
/* find the target table for 'stick' rules */
list_for_each_entry ( mrule , & px - > sticking_rules , list ) {
px - > be_req_ana | = AN_REQ_STICKING_RULES ;
if ( mrule - > flags & STK_IS_STORE )
px - > be_rsp_ana | = AN_RES_STORE_RULES ;
if ( ! resolve_stick_rule ( px , mrule ) )
cfgerr + + ;
* err_code | = warnif_tcp_http_cond ( px , mrule - > cond ) ;
}
/* find the target table for 'store response' rules */
list_for_each_entry ( mrule , & px - > storersp_rules , list ) {
px - > be_rsp_ana | = AN_RES_STORE_RULES ;
if ( ! resolve_stick_rule ( px , mrule ) )
cfgerr + + ;
}
/* check validity for 'tcp-request' layer 4/5/6/7 rules */
cfgerr + = check_action_rules ( & px - > tcp_req . l4_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > tcp_req . l5_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > tcp_req . inspect_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > tcp_rep . inspect_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > http_req_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > http_res_rules , px , err_code ) ;
cfgerr + = check_action_rules ( & px - > http_after_res_rules , px , err_code ) ;
/* Warn is a switch-mode http is used on a TCP listener with servers but no backend */
if ( ! px - > defbe . name & & LIST_ISEMPTY ( & px - > switching_rules ) & & px - > srv ) {
if ( ( px - > options & PR_O_HTTP_UPG ) & & px - > mode = = PR_MODE_TCP )
ha_warning ( " Proxy '%s' : 'switch-mode http' configured for a %s %s with no backend. "
" Incoming connections upgraded to HTTP cannot be routed to TCP servers \n " ,
px - > id , proxy_mode_str ( px - > mode ) , proxy_type_str ( px ) ) ;
}
if ( px - > table & & px - > table - > peers . name ) {
struct peers * curpeers ;
for ( curpeers = cfg_peers ; curpeers ; curpeers = curpeers - > next ) {
if ( strcmp ( curpeers - > id , px - > table - > peers . name ) = = 0 ) {
ha_free ( & px - > table - > peers . name ) ;
px - > table - > peers . p = curpeers ;
break ;
}
}
if ( ! curpeers ) {
ha_alert ( " Proxy '%s': unable to find sync peers '%s'. \n " ,
px - > id , px - > table - > peers . name ) ;
ha_free ( & px - > table - > peers . name ) ;
px - > table - > peers . p = NULL ;
cfgerr + + ;
}
else if ( curpeers - > disabled ) {
/* silently disable this peers section */
px - > table - > peers . p = NULL ;
}
else if ( ! curpeers - > peers_fe ) {
ha_alert ( " Proxy '%s': unable to find local peer '%s' in peers section '%s'. \n " ,
px - > id , localpeer , curpeers - > id ) ;
px - > table - > peers . p = NULL ;
cfgerr + + ;
}
}
if ( px - > email_alert . mailers . name ) {
struct mailers * curmailers = mailers ;
for ( curmailers = mailers ; curmailers ; curmailers = curmailers - > next ) {
if ( strcmp ( curmailers - > id , px - > email_alert . mailers . name ) = = 0 )
break ;
}
if ( ! curmailers ) {
ha_alert ( " Proxy '%s': unable to find mailers '%s'. \n " ,
px - > id , px - > email_alert . mailers . name ) ;
free_email_alert ( px ) ;
cfgerr + + ;
}
else {
err = NULL ;
if ( init_email_alert ( curmailers , px , & err ) ) {
ha_alert ( " Proxy '%s': %s. \n " , px - > id , err ) ;
free ( err ) ;
cfgerr + + ;
}
}
}
if ( px - > uri_auth & & ! ( px - > uri_auth - > flags & STAT_F_CONVDONE ) & &
! LIST_ISEMPTY ( & px - > uri_auth - > http_req_rules ) & &
( px - > uri_auth - > userlist | | px - > uri_auth - > auth_realm ) ) {
ha_alert ( " %s '%s': stats 'auth'/'realm' and 'http-request' can't be used at the same time. \n " ,
" proxy " , px - > id ) ;
cfgerr + + ;
goto out_uri_auth_compat ;
}
if ( px - > uri_auth & & px - > uri_auth - > userlist & &
( ! ( px - > uri_auth - > flags & STAT_F_CONVDONE ) | |
LIST_ISEMPTY ( & px - > uri_auth - > http_req_rules ) ) ) {
const char * uri_auth_compat_req [ 10 ] ;
struct act_rule * rule ;
i = 0 ;
/* build the ACL condition from scratch. We're relying on anonymous ACLs for that */
uri_auth_compat_req [ i + + ] = " auth " ;
if ( px - > uri_auth - > auth_realm ) {
uri_auth_compat_req [ i + + ] = " realm " ;
uri_auth_compat_req [ i + + ] = px - > uri_auth - > auth_realm ;
}
uri_auth_compat_req [ i + + ] = " unless " ;
uri_auth_compat_req [ i + + ] = " { " ;
uri_auth_compat_req [ i + + ] = " http_auth(.internal-stats-userlist) " ;
uri_auth_compat_req [ i + + ] = " } " ;
uri_auth_compat_req [ i + + ] = " " ;
rule = parse_http_req_cond ( uri_auth_compat_req , " internal-stats-auth-compat " , 0 , px ) ;
if ( ! rule ) {
cfgerr + + ;
goto out ;
}
LIST_APPEND ( & px - > uri_auth - > http_req_rules , & rule - > list ) ;
if ( px - > uri_auth - > auth_realm ) {
ha_free ( & px - > uri_auth - > auth_realm ) ;
}
px - > uri_auth - > flags | = STAT_F_CONVDONE ;
}
out_uri_auth_compat :
/* check whether we have a logger that uses RFC5424 log format */
list_for_each_entry ( tmplogger , & px - > loggers , list ) {
if ( tmplogger - > format = = LOG_FORMAT_RFC5424 ) {
if ( ! px - > logformat_sd . str ) {
/* set the default logformat_sd_string */
px - > logformat_sd . str = default_rfc5424_sd_log_format ;
}
break ;
}
}
/* compile the log format */
if ( ! ( px - > cap & PR_CAP_FE ) ) {
lf_expr_deinit ( & px - > logformat ) ;
lf_expr_deinit ( & px - > logformat_sd ) ;
}
if ( px - > logformat . str ) {
px - > conf . args . ctx = ARGC_LOG ;
px - > conf . args . file = px - > logformat . conf . file ;
px - > conf . args . line = px - > logformat . conf . line ;
err = NULL ;
if ( ! lf_expr_compile ( & px - > logformat , & px - > conf . args ,
LOG_OPT_MANDATORY | LOG_OPT_MERGE_SPACES ,
SMP_VAL_FE_LOG_END , & err ) | |
! lf_expr_postcheck ( & px - > logformat , px , & err ) ) {
ha_alert ( " Parsing [%s:%d]: failed to parse log-format : %s. \n " ,
px - > logformat . conf . file , px - > logformat . conf . line , err ) ;
free ( err ) ;
cfgerr + + ;
}
px - > conf . args . file = NULL ;
px - > conf . args . line = 0 ;
}
if ( px - > logformat_sd . str ) {
px - > conf . args . ctx = ARGC_LOGSD ;
px - > conf . args . file = px - > logformat_sd . conf . file ;
px - > conf . args . line = px - > logformat_sd . conf . line ;
err = NULL ;
if ( ! lf_expr_compile ( & px - > logformat_sd , & px - > conf . args ,
LOG_OPT_MANDATORY | LOG_OPT_MERGE_SPACES ,
SMP_VAL_FE_LOG_END , & err ) | |
! add_to_logformat_list ( NULL , NULL , LF_SEPARATOR , & px - > logformat_sd , & err ) | |
! lf_expr_postcheck ( & px - > logformat_sd , px , & err ) ) {
ha_alert ( " Parsing [%s:%d]: failed to parse log-format-sd : %s. \n " ,
px - > logformat_sd . conf . file , px - > logformat_sd . conf . line , err ) ;
free ( err ) ;
cfgerr + + ;
}
px - > conf . args . file = NULL ;
px - > conf . args . line = 0 ;
}
if ( px - > format_unique_id . str ) {
int where = 0 ;
px - > conf . args . ctx = ARGC_UIF ;
px - > conf . args . file = px - > format_unique_id . conf . file ;
px - > conf . args . line = px - > format_unique_id . conf . line ;
err = NULL ;
if ( px - > cap & PR_CAP_FE )
where | = SMP_VAL_FE_HRQ_HDR ;
if ( px - > cap & PR_CAP_BE )
where | = SMP_VAL_BE_HRQ_HDR ;
if ( ! lf_expr_compile ( & px - > format_unique_id , & px - > conf . args ,
LOG_OPT_HTTP | LOG_OPT_MERGE_SPACES , where , & err ) | |
! lf_expr_postcheck ( & px - > format_unique_id , px , & err ) ) {
ha_alert ( " Parsing [%s:%d]: failed to parse unique-id : %s. \n " ,
px - > format_unique_id . conf . file , px - > format_unique_id . conf . line , err ) ;
free ( err ) ;
cfgerr + + ;
}
px - > conf . args . file = NULL ;
px - > conf . args . line = 0 ;
}
if ( px - > logformat_error . str ) {
px - > conf . args . ctx = ARGC_LOG ;
px - > conf . args . file = px - > logformat_error . conf . file ;
px - > conf . args . line = px - > logformat_error . conf . line ;
err = NULL ;
if ( ! lf_expr_compile ( & px - > logformat_error , & px - > conf . args ,
LOG_OPT_MANDATORY | LOG_OPT_MERGE_SPACES ,
SMP_VAL_FE_LOG_END , & err ) | |
! lf_expr_postcheck ( & px - > logformat_error , px , & err ) ) {
ha_alert ( " Parsing [%s:%d]: failed to parse error-log-format : %s. \n " ,
px - > logformat_error . conf . file , px - > logformat_error . conf . line , err ) ;
free ( err ) ;
cfgerr + + ;
}
px - > conf . args . file = NULL ;
px - > conf . args . line = 0 ;
}
/* "balance hash" needs to compile its expression
* ( log backends will handle this in proxy log postcheck )
*/
if ( px - > mode ! = PR_MODE_SYSLOG & &
( px - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_SMP ) {
int idx = 0 ;
const char * args [ ] = {
px - > lbprm . arg_str ,
NULL ,
} ;
err = NULL ;
px - > conf . args . ctx = ARGC_USRV ; // same context as use_server.
px - > lbprm . expr =
sample_parse_expr ( ( char * * ) args , & idx ,
px - > conf . file , px - > conf . line ,
& err , & px - > conf . args , NULL ) ;
if ( ! px - > lbprm . expr ) {
ha_alert ( " %s '%s' [%s:%d]: failed to parse 'balance hash' expression '%s' in : %s. \n " ,
proxy_type_str ( px ) , px - > id ,
px - > conf . file , px - > conf . line ,
px - > lbprm . arg_str , err ) ;
ha_free ( & err ) ;
cfgerr + + ;
}
else if ( ! ( px - > lbprm . expr - > fetch - > val & SMP_VAL_BE_SET_SRV ) ) {
ha_alert ( " %s '%s' [%s:%d]: error detected while parsing 'balance hash' expression '%s' "
" which requires information from %s, which is not available here. \n " ,
proxy_type_str ( px ) , px - > id ,
px - > conf . file , px - > conf . line ,
px - > lbprm . arg_str , sample_src_names ( px - > lbprm . expr - > fetch - > use ) ) ;
cfgerr + + ;
}
else if ( px - > mode = = PR_MODE_HTTP & & ( px - > lbprm . expr - > fetch - > use & SMP_USE_L6REQ ) ) {
ha_warning ( " %s '%s' [%s:%d]: L6 sample fetch <%s> will be ignored in 'balance hash' expression in HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ,
px - > conf . file , px - > conf . line ,
px - > lbprm . arg_str ) ;
}
else
px - > http_needed | = ! ! ( px - > lbprm . expr - > fetch - > use & SMP_USE_HTTP_ANY ) ;
}
/* only now we can check if some args remain unresolved.
* This must be done after the users and groups resolution .
*/
err = NULL ;
i = smp_resolve_args ( px , & err ) ;
cfgerr + = i ;
if ( i ) {
indent_msg ( & err , 8 ) ;
ha_alert ( " %s%s \n " , i > 1 ? " multiple argument resolution errors: " : " " , err ) ;
ha_free ( & err ) ;
} else
cfgerr + = acl_find_targets ( px ) ;
if ( ! ( px - > cap & PR_CAP_INT ) & & ( px - > mode = = PR_MODE_TCP | | px - > mode = = PR_MODE_HTTP ) & &
( ( ( px - > cap & PR_CAP_FE ) & & ! px - > timeout . client ) | |
( ( px - > cap & PR_CAP_BE ) & & ( px - > srv ) & &
( ! px - > timeout . connect | |
( ! px - > timeout . server & & ( px - > mode = = PR_MODE_HTTP | | ! px - > timeout . tunnel ) ) ) ) ) ) {
ha_warning ( " missing timeouts for %s '%s'. \n "
" | While not properly invalid, you will certainly encounter various problems \n "
" | with such a configuration. To fix this, please ensure that all following \n "
" | timeouts are set to a non-zero value: 'client', 'connect', 'server'. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
/* Historically, the tarpit and queue timeouts were inherited from contimeout.
* We must still support older configurations , so let ' s find out whether those
* parameters have been set or must be copied from contimeouts .
*/
if ( ! px - > timeout . tarpit )
px - > timeout . tarpit = px - > timeout . connect ;
if ( ( px - > cap & PR_CAP_BE ) & & ! px - > timeout . queue )
px - > timeout . queue = px - > timeout . connect ;
if ( ( px - > tcpcheck_rules . flags & TCPCHK_RULES_UNUSED_TCP_RS ) ) {
ha_warning ( " %s '%s' uses tcp-check rules without 'option tcp-check', so the rules are ignored. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
/* ensure that cookie capture length is not too large */
if ( px - > capture_len > = global . tune . cookie_len ) {
ha_warning ( " truncating capture length to %d bytes for %s '%s'. \n " ,
global . tune . cookie_len - 1 , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
px - > capture_len = global . tune . cookie_len - 1 ;
}
/* The small pools required for the capture lists */
if ( px - > nb_req_cap ) {
px - > req_cap_pool = create_pool ( " ptrcap " ,
px - > nb_req_cap * sizeof ( char * ) ,
MEM_F_SHARED ) ;
}
if ( px - > nb_rsp_cap ) {
px - > rsp_cap_pool = create_pool ( " ptrcap " ,
px - > nb_rsp_cap * sizeof ( char * ) ,
MEM_F_SHARED ) ;
}
switch ( px - > load_server_state_from_file ) {
case PR_SRV_STATE_FILE_UNSPEC :
px - > load_server_state_from_file = PR_SRV_STATE_FILE_NONE ;
break ;
case PR_SRV_STATE_FILE_GLOBAL :
if ( ! global . server_state_file ) {
ha_warning ( " backend '%s' configured to load server state file from global section 'server-state-file' directive. Unfortunately, 'server-state-file' is not set! \n " ,
px - > id ) ;
* err_code | = ERR_WARN ;
}
break ;
}
/* first, we will invert the servers list order */
newsrv = NULL ;
while ( px - > srv ) {
struct server * next ;
next = px - > srv - > next ;
px - > srv - > next = newsrv ;
newsrv = px - > srv ;
if ( ! next )
break ;
px - > srv = next ;
}
/* Check that no server name conflicts. This causes trouble in the stats.
* We only emit an error for the first conflict affecting each server ,
* in order to avoid combinatory explosion if all servers have the same
* name . Since servers names are stored in a tree before landing here ,
* we simply have to check for the current server ' s duplicates to spot
* conflicts .
*/
for ( newsrv = px - > srv ; newsrv ; newsrv = newsrv - > next ) {
struct server * other_srv ;
/* Note: internal servers are not always registered and
* they do not conflict .
*/
if ( ! ceb_intree ( & newsrv - > conf . name_node ) )
continue ;
2026-02-23 04:10:05 -05:00
if ( ( other_srv = cebis_item_prev_dup ( & px - > conf . used_server_name , conf . name_node , id , newsrv ) ) ) {
2026-01-30 10:31:04 -05:00
ha_alert ( " parsing [%s:%d] : %s '%s', another server named '%s' was already defined at line %d, please use distinct names. \n " ,
newsrv - > conf . file , newsrv - > conf . line ,
proxy_type_str ( px ) , px - > id ,
newsrv - > id , other_srv - > conf . line ) ;
cfgerr + + ;
2026-02-23 04:10:05 -05:00
continue ;
2026-01-30 10:31:04 -05:00
}
}
/* assign automatic UIDs to servers which don't have one yet */
next_id = 1 ;
newsrv = px - > srv ;
while ( newsrv ! = NULL ) {
if ( ! newsrv - > puid ) {
/* server ID not set, use automatic numbering with first
* spare entry starting with next_svid .
*/
next_id = server_get_next_id ( px , next_id ) ;
newsrv - > puid = next_id ;
server_index_id ( px , newsrv ) ;
}
next_id + + ;
newsrv = newsrv - > next ;
}
px - > lbprm . wmult = 1 ; /* default weight multiplier */
px - > lbprm . wdiv = 1 ; /* default weight divider */
/*
* If this server supports a maxconn parameter , it needs a dedicated
* tasks to fill the emptied slots when a connection leaves .
* Also , resolve deferred tracking dependency if needed .
*/
newsrv = px - > srv ;
while ( newsrv ! = NULL ) {
set_usermsgs_ctx ( newsrv - > conf . file , newsrv - > conf . line , & newsrv - > obj_type ) ;
srv_minmax_conn_apply ( newsrv ) ;
/* this will also properly set the transport layer for
* prod and checks
* if default - server have use_ssl , prerare ssl init
* without activating it */
if ( newsrv - > use_ssl = = 1 | | newsrv - > check . use_ssl = = 1 | |
( newsrv - > proxy - > options & PR_O_TCPCHK_SSL ) | |
( ( newsrv - > flags & SRV_F_DEFSRV_USE_SSL ) & & newsrv - > use_ssl ! = 1 ) ) {
if ( xprt_get ( XPRT_SSL ) & & xprt_get ( XPRT_SSL ) - > prepare_srv )
cfgerr + = xprt_get ( XPRT_SSL ) - > prepare_srv ( newsrv ) ;
else if ( xprt_get ( XPRT_QUIC ) & & xprt_get ( XPRT_QUIC ) - > prepare_srv )
cfgerr + = xprt_get ( XPRT_QUIC ) - > prepare_srv ( newsrv ) ;
}
2026-02-19 10:31:25 -05:00
/* In HTTP only, if the SNI is not set and we can rely on the
* host header value , fill the sni expression accordingly
*/
if ( newsrv - > proxy - > mode = = PR_MODE_HTTP & &
( newsrv - > use_ssl = = 1 | | ( newsrv - > flags & SRV_F_DEFSRV_USE_SSL ) ) & &
! newsrv - > sni_expr & & ! ( newsrv - > ssl_ctx . options & SRV_SSL_O_NO_AUTO_SNI ) ) {
if ( srv_configure_auto_sni ( newsrv , err_code , & err ) ) {
ha_alert ( " parsing [%s:%d]: %s. \n " ,
newsrv - > conf . file , newsrv - > conf . line , err ) ;
ha_free ( & err ) ;
+ + cfgerr ;
if ( * err_code & ERR_ABORT )
2026-02-19 10:04:04 -05:00
goto out ;
2026-02-19 10:31:25 -05:00
goto next_srv ;
2026-01-30 10:31:04 -05:00
}
}
if ( ( newsrv - > flags & SRV_F_FASTOPEN ) & &
( ( px - > retry_type & ( PR_RE_DISCONNECTED | PR_RE_TIMEOUT ) ) ! =
( PR_RE_DISCONNECTED | PR_RE_TIMEOUT ) ) )
ha_warning ( " server has tfo activated, the backend should be configured with at least 'conn-failure', 'empty-response' and 'response-timeout' or we wouldn't be able to retry the connection on failure. \n " ) ;
if ( newsrv - > trackit ) {
if ( srv_apply_track ( newsrv , px ) ) {
+ + cfgerr ;
goto next_srv ;
}
}
next_srv :
reset_usermsgs_ctx ( ) ;
newsrv = newsrv - > next ;
}
/*
* Try to generate dynamic cookies for servers now .
* It couldn ' t be done earlier , since at the time we parsed
* the server line , we may not have known yet that we
* should use dynamic cookies , or the secret key may not
* have been provided yet .
*/
if ( px - > ck_opts & PR_CK_DYNAMIC ) {
newsrv = px - > srv ;
while ( newsrv ! = NULL ) {
srv_set_dyncookie ( newsrv ) ;
newsrv = newsrv - > next ;
}
}
/* We have to initialize the server lookup mechanism depending
* on what LB algorithm was chosen .
*/
px - > lbprm . algo & = ~ ( BE_LB_LKUP | BE_LB_PROP_DYN ) ;
switch ( px - > lbprm . algo & BE_LB_KIND ) {
case BE_LB_KIND_RR :
if ( ( px - > lbprm . algo & BE_LB_PARM ) = = BE_LB_RR_STATIC ) {
px - > lbprm . algo | = BE_LB_LKUP_MAP ;
init_server_map ( px ) ;
} else if ( ( px - > lbprm . algo & BE_LB_PARM ) = = BE_LB_RR_RANDOM ) {
px - > lbprm . algo | = BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN ;
if ( chash_init_server_tree ( px ) < 0 ) {
cfgerr + + ;
}
} else {
px - > lbprm . algo | = BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN ;
fwrr_init_server_groups ( px ) ;
}
break ;
case BE_LB_KIND_CB :
if ( ( px - > lbprm . algo & BE_LB_PARM ) = = BE_LB_CB_LC ) {
px - > lbprm . algo | = BE_LB_LKUP_LCTREE | BE_LB_PROP_DYN ;
fwlc_init_server_tree ( px ) ;
} else {
px - > lbprm . algo | = BE_LB_LKUP_FSTREE | BE_LB_PROP_DYN ;
fas_init_server_tree ( px ) ;
}
break ;
case BE_LB_KIND_HI :
if ( ( px - > lbprm . algo & BE_LB_HASH_TYPE ) = = BE_LB_HASH_CONS ) {
px - > lbprm . algo | = BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN ;
if ( chash_init_server_tree ( px ) < 0 ) {
cfgerr + + ;
}
} else {
px - > lbprm . algo | = BE_LB_LKUP_MAP ;
init_server_map ( px ) ;
}
break ;
case BE_LB_KIND_SA :
if ( ( px - > lbprm . algo & BE_LB_PARM ) = = BE_LB_SA_SS ) {
px - > lbprm . algo | = BE_LB_PROP_DYN ;
init_server_ss ( px ) ;
}
break ;
}
HA_RWLOCK_INIT ( & px - > lbprm . lock ) ;
if ( px - > options & PR_O_LOGASAP )
px - > to_log & = ~ LW_BYTES ;
if ( ! ( px - > cap & PR_CAP_INT ) & & ( px - > mode = = PR_MODE_TCP | | px - > mode = = PR_MODE_HTTP ) & &
( px - > cap & PR_CAP_FE ) & & LIST_ISEMPTY ( & px - > loggers ) & &
( ! lf_expr_isempty ( & px - > logformat ) | | ! lf_expr_isempty ( & px - > logformat_sd ) ) ) {
ha_warning ( " log format ignored for %s '%s' since it has no log address. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( px - > mode ! = PR_MODE_HTTP & & ! ( px - > options & PR_O_HTTP_UPG ) ) {
int optnum ;
if ( px - > uri_auth ) {
ha_warning ( " 'stats' statement ignored for %s '%s' as it requires HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
stats_uri_auth_drop ( px - > uri_auth ) ;
px - > uri_auth = NULL ;
}
if ( px - > capture_name ) {
ha_warning ( " 'capture' statement ignored for %s '%s' as it requires HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( isttest ( px - > monitor_uri ) ) {
ha_warning ( " 'monitor-uri' statement ignored for %s '%s' as it requires HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ! LIST_ISEMPTY ( & px - > http_req_rules ) ) {
ha_warning ( " 'http-request' rules ignored for %s '%s' as they require HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ! LIST_ISEMPTY ( & px - > http_res_rules ) ) {
ha_warning ( " 'http-response' rules ignored for %s '%s' as they require HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ! LIST_ISEMPTY ( & px - > http_after_res_rules ) ) {
ha_warning ( " 'http-after-response' rules ignored for %s '%s' as they require HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ! LIST_ISEMPTY ( & px - > redirect_rules ) ) {
ha_warning ( " 'redirect' rules ignored for %s '%s' as they require HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
}
for ( optnum = 0 ; cfg_opts [ optnum ] . name ; optnum + + ) {
if ( cfg_opts [ optnum ] . mode = = PR_MODE_HTTP & &
( px - > cap & cfg_opts [ optnum ] . cap ) & &
( px - > options & cfg_opts [ optnum ] . val ) ) {
ha_warning ( " 'option %s' ignored for %s '%s' as it requires HTTP mode. \n " ,
cfg_opts [ optnum ] . name , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
px - > options & = ~ cfg_opts [ optnum ] . val ;
}
}
for ( optnum = 0 ; cfg_opts2 [ optnum ] . name ; optnum + + ) {
if ( cfg_opts2 [ optnum ] . mode = = PR_MODE_HTTP & &
( px - > cap & cfg_opts2 [ optnum ] . cap ) & &
( px - > options2 & cfg_opts2 [ optnum ] . val ) ) {
ha_warning ( " 'option %s' ignored for %s '%s' as it requires HTTP mode. \n " ,
cfg_opts2 [ optnum ] . name , proxy_type_str ( px ) , px - > id ) ;
* err_code | = ERR_WARN ;
px - > options2 & = ~ cfg_opts2 [ optnum ] . val ;
}
}
# if defined(CONFIG_HAP_TRANSPARENT)
if ( px - > conn_src . bind_hdr_occ ) {
px - > conn_src . bind_hdr_occ = 0 ;
ha_warning ( " %s '%s' : ignoring use of header %s as source IP in non-HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id , px - > conn_src . bind_hdr_name ) ;
* err_code | = ERR_WARN ;
}
# endif /* CONFIG_HAP_TRANSPARENT */
}
/*
* ensure that we ' re not cross - dressing a TCP server into HTTP .
*/
newsrv = px - > srv ;
while ( newsrv ! = NULL ) {
if ( ( px - > mode ! = PR_MODE_HTTP ) & & newsrv - > rdr_len ) {
ha_alert ( " %s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id ) ;
cfgerr + + ;
}
if ( ( px - > mode ! = PR_MODE_HTTP ) & & newsrv - > cklen ) {
ha_warning ( " %s '%s' : ignoring cookie for server '%s' as HTTP mode is disabled. \n " ,
proxy_type_str ( px ) , px - > id , newsrv - > id ) ;
* err_code | = ERR_WARN ;
}
if ( ( newsrv - > flags & SRV_F_MAPPORTS ) & & ( px - > options2 & PR_O2_RDPC_PRST ) ) {
ha_warning ( " %s '%s' : RDP cookie persistence will not work for server '%s' because it lacks an explicit port number. \n " ,
proxy_type_str ( px ) , px - > id , newsrv - > id ) ;
* err_code | = ERR_WARN ;
}
# if defined(CONFIG_HAP_TRANSPARENT)
if ( px - > mode ! = PR_MODE_HTTP & & newsrv - > conn_src . bind_hdr_occ ) {
newsrv - > conn_src . bind_hdr_occ = 0 ;
ha_warning ( " %s '%s' : server %s cannot use header %s as source IP in non-HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id , newsrv - > id , newsrv - > conn_src . bind_hdr_name ) ;
* err_code | = ERR_WARN ;
}
# endif /* CONFIG_HAP_TRANSPARENT */
if ( ( px - > mode ! = PR_MODE_HTTP ) & & ( px - > options & PR_O_REUSE_MASK ) ! = PR_O_REUSE_NEVR )
px - > options & = ~ PR_O_REUSE_MASK ;
if ( px - > mode = = PR_MODE_SPOP )
px - > options | = PR_O_REUSE_ALWS ;
if ( ( px - > mode ! = PR_MODE_HTTP ) & & newsrv - > flags & SRV_F_RHTTP ) {
ha_alert ( " %s '%s' : server %s uses reverse HTTP addressing which can only be used with HTTP mode. \n " ,
proxy_type_str ( px ) , px - > id , newsrv - > id ) ;
cfgerr + + ;
* err_code | = ERR_FATAL | ERR_ALERT ;
goto out ;
}
newsrv = newsrv - > next ;
}
/* Check filter configuration, if any */
cfgerr + = flt_check ( px ) ;
if ( px - > cap & PR_CAP_FE ) {
if ( ! px - > accept )
px - > accept = frontend_accept ;
if ( ! LIST_ISEMPTY ( & px - > tcp_req . inspect_rules ) | |
( px - > defpx & & ! LIST_ISEMPTY ( & px - > defpx - > tcp_req . inspect_rules ) ) )
px - > fe_req_ana | = AN_REQ_INSPECT_FE ;
if ( px - > mode = = PR_MODE_HTTP ) {
px - > fe_req_ana | = AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE ;
px - > fe_rsp_ana | = AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_FE ;
}
if ( px - > mode = = PR_MODE_CLI ) {
px - > fe_req_ana | = AN_REQ_WAIT_CLI ;
px - > fe_rsp_ana | = AN_RES_WAIT_CLI ;
}
/* both TCP and HTTP must check switching rules */
px - > fe_req_ana | = AN_REQ_SWITCHING_RULES ;
/* Add filters analyzers if needed */
if ( ! LIST_ISEMPTY ( & px - > filter_configs ) ) {
px - > fe_req_ana | = AN_REQ_FLT_START_FE | AN_REQ_FLT_XFER_DATA | AN_REQ_FLT_END ;
px - > fe_rsp_ana | = AN_RES_FLT_START_FE | AN_RES_FLT_XFER_DATA | AN_RES_FLT_END ;
}
}
if ( px - > cap & PR_CAP_BE ) {
if ( ! LIST_ISEMPTY ( & px - > tcp_req . inspect_rules ) | |
( px - > defpx & & ! LIST_ISEMPTY ( & px - > defpx - > tcp_req . inspect_rules ) ) )
px - > be_req_ana | = AN_REQ_INSPECT_BE ;
if ( ! LIST_ISEMPTY ( & px - > tcp_rep . inspect_rules ) | |
( px - > defpx & & ! LIST_ISEMPTY ( & px - > defpx - > tcp_rep . inspect_rules ) ) )
px - > be_rsp_ana | = AN_RES_INSPECT ;
if ( px - > mode = = PR_MODE_HTTP ) {
px - > be_req_ana | = AN_REQ_WAIT_HTTP | AN_REQ_HTTP_INNER | AN_REQ_HTTP_PROCESS_BE ;
px - > be_rsp_ana | = AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_BE ;
}
/* If the backend does requires RDP cookie persistence, we have to
* enable the corresponding analyser .
*/
if ( px - > options2 & PR_O2_RDPC_PRST )
px - > be_req_ana | = AN_REQ_PRST_RDP_COOKIE ;
/* Add filters analyzers if needed */
if ( ! LIST_ISEMPTY ( & px - > filter_configs ) ) {
px - > be_req_ana | = AN_REQ_FLT_START_BE | AN_REQ_FLT_XFER_DATA | AN_REQ_FLT_END ;
px - > be_rsp_ana | = AN_RES_FLT_START_BE | AN_RES_FLT_XFER_DATA | AN_RES_FLT_END ;
}
}
/* Check the mux protocols, if any, for each server attached to
* the current proxy */
for ( newsrv = px - > srv ; newsrv ; newsrv = newsrv - > next ) {
int mode = conn_pr_mode_to_proto_mode ( px - > mode ) ;
const struct mux_proto_list * mux_ent ;
if ( srv_is_quic ( newsrv ) ) {
if ( ! newsrv - > mux_proto ) {
/* Force QUIC as mux-proto on server with quic addresses, similarly to bind on FE side. */
newsrv - > mux_proto = get_mux_proto ( ist ( " quic " ) ) ;
}
}
if ( ! newsrv - > mux_proto )
continue ;
/* it is possible that an incorrect mux was referenced
* due to the proxy ' s mode not being taken into account
* on first pass . Let ' s adjust it now .
*/
mux_ent = conn_get_best_mux_entry ( newsrv - > mux_proto - > token , PROTO_SIDE_BE , mode ) ;
if ( ! mux_ent | | ! isteq ( mux_ent - > token , newsrv - > mux_proto - > token ) ) {
ha_alert ( " %s '%s' : MUX protocol '%.*s' is not usable for server '%s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) newsrv - > mux_proto - > token . len ,
newsrv - > mux_proto - > token . ptr ,
newsrv - > id , newsrv - > conf . file , newsrv - > conf . line ) ;
cfgerr + + ;
}
else {
if ( ( mux_ent - > mux - > flags & MX_FL_FRAMED ) & & ! srv_is_quic ( newsrv ) ) {
ha_alert ( " %s '%s' : MUX protocol '%.*s' is incompatible with stream transport used by server '%s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) newsrv - > mux_proto - > token . len ,
newsrv - > mux_proto - > token . ptr ,
newsrv - > id , newsrv - > conf . file , newsrv - > conf . line ) ;
cfgerr + + ;
}
else if ( ! ( mux_ent - > mux - > flags & MX_FL_FRAMED ) & & srv_is_quic ( newsrv ) ) {
ha_alert ( " %s '%s' : MUX protocol '%.*s' is incompatible with framed transport used by server '%s' at [%s:%d]. \n " ,
proxy_type_str ( px ) , px - > id ,
( int ) newsrv - > mux_proto - > token . len ,
newsrv - > mux_proto - > token . ptr ,
newsrv - > id , newsrv - > conf . file , newsrv - > conf . line ) ;
cfgerr + + ;
}
}
/* update the mux */
newsrv - > mux_proto = mux_ent ;
}
/* Allocate default tcp-check rules for proxies without
* explicit rules .
*/
if ( px - > cap & PR_CAP_BE ) {
if ( ! ( px - > options2 & PR_O2_CHK_ANY ) ) {
struct tcpcheck_ruleset * rs = NULL ;
struct tcpcheck_rules * rules = & px - > tcpcheck_rules ;
px - > options2 | = PR_O2_TCPCHK_CHK ;
rs = find_tcpcheck_ruleset ( " *tcp-check " ) ;
if ( ! rs ) {
rs = create_tcpcheck_ruleset ( " *tcp-check " ) ;
if ( rs = = NULL ) {
ha_alert ( " config: %s '%s': out of memory. \n " ,
proxy_type_str ( px ) , px - > id ) ;
cfgerr + + ;
}
}
free_tcpcheck_vars ( & rules - > preset_vars ) ;
rules - > list = & rs - > rules ;
rules - > flags = 0 ;
}
}
out :
if ( cfgerr )
* err_code | = ERR_ALERT | ERR_FATAL ;
return cfgerr ;
}
2021-02-12 04:38:49 -05:00
/* Frees all dynamic settings allocated on a default proxy that's about to be
2024-06-10 13:31:19 -04:00
* destroyed . Note that most of the fields are not even reset , so extreme care
2026-01-20 05:41:37 -05:00
* is required here .
2021-02-12 04:38:49 -05:00
*/
2026-01-22 05:16:14 -05:00
static void defaults_px_free ( struct proxy * defproxy )
2021-02-12 04:38:49 -05:00
{
2022-04-25 08:30:58 -04:00
struct cap_hdr * h , * h_next ;
2021-10-15 08:33:34 -04:00
2024-06-10 13:31:19 -04:00
proxy_free_common ( defproxy ) ;
/* default proxy specific cleanup */
2025-07-10 11:03:13 -04:00
if ( defproxy - > defsrv )
ha_free ( ( char * * ) & defproxy - > defsrv - > conf . file ) ;
2021-02-20 04:46:51 -05:00
ha_free ( & defproxy - > defbe . name ) ;
2025-08-13 05:52:59 -04:00
srv_free ( & defproxy - > defsrv ) ;
2021-10-15 08:33:34 -04:00
2022-04-25 08:30:58 -04:00
h = defproxy - > req_cap ;
while ( h ) {
h_next = h - > next ;
free ( h - > name ) ;
pool_destroy ( h - > pool ) ;
free ( h ) ;
h = h_next ;
}
h = defproxy - > rsp_cap ;
while ( h ) {
h_next = h - > next ;
free ( h - > name ) ;
pool_destroy ( h - > pool ) ;
free ( h ) ;
h = h_next ;
}
2021-02-12 04:38:49 -05:00
proxy_release_conf_errors ( defproxy ) ;
deinit_proxy_tcpcheck ( defproxy ) ;
}
2026-01-22 05:16:14 -05:00
/* Removes <px> defaults instance from the name tree, free its content and
* storage . This must only be used if < px > is unreferenced .
2021-02-12 07:52:11 -05:00
*/
2026-01-22 05:16:14 -05:00
void defaults_px_destroy ( struct proxy * px )
2021-02-12 07:52:11 -05:00
{
2026-01-22 05:16:14 -05:00
BUG_ON ( ! ( px - > cap & PR_CAP_DEF ) ) ;
2021-10-13 03:50:53 -04:00
BUG_ON ( px - > conf . refcount ! = 0 ) ;
BUG/MINOR: proxy: fix deinit crash on defaults with duplicate name
A defaults proxy instance may be move into the orphaned list when it is
replaced by a newer section with the same name. This is attached via
<next> member as a single linked list entry. However, proxy free does
not clear <next> attach point.
This causes a crash on deinit if orphaned list is not empty. First, all
frontend/backend instances are freed. This triggers the release of every
referenced defaults instances as their refcount reach zero, but orphaned
list is not clean up. A loop is then conducted on orphaned list via
proxy_destroy_all_unref_defaults(). This causes a segfault due to access
on already freed entries.
To fix this, this patch extends proxy_destroy_defaults(). If orphaned
list is not empty, a loop is performed to remove a possible entry of the
currently released defaults instance. This ensures that loop over
orphaned list won't be able to access to already freed entries.
This bug is pretty rare as it requires to have duplicate name in
defaults sections, and also to use settings which forces defaults
referencing, such as TCP/HTTP rules. This can be reproduced with the
minimal config here :
defaults def
http-request return status 200
frontend fe
bind :20080
defaults def
Note that in fact orphaned list looping is not strictly necessary, as
defaults instances are automatically removed via refcounting. This will
be the purpose of a future patch. However, to limit the risk of
regression on stable releases during backport, this patch uses the more
direct approach for now.
This must be backported up to 3.1.
2026-01-22 09:20:31 -05:00
2026-01-22 05:16:14 -05:00
cebis_item_delete ( & defproxy_by_name , conf . name_node , id , px ) ;
2026-01-20 08:33:46 -05:00
LIST_DELETE ( & px - > el ) ;
BUG/MINOR: proxy: fix deinit crash on defaults with duplicate name
A defaults proxy instance may be move into the orphaned list when it is
replaced by a newer section with the same name. This is attached via
<next> member as a single linked list entry. However, proxy free does
not clear <next> attach point.
This causes a crash on deinit if orphaned list is not empty. First, all
frontend/backend instances are freed. This triggers the release of every
referenced defaults instances as their refcount reach zero, but orphaned
list is not clean up. A loop is then conducted on orphaned list via
proxy_destroy_all_unref_defaults(). This causes a segfault due to access
on already freed entries.
To fix this, this patch extends proxy_destroy_defaults(). If orphaned
list is not empty, a loop is performed to remove a possible entry of the
currently released defaults instance. This ensures that loop over
orphaned list won't be able to access to already freed entries.
This bug is pretty rare as it requires to have duplicate name in
defaults sections, and also to use settings which forces defaults
referencing, such as TCP/HTTP rules. This can be reproduced with the
minimal config here :
defaults def
http-request return status 200
frontend fe
bind :20080
defaults def
Note that in fact orphaned list looping is not strictly necessary, as
defaults instances are automatically removed via refcounting. This will
be the purpose of a future patch. However, to limit the risk of
regression on stable releases during backport, this patch uses the more
direct approach for now.
This must be backported up to 3.1.
2026-01-22 09:20:31 -05:00
2026-01-22 05:16:14 -05:00
defaults_px_free ( px ) ;
2021-02-12 07:52:11 -05:00
free ( px ) ;
}
2021-10-13 03:50:53 -04:00
/* delete all unreferenced default proxies. A default proxy is unreferenced if
* its refcount is equal to zero .
*/
2026-01-22 05:16:14 -05:00
void defaults_px_destroy_all_unref ( void )
2021-02-12 08:08:31 -05:00
{
2024-09-20 09:59:04 -04:00
struct proxy * px , * nx ;
2021-02-12 08:08:31 -05:00
2025-07-15 05:47:54 -04:00
for ( px = cebis_item_first ( & defproxy_by_name , conf . name_node , id , struct proxy ) ; px ; px = nx ) {
2021-02-12 08:08:31 -05:00
BUG_ON ( ! ( px - > cap & PR_CAP_DEF ) ) ;
2025-07-15 05:47:54 -04:00
nx = cebis_item_next ( & defproxy_by_name , conf . name_node , id , px ) ;
2021-10-13 03:50:53 -04:00
if ( ! px - > conf . refcount )
2026-01-22 05:16:14 -05:00
defaults_px_destroy ( px ) ;
2021-02-12 08:08:31 -05:00
}
2024-09-20 09:59:04 -04:00
}
2026-01-22 05:16:14 -05:00
/* Removes <px> defaults from the name tree. This operation is useful when a
* section is made invisible by a newer instance with the same name . If < px > is
2026-01-20 08:33:46 -05:00
* not referenced it is freed immediately , else it is kept in defaults_list .
2024-09-20 09:59:04 -04:00
*/
2026-01-22 05:16:14 -05:00
void defaults_px_detach ( struct proxy * px )
2024-09-20 09:59:04 -04:00
{
2026-01-22 05:16:14 -05:00
BUG_ON ( ! ( px - > cap & PR_CAP_DEF ) ) ;
cebis_item_delete ( & defproxy_by_name , conf . name_node , id , px ) ;
2026-01-20 08:33:46 -05:00
if ( ! px - > conf . refcount )
2026-01-22 05:16:14 -05:00
defaults_px_destroy ( px ) ;
2026-01-20 08:33:46 -05:00
/* If not destroyed, <px> can still be accessed in <defaults_list>. */
2021-02-12 08:08:31 -05:00
}
2025-12-18 12:09:13 -05:00
void defaults_px_ref_all ( void )
{
struct proxy * px ;
for ( px = cebis_item_first ( & defproxy_by_name , conf . name_node , id , struct proxy ) ;
px ;
px = cebis_item_next ( & defproxy_by_name , conf . name_node , id , px ) ) {
+ + px - > conf . refcount ;
}
}
void defaults_px_unref_all ( void )
{
struct proxy * px , * nx ;
for ( px = cebis_item_first ( & defproxy_by_name , conf . name_node , id , struct proxy ) ; px ; px = nx ) {
nx = cebis_item_next ( & defproxy_by_name , conf . name_node , id , px ) ;
BUG_ON ( ! px - > conf . refcount ) ;
if ( ! - - px - > conf . refcount )
defaults_px_destroy ( px ) ;
}
}
2021-10-13 03:50:53 -04:00
/* Add a reference on the default proxy <defpx> for the proxy <px> Nothing is
* done if < px > already references < defpx > . Otherwise , the default proxy
2025-12-18 03:51:27 -05:00
* refcount is incremented by one .
*
* This operation is not thread safe . It must only be performed during init
* stage or under thread isolation .
2021-10-13 03:50:53 -04:00
*/
2025-12-22 05:59:33 -05:00
static inline void defaults_px_ref ( struct proxy * defpx , struct proxy * px )
2021-10-13 03:50:53 -04:00
{
if ( px - > defpx = = defpx )
return ;
2025-12-22 05:59:33 -05:00
/* <px> is already referencing another defaults. */
BUG_ON ( px - > defpx ) ;
2021-10-13 03:50:53 -04:00
px - > defpx = defpx ;
defpx - > conf . refcount + + ;
}
2025-12-22 05:59:33 -05:00
/* Check that <px> can inherits from <defpx> default proxy. If some settings
* cannot be copied , refcount of the defaults instance is incremented .
* Inheritance may be impossible due to incompatibility issues . In this case ,
* < errmsg > will be allocated to point to a textual description of the error .
*
* Returns ERR_NONE on success and a combination of ERR_CODE on failure
*/
int proxy_ref_defaults ( struct proxy * px , struct proxy * defpx , char * * errmsg )
{
char defcap = defpx - > cap & PR_CAP_LISTEN ;
int err_code = ERR_NONE ;
if ( ( px - > cap & PR_CAP_BE ) & & ( defpx - > nb_req_cap | | defpx - > nb_rsp_cap ) ) {
memprintf ( errmsg , " backend or defaults sections cannot inherit from a defaults section defining "
" captures (defaults section at %s:%d) " ,
defpx - > conf . file , defpx - > conf . line ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
/* If the current default proxy defines TCP/HTTP rules, the
* current proxy will keep a reference on it . But some sanity
* checks are performed first :
*
* - It cannot be used to init a defaults section
* - It cannot be used to init a listen section
* - It cannot be used to init backend and frontend sections at
* same time . It can be used to init several sections of the
* same type only .
* - It cannot define L4 / L5 TCP rules if it is used to init
* backend sections .
* - It cannot define ' tcp - response content ' rules if it
* is used to init frontend sections .
*
* If no error is found , refcount of the default proxy is incremented .
*/
if ( ( ! LIST_ISEMPTY ( & defpx - > http_req_rules ) | |
! LIST_ISEMPTY ( & defpx - > http_res_rules ) | |
! LIST_ISEMPTY ( & defpx - > http_after_res_rules ) | |
! LIST_ISEMPTY ( & defpx - > tcp_req . l4_rules ) | |
! LIST_ISEMPTY ( & defpx - > tcp_req . l5_rules ) | |
! LIST_ISEMPTY ( & defpx - > tcp_req . inspect_rules ) | |
! LIST_ISEMPTY ( & defpx - > tcp_rep . inspect_rules ) ) ) {
/* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
if ( px - > cap & PR_CAP_DEF ) {
memprintf ( errmsg , " a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d) " ,
defpx - > conf . file , defpx - > conf . line ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
else if ( ( px - > cap & PR_CAP_LISTEN ) = = PR_CAP_LISTEN ) {
memprintf ( errmsg , " a listen section cannot inherit from a defaults section defining TCP/HTTP rules " ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
else if ( ( defcap = = PR_CAP_BE | | defcap = = PR_CAP_FE ) & & ( px - > cap & PR_CAP_LISTEN ) ! = defcap ) {
memprintf ( errmsg , " frontends and backends cannot inherit from the same defaults section "
" if it defines TCP/HTTP rules (defaults section at %s:%d) " ,
defpx - > conf . file , defpx - > conf . line ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
else if ( ! ( px - > cap & PR_CAP_FE ) & & ( ! LIST_ISEMPTY ( & defpx - > tcp_req . l4_rules ) | |
! LIST_ISEMPTY ( & defpx - > tcp_req . l5_rules ) ) ) {
memprintf ( errmsg , " a backend section cannot inherit from a defaults section defining "
" 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d) " ,
defpx - > conf . file , defpx - > conf . line ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
else if ( ! ( px - > cap & PR_CAP_BE ) & & ! LIST_ISEMPTY ( & defpx - > tcp_rep . inspect_rules ) ) {
memprintf ( errmsg , " a frontend section cannot inherit from a defaults section defining "
" 'tcp-response content' rules (defaults section at %s:%d) " ,
defpx - > conf . file , defpx - > conf . line ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
defpx - > cap = ( defpx - > cap & ~ PR_CAP_LISTEN ) | ( px - > cap & PR_CAP_LISTEN ) ;
defaults_px_ref ( defpx , px ) ;
}
if ( ( defpx - > tcpcheck_rules . flags & TCPCHK_RULES_PROTO_CHK ) & &
( px - > cap & PR_CAP_LISTEN ) = = PR_CAP_BE ) {
/* If the current default proxy defines tcpcheck rules, the
* current proxy will keep a reference on it . but only if the
* current proxy has the backend capability .
*/
defaults_px_ref ( defpx , px ) ;
}
out :
return err_code ;
}
2021-10-13 03:50:53 -04:00
/* proxy <px> removes its reference on its default proxy. The default proxy
* refcount is decremented by one . If it was the last reference , the
* corresponding default proxy is destroyed . For now this operation is not
* thread safe and is performed during deinit staged only .
*/
void proxy_unref_defaults ( struct proxy * px )
{
if ( px - > defpx = = NULL )
return ;
if ( ! - - px - > defpx - > conf . refcount )
2026-01-22 05:16:14 -05:00
defaults_px_destroy ( px - > defpx ) ;
2021-10-13 03:50:53 -04:00
px - > defpx = NULL ;
}
2025-04-09 15:05:35 -04:00
/* prepares a new proxy <name> of type <cap> from the provided <px>
* pointer .
* < px > is assumed to be freshly allocated
2025-07-09 15:05:55 -04:00
* < name > may be NULL : proxy id assignment will be skipped .
2025-04-09 15:05:35 -04:00
*
* Returns a 1 on success or 0 on failure ( in which case errmsg must be checked
* then freed ) .
*/
int setup_new_proxy ( struct proxy * px , const char * name , unsigned int cap , char * * errmsg )
{
init_new_proxy ( px ) ;
if ( name ) {
px - > id = strdup ( name ) ;
if ( ! px - > id ) {
2025-04-08 12:16:38 -04:00
memprintf ( errmsg , " out of memory " ) ;
goto fail ;
2025-04-09 15:05:35 -04:00
}
}
px - > cap = cap ;
2025-06-30 09:45:44 -04:00
px - > last_change = ns_to_sec ( now_ns ) ;
2025-04-09 15:05:35 -04:00
MEDIUM: cfgparse: do not store unnamed defaults in name tree
Defaults section are indexed by their name in defproxy_by_name tree. For
named sections, there is no duplicate : if two instances have the same
name, the older one is removed from the tree. However, this was not the
case for unnamed defaults which are all stored inconditionnally in
defproxy_by_name.
This commit introduces a new approach for unnamed defaults. Now, these
instances are never inserted in the defproxy_by_name tree. Indeed, this
is not needed as no tree lookup is performed with empty names. This may
optimize slightly config parsing with a huge number of named and unnamed
defaults sections, as the first ones won't fill up the tree needlessly.
However, defproxy_by_name tree is also used to purge unreferenced
defaults instances, both on postparsing and deinit. Thus, a new approach
is needed for unnamed sections cleanup. Now, each time a new defaults is
parsed, if the previous instance is unnamed, it is freed unless if
referenced by a proxy. When config parsing is ended, a similar operation
is performed to ensure the last unnamed defaults section won't stay in
memory. To implement this, last_defproxy static variable is now set to
global. Unnamed sections which cannot be removed due to proxies
referencing proxies will still be removed when such proxies are freed
themselves, at runtime or on deinit.
2026-01-21 04:22:23 -05:00
/* Internal proxies or with empty name are not stored in the named tree. */
if ( name & & name [ 0 ] ! = ' \0 ' & & ! ( cap & PR_CAP_INT ) )
2025-04-09 15:05:35 -04:00
proxy_store_name ( px ) ;
2025-05-09 10:02:09 -04:00
if ( ! ( cap & PR_CAP_DEF ) )
LIST_APPEND ( & proxies , & px - > global_list ) ;
2025-04-09 15:05:35 -04:00
return 1 ;
2025-04-08 12:16:38 -04:00
fail :
if ( name )
memprintf ( errmsg , " proxy '%s': %s " , name , * errmsg ) ;
2025-08-13 05:52:59 -04:00
srv_free ( & px - > defsrv ) ;
2025-04-08 12:16:38 -04:00
ha_free ( & px - > id ) ;
2025-07-22 11:15:02 -04:00
counters_fe_shared_drop ( & px - > fe_counters . shared ) ;
counters_be_shared_drop ( & px - > be_counters . shared ) ;
2025-04-08 12:16:38 -04:00
return 0 ;
2025-04-09 15:05:35 -04:00
}
2021-03-23 12:27:05 -04:00
/* Allocates a new proxy <name> of type <cap>.
* Returns the proxy instance on success . On error , NULL is returned .
2021-02-12 02:49:47 -05:00
*/
2021-03-23 12:27:05 -04:00
struct proxy * alloc_new_proxy ( const char * name , unsigned int cap , char * * errmsg )
2021-02-12 02:49:47 -05:00
{
struct proxy * curproxy ;
2025-11-07 16:05:21 -05:00
if ( ( curproxy = ha_aligned_zalloc_typed ( 1 , typeof ( * curproxy ) ) ) = = NULL ) {
2021-02-12 02:49:47 -05:00
memprintf ( errmsg , " proxy '%s': out of memory " , name ) ;
goto fail ;
}
2025-04-09 15:05:35 -04:00
if ( ! setup_new_proxy ( curproxy , name , cap , errmsg ) )
goto fail ;
2021-02-12 02:49:47 -05:00
2021-03-23 12:27:05 -04:00
done :
return curproxy ;
fail :
/* Note: in case of fatal error here, we WILL make valgrind unhappy,
* but its not worth trying to unroll everything here just before
* quitting .
*/
2025-07-10 10:16:24 -04:00
if ( curproxy )
2025-08-13 05:52:59 -04:00
srv_free ( & curproxy - > defsrv ) ;
2021-03-23 12:27:05 -04:00
free ( curproxy ) ;
return NULL ;
}
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
/* post-check for proxies */
static int proxy_postcheck ( struct proxy * px )
{
2025-08-08 08:56:18 -04:00
struct listener * listener ;
2025-08-27 08:51:48 -04:00
char * errmsg = NULL ;
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
int err_code = ERR_NONE ;
/* allocate private memory for shared counters: used as a fallback
* or when sharing is disabled . If sharing is enabled pointers will
* be updated to point to the proper shared memory location during
* proxy postparsing , see proxy_postparse ( )
*/
if ( px - > cap & PR_CAP_FE ) {
2025-08-27 08:51:48 -04:00
if ( ! counters_fe_shared_prepare ( & px - > fe_counters . shared , & px - > guid , & errmsg ) ) {
ha_alert ( " out of memory while setting up shared counters for %s %s : %s \n " ,
proxy_type_str ( px ) , px - > id , errmsg ) ;
ha_free ( & errmsg ) ;
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
if ( px - > cap & ( PR_CAP_FE | PR_CAP_BE ) ) {
/* by default stream->be points to stream->fe, thus proxy
* be_counters may be used even if the proxy lacks the backend
* capability
*/
2025-08-27 08:51:48 -04:00
if ( ! counters_be_shared_prepare ( & px - > be_counters . shared , & px - > guid , & errmsg ) ) {
ha_alert ( " out of memory while setting up shared counters for %s %s : %s \n " ,
proxy_type_str ( px ) , px - > id , errmsg ) ;
ha_free ( & errmsg ) ;
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
2025-08-08 08:56:18 -04:00
list_for_each_entry ( listener , & px - > conf . listeners , by_fe ) {
if ( listener - > counters ) {
2025-08-27 08:51:48 -04:00
if ( ! counters_fe_shared_prepare ( & listener - > counters - > shared , & listener - > guid , & errmsg ) ) {
2025-08-08 08:56:18 -04:00
ha_free ( & listener - > counters ) ;
2025-08-27 08:51:48 -04:00
ha_alert ( " out of memory while setting up shared listener counters for %s %s : %s \n " ,
proxy_type_str ( px ) , px - > id , errmsg ) ;
ha_free ( & errmsg ) ;
2025-08-08 08:56:18 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
}
MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.
When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.
The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.
Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.
No change of behavior is expected, this is only preparation work.
2025-05-07 17:42:04 -04:00
out :
return err_code ;
}
REGISTER_POST_PROXY_CHECK ( proxy_postcheck ) ;
2021-03-23 12:27:05 -04:00
/* Copy the proxy settings from <defproxy> to <curproxy>.
* Returns 0 on success .
* Returns 1 on error . < errmsg > will be allocated with an error description .
*/
static int proxy_defproxy_cpy ( struct proxy * curproxy , const struct proxy * defproxy ,
char * * errmsg )
{
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * tmplogger ;
2021-03-23 12:27:05 -04:00
char * tmpmsg = NULL ;
2021-02-12 03:15:16 -05:00
/* set default values from the specified default proxy */
2025-07-11 02:40:17 -04:00
if ( defproxy - > defsrv ) {
if ( ! curproxy - > defsrv ) {
/* there's a default-server in the defaults proxy but
* none allocated yet in the current proxy so we have
* to allocate and pre - initialize it right now .
*/
2025-08-13 05:52:59 -04:00
curproxy - > defsrv = srv_alloc ( ) ;
2025-07-11 02:40:17 -04:00
if ( ! curproxy - > defsrv ) {
memprintf ( errmsg , " proxy '%s': out of memory allocating default-server " , curproxy - > id ) ;
return 1 ;
}
curproxy - > defsrv - > id = " default-server " ;
srv_settings_init ( curproxy - > defsrv ) ;
}
2025-07-10 11:03:13 -04:00
srv_settings_cpy ( curproxy - > defsrv , defproxy - > defsrv , 0 ) ;
2025-07-11 02:40:17 -04:00
}
2021-02-12 02:49:47 -05:00
2021-10-13 04:10:09 -04:00
curproxy - > flags = ( defproxy - > flags & PR_FL_DISABLED ) ; /* Only inherit from disabled flag */
2021-02-12 02:49:47 -05:00
curproxy - > options = defproxy - > options ;
curproxy - > options2 = defproxy - > options2 ;
curproxy - > no_options = defproxy - > no_options ;
curproxy - > no_options2 = defproxy - > no_options2 ;
curproxy - > retry_type = defproxy - > retry_type ;
2021-10-13 09:40:15 -04:00
curproxy - > tcp_req . inspect_delay = defproxy - > tcp_req . inspect_delay ;
curproxy - > tcp_rep . inspect_delay = defproxy - > tcp_rep . inspect_delay ;
2021-02-12 02:49:47 -05:00
2023-01-09 05:09:03 -05:00
http_ext_clean ( curproxy ) ;
http_ext_dup ( defproxy , curproxy ) ;
2021-02-12 02:49:47 -05:00
2022-03-04 18:52:43 -05:00
if ( isttest ( defproxy - > server_id_hdr_name ) )
curproxy - > server_id_hdr_name = istdup ( defproxy - > server_id_hdr_name ) ;
2021-02-12 02:49:47 -05:00
/* initialize error relocations */
if ( ! proxy_dup_default_conf_errors ( curproxy , defproxy , & tmpmsg ) ) {
memprintf ( errmsg , " proxy '%s' : %s " , curproxy - > id , tmpmsg ) ;
2021-03-23 12:27:05 -04:00
free ( tmpmsg ) ;
return 1 ;
2021-02-12 02:49:47 -05:00
}
if ( curproxy - > cap & PR_CAP_FE ) {
curproxy - > maxconn = defproxy - > maxconn ;
curproxy - > backlog = defproxy - > backlog ;
curproxy - > fe_sps_lim = defproxy - > fe_sps_lim ;
curproxy - > to_log = defproxy - > to_log & ~ LW_COOKIE & ~ LW_REQHDR & ~ LW_RSPHDR ;
curproxy - > max_out_conns = defproxy - > max_out_conns ;
curproxy - > clitcpka_cnt = defproxy - > clitcpka_cnt ;
curproxy - > clitcpka_idle = defproxy - > clitcpka_idle ;
curproxy - > clitcpka_intvl = defproxy - > clitcpka_intvl ;
2026-02-11 08:43:58 -05:00
curproxy - > stream_new_from_sc = defproxy - > stream_new_from_sc ;
2021-02-12 02:49:47 -05:00
}
if ( curproxy - > cap & PR_CAP_BE ) {
curproxy - > lbprm . algo = defproxy - > lbprm . algo ;
curproxy - > lbprm . hash_balance_factor = defproxy - > lbprm . hash_balance_factor ;
curproxy - > fullconn = defproxy - > fullconn ;
curproxy - > conn_retries = defproxy - > conn_retries ;
curproxy - > redispatch_after = defproxy - > redispatch_after ;
curproxy - > max_ka_queue = defproxy - > max_ka_queue ;
curproxy - > tcpcheck_rules . flags = ( defproxy - > tcpcheck_rules . flags & ~ TCPCHK_RULES_UNUSED_RS ) ;
curproxy - > tcpcheck_rules . list = defproxy - > tcpcheck_rules . list ;
if ( ! LIST_ISEMPTY ( & defproxy - > tcpcheck_rules . preset_vars ) ) {
if ( ! dup_tcpcheck_vars ( & curproxy - > tcpcheck_rules . preset_vars ,
& defproxy - > tcpcheck_rules . preset_vars ) ) {
2021-03-23 12:27:05 -04:00
memprintf ( errmsg , " proxy '%s': failed to duplicate tcpcheck preset-vars " , curproxy - > id ) ;
return 1 ;
2021-02-12 02:49:47 -05:00
}
}
curproxy - > ck_opts = defproxy - > ck_opts ;
2022-12-28 09:37:57 -05:00
2021-02-12 02:49:47 -05:00
if ( defproxy - > cookie_name )
curproxy - > cookie_name = strdup ( defproxy - > cookie_name ) ;
curproxy - > cookie_len = defproxy - > cookie_len ;
if ( defproxy - > dyncookie_key )
curproxy - > dyncookie_key = strdup ( defproxy - > dyncookie_key ) ;
if ( defproxy - > cookie_domain )
curproxy - > cookie_domain = strdup ( defproxy - > cookie_domain ) ;
if ( defproxy - > cookie_maxidle )
curproxy - > cookie_maxidle = defproxy - > cookie_maxidle ;
if ( defproxy - > cookie_maxlife )
curproxy - > cookie_maxlife = defproxy - > cookie_maxlife ;
if ( defproxy - > rdp_cookie_name )
curproxy - > rdp_cookie_name = strdup ( defproxy - > rdp_cookie_name ) ;
curproxy - > rdp_cookie_len = defproxy - > rdp_cookie_len ;
if ( defproxy - > cookie_attrs )
curproxy - > cookie_attrs = strdup ( defproxy - > cookie_attrs ) ;
if ( defproxy - > lbprm . arg_str )
curproxy - > lbprm . arg_str = strdup ( defproxy - > lbprm . arg_str ) ;
curproxy - > lbprm . arg_len = defproxy - > lbprm . arg_len ;
curproxy - > lbprm . arg_opt1 = defproxy - > lbprm . arg_opt1 ;
curproxy - > lbprm . arg_opt2 = defproxy - > lbprm . arg_opt2 ;
curproxy - > lbprm . arg_opt3 = defproxy - > lbprm . arg_opt3 ;
if ( defproxy - > conn_src . iface_name )
curproxy - > conn_src . iface_name = strdup ( defproxy - > conn_src . iface_name ) ;
curproxy - > conn_src . iface_len = defproxy - > conn_src . iface_len ;
curproxy - > conn_src . opts = defproxy - > conn_src . opts ;
# if defined(CONFIG_HAP_TRANSPARENT)
curproxy - > conn_src . tproxy_addr = defproxy - > conn_src . tproxy_addr ;
# endif
curproxy - > load_server_state_from_file = defproxy - > load_server_state_from_file ;
curproxy - > srvtcpka_cnt = defproxy - > srvtcpka_cnt ;
curproxy - > srvtcpka_idle = defproxy - > srvtcpka_idle ;
curproxy - > srvtcpka_intvl = defproxy - > srvtcpka_intvl ;
}
if ( curproxy - > cap & PR_CAP_FE ) {
if ( defproxy - > capture_name )
curproxy - > capture_name = strdup ( defproxy - > capture_name ) ;
curproxy - > capture_namelen = defproxy - > capture_namelen ;
curproxy - > capture_len = defproxy - > capture_len ;
2022-04-25 08:30:58 -04:00
curproxy - > nb_req_cap = defproxy - > nb_req_cap ;
curproxy - > req_cap = defproxy - > req_cap ;
curproxy - > nb_rsp_cap = defproxy - > nb_rsp_cap ;
curproxy - > rsp_cap = defproxy - > rsp_cap ;
2021-02-12 02:49:47 -05:00
}
if ( curproxy - > cap & PR_CAP_FE ) {
curproxy - > timeout . client = defproxy - > timeout . client ;
2023-11-17 12:03:20 -05:00
curproxy - > timeout . client_hs = defproxy - > timeout . client_hs ;
2021-02-12 02:49:47 -05:00
curproxy - > timeout . clientfin = defproxy - > timeout . clientfin ;
curproxy - > timeout . tarpit = defproxy - > timeout . tarpit ;
curproxy - > timeout . httpreq = defproxy - > timeout . httpreq ;
curproxy - > timeout . httpka = defproxy - > timeout . httpka ;
2022-03-04 18:52:40 -05:00
if ( isttest ( defproxy - > monitor_uri ) )
curproxy - > monitor_uri = istdup ( defproxy - > monitor_uri ) ;
2021-02-12 02:49:47 -05:00
if ( defproxy - > defbe . name )
curproxy - > defbe . name = strdup ( defproxy - > defbe . name ) ;
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
lf_expr_dup ( & defproxy - > logformat , & curproxy - > logformat ) ;
lf_expr_dup ( & defproxy - > logformat_sd , & curproxy - > logformat_sd ) ;
lf_expr_dup ( & defproxy - > logformat_error , & curproxy - > logformat_error ) ;
2021-02-12 02:49:47 -05:00
}
if ( curproxy - > cap & PR_CAP_BE ) {
curproxy - > timeout . connect = defproxy - > timeout . connect ;
curproxy - > timeout . server = defproxy - > timeout . server ;
curproxy - > timeout . serverfin = defproxy - > timeout . serverfin ;
curproxy - > timeout . check = defproxy - > timeout . check ;
curproxy - > timeout . queue = defproxy - > timeout . queue ;
curproxy - > timeout . tarpit = defproxy - > timeout . tarpit ;
curproxy - > timeout . httpreq = defproxy - > timeout . httpreq ;
curproxy - > timeout . httpka = defproxy - > timeout . httpka ;
curproxy - > timeout . tunnel = defproxy - > timeout . tunnel ;
curproxy - > conn_src . source_addr = defproxy - > conn_src . source_addr ;
}
curproxy - > mode = defproxy - > mode ;
2024-11-13 13:54:32 -05:00
/* for stats */
stats_uri_auth_drop ( curproxy - > uri_auth ) ;
stats_uri_auth_take ( defproxy - > uri_auth ) ;
curproxy - > uri_auth = defproxy - > uri_auth ;
2021-02-12 02:49:47 -05:00
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* copy default loggers to curproxy */
list_for_each_entry ( tmplogger , & defproxy - > loggers , list ) {
struct logger * node = dup_logger ( tmplogger ) ;
2021-02-12 02:49:47 -05:00
if ( ! node ) {
2021-03-23 12:27:05 -04:00
memprintf ( errmsg , " proxy '%s': out of memory " , curproxy - > id ) ;
return 1 ;
2021-02-12 02:49:47 -05:00
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
LIST_APPEND ( & curproxy - > loggers , & node - > list ) ;
2021-02-12 02:49:47 -05:00
}
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
lf_expr_dup ( & defproxy - > format_unique_id , & curproxy - > format_unique_id ) ;
2021-02-12 02:49:47 -05:00
chunk_dup ( & curproxy - > log_tag , & defproxy - > log_tag ) ;
/* copy default header unique id */
if ( isttest ( defproxy - > header_unique_id ) ) {
const struct ist copy = istdup ( defproxy - > header_unique_id ) ;
if ( ! isttest ( copy ) ) {
2021-03-23 12:27:05 -04:00
memprintf ( errmsg , " proxy '%s': out of memory for unique-id-header " , curproxy - > id ) ;
return 1 ;
2021-02-12 02:49:47 -05:00
}
curproxy - > header_unique_id = copy ;
}
/* default compression options */
if ( defproxy - > comp ! = NULL ) {
curproxy - > comp = calloc ( 1 , sizeof ( * curproxy - > comp ) ) ;
2021-05-12 12:07:27 -04:00
if ( ! curproxy - > comp ) {
memprintf ( errmsg , " proxy '%s': out of memory for default compression options " , curproxy - > id ) ;
return 1 ;
}
2023-04-05 11:32:36 -04:00
curproxy - > comp - > algos_res = defproxy - > comp - > algos_res ;
curproxy - > comp - > algo_req = defproxy - > comp - > algo_req ;
curproxy - > comp - > types_res = defproxy - > comp - > types_res ;
curproxy - > comp - > types_req = defproxy - > comp - > types_req ;
2025-02-21 16:37:57 -05:00
curproxy - > comp - > minsize_res = defproxy - > comp - > minsize_res ;
curproxy - > comp - > minsize_req = defproxy - > comp - > minsize_req ;
2023-05-10 10:39:00 -04:00
curproxy - > comp - > flags = defproxy - > comp - > flags ;
2021-02-12 02:49:47 -05:00
}
if ( defproxy - > check_path )
curproxy - > check_path = strdup ( defproxy - > check_path ) ;
if ( defproxy - > check_command )
curproxy - > check_command = strdup ( defproxy - > check_command ) ;
2024-06-17 12:53:48 -04:00
BUG_ON ( curproxy - > email_alert . flags & PR_EMAIL_ALERT_RESOLVED ) ;
2021-02-12 02:49:47 -05:00
if ( defproxy - > email_alert . mailers . name )
curproxy - > email_alert . mailers . name = strdup ( defproxy - > email_alert . mailers . name ) ;
if ( defproxy - > email_alert . from )
curproxy - > email_alert . from = strdup ( defproxy - > email_alert . from ) ;
if ( defproxy - > email_alert . to )
curproxy - > email_alert . to = strdup ( defproxy - > email_alert . to ) ;
if ( defproxy - > email_alert . myhostname )
curproxy - > email_alert . myhostname = strdup ( defproxy - > email_alert . myhostname ) ;
curproxy - > email_alert . level = defproxy - > email_alert . level ;
2024-06-17 12:53:48 -04:00
curproxy - > email_alert . flags = defproxy - > email_alert . flags ;
2021-02-12 03:15:16 -05:00
2025-07-22 04:14:47 -04:00
if ( curproxy - > cap & PR_CAP_FE ) // don't inherit on backends
2025-08-29 05:10:56 -04:00
curproxy - > conf . log_steps = defproxy - > conf . log_steps ;
2024-08-20 12:29:06 -04:00
2021-03-23 12:27:05 -04:00
return 0 ;
}
/* Allocates a new proxy <name> of type <cap> found at position <file:linenum>,
* preset it from the defaults of < defproxy > and returns it . In case of error ,
* an alert is printed and NULL is returned .
*/
struct proxy * parse_new_proxy ( const char * name , unsigned int cap ,
const char * file , int linenum ,
const struct proxy * defproxy )
{
struct proxy * curproxy = NULL ;
2022-02-24 10:37:19 -05:00
char * errmsg = NULL ;
2021-03-23 12:27:05 -04:00
if ( ! ( curproxy = alloc_new_proxy ( name , cap , & errmsg ) ) ) {
ha_alert ( " parsing [%s:%d] : %s \n " , file , linenum , errmsg ) ;
free ( errmsg ) ;
return NULL ;
}
if ( defproxy ) {
if ( proxy_defproxy_cpy ( curproxy , defproxy , & errmsg ) ) {
ha_alert ( " parsing [%s:%d] : %s \n " , file , linenum , errmsg ) ;
free ( errmsg ) ;
ha_free ( & curproxy ) ;
return NULL ;
}
}
2024-09-19 09:35:11 -04:00
curproxy - > conf . args . file = curproxy - > conf . file = copy_file_name ( file ) ;
2021-03-23 12:27:05 -04:00
curproxy - > conf . args . line = curproxy - > conf . line = linenum ;
2021-02-12 02:49:47 -05:00
return curproxy ;
}
2022-09-09 09:51:37 -04:00
/* to be called under the proxy lock after pausing some listeners. This will
* automatically update the p - > flags flag
*/
void proxy_cond_pause ( struct proxy * p )
{
if ( p - > li_ready )
return ;
p - > flags | = PR_FL_PAUSED ;
}
/* to be called under the proxy lock after resuming some listeners. This will
* automatically update the p - > flags flag
*/
void proxy_cond_resume ( struct proxy * p )
{
if ( ! p - > li_ready )
return ;
p - > flags & = ~ PR_FL_PAUSED ;
}
2020-10-07 10:31:39 -04:00
/* to be called under the proxy lock after stopping some listeners. This will
2021-10-06 08:24:19 -04:00
* automatically update the p - > flags flag after stopping the last one , and
2020-10-07 10:31:39 -04:00
* will emit a log indicating the proxy ' s condition . The function is idempotent
* so that it will not emit multiple logs ; a proxy will be disabled only once .
*/
void proxy_cond_disable ( struct proxy * p )
{
2025-05-12 11:12:49 -04:00
long long cum_conn = 0 ;
long long cum_sess = 0 ;
2021-10-06 08:24:19 -04:00
if ( p - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
2020-10-07 10:31:39 -04:00
return ;
if ( p - > li_ready + p - > li_paused > 0 )
return ;
2021-10-06 08:24:19 -04:00
p - > flags | = PR_FL_STOPPED ;
2020-10-07 10:31:39 -04:00
/* Note: syslog proxies use their own loggers so while it's somewhat OK
* to report them being stopped as a warning , we must not spam their log
* servers which are in fact production servers . For other types ( CLI ,
* peers , etc ) we must not report them at all as they ' re not really on
* the data plane but on the control plane .
*/
2025-09-08 05:01:02 -04:00
if ( ! ( global . mode & MODE_STARTING ) ) {
if ( p - > cap & PR_CAP_FE )
cum_conn = COUNTERS_SHARED_TOTAL ( p - > fe_counters . shared . tg , cum_conn , HA_ATOMIC_LOAD ) ;
if ( p - > cap & PR_CAP_BE )
cum_sess = COUNTERS_SHARED_TOTAL ( p - > be_counters . shared . tg , cum_sess , HA_ATOMIC_LOAD ) ;
}
2025-05-12 11:12:49 -04:00
2024-07-04 03:58:12 -04:00
if ( ( p - > mode = = PR_MODE_TCP | | p - > mode = = PR_MODE_HTTP | | p - > mode = = PR_MODE_SYSLOG | | p - > mode = = PR_MODE_SPOP ) & & ! ( p - > cap & PR_CAP_INT ) )
2020-10-07 10:31:39 -04:00
ha_warning ( " Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld). \n " ,
2025-05-12 11:12:49 -04:00
p - > id , cum_conn , cum_sess ) ;
2020-10-07 10:31:39 -04:00
2024-07-04 03:58:12 -04:00
if ( ( p - > mode = = PR_MODE_TCP | | p - > mode = = PR_MODE_HTTP | | p - > mode = = PR_MODE_SPOP ) & & ! ( p - > cap & PR_CAP_INT ) )
2020-10-07 10:31:39 -04:00
send_log ( p , LOG_WARNING , " Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld). \n " ,
2025-05-12 11:12:49 -04:00
p - > id , cum_conn , cum_sess ) ;
2020-10-07 10:31:39 -04:00
if ( p - > table & & p - > table - > size & & p - > table - > sync_task )
task_wakeup ( p - > table - > sync_task , TASK_WOKEN_MSG ) ;
if ( p - > task )
task_wakeup ( p - > task , TASK_WOKEN_MSG ) ;
}
2006-06-25 20:48:02 -04:00
/*
2011-07-25 10:33:49 -04:00
* This is the proxy management task . It enables proxies when there are enough
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
* free streams , or stops them when the table is full . It is designed to be
2011-07-25 10:33:49 -04:00
* called as a task which is woken up upon stopping or when rate limiting must
* be enforced .
2006-06-25 20:48:02 -04:00
*/
2021-03-02 10:09:26 -05:00
struct task * manage_proxy ( struct task * t , void * context , unsigned int state )
2006-06-25 20:48:02 -04:00
{
2018-05-25 08:04:04 -04:00
struct proxy * p = context ;
2011-07-25 10:33:49 -04:00
int next = TICK_ETERNITY ;
2009-03-06 03:18:27 -05:00
unsigned int wait ;
2006-06-25 20:48:02 -04:00
2011-07-25 10:33:49 -04:00
/* We should periodically try to enable listeners waiting for a
* global resource here .
*/
2013-09-04 11:54:01 -04:00
/* If the proxy holds a stick table, we need to purge all unused
* entries . These are all the ones in the table with ref_cnt = = 0
* and all the ones in the pool used to allocate new entries . Any
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
* entry attached to an existing stream waiting for a store will
2013-09-04 11:54:01 -04:00
* be in neither list . Any entry being dumped will have ref_cnt > 0.
* However we protect tables that are being synced to peers .
*/
2021-10-06 08:24:19 -04:00
if ( unlikely ( stopping & & ( p - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) ) & & p - > table & & p - > table - > current ) ) {
2021-04-23 06:21:26 -04:00
if ( ! p - > table - > refcnt ) {
/* !table->refcnt means there
* is no more pending full resync
* to push to a new process and
* we are free to flush the table .
*/
BUG/MEDIUM: proxy/sktable: prevent watchdog trigger on soft-stop
During soft-stop, manage_proxy() (p->task) will try to purge
trashable (expired and not referenced) sticktable entries,
effectively releasing the process memory to leave some space
for new processes.
This is done by calling stktable_trash_oldest(), immediately
followed by a pool_gc() to give the memory back to the OS.
As already mentioned in dfe7925 ("BUG/MEDIUM: stick-table:
limit the time spent purging old entries"), calling
stktable_trash_oldest() with a huge batch can result in the function
spending too much time searching and purging entries, and ultimately
triggering the watchdog.
Lately, an internal issue was reported in which we could see
that the watchdog is being triggered in stktable_trash_oldest()
on soft-stop (thus initiated by manage_proxy())
According to the report, the crash seems to only occur since 5938021
("BUG/MEDIUM: stick-table: do not leave entries in end of window during purge")
This could be the result of stktable_trash_oldest() now working
as expected, and thus spending a large amount of time purging
entries when called with a large enough <to_batch>.
Instead of adding new checks in stktable_trash_oldest(), here we
chose to address the issue directly in manage_proxy().
Since the stktable_trash_oldest() function is called with
<to_batch> == <p->table->current>, it's pretty obvious that it could
cause some issues during soft-stop if a large table, assuming it is
full prior to the soft-stop, suddenly sees most of its entries
becoming trashable because of the soft-stop.
Moreover, we should note that the call to stktable_trash_oldest() is
immediately followed by a call to pool_gc():
We know for sure that pool_gc(), as it involves malloc_trim() on
glibc, is rather expensive, and the more memory to reclaim,
the longer the call.
We need to ensure that both stktable_trash_oldest() + consequent
pool_gc() call both theoretically fit in a single task execution window
to avoid contention, and thus prevent the watchdog from being triggered.
To do this, we now allocate a "budget" for each purging attempt.
budget is maxed out to 32K, it means that each sticktable cleanup
attempt will trash at most 32K entries.
32K value is quite arbitrary here, and might need to be adjusted or
even deducted from other parameters if this fails to properly address
the issue without introducing new side-effects.
The goal is to find a good balance between the max duration of each
cleanup batch and the frequency of (expensive) pool_gc() calls.
If most of the budget is actually spent trashing entries, then the task
will immediately be rescheduled to continue the purge.
This way, the purge is effectively batched over multiple task runs.
This may be slowly backported to all stable versions.
[Please note that this commit depends on 6e1fe25 ("MINOR: proxy/pool:
prevent unnecessary calls to pool_gc()")]
2023-03-29 10:18:50 -04:00
int cleaned_up ;
/* We purposely enforce a budget limitation since we don't want
* to spend too much time purging old entries
*
* This is known to cause the watchdog to occasionnaly trigger if
* the table is huge and all entries become available for purge
* at the same time
*
* Moreover , we must also anticipate the pool_gc ( ) call which
* will also be much slower if there is too much work at once
*/
MEDIUM: stick-tables: relax stktable_trash_oldest() to only purge what is needed
stktable_trash_oldest() does insist a lot on purging what was requested,
only limited by STKTABLE_MAX_UPDATES_AT_ONCE. This is called in two
conditions, one to allocate a new stksess, and the other one to purge
entries of a stopping process. The cost of iterating over all shards
is huge, and a shard lock is taken each time before looking up entries.
Moreover, multiple threads can end up doing the same and looking hard for
many entries to purge when only one is needed. Furthermore, all threads
start from the same shard, hence synchronize their locks. All of this
costs a lot to other operations such as access from peers.
This commit simplifies the approach by ignoring the budget, starting
from a random shard number, and using a trylock so as to be able to
give up early in case of contention. The approach chosen here consists
in trying hard to flush at least one entry, but once at least one is
evicted or at least one trylock failed, then a failure on the trylock
will result in finishing.
The function now returns a success as long as one entry was freed.
With this, tests no longer show watchdog warnings during tests, though
a few still remain when stopping the tests (which are not related to
this function but to the contention from process_table_expire()).
With this change, under high contention some entries' purge might be
postponed and the table may occasionally contain slightly more entries
than their size (though this already happens since stksess_new() first
increments ->current before decrementing it).
Measures were made on a 64-core system with 8 peers
of 16 threads each, at CPU saturation (350k req/s each doing 10
track-sc) for 10M req, with 3 different approaches:
- this one resulted in 1500 failures to find an entry (0.015%
size overhead), with the lowest contention and the fairest
peers distibution.
- leaving only after a success resulted in 229 failures (0.0029%
size overhead) but doubled the time spent in the function (on
the write lock precisely).
- leaving only when both a success and a failed lock were met
resulted in 31 failures (0.00031% overhead) but the contention
was high enough again so that peers were not all up to date.
Considering that a saturated machine might exceed its entries by
0.015% is pretty minimal, the mechanism is kept.
This should be backported to 3.2 after a bit more testing as it
resolves some watchdog warnings and panics. It requires precedent
commit "MINOR: stick-table: permit stksess_new() to temporarily
allocate more entries" to over-allocate instead of failing in case
of contention.
2025-09-09 05:56:11 -04:00
cleaned_up = stktable_trash_oldest ( p - > table ) ;
BUG/MEDIUM: proxy/sktable: prevent watchdog trigger on soft-stop
During soft-stop, manage_proxy() (p->task) will try to purge
trashable (expired and not referenced) sticktable entries,
effectively releasing the process memory to leave some space
for new processes.
This is done by calling stktable_trash_oldest(), immediately
followed by a pool_gc() to give the memory back to the OS.
As already mentioned in dfe7925 ("BUG/MEDIUM: stick-table:
limit the time spent purging old entries"), calling
stktable_trash_oldest() with a huge batch can result in the function
spending too much time searching and purging entries, and ultimately
triggering the watchdog.
Lately, an internal issue was reported in which we could see
that the watchdog is being triggered in stktable_trash_oldest()
on soft-stop (thus initiated by manage_proxy())
According to the report, the crash seems to only occur since 5938021
("BUG/MEDIUM: stick-table: do not leave entries in end of window during purge")
This could be the result of stktable_trash_oldest() now working
as expected, and thus spending a large amount of time purging
entries when called with a large enough <to_batch>.
Instead of adding new checks in stktable_trash_oldest(), here we
chose to address the issue directly in manage_proxy().
Since the stktable_trash_oldest() function is called with
<to_batch> == <p->table->current>, it's pretty obvious that it could
cause some issues during soft-stop if a large table, assuming it is
full prior to the soft-stop, suddenly sees most of its entries
becoming trashable because of the soft-stop.
Moreover, we should note that the call to stktable_trash_oldest() is
immediately followed by a call to pool_gc():
We know for sure that pool_gc(), as it involves malloc_trim() on
glibc, is rather expensive, and the more memory to reclaim,
the longer the call.
We need to ensure that both stktable_trash_oldest() + consequent
pool_gc() call both theoretically fit in a single task execution window
to avoid contention, and thus prevent the watchdog from being triggered.
To do this, we now allocate a "budget" for each purging attempt.
budget is maxed out to 32K, it means that each sticktable cleanup
attempt will trash at most 32K entries.
32K value is quite arbitrary here, and might need to be adjusted or
even deducted from other parameters if this fails to properly address
the issue without introducing new side-effects.
The goal is to find a good balance between the max duration of each
cleanup batch and the frequency of (expensive) pool_gc() calls.
If most of the budget is actually spent trashing entries, then the task
will immediately be rescheduled to continue the purge.
This way, the purge is effectively batched over multiple task runs.
This may be slowly backported to all stable versions.
[Please note that this commit depends on 6e1fe25 ("MINOR: proxy/pool:
prevent unnecessary calls to pool_gc()")]
2023-03-29 10:18:50 -04:00
if ( cleaned_up ) {
/* immediately release freed memory since we are stopping */
2023-03-28 09:14:48 -04:00
pool_gc ( NULL ) ;
MEDIUM: stick-tables: relax stktable_trash_oldest() to only purge what is needed
stktable_trash_oldest() does insist a lot on purging what was requested,
only limited by STKTABLE_MAX_UPDATES_AT_ONCE. This is called in two
conditions, one to allocate a new stksess, and the other one to purge
entries of a stopping process. The cost of iterating over all shards
is huge, and a shard lock is taken each time before looking up entries.
Moreover, multiple threads can end up doing the same and looking hard for
many entries to purge when only one is needed. Furthermore, all threads
start from the same shard, hence synchronize their locks. All of this
costs a lot to other operations such as access from peers.
This commit simplifies the approach by ignoring the budget, starting
from a random shard number, and using a trylock so as to be able to
give up early in case of contention. The approach chosen here consists
in trying hard to flush at least one entry, but once at least one is
evicted or at least one trylock failed, then a failure on the trylock
will result in finishing.
The function now returns a success as long as one entry was freed.
With this, tests no longer show watchdog warnings during tests, though
a few still remain when stopping the tests (which are not related to
this function but to the contention from process_table_expire()).
With this change, under high contention some entries' purge might be
postponed and the table may occasionally contain slightly more entries
than their size (though this already happens since stksess_new() first
increments ->current before decrementing it).
Measures were made on a 64-core system with 8 peers
of 16 threads each, at CPU saturation (350k req/s each doing 10
track-sc) for 10M req, with 3 different approaches:
- this one resulted in 1500 failures to find an entry (0.015%
size overhead), with the lowest contention and the fairest
peers distibution.
- leaving only after a success resulted in 229 failures (0.0029%
size overhead) but doubled the time spent in the function (on
the write lock precisely).
- leaving only when both a success and a failed lock were met
resulted in 31 failures (0.00031% overhead) but the contention
was high enough again so that peers were not all up to date.
Considering that a saturated machine might exceed its entries by
0.015% is pretty minimal, the mechanism is kept.
This should be backported to 3.2 after a bit more testing as it
resolves some watchdog warnings and panics. It requires precedent
commit "MINOR: stick-table: permit stksess_new() to temporarily
allocate more entries" to over-allocate instead of failing in case
of contention.
2025-09-09 05:56:11 -04:00
if ( cleaned_up ) {
/* it is very likely that there are still trashable
BUG/MEDIUM: proxy/sktable: prevent watchdog trigger on soft-stop
During soft-stop, manage_proxy() (p->task) will try to purge
trashable (expired and not referenced) sticktable entries,
effectively releasing the process memory to leave some space
for new processes.
This is done by calling stktable_trash_oldest(), immediately
followed by a pool_gc() to give the memory back to the OS.
As already mentioned in dfe7925 ("BUG/MEDIUM: stick-table:
limit the time spent purging old entries"), calling
stktable_trash_oldest() with a huge batch can result in the function
spending too much time searching and purging entries, and ultimately
triggering the watchdog.
Lately, an internal issue was reported in which we could see
that the watchdog is being triggered in stktable_trash_oldest()
on soft-stop (thus initiated by manage_proxy())
According to the report, the crash seems to only occur since 5938021
("BUG/MEDIUM: stick-table: do not leave entries in end of window during purge")
This could be the result of stktable_trash_oldest() now working
as expected, and thus spending a large amount of time purging
entries when called with a large enough <to_batch>.
Instead of adding new checks in stktable_trash_oldest(), here we
chose to address the issue directly in manage_proxy().
Since the stktable_trash_oldest() function is called with
<to_batch> == <p->table->current>, it's pretty obvious that it could
cause some issues during soft-stop if a large table, assuming it is
full prior to the soft-stop, suddenly sees most of its entries
becoming trashable because of the soft-stop.
Moreover, we should note that the call to stktable_trash_oldest() is
immediately followed by a call to pool_gc():
We know for sure that pool_gc(), as it involves malloc_trim() on
glibc, is rather expensive, and the more memory to reclaim,
the longer the call.
We need to ensure that both stktable_trash_oldest() + consequent
pool_gc() call both theoretically fit in a single task execution window
to avoid contention, and thus prevent the watchdog from being triggered.
To do this, we now allocate a "budget" for each purging attempt.
budget is maxed out to 32K, it means that each sticktable cleanup
attempt will trash at most 32K entries.
32K value is quite arbitrary here, and might need to be adjusted or
even deducted from other parameters if this fails to properly address
the issue without introducing new side-effects.
The goal is to find a good balance between the max duration of each
cleanup batch and the frequency of (expensive) pool_gc() calls.
If most of the budget is actually spent trashing entries, then the task
will immediately be rescheduled to continue the purge.
This way, the purge is effectively batched over multiple task runs.
This may be slowly backported to all stable versions.
[Please note that this commit depends on 6e1fe25 ("MINOR: proxy/pool:
prevent unnecessary calls to pool_gc()")]
2023-03-29 10:18:50 -04:00
* entries in the table , reschedule a new cleanup
* attempt ASAP
*/
t - > expire = TICK_ETERNITY ;
task_wakeup ( t , TASK_WOKEN_RES ) ;
return t ;
}
}
2013-09-04 11:54:01 -04:00
}
2019-03-14 02:07:41 -04:00
if ( p - > table - > current ) {
BUG/MEDIUM: proxy/sktable: prevent watchdog trigger on soft-stop
During soft-stop, manage_proxy() (p->task) will try to purge
trashable (expired and not referenced) sticktable entries,
effectively releasing the process memory to leave some space
for new processes.
This is done by calling stktable_trash_oldest(), immediately
followed by a pool_gc() to give the memory back to the OS.
As already mentioned in dfe7925 ("BUG/MEDIUM: stick-table:
limit the time spent purging old entries"), calling
stktable_trash_oldest() with a huge batch can result in the function
spending too much time searching and purging entries, and ultimately
triggering the watchdog.
Lately, an internal issue was reported in which we could see
that the watchdog is being triggered in stktable_trash_oldest()
on soft-stop (thus initiated by manage_proxy())
According to the report, the crash seems to only occur since 5938021
("BUG/MEDIUM: stick-table: do not leave entries in end of window during purge")
This could be the result of stktable_trash_oldest() now working
as expected, and thus spending a large amount of time purging
entries when called with a large enough <to_batch>.
Instead of adding new checks in stktable_trash_oldest(), here we
chose to address the issue directly in manage_proxy().
Since the stktable_trash_oldest() function is called with
<to_batch> == <p->table->current>, it's pretty obvious that it could
cause some issues during soft-stop if a large table, assuming it is
full prior to the soft-stop, suddenly sees most of its entries
becoming trashable because of the soft-stop.
Moreover, we should note that the call to stktable_trash_oldest() is
immediately followed by a call to pool_gc():
We know for sure that pool_gc(), as it involves malloc_trim() on
glibc, is rather expensive, and the more memory to reclaim,
the longer the call.
We need to ensure that both stktable_trash_oldest() + consequent
pool_gc() call both theoretically fit in a single task execution window
to avoid contention, and thus prevent the watchdog from being triggered.
To do this, we now allocate a "budget" for each purging attempt.
budget is maxed out to 32K, it means that each sticktable cleanup
attempt will trash at most 32K entries.
32K value is quite arbitrary here, and might need to be adjusted or
even deducted from other parameters if this fails to properly address
the issue without introducing new side-effects.
The goal is to find a good balance between the max duration of each
cleanup batch and the frequency of (expensive) pool_gc() calls.
If most of the budget is actually spent trashing entries, then the task
will immediately be rescheduled to continue the purge.
This way, the purge is effectively batched over multiple task runs.
This may be slowly backported to all stable versions.
[Please note that this commit depends on 6e1fe25 ("MINOR: proxy/pool:
prevent unnecessary calls to pool_gc()")]
2023-03-29 10:18:50 -04:00
/* some entries still remain but are not yet available
* for cleanup , let ' s recheck in one second
*/
2013-09-04 11:54:01 -04:00
next = tick_first ( next , tick_add ( now_ms , 1000 ) ) ;
}
}
2011-07-25 10:33:49 -04:00
/* the rest below is just for frontends */
if ( ! ( p - > cap & PR_CAP_FE ) )
goto out ;
2011-07-25 01:37:28 -04:00
2011-07-25 10:33:49 -04:00
/* check the various reasons we may find to block the frontend */
2020-09-24 01:35:46 -04:00
if ( unlikely ( p - > feconn > = p - > maxconn ) )
2011-07-25 10:33:49 -04:00
goto out ;
2009-03-05 17:48:25 -05:00
2011-07-25 10:33:49 -04:00
if ( p - > fe_sps_lim & &
2025-07-22 11:15:02 -04:00
( wait = COUNTERS_SHARED_TOTAL_ARG2 ( p - > fe_counters . shared . tg , sess_per_sec , next_event_delay , p - > fe_sps_lim , 0 ) ) ) {
2025-05-15 13:55:11 -04:00
2011-07-25 10:33:49 -04:00
/* we're blocking because a limit was reached on the number of
* requests / s on the frontend . We want to re - check ASAP , which
* means in 1 ms before estimated expiration date , because the
* timer will have settled down .
*/
next = tick_first ( next , tick_add ( now_ms , wait ) ) ;
goto out ;
2006-06-25 20:48:02 -04:00
}
2011-07-25 10:33:49 -04:00
/* The proxy is not limited so we can re-enable any waiting listener */
2024-09-25 05:37:25 -04:00
dequeue_proxy_listeners ( p , 0 ) ;
2011-07-25 10:33:49 -04:00
out :
t - > expire = next ;
task_queue ( t ) ;
return t ;
2006-06-25 20:48:02 -04:00
}
2021-09-07 04:49:45 -04:00
static int proxy_parse_grace ( char * * args , int section_type , struct proxy * curpx ,
const struct proxy * defpx , const char * file , int line ,
char * * err )
{
const char * res ;
if ( ! * args [ 1 ] ) {
memprintf ( err , " '%s' expects <time> as argument. \n " , args [ 0 ] ) ;
return - 1 ;
}
res = parse_time_err ( args [ 1 ] , & global . grace_delay , TIME_UNIT_MS ) ;
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res ) {
memprintf ( err , " unexpected character '%c' in argument to <%s>. \n " , * res , args [ 0 ] ) ;
return - 1 ;
}
return 0 ;
}
2017-03-23 17:44:13 -04:00
static int proxy_parse_hard_stop_after ( char * * args , int section_type , struct proxy * curpx ,
2021-03-09 03:53:46 -05:00
const struct proxy * defpx , const char * file , int line ,
2017-03-23 17:44:13 -04:00
char * * err )
{
const char * res ;
if ( ! * args [ 1 ] ) {
memprintf ( err , " '%s' expects <time> as argument. \n " , args [ 0 ] ) ;
return - 1 ;
}
res = parse_time_err ( args [ 1 ] , & global . hard_stop_after , TIME_UNIT_MS ) ;
2019-06-07 13:00:37 -04:00
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res ) {
2017-03-23 17:44:13 -04:00
memprintf ( err , " unexpected character '%c' in argument to <%s>. \n " , * res , args [ 0 ] ) ;
return - 1 ;
}
return 0 ;
}
MEDIUM: global: Add a "close-spread-time" option to spread soft-stop on time window
The new 'close-spread-time' global option can be used to spread idle and
active HTTP connction closing after a SIGUSR1 signal is received. This
allows to limit bursts of reconnections when too many idle connections
are closed at once. Indeed, without this new mechanism, in case of
soft-stop, all the idle connections would be closed at once (after the
grace period is over), and all active HTTP connections would be closed
by appending a "Connection: close" header to the next response that goes
over it (or via a GOAWAY frame in case of HTTP2).
This patch adds the support of this new option for HTTP as well as HTTP2
connections. It works differently on active and idle connections.
On active connections, instead of sending systematically the GOAWAY
frame or adding the 'Connection: close' header like before once the
soft-stop has started, a random based on the remainder of the close
window is calculated, and depending on its result we could decide to
keep the connection alive. The random will be recalculated for any
subsequent request/response on this connection so the GOAWAY will still
end up being sent, but we might wait a few more round trips. This will
ensure that goaways are distributed along a longer time window than
before.
On idle connections, a random factor is used when determining the expire
field of the connection's task, which should naturally spread connection
closings on the time window (see h2c_update_timeout).
This feature request was described in GitHub issue #1614.
This patch should be backported to 2.5. It depends on "BUG/MEDIUM:
mux-h2: make use of http-request and keep-alive timeouts" which
refactorized the timeout management of HTTP2 connections.
2022-04-08 12:04:18 -04:00
static int proxy_parse_close_spread_time ( char * * args , int section_type , struct proxy * curpx ,
const struct proxy * defpx , const char * file , int line ,
char * * err )
{
const char * res ;
if ( ! * args [ 1 ] ) {
memprintf ( err , " '%s' expects <time> as argument. \n " , args [ 0 ] ) ;
return - 1 ;
}
2022-04-26 09:17:18 -04:00
/* If close-spread-time is set to "infinite", disable the active connection
* closing during soft - stop .
*/
if ( strcmp ( args [ 1 ] , " infinite " ) = = 0 ) {
global . tune . options | = GTUNE_DISABLE_ACTIVE_CLOSE ;
global . close_spread_time = TICK_ETERNITY ;
return 0 ;
}
MEDIUM: global: Add a "close-spread-time" option to spread soft-stop on time window
The new 'close-spread-time' global option can be used to spread idle and
active HTTP connction closing after a SIGUSR1 signal is received. This
allows to limit bursts of reconnections when too many idle connections
are closed at once. Indeed, without this new mechanism, in case of
soft-stop, all the idle connections would be closed at once (after the
grace period is over), and all active HTTP connections would be closed
by appending a "Connection: close" header to the next response that goes
over it (or via a GOAWAY frame in case of HTTP2).
This patch adds the support of this new option for HTTP as well as HTTP2
connections. It works differently on active and idle connections.
On active connections, instead of sending systematically the GOAWAY
frame or adding the 'Connection: close' header like before once the
soft-stop has started, a random based on the remainder of the close
window is calculated, and depending on its result we could decide to
keep the connection alive. The random will be recalculated for any
subsequent request/response on this connection so the GOAWAY will still
end up being sent, but we might wait a few more round trips. This will
ensure that goaways are distributed along a longer time window than
before.
On idle connections, a random factor is used when determining the expire
field of the connection's task, which should naturally spread connection
closings on the time window (see h2c_update_timeout).
This feature request was described in GitHub issue #1614.
This patch should be backported to 2.5. It depends on "BUG/MEDIUM:
mux-h2: make use of http-request and keep-alive timeouts" which
refactorized the timeout management of HTTP2 connections.
2022-04-08 12:04:18 -04:00
res = parse_time_err ( args [ 1 ] , & global . close_spread_time , TIME_UNIT_MS ) ;
if ( res = = PARSE_TIME_OVER ) {
memprintf ( err , " timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( err , " timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms) " ,
args [ 1 ] , args [ 0 ] ) ;
return - 1 ;
}
else if ( res ) {
memprintf ( err , " unexpected character '%c' in argument to <%s>. \n " , * res , args [ 0 ] ) ;
return - 1 ;
}
2022-04-26 09:17:18 -04:00
global . tune . options & = ~ GTUNE_DISABLE_ACTIVE_CLOSE ;
MEDIUM: global: Add a "close-spread-time" option to spread soft-stop on time window
The new 'close-spread-time' global option can be used to spread idle and
active HTTP connction closing after a SIGUSR1 signal is received. This
allows to limit bursts of reconnections when too many idle connections
are closed at once. Indeed, without this new mechanism, in case of
soft-stop, all the idle connections would be closed at once (after the
grace period is over), and all active HTTP connections would be closed
by appending a "Connection: close" header to the next response that goes
over it (or via a GOAWAY frame in case of HTTP2).
This patch adds the support of this new option for HTTP as well as HTTP2
connections. It works differently on active and idle connections.
On active connections, instead of sending systematically the GOAWAY
frame or adding the 'Connection: close' header like before once the
soft-stop has started, a random based on the remainder of the close
window is calculated, and depending on its result we could decide to
keep the connection alive. The random will be recalculated for any
subsequent request/response on this connection so the GOAWAY will still
end up being sent, but we might wait a few more round trips. This will
ensure that goaways are distributed along a longer time window than
before.
On idle connections, a random factor is used when determining the expire
field of the connection's task, which should naturally spread connection
closings on the time window (see h2c_update_timeout).
This feature request was described in GitHub issue #1614.
This patch should be backported to 2.5. It depends on "BUG/MEDIUM:
mux-h2: make use of http-request and keep-alive timeouts" which
refactorized the timeout management of HTTP2 connections.
2022-04-08 12:04:18 -04:00
return 0 ;
}
2021-03-02 10:09:26 -05:00
struct task * hard_stop ( struct task * t , void * context , unsigned int state )
2017-03-23 17:44:13 -04:00
{
struct proxy * p ;
struct stream * s ;
2021-02-24 05:13:59 -05:00
int thr ;
2017-03-23 17:44:13 -04:00
if ( killed ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Some tasks resisted to hard-stop, exiting now. \n " ) ;
2017-03-23 17:44:13 -04:00
send_log ( NULL , LOG_WARNING , " Some tasks resisted to hard-stop, exiting now. \n " ) ;
2019-06-02 05:11:29 -04:00
killed = 2 ;
2021-02-24 05:13:59 -05:00
for ( thr = 0 ; thr < global . nbthread ; thr + + )
2023-01-19 13:14:18 -05:00
if ( _HA_ATOMIC_LOAD ( & ha_thread_info [ thr ] . tg - > threads_enabled ) & ha_thread_info [ thr ] . ltid_bit )
2021-02-24 05:13:59 -05:00
wake_thread ( thr ) ;
2019-06-02 05:11:29 -04:00
t - > expire = TICK_ETERNITY ;
return t ;
2017-03-23 17:44:13 -04:00
}
2017-11-24 10:50:31 -05:00
ha_warning ( " soft-stop running for too long, performing a hard-stop. \n " ) ;
2017-03-23 17:44:13 -04:00
send_log ( NULL , LOG_WARNING , " soft-stop running for too long, performing a hard-stop. \n " ) ;
2017-11-24 10:54:05 -05:00
p = proxies_list ;
2017-03-23 17:44:13 -04:00
while ( p ) {
if ( ( p - > cap & PR_CAP_FE ) & & ( p - > feconn > 0 ) ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Proxy %s hard-stopped (%d remaining conns will be closed). \n " ,
p - > id , p - > feconn ) ;
2017-03-23 17:44:13 -04:00
send_log ( p , LOG_WARNING , " Proxy %s hard-stopped (%d remaining conns will be closed). \n " ,
p - > id , p - > feconn ) ;
}
p = p - > next ;
}
2021-02-24 05:08:56 -05:00
thread_isolate ( ) ;
2021-02-24 04:37:01 -05:00
for ( thr = 0 ; thr < global . nbthread ; thr + + ) {
2021-09-30 13:02:18 -04:00
list_for_each_entry ( s , & ha_thread_ctx [ thr ] . streams , list ) {
2021-02-24 04:37:01 -05:00
stream_shutdown ( s , SF_ERR_KILLED ) ;
}
2017-03-23 17:44:13 -04:00
}
2021-02-24 04:37:01 -05:00
2021-02-24 05:08:56 -05:00
thread_release ( ) ;
2017-03-23 17:44:13 -04:00
killed = 1 ;
t - > expire = tick_add ( now_ms , MS_TO_TICKS ( 1000 ) ) ;
return t ;
}
2021-09-07 04:49:45 -04:00
/* perform the soft-stop right now (i.e. unbind listeners) */
static void do_soft_stop_now ( )
2006-06-25 20:48:02 -04:00
{
2023-03-14 09:33:11 -04:00
struct proxy * p ;
2017-03-23 17:44:13 -04:00
struct task * task ;
2006-06-25 20:48:02 -04:00
2019-12-28 09:36:02 -05:00
/* disable busy polling to avoid cpu eating for the new process */
global . tune . options & = ~ GTUNE_BUSY_POLLING ;
2021-09-07 04:49:45 -04:00
MEDIUM: global: Add a "close-spread-time" option to spread soft-stop on time window
The new 'close-spread-time' global option can be used to spread idle and
active HTTP connction closing after a SIGUSR1 signal is received. This
allows to limit bursts of reconnections when too many idle connections
are closed at once. Indeed, without this new mechanism, in case of
soft-stop, all the idle connections would be closed at once (after the
grace period is over), and all active HTTP connections would be closed
by appending a "Connection: close" header to the next response that goes
over it (or via a GOAWAY frame in case of HTTP2).
This patch adds the support of this new option for HTTP as well as HTTP2
connections. It works differently on active and idle connections.
On active connections, instead of sending systematically the GOAWAY
frame or adding the 'Connection: close' header like before once the
soft-stop has started, a random based on the remainder of the close
window is calculated, and depending on its result we could decide to
keep the connection alive. The random will be recalculated for any
subsequent request/response on this connection so the GOAWAY will still
end up being sent, but we might wait a few more round trips. This will
ensure that goaways are distributed along a longer time window than
before.
On idle connections, a random factor is used when determining the expire
field of the connection's task, which should naturally spread connection
closings on the time window (see h2c_update_timeout).
This feature request was described in GitHub issue #1614.
This patch should be backported to 2.5. It depends on "BUG/MEDIUM:
mux-h2: make use of http-request and keep-alive timeouts" which
refactorized the timeout management of HTTP2 connections.
2022-04-08 12:04:18 -04:00
if ( tick_isset ( global . close_spread_time ) ) {
global . close_spread_end = tick_add ( now_ms , global . close_spread_time ) ;
}
2021-09-07 04:49:45 -04:00
/* schedule a hard-stop after a delay if needed */
2017-03-23 17:44:13 -04:00
if ( tick_isset ( global . hard_stop_after ) ) {
2021-10-01 12:23:30 -04:00
task = task_new_anywhere ( ) ;
2017-03-23 17:44:13 -04:00
if ( task ) {
task - > process = hard_stop ;
task_schedule ( task , tick_add ( now_ms , global . hard_stop_after ) ) ;
}
else {
2017-11-24 10:50:31 -05:00
ha_alert ( " out of memory trying to allocate the hard-stop task. \n " ) ;
2017-03-23 17:44:13 -04:00
}
}
2020-10-07 10:52:43 -04:00
2022-07-15 13:15:02 -04:00
/* we isolate so that we have a chance of stopping listeners in other groups */
thread_isolate ( ) ;
2021-06-11 10:27:10 -04:00
/* stop all stoppable listeners */
2020-10-07 10:52:43 -04:00
protocol_stop_now ( ) ;
2022-07-15 13:15:02 -04:00
thread_release ( ) ;
2023-03-14 09:33:11 -04:00
/* Loop on proxies to stop backends */
p = proxies_list ;
while ( p ) {
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & p - > lock ) ;
proxy_cond_disable ( p ) ;
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
p = p - > next ;
}
2010-08-27 12:26:11 -04:00
/* signal zero is used to broadcast the "stopping" event */
signal_handler ( 0 ) ;
2006-06-25 20:48:02 -04:00
}
2021-09-07 04:49:45 -04:00
/* triggered by a soft-stop delayed with `grace` */
static struct task * grace_expired ( struct task * t , void * context , unsigned int state )
{
ha_notice ( " Grace period expired, proceeding with soft-stop now. \n " ) ;
send_log ( NULL , LOG_NOTICE , " Grace period expired, proceeding with soft-stop now. \n " ) ;
do_soft_stop_now ( ) ;
task_destroy ( t ) ;
return NULL ;
}
/*
* this function disables health - check servers so that the process will quickly be ignored
* by load balancers .
*/
void soft_stop ( void )
{
struct task * task ;
stopping = 1 ;
if ( tick_isset ( global . grace_delay ) ) {
2021-10-01 12:23:30 -04:00
task = task_new_anywhere ( ) ;
2021-09-07 04:49:45 -04:00
if ( task ) {
ha_notice ( " Scheduling a soft-stop in %u ms. \n " , global . grace_delay ) ;
send_log ( NULL , LOG_WARNING , " Scheduling a soft-stop in %u ms. \n " , global . grace_delay ) ;
task - > process = grace_expired ;
task_schedule ( task , tick_add ( now_ms , global . grace_delay ) ) ;
return ;
}
else {
ha_alert ( " out of memory trying to allocate the stop-stop task, stopping now. \n " ) ;
}
}
/* no grace (or failure to enforce it): stop now */
do_soft_stop_now ( ) ;
}
2006-06-25 20:48:02 -04:00
2011-07-24 12:28:10 -04:00
/* Temporarily disables listening on all of the proxy's listeners. Upon
2020-09-24 01:44:34 -04:00
* success , the proxy enters the PR_PAUSED state . The function returns 0
2011-09-07 13:14:57 -04:00
* if it fails , or non - zero on success .
2022-09-08 08:35:35 -04:00
* The function takes the proxy ' s lock so it ' s safe to
* call from multiple places .
2006-06-25 20:48:02 -04:00
*/
2011-09-07 13:14:57 -04:00
int pause_proxy ( struct proxy * p )
2006-06-25 20:48:02 -04:00
{
struct listener * l ;
2011-09-07 13:14:57 -04:00
2022-09-08 08:35:35 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & p - > lock ) ;
2021-10-06 08:24:19 -04:00
if ( ! ( p - > cap & PR_CAP_FE ) | | ( p - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) ) | | ! p - > li_ready )
2022-09-08 08:35:35 -04:00
goto end ;
2011-09-07 13:14:57 -04:00
2020-09-24 01:44:34 -04:00
list_for_each_entry ( l , & p - > conf . listeners , by_fe )
MINOR: listener: pause_listener() becomes suspend_listener()
We are simply renaming pause_listener() to suspend_listener() to prevent
confusion around listener pausing.
A suspended listener can be in two differents valid states:
- LI_PAUSED: the listener is effectively paused, it will unpause on
resume_listener()
- LI_ASSIGNED (not bound): the listener does not support the LI_PAUSED
state, so it was unbound to satisfy the suspend request, it will
correcly re-bind on resume_listener()
Besides that, we add the LI_F_SUSPENDED flag to mark suspended listeners in
suspend_listener() and unmark them in resume_listener().
We're also adding li_suspend proxy variable to track the number of currently
suspended listeners:
That is, the number of listeners that were suspended through suspend_listener()
and that are either in LI_PAUSED or LI_ASSIGNED state.
Counter is increased on successful suspend in suspend_listener() and it is
decreased on successful resume in resume_listener()
--
Backport notes:
-> 2.4 only, as "MINOR: proxy/listener: support for additional PAUSED state"
was not backported:
Replace this:
| /* PROXY_LOCK is require
| proxy_cond_resume(px);
By this:
| ha_warning("Resumed %s %s.\n", proxy_cap_str(px->cap), px->id);
| send_log(px, LOG_WARNING, "Resumed %s %s.\n", proxy_cap_str(px->cap), px->id);
-> 2.6 and 2.7 only, as "MINOR: listener: make sure we don't pause/resume" was
custom patched:
Replace this:
|@@ -253,6 +253,7 @@ struct listener {
|
| /* listener flags (16 bits) */
| #define LI_F_FINALIZED 0x0001 /* listener made it to the READY||LIMITED||FULL state at least once, may be suspended/resumed safely */
|+#define LI_F_SUSPENDED 0x0002 /* listener has been suspended using suspend_listener(), it is either is LI_PAUSED or LI_ASSIGNED state */
|
| /* Descriptor for a "bind" keyword. The ->parse() function returns 0 in case of
| * success, or a combination of ERR_* flags if an error is encountered. The
By this:
|@@ -222,6 +222,7 @@ struct li_per_thread {
|
| #define LI_F_QUIC_LISTENER 0x00000001 /* listener uses proto quic */
| #define LI_F_FINALIZED 0x00000002 /* listener made it to the READY||LIMITED||FULL state at least once, may be suspended/resumed safely */
|+#define LI_F_SUSPENDED 0x00000004 /* listener has been suspended using suspend_listener(), it is either is LI_PAUSED or LI_ASSIGNED state */
|
| /* The listener will be directly referenced by the fdtab[] which holds its
| * socket. The listener provides the protocol-specific accept() function to
2023-02-13 11:45:08 -05:00
suspend_listener ( l , 1 , 0 ) ;
2011-09-07 13:14:57 -04:00
2020-09-24 01:44:34 -04:00
if ( p - > li_ready ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " %s %s failed to enter pause mode. \n " , proxy_cap_str ( p - > cap ) , p - > id ) ;
2011-09-07 13:14:57 -04:00
send_log ( p , LOG_WARNING , " %s %s failed to enter pause mode. \n " , proxy_cap_str ( p - > cap ) , p - > id ) ;
2022-09-08 08:35:35 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
2011-09-07 13:14:57 -04:00
return 0 ;
}
2022-09-08 08:35:35 -04:00
end :
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
2011-09-07 13:14:57 -04:00
return 1 ;
2008-10-12 06:07:48 -04:00
}
/*
* This function completely stops a proxy and releases its listeners . It has
* to be called when going down in order to release the ports so that another
* process may bind to them . It must also be called on disabled proxies at the
2018-11-16 10:57:21 -05:00
* end of start - up . If all listeners are closed , the proxy is set to the
2022-09-08 08:35:35 -04:00
* PR_STOPPED state .
* The function takes the proxy ' s lock so it ' s safe to
2019-07-24 11:42:44 -04:00
* call from multiple places .
2008-10-12 06:07:48 -04:00
*/
void stop_proxy ( struct proxy * p )
{
struct listener * l ;
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & p - > lock ) ;
2019-07-24 11:42:44 -04:00
2020-10-07 10:20:34 -04:00
list_for_each_entry ( l , & p - > conf . listeners , by_fe )
MINOR: listener/api: add lli hint to listener functions
Add listener lock hint (AKA lli) to (stop/resume/pause)_listener() functions.
All these functions implicitely take the listener lock when they are called:
It could be useful to be able to call them while already holding the lock, so
we're adding lli hint to make them take the lock only when it is missing.
This should only be backported if explicitly required by another commit
--
-> 2.4 and 2.5 common backport notes:
These 2 commits need to be backported first:
- 187396e34 "CLEANUP: listener: function comment typo in stop_listener()"
- a57786e87 "BUG/MINOR: listener: null pointer dereference suspected by
coverity"
-> 2.4 special backport notes:
In addition to the previously mentionned dependencies, the patch needs to be
slightly adapted to match the corresponding contextual lines:
Replace this:
|@@ -471,7 +474,8 @@ int pause_listener(struct listener *l, int lpx)
| if (!lpx && px)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
|
|- HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|+ if (!lli)
|+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|
| if (l->state <= LI_PAUSED)
| goto end;
By this:
|@@ -471,7 +474,8 @@ int pause_listener(struct listener *l, int lpx)
| if (!lpx && px)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
|
|- HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|+ if (!lli)
|+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|
| if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) &&
| !(proc_mask(l->rx.settings->bind_proc) & pid_bit))
Replace this:
|@@ -169,7 +169,7 @@ void protocol_stop_now(void)
| HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
| list_for_each_entry(proto, &protocols, list) {
| list_for_each_entry_safe(listener, lback, &proto->receivers, rx.proto_list)
|- stop_listener(listener, 0, 1);
|+ stop_listener(listener, 0, 1, 0);
| }
| HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
| }
By this:
|@@ -169,7 +169,7 @@ void protocol_stop_now(void)
| HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
| list_for_each_entry(proto, &protocols, list) {
| list_for_each_entry_safe(listener, lback, &proto->receivers, rx.proto_list)
| if (!listener->bind_conf->frontend->grace)
|- stop_listener(listener, 0, 1);
|+ stop_listener(listener, 0, 1, 0);
| }
| HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
Replace this:
|@@ -2315,7 +2315,7 @@ void stop_proxy(struct proxy *p)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
|
| list_for_each_entry(l, &p->conf.listeners, by_fe)
|- stop_listener(l, 1, 0);
|+ stop_listener(l, 1, 0, 0);
|
| if (!(p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && !p->li_ready) {
| /* might be just a backend */
By this:
|@@ -2315,7 +2315,7 @@ void stop_proxy(struct proxy *p)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
|
| list_for_each_entry(l, &p->conf.listeners, by_fe)
|- stop_listener(l, 1, 0);
|+ stop_listener(l, 1, 0, 0);
|
| if (!p->disabled && !p->li_ready) {
| /* might be just a backend */
2023-02-06 11:06:03 -05:00
stop_listener ( l , 1 , 0 , 0 ) ;
2019-07-24 11:42:44 -04:00
2021-10-06 08:24:19 -04:00
if ( ! ( p - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) ) & & ! p - > li_ready ) {
2020-10-16 09:10:11 -04:00
/* might be just a backend */
2021-10-06 08:24:19 -04:00
p - > flags | = PR_FL_STOPPED ;
2020-10-16 09:10:11 -04:00
}
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
2006-06-25 20:48:02 -04:00
}
2011-09-07 15:33:14 -04:00
/* This function resumes listening on the specified proxy. It scans all of its
* listeners and tries to enable them all . If any of them fails , the proxy is
* put back to the paused state . It returns 1 upon success , or zero if an error
* is encountered .
2022-09-08 08:35:35 -04:00
* The function takes the proxy ' s lock so it ' s safe to
* call from multiple places .
2011-09-07 15:33:14 -04:00
*/
int resume_proxy ( struct proxy * p )
{
struct listener * l ;
int fail ;
2022-09-08 08:35:35 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & p - > lock ) ;
2021-10-06 08:24:19 -04:00
if ( ( p - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) ) | | ! p - > li_paused )
2022-09-08 08:35:35 -04:00
goto end ;
2011-09-07 15:33:14 -04:00
fail = 0 ;
2012-09-20 10:48:07 -04:00
list_for_each_entry ( l , & p - > conf . listeners , by_fe ) {
MINOR: listener/api: add lli hint to listener functions
Add listener lock hint (AKA lli) to (stop/resume/pause)_listener() functions.
All these functions implicitely take the listener lock when they are called:
It could be useful to be able to call them while already holding the lock, so
we're adding lli hint to make them take the lock only when it is missing.
This should only be backported if explicitly required by another commit
--
-> 2.4 and 2.5 common backport notes:
These 2 commits need to be backported first:
- 187396e34 "CLEANUP: listener: function comment typo in stop_listener()"
- a57786e87 "BUG/MINOR: listener: null pointer dereference suspected by
coverity"
-> 2.4 special backport notes:
In addition to the previously mentionned dependencies, the patch needs to be
slightly adapted to match the corresponding contextual lines:
Replace this:
|@@ -471,7 +474,8 @@ int pause_listener(struct listener *l, int lpx)
| if (!lpx && px)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
|
|- HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|+ if (!lli)
|+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|
| if (l->state <= LI_PAUSED)
| goto end;
By this:
|@@ -471,7 +474,8 @@ int pause_listener(struct listener *l, int lpx)
| if (!lpx && px)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
|
|- HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|+ if (!lli)
|+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
|
| if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) &&
| !(proc_mask(l->rx.settings->bind_proc) & pid_bit))
Replace this:
|@@ -169,7 +169,7 @@ void protocol_stop_now(void)
| HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
| list_for_each_entry(proto, &protocols, list) {
| list_for_each_entry_safe(listener, lback, &proto->receivers, rx.proto_list)
|- stop_listener(listener, 0, 1);
|+ stop_listener(listener, 0, 1, 0);
| }
| HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
| }
By this:
|@@ -169,7 +169,7 @@ void protocol_stop_now(void)
| HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
| list_for_each_entry(proto, &protocols, list) {
| list_for_each_entry_safe(listener, lback, &proto->receivers, rx.proto_list)
| if (!listener->bind_conf->frontend->grace)
|- stop_listener(listener, 0, 1);
|+ stop_listener(listener, 0, 1, 0);
| }
| HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
Replace this:
|@@ -2315,7 +2315,7 @@ void stop_proxy(struct proxy *p)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
|
| list_for_each_entry(l, &p->conf.listeners, by_fe)
|- stop_listener(l, 1, 0);
|+ stop_listener(l, 1, 0, 0);
|
| if (!(p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && !p->li_ready) {
| /* might be just a backend */
By this:
|@@ -2315,7 +2315,7 @@ void stop_proxy(struct proxy *p)
| HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
|
| list_for_each_entry(l, &p->conf.listeners, by_fe)
|- stop_listener(l, 1, 0);
|+ stop_listener(l, 1, 0, 0);
|
| if (!p->disabled && !p->li_ready) {
| /* might be just a backend */
2023-02-06 11:06:03 -05:00
if ( ! resume_listener ( l , 1 , 0 ) ) {
2011-09-07 15:33:14 -04:00
int port ;
2020-08-27 01:48:42 -04:00
port = get_host_port ( & l - > rx . addr ) ;
2011-09-07 15:33:14 -04:00
if ( port ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Port %d busy while trying to enable %s %s. \n " ,
port , proxy_cap_str ( p - > cap ) , p - > id ) ;
2011-09-07 15:33:14 -04:00
send_log ( p , LOG_WARNING , " Port %d busy while trying to enable %s %s. \n " ,
port , proxy_cap_str ( p - > cap ) , p - > id ) ;
}
else {
2017-11-24 10:50:31 -05:00
ha_warning ( " Bind on socket %d busy while trying to enable %s %s. \n " ,
l - > luid , proxy_cap_str ( p - > cap ) , p - > id ) ;
2011-09-07 15:33:14 -04:00
send_log ( p , LOG_WARNING , " Bind on socket %d busy while trying to enable %s %s. \n " ,
l - > luid , proxy_cap_str ( p - > cap ) , p - > id ) ;
}
/* Another port might have been enabled. Let's stop everything. */
fail = 1 ;
break ;
}
}
if ( fail ) {
2022-09-08 08:35:35 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
/* pause_proxy will take PROXY_LOCK */
2011-09-07 15:33:14 -04:00
pause_proxy ( p ) ;
return 0 ;
}
2022-09-08 08:35:35 -04:00
end :
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & p - > lock ) ;
2011-09-07 15:33:14 -04:00
return 1 ;
}
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
/* Set current stream's backend to <be>. Nothing is done if the
* stream already had a backend assigned , which is indicated by
2015-04-02 19:14:29 -04:00
* s - > flags & SF_BE_ASSIGNED .
2009-07-07 09:10:31 -04:00
* All flags , stats and counters which need be updated are updated .
2009-07-12 02:27:39 -04:00
* Returns 1 if done , 0 in case of internal error , eg : lack of resource .
2009-07-07 09:10:31 -04:00
*/
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
int stream_set_backend ( struct stream * s , struct proxy * be )
2009-07-07 09:10:31 -04:00
{
2021-03-15 05:42:02 -04:00
unsigned int req_ana ;
2015-04-02 19:14:29 -04:00
if ( s - > flags & SF_BE_ASSIGNED )
2009-07-12 02:27:39 -04:00
return 1 ;
2016-06-21 05:54:52 -04:00
if ( flt_set_stream_backend ( s , be ) < 0 )
return 0 ;
2009-07-07 09:10:31 -04:00
s - > be = be ;
2026-01-11 22:25:34 -05:00
if ( be - > be_counters . shared . tg )
s - > be_tgcounters = be - > be_counters . shared . tg [ tgid - 1 ] ;
else
s - > be_tgcounters = NULL ;
2017-06-02 09:33:24 -04:00
HA_ATOMIC_UPDATE_MAX ( & be - > be_counters . conn_max ,
2021-04-06 05:44:07 -04:00
HA_ATOMIC_ADD_FETCH ( & be - > beconn , 1 ) ) ;
2009-07-07 09:10:31 -04:00
proxy_inc_be_ctr ( be ) ;
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
/* assign new parameters to the stream from the new backend */
2022-05-17 13:44:42 -04:00
s - > scb - > flags & = ~ SC_FL_INDEP_STR ;
[MEDIUM] new option "independant-streams" to stop updating read timeout on writes
By default, when data is sent over a socket, both the write timeout and the
read timeout for that socket are refreshed, because we consider that there is
activity on that socket, and we have no other means of guessing if we should
receive data or not.
While this default behaviour is desirable for almost all applications, there
exists a situation where it is desirable to disable it, and only refresh the
read timeout if there are incoming data. This happens on sessions with large
timeouts and low amounts of exchanged data such as telnet session. If the
server suddenly disappears, the output data accumulates in the system's
socket buffers, both timeouts are correctly refreshed, and there is no way
to know the server does not receive them, so we don't timeout. However, when
the underlying protocol always echoes sent data, it would be enough by itself
to detect the issue using the read timeout. Note that this problem does not
happen with more verbose protocols because data won't accumulate long in the
socket buffers.
When this option is set on the frontend, it will disable read timeout updates
on data sent to the client. There probably is little use of this case. When
the option is set on the backend, it will disable read timeout updates on
data sent to the server. Doing so will typically break large HTTP posts from
slow lines, so use it with caution.
2009-10-03 16:01:18 -04:00
if ( be - > options2 & PR_O2_INDEPSTR )
2022-05-17 13:44:42 -04:00
s - > scb - > flags | = SC_FL_INDEP_STR ;
[MEDIUM] new option "independant-streams" to stop updating read timeout on writes
By default, when data is sent over a socket, both the write timeout and the
read timeout for that socket are refreshed, because we consider that there is
activity on that socket, and we have no other means of guessing if we should
receive data or not.
While this default behaviour is desirable for almost all applications, there
exists a situation where it is desirable to disable it, and only refresh the
read timeout if there are incoming data. This happens on sessions with large
timeouts and low amounts of exchanged data such as telnet session. If the
server suddenly disappears, the output data accumulates in the system's
socket buffers, both timeouts are correctly refreshed, and there is no way
to know the server does not receive them, so we don't timeout. However, when
the underlying protocol always echoes sent data, it would be enough by itself
to detect the issue using the read timeout. Note that this problem does not
happen with more verbose protocols because data won't accumulate long in the
socket buffers.
When this option is set on the frontend, it will disable read timeout updates
on data sent to the client. There probably is little use of this case. When
the option is set on the backend, it will disable read timeout updates on
data sent to the server. Doing so will typically break large HTTP posts from
slow lines, so use it with caution.
2009-10-03 16:01:18 -04:00
2015-05-01 16:42:08 -04:00
/* We want to enable the backend-specific analysers except those which
* were already run as part of the frontend / listener . Note that it would
* be more reliable to store the list of analysers that have been run ,
* but what we do here is OK for now .
*/
2021-03-15 05:42:02 -04:00
req_ana = be - > be_req_ana ;
if ( ! ( strm_fe ( s ) - > options & PR_O_WREQ_BODY ) & & be - > options & PR_O_WREQ_BODY ) {
/* The backend request to parse a request body while it was not
* performed on the frontend , so add the corresponding analyser
*/
req_ana | = AN_REQ_HTTP_BODY ;
}
if ( IS_HTX_STRM ( s ) & & strm_fe ( s ) - > mode ! = PR_MODE_HTTP ) {
/* The stream was already upgraded to HTTP, so remove analysers
* set during the upgrade
*/
req_ana & = ~ ( AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE ) ;
}
2023-01-12 12:39:42 -05:00
s - > req . analysers | = req_ana & ~ ( strm_li ( s ) ? strm_li ( s ) - > bind_conf - > analysers : 0 ) ;
2009-07-12 03:47:04 -04:00
2021-03-15 05:42:02 -04:00
if ( ! IS_HTX_STRM ( s ) & & be - > mode = = PR_MODE_HTTP ) {
2019-04-08 04:53:51 -04:00
/* If we chain a TCP frontend to an HTX backend, we must upgrade
* the client mux */
2021-03-15 07:03:44 -04:00
if ( ! stream_set_http_mode ( s , NULL ) )
2021-03-15 05:42:02 -04:00
return 0 ;
}
else if ( IS_HTX_STRM ( s ) & & be - > mode ! = PR_MODE_HTTP ) {
/* If a TCP backend is assgiend to an HTX stream, return an
* error . It may happens for a new stream on a previously
* upgraded connections . */
if ( ! ( s - > flags & SF_ERR_MASK ) )
s - > flags | = SF_ERR_INTERNAL ;
return 0 ;
}
else {
/* If the target backend requires HTTP processing, we have to allocate
* the HTTP transaction if we did not have one .
*/
if ( unlikely ( ! s - > txn & & be - > http_needed & & ! http_create_txn ( s ) ) )
2019-12-20 09:59:20 -05:00
return 0 ;
2015-04-03 17:46:31 -04:00
}
s - > flags | = SF_BE_ASSIGNED ;
2011-05-30 12:10:30 -04:00
if ( be - > options2 & PR_O2_NODELAY ) {
2023-03-17 10:38:18 -04:00
s - > scf - > flags | = SC_FL_SND_NEVERWAIT ;
s - > scb - > flags | = SC_FL_SND_NEVERWAIT ;
2011-05-30 12:10:30 -04:00
}
2009-07-12 02:27:39 -04:00
return 1 ;
2009-07-07 09:10:31 -04:00
}
2018-09-07 11:43:26 -04:00
/* Capture a bad request or response and archive it in the proxy's structure.
* It is relatively protocol - agnostic so it requires that a number of elements
* are passed :
* - < proxy > is the proxy where the error was detected and where the snapshot
* needs to be stored
2018-11-15 14:46:55 -05:00
* - < is_back > indicates that the error happened when receiving the response
2018-09-07 11:43:26 -04:00
* - < other_end > is a pointer to the proxy on the other side when known
* - < target > is the target of the connection , usually a server or a proxy
* - < sess > is the session which experienced the error
* - < ctx > may be NULL or should contain any info relevant to the protocol
* - < buf > is the buffer containing the offending data
* - < buf_ofs > is the position of this buffer ' s input data in the input
* stream , starting at zero . It may be passed as zero if unknown .
* - < buf_out > is the portion of < buf - > data > which was already forwarded and
* which precedes the buffer ' s input . The buffer ' s input starts at
* buf - > head + buf_out .
* - < err_pos > is the pointer to the faulty byte in the buffer ' s input .
* - < show > is the callback to use to display < ctx > . It may be NULL .
*/
void proxy_capture_error ( struct proxy * proxy , int is_back ,
struct proxy * other_end , enum obj_type * target ,
const struct session * sess ,
const struct buffer * buf , long buf_ofs ,
unsigned int buf_out , unsigned int err_pos ,
const union error_snapshot_ctx * ctx ,
void ( * show ) ( struct buffer * , const struct error_snapshot * ) )
{
struct error_snapshot * es ;
unsigned int buf_len ;
int len1 , len2 ;
2018-09-07 13:02:32 -04:00
unsigned int ev_id ;
2021-04-06 05:57:41 -04:00
ev_id = HA_ATOMIC_FETCH_ADD ( & error_snapshot_id , 1 ) ;
2018-09-07 13:02:32 -04:00
2018-09-07 14:07:17 -04:00
buf_len = b_data ( buf ) - buf_out ;
es = malloc ( sizeof ( * es ) + buf_len ) ;
2018-09-07 13:02:32 -04:00
if ( ! es )
return ;
2026-01-28 04:54:41 -05:00
es - > buf_size = buf - > size ;
2018-09-07 14:07:17 -04:00
es - > buf_len = buf_len ;
es - > ev_id = ev_id ;
2018-09-07 11:43:26 -04:00
2020-01-06 05:37:00 -05:00
len1 = b_size ( buf ) - b_peek_ofs ( buf , buf_out ) ;
2018-09-07 11:43:26 -04:00
if ( len1 > buf_len )
len1 = buf_len ;
2018-09-07 14:07:17 -04:00
if ( len1 ) {
2018-09-07 11:43:26 -04:00
memcpy ( es - > buf , b_peek ( buf , buf_out ) , len1 ) ;
2018-09-07 14:07:17 -04:00
len2 = buf_len - len1 ;
2018-09-07 11:43:26 -04:00
if ( len2 )
memcpy ( es - > buf + len1 , b_orig ( buf ) , len2 ) ;
}
es - > buf_err = err_pos ;
es - > when = date ; // user-visible date
es - > srv = objt_server ( target ) ;
es - > oe = other_end ;
2020-03-12 10:30:17 -04:00
if ( sess & & objt_conn ( sess - > origin ) & & conn_get_src ( __objt_conn ( sess - > origin ) ) )
2019-07-17 09:20:02 -04:00
es - > src = * __objt_conn ( sess - > origin ) - > src ;
2018-09-07 11:43:26 -04:00
else
memset ( & es - > src , 0 , sizeof ( es - > src ) ) ;
es - > buf_wrap = b_wrap ( buf ) - b_peek ( buf , buf_out ) ;
es - > buf_out = buf_out ;
es - > buf_ofs = buf_ofs ;
/* be sure to indicate the offset of the first IN byte */
if ( es - > buf_ofs > = es - > buf_len )
es - > buf_ofs - = es - > buf_len ;
else
es - > buf_ofs = 0 ;
/* protocol-specific part now */
if ( ctx )
es - > ctx = * ctx ;
else
memset ( & es - > ctx , 0 , sizeof ( es - > ctx ) ) ;
es - > show = show ;
2018-09-07 13:02:32 -04:00
/* note: we still lock since we have to be certain that nobody is
* dumping the output while we free .
*/
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & proxy - > lock ) ;
2018-09-07 13:02:32 -04:00
if ( is_back ) {
es = HA_ATOMIC_XCHG ( & proxy - > invalid_rep , es ) ;
} else {
es = HA_ATOMIC_XCHG ( & proxy - > invalid_req , es ) ;
}
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & proxy - > lock ) ;
2022-09-17 05:07:19 -04:00
ha_free ( & es ) ;
2018-09-07 11:43:26 -04:00
}
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
/* Configure all proxies which lack a maxconn setting to use the global one by
* default . This avoids the common mistake consisting in setting maxconn only
* in the global section and discovering the hard way that it doesn ' t propagate
* through the frontends . These values are also propagated through the various
2020-06-21 12:42:57 -04:00
* targeted backends , whose fullconn is finally calculated if not yet set .
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
*/
void proxy_adjust_all_maxconn ( )
{
struct proxy * curproxy ;
struct switching_rule * swrule1 , * swrule2 ;
for ( curproxy = proxies_list ; curproxy ; curproxy = curproxy - > next ) {
2021-10-06 08:24:19 -04:00
if ( curproxy - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
continue ;
if ( ! ( curproxy - > cap & PR_CAP_FE ) )
continue ;
if ( ! curproxy - > maxconn )
curproxy - > maxconn = global . maxconn ;
/* update the target backend's fullconn count : default_backend */
if ( curproxy - > defbe . be )
curproxy - > defbe . be - > tot_fe_maxconn + = curproxy - > maxconn ;
else if ( ( curproxy - > cap & PR_CAP_LISTEN ) = = PR_CAP_LISTEN )
curproxy - > tot_fe_maxconn + = curproxy - > maxconn ;
list_for_each_entry ( swrule1 , & curproxy - > switching_rules , list ) {
/* For each target of switching rules, we update their
* tot_fe_maxconn , except if a previous rule points to
* the same backend or to the default backend .
*/
if ( swrule1 - > be . backend ! = curproxy - > defbe . be ) {
2019-03-07 09:02:52 -05:00
/* note: swrule1->be.backend isn't a backend if the rule
* is dynamic , it ' s an expression instead , so it must not
* be dereferenced as a backend before being certain it is .
*/
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
list_for_each_entry ( swrule2 , & curproxy - > switching_rules , list ) {
if ( swrule2 = = swrule1 ) {
2019-03-07 09:02:52 -05:00
if ( ! swrule1 - > dynamic )
swrule1 - > be . backend - > tot_fe_maxconn + = curproxy - > maxconn ;
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
break ;
}
else if ( ! swrule2 - > dynamic & & swrule2 - > be . backend = = swrule1 - > be . backend ) {
/* there are multiple refs of this backend */
break ;
}
}
}
}
}
/* automatically compute fullconn if not set. We must not do it in the
* loop above because cross - references are not yet fully resolved .
*/
for ( curproxy = proxies_list ; curproxy ; curproxy = curproxy - > next ) {
2021-10-06 08:24:19 -04:00
if ( curproxy - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
MEDIUM: config: don't enforce a low frontend maxconn value anymore
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.
There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.
This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.
This comes with two benefits :
1) a configuration missing "maxconn" in the defaults section will not
limit itself to a magically hardcoded value but will scale up to the
global maxconn ;
2) when the global maxconn is not set and memory limits are used instead,
the frontends' maxconn automatically adapts, and the backends' fullconn
as well.
2019-02-27 11:25:52 -05:00
continue ;
/* If <fullconn> is not set, let's set it to 10% of the sum of
* the possible incoming frontend ' s maxconns .
*/
if ( ! curproxy - > fullconn & & ( curproxy - > cap & PR_CAP_BE ) ) {
/* we have the sum of the maxconns in <total>. We only
* keep 10 % of that sum to set the default fullconn , with
* a hard minimum of 1 ( to avoid a divide by zero ) .
*/
curproxy - > fullconn = ( curproxy - > tot_fe_maxconn + 9 ) / 10 ;
if ( ! curproxy - > fullconn )
curproxy - > fullconn = 1 ;
}
}
}
2025-07-11 02:58:48 -04:00
/* releases what's no longer needed after a proxy section covering <curproxy>.
* Returns an error code made of ERR_ * , or 0 on success .
*/
static int post_section_px_cleanup ( )
{
2025-08-07 07:04:26 -04:00
if ( ! curproxy )
return 0 ; // nothing to do
2025-07-11 02:58:48 -04:00
if ( ( curproxy - > cap & PR_CAP_LISTEN ) & & ! ( curproxy - > cap & PR_CAP_DEF ) ) {
/* This is a regular proxy (not defaults). It doesn't need
* to keep a default - server section if it still had one . We
* want to keep it for defaults however , obviously .
*/
if ( curproxy - > defsrv ) {
ha_free ( ( char * * ) & curproxy - > defsrv - > conf . file ) ;
2025-08-13 05:52:59 -04:00
srv_free ( & curproxy - > defsrv ) ;
2025-07-11 02:58:48 -04:00
}
}
return 0 ;
}
REGISTER_CONFIG_POST_SECTION ( " frontend " , post_section_px_cleanup ) ;
REGISTER_CONFIG_POST_SECTION ( " backend " , post_section_px_cleanup ) ;
REGISTER_CONFIG_POST_SECTION ( " listen " , post_section_px_cleanup ) ;
REGISTER_CONFIG_POST_SECTION ( " defaults " , post_section_px_cleanup ) ;
2018-09-07 11:43:26 -04:00
/* Config keywords below */
2013-06-21 17:16:39 -04:00
static struct cfg_kw_list cfg_kws = { ILH , {
2021-09-07 04:49:45 -04:00
{ CFG_GLOBAL , " grace " , proxy_parse_grace } ,
2017-03-23 17:44:13 -04:00
{ CFG_GLOBAL , " hard-stop-after " , proxy_parse_hard_stop_after } ,
MEDIUM: global: Add a "close-spread-time" option to spread soft-stop on time window
The new 'close-spread-time' global option can be used to spread idle and
active HTTP connction closing after a SIGUSR1 signal is received. This
allows to limit bursts of reconnections when too many idle connections
are closed at once. Indeed, without this new mechanism, in case of
soft-stop, all the idle connections would be closed at once (after the
grace period is over), and all active HTTP connections would be closed
by appending a "Connection: close" header to the next response that goes
over it (or via a GOAWAY frame in case of HTTP2).
This patch adds the support of this new option for HTTP as well as HTTP2
connections. It works differently on active and idle connections.
On active connections, instead of sending systematically the GOAWAY
frame or adding the 'Connection: close' header like before once the
soft-stop has started, a random based on the remainder of the close
window is calculated, and depending on its result we could decide to
keep the connection alive. The random will be recalculated for any
subsequent request/response on this connection so the GOAWAY will still
end up being sent, but we might wait a few more round trips. This will
ensure that goaways are distributed along a longer time window than
before.
On idle connections, a random factor is used when determining the expire
field of the connection's task, which should naturally spread connection
closings on the time window (see h2c_update_timeout).
This feature request was described in GitHub issue #1614.
This patch should be backported to 2.5. It depends on "BUG/MEDIUM:
mux-h2: make use of http-request and keep-alive timeouts" which
refactorized the timeout management of HTTP2 connections.
2022-04-08 12:04:18 -04:00
{ CFG_GLOBAL , " close-spread-time " , proxy_parse_close_spread_time } ,
2008-07-09 14:34:27 -04:00
{ CFG_LISTEN , " timeout " , proxy_parse_timeout } ,
2019-05-14 14:57:59 -04:00
{ CFG_LISTEN , " clitimeout " , proxy_parse_timeout } , /* This keyword actually fails to parse, this line remains for better error messages. */
{ CFG_LISTEN , " contimeout " , proxy_parse_timeout } , /* This keyword actually fails to parse, this line remains for better error messages. */
{ CFG_LISTEN , " srvtimeout " , proxy_parse_timeout } , /* This keyword actually fails to parse, this line remains for better error messages. */
2009-03-05 17:48:25 -05:00
{ CFG_LISTEN , " rate-limit " , proxy_parse_rate_limit } ,
2014-04-25 07:58:37 -04:00
{ CFG_LISTEN , " max-keep-alive-queue " , proxy_parse_max_ka_queue } ,
2015-05-26 11:44:32 -04:00
{ CFG_LISTEN , " declare " , proxy_parse_declare } ,
MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.
To do so, add a new backend keyword, "retry-on".
It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".
The default is "conn-failure".
2019-04-05 09:30:12 -04:00
{ CFG_LISTEN , " retry-on " , proxy_parse_retry_on } ,
2025-03-21 06:27:21 -04:00
{ CFG_LISTEN , " hash-preserve-affinity " , proxy_parse_hash_preserve_affinity } ,
2020-07-08 23:58:51 -04:00
# ifdef TCP_KEEPCNT
2020-07-08 22:13:20 -04:00
{ CFG_LISTEN , " clitcpka-cnt " , proxy_parse_tcpka_cnt } ,
{ CFG_LISTEN , " srvtcpka-cnt " , proxy_parse_tcpka_cnt } ,
2020-07-08 23:58:51 -04:00
# endif
# ifdef TCP_KEEPIDLE
{ CFG_LISTEN , " clitcpka-idle " , proxy_parse_tcpka_idle } ,
2020-07-08 22:13:20 -04:00
{ CFG_LISTEN , " srvtcpka-idle " , proxy_parse_tcpka_idle } ,
2020-07-08 23:58:51 -04:00
# endif
# ifdef TCP_KEEPINTVL
{ CFG_LISTEN , " clitcpka-intvl " , proxy_parse_tcpka_intvl } ,
2020-07-08 22:13:20 -04:00
{ CFG_LISTEN , " srvtcpka-intvl " , proxy_parse_tcpka_intvl } ,
2020-07-08 23:58:51 -04:00
# endif
2026-01-07 08:15:14 -05:00
{ CFG_LISTEN , " force-be-switch " , proxy_parse_force_be_switch } ,
2024-03-26 10:26:43 -04:00
{ CFG_LISTEN , " guid " , proxy_parse_guid } ,
2008-07-09 14:34:27 -04:00
{ 0 , NULL , NULL } ,
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , cfg_register_keywords , & cfg_kws ) ;
2016-11-24 06:02:29 -05:00
/* Expects to find a frontend named <arg> and returns it, otherwise displays various
* adequate error messages and returns NULL . This function is designed to be used by
* functions requiring a frontend on the CLI .
*/
struct proxy * cli_find_frontend ( struct appctx * appctx , const char * arg )
{
struct proxy * px ;
if ( ! * arg ) {
2019-08-09 05:21:01 -04:00
cli_err ( appctx , " A frontend name is expected. \n " ) ;
2016-11-24 06:02:29 -05:00
return NULL ;
}
px = proxy_fe_by_name ( arg ) ;
if ( ! px ) {
2019-08-09 05:21:01 -04:00
cli_err ( appctx , " No such frontend. \n " ) ;
2016-11-24 06:02:29 -05:00
return NULL ;
}
return px ;
}
2017-03-14 15:08:46 -04:00
/* Expects to find a backend named <arg> and returns it, otherwise displays various
* adequate error messages and returns NULL . This function is designed to be used by
* functions requiring a frontend on the CLI .
*/
struct proxy * cli_find_backend ( struct appctx * appctx , const char * arg )
{
struct proxy * px ;
if ( ! * arg ) {
2019-08-09 05:21:01 -04:00
cli_err ( appctx , " A backend name is expected. \n " ) ;
2017-03-14 15:08:46 -04:00
return NULL ;
}
px = proxy_be_by_name ( arg ) ;
if ( ! px ) {
2019-08-09 05:21:01 -04:00
cli_err ( appctx , " No such backend. \n " ) ;
2017-03-14 15:08:46 -04:00
return NULL ;
}
return px ;
}
2020-07-01 01:00:59 -04:00
/* parse a "show servers [state|conn]" CLI line, returns 0 if it wants to start
* the dump or 1 if it stops immediately . If an argument is specified , it will
2022-05-05 11:00:20 -04:00
* reserve a show_srv_ctx context and set the proxy pointer into - > px , its ID
* into - > only_pxid , and - > show_conn to 0 for " state " , or 1 for " conn " .
2016-11-18 20:25:36 -05:00
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_show_servers ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-11-18 20:25:36 -05:00
{
2022-05-05 11:00:20 -04:00
struct show_srv_ctx * ctx = applet_reserve_svcctx ( appctx , sizeof ( * ctx ) ) ;
2016-12-16 12:23:39 -05:00
struct proxy * px ;
2016-11-18 20:25:36 -05:00
2022-05-05 11:00:20 -04:00
ctx - > show_conn = * args [ 2 ] = = ' c ' ; // "conn" vs "state"
2020-07-01 01:00:59 -04:00
2016-11-18 20:25:36 -05:00
/* check if a backend name has been provided */
if ( * args [ 3 ] ) {
/* read server state from local file */
2016-12-16 12:23:39 -05:00
px = proxy_be_by_name ( args [ 3 ] ) ;
2016-11-18 20:25:36 -05:00
2019-08-09 05:21:01 -04:00
if ( ! px )
return cli_err ( appctx , " Can't find backend. \n " ) ;
2022-05-05 11:00:20 -04:00
ctx - > px = px ;
ctx - > only_pxid = px - > uuid ;
2016-11-18 20:25:36 -05:00
}
return 0 ;
}
2021-02-11 16:51:26 -05:00
/* helper to dump server addr */
static void dump_server_addr ( const struct sockaddr_storage * addr , char * addr_str )
{
addr_str [ 0 ] = ' \0 ' ;
switch ( addr - > ss_family ) {
case AF_INET :
case AF_INET6 :
addr_to_str ( addr , addr_str , INET6_ADDRSTRLEN + 1 ) ;
break ;
default :
memcpy ( addr_str , " - \0 " , 2 ) ;
break ;
}
}
2020-07-01 01:02:42 -04:00
/* dumps server state information for all the servers found in backend cli.p0.
2016-11-18 20:25:36 -05:00
* These information are all the parameters which may change during HAProxy runtime .
2022-05-05 11:00:20 -04:00
* By default , we only export to the last known server state file format . These
* information can be used at next startup to recover same level of server
* state . It takes its context from show_srv_ctx , with the proxy pointer from
* - > px , the proxy ' s id - > only_pxid , the server ' s pointer from - > sv , and the
* choice of what to dump from - > show_conn .
2016-11-18 20:25:36 -05:00
*/
2024-02-06 08:54:54 -05:00
static int dump_servers_state ( struct appctx * appctx )
2016-11-18 20:25:36 -05:00
{
2022-05-05 11:00:20 -04:00
struct show_srv_ctx * ctx = appctx - > svcctx ;
struct proxy * px = ctx - > px ;
2016-11-18 20:25:36 -05:00
struct server * srv ;
char srv_addr [ INET6_ADDRSTRLEN + 1 ] ;
2021-02-11 16:51:26 -05:00
char srv_agent_addr [ INET6_ADDRSTRLEN + 1 ] ;
char srv_check_addr [ INET6_ADDRSTRLEN + 1 ] ;
2016-11-18 20:25:36 -05:00
time_t srv_time_since_last_change ;
int bk_f_forced_id , srv_f_forced_id ;
2018-07-02 11:00:54 -04:00
char * srvrecord ;
2016-11-18 20:25:36 -05:00
2022-05-05 11:00:20 -04:00
if ( ! ctx - > sv )
ctx - > sv = px - > srv ;
2016-11-18 20:25:36 -05:00
2022-05-05 11:00:20 -04:00
for ( ; ctx - > sv ! = NULL ; ctx - > sv = srv - > next ) {
srv = ctx - > sv ;
2016-11-18 20:25:36 -05:00
2021-02-11 16:51:26 -05:00
dump_server_addr ( & srv - > addr , srv_addr ) ;
dump_server_addr ( & srv - > check . addr , srv_check_addr ) ;
dump_server_addr ( & srv - > agent . addr , srv_agent_addr ) ;
2025-06-30 04:57:29 -04:00
srv_time_since_last_change = ns_to_sec ( now_ns ) - srv - > last_change ;
2016-12-16 12:23:39 -05:00
bk_f_forced_id = px - > options & PR_O_FORCED_ID ? 1 : 0 ;
2016-11-18 20:25:36 -05:00
srv_f_forced_id = srv - > flags & SRV_F_FORCED_ID ? 1 : 0 ;
2018-07-02 11:00:54 -04:00
srvrecord = NULL ;
if ( srv - > srvrq & & srv - > srvrq - > name )
srvrecord = srv - > srvrq - > name ;
2022-05-05 11:00:20 -04:00
if ( ctx - > show_conn = = 0 ) {
2020-07-01 01:00:59 -04:00
/* show servers state */
chunk_printf ( & trash ,
" %d %s "
" %d %s %s "
" %d %d %d %d %ld "
" %d %d %d %d %d "
2020-11-14 13:25:33 -05:00
" %d %d %s %u "
2021-02-11 16:51:26 -05:00
" %s %d %d "
" %s %s %d "
2020-07-01 01:00:59 -04:00
" \n " ,
2022-09-14 11:48:55 -04:00
px - > uuid , HA_ANON_CLI ( px - > id ) ,
2022-09-29 04:27:33 -04:00
srv - > puid , HA_ANON_CLI ( srv - > id ) ,
2025-04-24 05:17:07 -04:00
hash_ipanon ( appctx - > cli_ctx . anon_key , srv_addr , 0 ) ,
2022-09-14 11:48:55 -04:00
srv - > cur_state , srv - > cur_admin , srv - > uweight , srv - > iweight ,
( long int ) srv_time_since_last_change ,
srv - > check . status , srv - > check . result , srv - > check . health ,
2022-10-12 15:40:31 -04:00
srv - > check . state & 0x0F , srv - > agent . state & 0x1F ,
2022-09-29 04:28:44 -04:00
bk_f_forced_id , srv_f_forced_id ,
srv - > hostname ? HA_ANON_CLI ( srv - > hostname ) : " - " , srv - > svc_port ,
2021-02-11 16:51:26 -05:00
srvrecord ? srvrecord : " - " , srv - > use_ssl , srv - > check . port ,
srv_check_addr , srv_agent_addr , srv - > agent . port ) ;
2020-07-01 01:00:59 -04:00
} else {
/* show servers conn */
int thr ;
chunk_printf ( & trash ,
2025-08-19 09:23:21 -04:00
" %s/%s %d/%d %s %u - %u %u %u %u %u %u %u %u %d %u " ,
2022-09-14 11:48:55 -04:00
HA_ANON_CLI ( px - > id ) , HA_ANON_CLI ( srv - > id ) ,
2025-04-24 05:17:07 -04:00
px - > uuid , srv - > puid , hash_ipanon ( appctx - > cli_ctx . anon_key , srv_addr , 0 ) ,
2022-09-14 11:48:55 -04:00
srv - > svc_port , srv - > pool_purge_delay ,
2025-08-19 09:23:21 -04:00
srv - > served ,
2020-07-01 01:00:59 -04:00
srv - > curr_used_conns , srv - > max_used_conns , srv - > est_need_conns ,
2025-08-19 09:23:21 -04:00
srv - > curr_sess_idle_conns ,
2020-07-01 01:00:59 -04:00
srv - > curr_idle_nb , srv - > curr_safe_nb , ( int ) srv - > max_idle_conns , srv - > curr_idle_conns ) ;
2020-07-02 09:19:57 -04:00
for ( thr = 0 ; thr < global . nbthread & & srv - > curr_idle_thr ; thr + + )
2020-07-01 01:00:59 -04:00
chunk_appendf ( & trash , " %u " , srv - > curr_idle_thr [ thr ] ) ;
chunk_appendf ( & trash , " \n " ) ;
}
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 ) {
2016-11-18 20:25:36 -05:00
return 0 ;
}
}
return 1 ;
}
/* Parses backend list or simply use backend name provided by the user to return
2022-05-05 11:00:20 -04:00
* states of servers to stdout . It takes its context from show_srv_ctx and dumps
* proxy - > px and stops if - > only_pxid is non - null .
2016-11-18 20:25:36 -05:00
*/
static int cli_io_handler_servers_state ( struct appctx * appctx )
{
2022-05-05 11:00:20 -04:00
struct show_srv_ctx * ctx = appctx - > svcctx ;
2016-11-18 20:25:36 -05:00
struct proxy * curproxy ;
2022-05-05 13:26:18 -04:00
if ( ctx - > state = = SHOW_SRV_HEAD ) {
2022-05-05 11:00:20 -04:00
if ( ctx - > show_conn = = 0 )
2020-07-01 01:00:59 -04:00
chunk_printf ( & trash , " %d \n # %s \n " , SRV_STATE_FILE_VERSION , SRV_STATE_FILE_FIELD_NAMES ) ;
else
chunk_printf ( & trash ,
2025-08-19 09:23:21 -04:00
" # bkname/svname bkid/svid addr port - purge_delay served used_cur used_max need_est idle_sess unsafe_nb safe_nb idle_lim idle_cur idle_per_thr[%d] \n " ,
2020-07-01 01:00:59 -04:00
global . nbthread ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2016-11-18 20:25:36 -05:00
return 0 ;
2022-05-18 09:07:19 -04:00
2022-05-05 13:26:18 -04:00
ctx - > state = SHOW_SRV_LIST ;
if ( ! ctx - > px )
ctx - > px = proxies_list ;
2016-11-18 20:25:36 -05:00
}
2022-05-05 11:00:20 -04:00
for ( ; ctx - > px ! = NULL ; ctx - > px = curproxy - > next ) {
curproxy = ctx - > px ;
2016-11-18 20:25:36 -05:00
/* servers are only in backends */
2021-08-25 12:15:31 -04:00
if ( ( curproxy - > cap & PR_CAP_BE ) & & ! ( curproxy - > cap & PR_CAP_INT ) ) {
2024-02-06 08:54:54 -05:00
if ( ! dump_servers_state ( appctx ) )
2016-11-18 20:25:36 -05:00
return 0 ;
}
/* only the selected proxy is dumped */
2022-05-05 11:00:20 -04:00
if ( ctx - > only_pxid )
2016-11-18 20:25:36 -05:00
break ;
}
return 1 ;
}
2016-12-16 12:01:15 -05:00
/* Parses backend list and simply report backend names. It keeps the proxy
2022-05-05 11:05:38 -04:00
* pointer in svcctx since there ' s nothing else to store there .
2016-12-16 12:01:15 -05:00
*/
2016-11-22 06:34:16 -05:00
static int cli_io_handler_show_backend ( struct appctx * appctx )
{
struct proxy * curproxy ;
chunk_reset ( & trash ) ;
2022-05-05 11:05:38 -04:00
if ( ! appctx - > svcctx ) {
2016-11-22 06:34:16 -05:00
chunk_printf ( & trash , " # name \n " ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2016-11-22 06:34:16 -05:00
return 0 ;
2022-05-18 09:07:19 -04:00
2022-05-05 11:05:38 -04:00
appctx - > svcctx = proxies_list ;
2016-11-22 06:34:16 -05:00
}
2022-05-05 11:05:38 -04:00
for ( ; appctx - > svcctx ! = NULL ; appctx - > svcctx = curproxy - > next ) {
curproxy = appctx - > svcctx ;
2016-11-22 06:34:16 -05:00
2022-05-05 11:10:03 -04:00
/* looking for non-internal backends only */
if ( ( curproxy - > cap & ( PR_CAP_BE | PR_CAP_INT ) ) ! = PR_CAP_BE )
2016-11-22 06:34:16 -05:00
continue ;
chunk_appendf ( & trash , " %s \n " , curproxy - > id ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2016-11-22 06:34:16 -05:00
return 0 ;
}
return 1 ;
}
2016-11-18 20:25:36 -05:00
2018-08-21 08:50:44 -04:00
/* Parses the "enable dynamic-cookies backend" directive, it always returns 1.
*
* Grabs the proxy lock and each server ' s lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_enable_dyncookie_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
2017-03-14 15:08:46 -04:00
{
struct proxy * px ;
struct server * s ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_backend ( appctx , args [ 3 ] ) ;
if ( ! px )
return 1 ;
2023-09-20 04:54:06 -04:00
if ( px - > mode ! = PR_MODE_TCP & & px - > mode ! = PR_MODE_HTTP )
return cli_err ( appctx , " Not available. \n " ) ;
2019-07-30 05:59:34 -04:00
/* Note: this lock is to make sure this doesn't change while another
* thread is in srv_set_dyncookie ( ) .
*/
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
px - > ck_opts | = PR_CK_DYNAMIC ;
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
2018-08-21 08:50:44 -04:00
for ( s = px - > srv ; s ! = NULL ; s = s - > next ) {
HA_SPIN_LOCK ( SERVER_LOCK , & s - > lock ) ;
2017-03-14 15:08:46 -04:00
srv_set_dyncookie ( s ) ;
2018-08-21 08:50:44 -04:00
HA_SPIN_UNLOCK ( SERVER_LOCK , & s - > lock ) ;
}
2017-03-14 15:08:46 -04:00
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "disable dynamic-cookies backend" directive, it always returns 1.
*
* Grabs the proxy lock and each server ' s lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_disable_dyncookie_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
2017-03-14 15:08:46 -04:00
{
struct proxy * px ;
struct server * s ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_backend ( appctx , args [ 3 ] ) ;
if ( ! px )
return 1 ;
2023-09-20 04:54:06 -04:00
if ( px - > mode ! = PR_MODE_TCP & & px - > mode ! = PR_MODE_HTTP )
return cli_err ( appctx , " Not available. \n " ) ;
2019-07-30 05:59:34 -04:00
/* Note: this lock is to make sure this doesn't change while another
* thread is in srv_set_dyncookie ( ) .
*/
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
px - > ck_opts & = ~ PR_CK_DYNAMIC ;
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
for ( s = px - > srv ; s ! = NULL ; s = s - > next ) {
2018-08-21 08:50:44 -04:00
HA_SPIN_LOCK ( SERVER_LOCK , & s - > lock ) ;
2021-02-20 04:46:51 -05:00
if ( ! ( s - > flags & SRV_F_COOKIESET ) )
ha_free ( & s - > cookie ) ;
2018-08-21 08:50:44 -04:00
HA_SPIN_UNLOCK ( SERVER_LOCK , & s - > lock ) ;
2017-03-14 15:08:46 -04:00
}
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "set dynamic-cookie-key backend" directive, it always returns 1.
*
* Grabs the proxy lock and each server ' s lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_set_dyncookie_key_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
2017-03-14 15:08:46 -04:00
{
struct proxy * px ;
struct server * s ;
char * newkey ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_backend ( appctx , args [ 3 ] ) ;
if ( ! px )
return 1 ;
2023-09-20 04:54:06 -04:00
if ( px - > mode ! = PR_MODE_TCP & & px - > mode ! = PR_MODE_HTTP )
return cli_err ( appctx , " Not available. \n " ) ;
2019-08-09 05:21:01 -04:00
if ( ! * args [ 4 ] )
return cli_err ( appctx , " String value expected. \n " ) ;
2017-03-14 15:08:46 -04:00
newkey = strdup ( args [ 4 ] ) ;
2019-08-09 05:21:01 -04:00
if ( ! newkey )
return cli_err ( appctx , " Failed to allocate memory. \n " ) ;
2018-08-21 08:50:44 -04:00
2019-07-30 05:59:34 -04:00
/* Note: this lock is to make sure this doesn't change while another
* thread is in srv_set_dyncookie ( ) .
*/
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
free ( px - > dyncookie_key ) ;
px - > dyncookie_key = newkey ;
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & px - > lock ) ;
2017-03-14 15:08:46 -04:00
2018-08-21 08:50:44 -04:00
for ( s = px - > srv ; s ! = NULL ; s = s - > next ) {
HA_SPIN_LOCK ( SERVER_LOCK , & s - > lock ) ;
2017-03-14 15:08:46 -04:00
srv_set_dyncookie ( s ) ;
2018-08-21 08:50:44 -04:00
HA_SPIN_UNLOCK ( SERVER_LOCK , & s - > lock ) ;
}
2017-03-14 15:08:46 -04:00
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "set maxconn frontend" directive, it always returns 1.
*
* Grabs the proxy lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_set_maxconn_frontend ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-11-23 10:22:04 -05:00
{
struct proxy * px ;
struct listener * l ;
int v ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_frontend ( appctx , args [ 3 ] ) ;
if ( ! px )
return 1 ;
2019-08-09 05:21:01 -04:00
if ( ! * args [ 4 ] )
return cli_err ( appctx , " Integer value expected. \n " ) ;
2016-11-23 10:22:04 -05:00
v = atoi ( args [ 4 ] ) ;
2019-08-09 05:21:01 -04:00
if ( v < 0 )
return cli_err ( appctx , " Value out of range. \n " ) ;
2016-11-23 10:22:04 -05:00
/* OK, the value is fine, so we assign it to the proxy and to all of
* its listeners . The blocked ones will be dequeued .
*/
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRLOCK ( PROXY_LOCK , & px - > lock ) ;
2018-08-21 08:50:44 -04:00
2016-11-23 10:22:04 -05:00
px - > maxconn = v ;
list_for_each_entry ( l , & px - > conf . listeners , by_fe ) {
if ( l - > state = = LI_FULL )
2023-02-06 11:19:58 -05:00
relax_listener ( l , 1 , 0 ) ;
2016-11-23 10:22:04 -05:00
}
2019-12-10 08:10:52 -05:00
if ( px - > maxconn > px - > feconn )
2024-09-25 05:37:25 -04:00
dequeue_proxy_listeners ( px , 1 ) ;
2016-11-23 10:22:04 -05:00
2020-10-20 11:24:27 -04:00
HA_RWLOCK_WRUNLOCK ( PROXY_LOCK , & px - > lock ) ;
2018-08-21 08:50:44 -04:00
2016-11-23 10:22:04 -05:00
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "shutdown frontend" directive, it always returns 1.
*
* Grabs the proxy lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_shutdown_frontend ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-11-24 05:13:06 -05:00
{
struct proxy * px ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_frontend ( appctx , args [ 2 ] ) ;
if ( ! px )
return 1 ;
2021-10-06 08:24:19 -04:00
if ( px - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
2019-08-09 05:21:01 -04:00
return cli_msg ( appctx , LOG_NOTICE , " Frontend was already shut down. \n " ) ;
2016-11-24 05:13:06 -05:00
stop_proxy ( px ) ;
return 1 ;
}
2025-12-17 04:57:40 -05:00
/* Parses a "add backend" CLI command to allocate a new backend instance,
* derived from a default proxy instance . This operation is performed under
* thread isolation .
*
* Always returns 1.
*/
static int cli_parse_add_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
{
2025-12-18 03:51:27 -05:00
struct proxy * px , * defpx , * next ;
struct post_proxy_check_fct * ppcf ;
2026-01-13 10:13:27 -05:00
const char * be_name , * def_name , * guid = NULL , * err ;
2025-12-17 04:57:40 -05:00
char * msg = NULL ;
2026-01-12 09:25:52 -05:00
enum pr_mode mode = 0 ;
2025-12-18 03:51:27 -05:00
int err_code = ERR_NONE ;
2025-12-17 04:57:40 -05:00
usermsgs_clr ( " CLI " ) ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
+ + args ;
be_name = args [ 1 ] ;
if ( ! * be_name ) {
cli_err ( appctx , " Require backend name. \n " ) ;
return 1 ;
}
if ( ( err = invalid_char ( be_name ) ) ) {
cli_dynerr ( appctx , memprintf ( & msg , " Invalid character '%c' in backend name. \n " , * err ) ) ;
return 1 ;
}
+ + args ;
def_name = args [ 2 ] ;
if ( ! * args [ 1 ] | | ! * def_name | | strcmp ( args [ 1 ] , " from " ) ! = 0 ) {
cli_err ( appctx , " Usage: add backend <name> from <defproxy>. \n " ) ;
return 1 ;
}
2026-01-12 09:25:52 -05:00
/* Parse optional arguments */
args + = 2 ;
while ( * args [ 1 ] ) {
/* "mode" */
if ( * args [ 2 ] & & ! mode & & strcmp ( args [ 1 ] , " mode " ) = = 0 ) {
mode = str_to_proxy_mode ( args [ 2 ] ) ;
if ( mode = = PR_MODES ) {
cli_err ( appctx , " Unknown proxy mode. \n " ) ;
return 1 ;
}
if ( mode ! = PR_MODE_TCP & & mode ! = PR_MODE_HTTP ) {
cli_err ( appctx , " Dynamic backends are compatible with only TCP or HTTP mode. \n " ) ;
return 1 ;
}
}
2026-01-13 10:13:27 -05:00
/* guid */
else if ( * args [ 2 ] & & ! guid & & strcmp ( args [ 1 ] , " guid " ) = = 0 ) {
guid = args [ 2 ] ;
}
2026-01-12 09:25:52 -05:00
/* unknown, malformed or duplicate argument */
else {
2026-01-13 10:13:27 -05:00
cli_err ( appctx , " Usage: add backend <name> from <defproxy> [mode <px_mode>] [guid <val>]. \n " ) ;
2026-01-12 09:25:52 -05:00
return 1 ;
}
args + = 2 ;
}
2025-12-17 04:57:40 -05:00
defpx = proxy_find_by_name ( def_name , PR_CAP_DEF , 0 ) ;
if ( ! defpx ) {
cli_dynerr ( appctx , memprintf ( & msg , " Cannot find default proxy '%s'. \n " , def_name ) ) ;
return 1 ;
}
2026-01-12 09:25:52 -05:00
if ( ! ( defpx - > flags & PR_FL_DEF_EXPLICIT_MODE ) & & ! mode ) {
cli_dynerr ( appctx , memprintf ( & msg , " Mode is required as '%s' default proxy does not explicitely defines it. \n " , def_name ) ) ;
return 1 ;
}
2026-02-06 07:51:02 -05:00
if ( defpx - > mode ! = PR_MODE_TCP & & defpx - > mode ! = PR_MODE_HTTP ) {
cli_dynerr ( appctx , memprintf ( & msg , " Dynamic backends only support TCP or HTTP mode, whereas default proxy '%s' uses 'mode %s'. \n " ,
def_name , proxy_mode_str ( defpx - > mode ) ) ) ;
return 1 ;
}
if ( ! LIST_ISEMPTY ( & defpx - > conf . errors ) ) {
cli_dynerr ( appctx , memprintf ( & msg , " Dynamic backends cannot inherit from default proxy '%s' because it references HTTP errors. \n " , def_name ) ) ;
return 1 ;
}
2025-12-17 04:57:40 -05:00
thread_isolate ( ) ;
if ( ( px = proxy_find_by_name ( be_name , PR_CAP_NONE , 0 ) ) | |
( px = proxy_find_by_name ( be_name , PR_CAP_DEF , 0 ) ) ) {
memprintf ( & msg ,
" name is already used by other proxy '%s %s' " ,
proxy_cap_str ( px - > cap ) , be_name ) ;
px = NULL ;
goto err ;
}
2025-12-18 03:51:27 -05:00
px = alloc_new_proxy ( be_name , PR_CAP_BE , & msg ) ;
if ( ! px )
goto err ;
if ( guid & & guid_insert ( & px - > obj_type , guid , & msg ) ) {
memprintf ( & msg , " GUID insertion : %s " , msg ) ;
goto err ;
}
if ( proxy_defproxy_cpy ( px , defpx , & msg ) )
goto err ;
/* Override default-proxy mode if defined. */
if ( mode )
px - > mode = mode ;
if ( proxy_ref_defaults ( px , defpx , & msg ) )
goto err ;
proxy_init_per_thr ( px ) ;
if ( proxy_finalize ( px , & err_code ) )
goto err ;
list_for_each_entry ( ppcf , & post_proxy_check_list , list ) {
err_code | = ppcf - > fct ( px ) ;
if ( err_code & ( ERR_ABORT | ERR_FATAL ) )
goto err ;
}
px - > flags | = PR_FL_BE_UNPUBLISHED ;
if ( ! stats_allocate_proxy_counters_internal ( & px - > extra_counters_be ,
COUNTERS_BE ,
2026-02-24 14:08:49 -05:00
STATS_PX_CAP_BE ,
2026-02-25 03:53:13 -05:00
& px - > per_tgrp - > extra_counters_be_storage ,
& px - > per_tgrp [ 1 ] . extra_counters_be_storage -
& px - > per_tgrp [ 0 ] . extra_counters_be_storage ) ) {
2025-12-18 03:51:27 -05:00
memprintf ( & msg , " failed to allocate extra counters " ) ;
goto err ;
}
2025-12-23 10:15:47 -05:00
/* Assign automatically proxy ID. */
px - > uuid = proxy_get_next_id ( dynpx_next_id ) ;
if ( ! px - > uuid ) {
memprintf ( & msg , " no spare proxy ID available " ) ;
goto err ;
}
dynpx_next_id = px - > uuid ;
2025-12-18 03:51:27 -05:00
if ( ! proxies_list ) {
2026-02-06 15:28:42 -05:00
proxies_list = px ;
2025-12-18 03:51:27 -05:00
}
else {
for ( next = proxies_list ; next - > next ; next = next - > next )
;
next - > next = px ;
}
px - > next = NULL ;
2025-12-17 04:57:40 -05:00
thread_release ( ) ;
2025-12-18 03:51:27 -05:00
if ( unlikely ( ! be_supports_dynamic_srv ( px , & msg ) ) )
2026-02-06 15:11:37 -05:00
memprintf ( & msg , " New backend registered (no support for dynamic servers: %s) " , msg ) ;
2025-12-18 03:51:27 -05:00
else
2026-02-06 15:11:37 -05:00
memprintf ( & msg , " New backend registered " ) ;
ha_notice ( " %s. \n " , msg ) ;
2025-12-18 03:51:27 -05:00
ha_free ( & msg ) ;
2025-12-17 04:57:40 -05:00
cli_umsg ( appctx , LOG_INFO ) ;
2025-12-18 03:51:27 -05:00
2025-12-17 04:57:40 -05:00
return 1 ;
err :
2025-12-18 03:51:27 -05:00
/* free_proxy() ensures any potential refcounting on defpx is decremented. */
free_proxy ( px ) ;
2025-12-17 04:57:40 -05:00
thread_release ( ) ;
2025-12-18 03:51:27 -05:00
if ( msg ) {
memprintf ( & msg , " Error during backend creation : %s. \n " , msg ) ;
2025-12-17 04:57:40 -05:00
cli_dynerr ( appctx , msg ) ;
2025-12-18 03:51:27 -05:00
}
else {
ha_alert ( " Error during backend creation. \n " ) ;
cli_umsgerr ( appctx ) ;
}
2025-12-17 04:57:40 -05:00
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "disable frontend" directive, it always returns 1.
*
* Grabs the proxy lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_disable_frontend ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-11-24 05:55:28 -05:00
{
struct proxy * px ;
2018-08-21 08:50:44 -04:00
int ret ;
2016-11-24 05:55:28 -05:00
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_frontend ( appctx , args [ 2 ] ) ;
if ( ! px )
return 1 ;
2021-10-06 08:24:19 -04:00
if ( px - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
2019-08-09 05:21:01 -04:00
return cli_msg ( appctx , LOG_NOTICE , " Frontend was previously shut down, cannot disable. \n " ) ;
2016-11-24 05:55:28 -05:00
2020-09-24 02:04:27 -04:00
if ( ! px - > li_ready )
return cli_msg ( appctx , LOG_NOTICE , " All sockets are already disabled. \n " ) ;
2016-11-24 05:55:28 -05:00
2022-09-08 08:35:35 -04:00
/* pause_proxy will take PROXY_LOCK */
2018-08-21 08:50:44 -04:00
ret = pause_proxy ( px ) ;
2019-08-09 05:21:01 -04:00
if ( ! ret )
return cli_err ( appctx , " Failed to pause frontend, check logs for precise cause. \n " ) ;
2016-11-24 05:55:28 -05:00
return 1 ;
}
2018-08-21 08:50:44 -04:00
/* Parses the "enable frontend" directive, it always returns 1.
*
* Grabs the proxy lock .
*/
2018-04-18 07:26:46 -04:00
static int cli_parse_enable_frontend ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-11-24 05:55:28 -05:00
{
struct proxy * px ;
2018-08-21 08:50:44 -04:00
int ret ;
2016-11-24 05:55:28 -05:00
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_frontend ( appctx , args [ 2 ] ) ;
if ( ! px )
return 1 ;
2021-10-06 08:24:19 -04:00
if ( px - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) )
2019-08-09 05:21:01 -04:00
return cli_err ( appctx , " Frontend was previously shut down, cannot enable. \n " ) ;
2016-11-24 05:55:28 -05:00
2020-09-24 02:04:27 -04:00
if ( px - > li_ready = = px - > li_all )
return cli_msg ( appctx , LOG_NOTICE , " All sockets are already enabled. \n " ) ;
2016-11-24 05:55:28 -05:00
2022-09-08 08:35:35 -04:00
/* resume_proxy will take PROXY_LOCK */
2018-08-21 08:50:44 -04:00
ret = resume_proxy ( px ) ;
2019-08-09 05:21:01 -04:00
if ( ! ret )
return cli_err ( appctx , " Failed to resume frontend, check logs for precise cause (port conflict?) . \ n " ) ;
2016-11-24 05:55:28 -05:00
return 1 ;
}
2026-01-06 05:04:18 -05:00
static int cli_parse_publish_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
{
struct proxy * px ;
usermsgs_clr ( " CLI " ) ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_backend ( appctx , args [ 2 ] ) ;
if ( ! px )
return cli_err ( appctx , " No such backend. \n " ) ;
if ( px - > flags & PR_FL_DISABLED )
return cli_err ( appctx , " No effect on a disabled backend. \n " ) ;
thread_isolate ( ) ;
px - > flags & = ~ PR_FL_BE_UNPUBLISHED ;
thread_release ( ) ;
ha_notice ( " Backend published. \n " ) ;
return cli_umsg ( appctx , LOG_INFO ) ;
}
static int cli_parse_unpublish_backend ( char * * args , char * payload , struct appctx * appctx , void * private )
{
struct proxy * px ;
usermsgs_clr ( " CLI " ) ;
if ( ! cli_has_level ( appctx , ACCESS_LVL_ADMIN ) )
return 1 ;
px = cli_find_backend ( appctx , args [ 2 ] ) ;
if ( ! px )
return cli_err ( appctx , " No such backend. \n " ) ;
if ( px - > flags & PR_FL_DISABLED )
return cli_err ( appctx , " No effect on a disabled backend. \n " ) ;
thread_isolate ( ) ;
px - > flags | = PR_FL_BE_UNPUBLISHED ;
thread_release ( ) ;
ha_notice ( " Backend unpublished. \n " ) ;
return cli_umsg ( appctx , LOG_INFO ) ;
}
2022-05-03 05:24:24 -04:00
/* appctx context used during "show errors" */
struct show_errors_ctx {
struct proxy * px ; /* current proxy being dumped, NULL = not started yet. */
unsigned int flag ; /* bit0: buffer being dumped, 0 = req, 1 = resp ; bit1=skip req ; bit2=skip resp. */
unsigned int ev_id ; /* event ID of error being dumped */
int iid ; /* if >= 0, ID of the proxy to filter on */
int ptr ; /* <0: headers, >=0 : text pointer to restart from */
int bol ; /* pointer to beginning of current line */
} ;
2018-09-07 12:34:24 -04:00
/* "show errors" handler for the CLI. Returns 0 if wants to continue, 1 to stop
* now .
*/
static int cli_parse_show_errors ( char * * args , char * payload , struct appctx * appctx , void * private )
{
2022-05-03 05:24:24 -04:00
struct show_errors_ctx * ctx = applet_reserve_svcctx ( appctx , sizeof ( * ctx ) ) ;
2018-09-07 12:34:24 -04:00
if ( ! cli_has_level ( appctx , ACCESS_LVL_OPER ) )
return 1 ;
if ( * args [ 2 ] ) {
struct proxy * px ;
px = proxy_find_by_name ( args [ 2 ] , 0 , 0 ) ;
if ( px )
2022-05-03 05:24:24 -04:00
ctx - > iid = px - > uuid ;
2018-09-07 12:34:24 -04:00
else
2022-05-03 05:24:24 -04:00
ctx - > iid = atoi ( args [ 2 ] ) ;
2018-09-07 12:34:24 -04:00
2022-05-03 05:24:24 -04:00
if ( ! ctx - > iid )
2019-08-09 05:21:01 -04:00
return cli_err ( appctx , " No such proxy. \n " ) ;
2018-09-07 12:34:24 -04:00
}
else
2022-05-03 05:24:24 -04:00
ctx - > iid = - 1 ; // dump all proxies
2018-09-07 12:34:24 -04:00
2022-05-03 05:24:24 -04:00
ctx - > flag = 0 ;
2018-09-07 12:34:24 -04:00
if ( strcmp ( args [ 3 ] , " request " ) = = 0 )
2022-05-03 05:24:24 -04:00
ctx - > flag | = 4 ; // ignore response
2018-09-07 12:34:24 -04:00
else if ( strcmp ( args [ 3 ] , " response " ) = = 0 )
2022-05-03 05:24:24 -04:00
ctx - > flag | = 2 ; // ignore request
ctx - > px = NULL ;
2018-09-07 12:34:24 -04:00
return 0 ;
}
2022-05-17 13:07:51 -04:00
/* This function dumps all captured errors onto the stream connector's
2018-09-07 12:34:24 -04:00
* read buffer . It returns 0 if the output buffer is full and it needs
* to be called again , otherwise non - zero .
*/
static int cli_io_handler_show_errors ( struct appctx * appctx )
{
2022-05-03 05:24:24 -04:00
struct show_errors_ctx * ctx = appctx - > svcctx ;
2018-09-07 12:34:24 -04:00
extern const char * monthname [ 12 ] ;
chunk_reset ( & trash ) ;
2022-05-03 05:24:24 -04:00
if ( ! ctx - > px ) {
2018-09-07 12:34:24 -04:00
/* the function had not been called yet, let's prepare the
* buffer for a response .
*/
struct tm tm ;
get_localtime ( date . tv_sec , & tm ) ;
chunk_appendf ( & trash , " Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u \n " ,
tm . tm_mday , monthname [ tm . tm_mon ] , tm . tm_year + 1900 ,
tm . tm_hour , tm . tm_min , tm . tm_sec , ( int ) ( date . tv_usec / 1000 ) ,
error_snapshot_id ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2018-09-07 13:55:44 -04:00
goto cant_send ;
2018-09-07 12:34:24 -04:00
2022-05-03 05:24:24 -04:00
ctx - > px = proxies_list ;
ctx - > bol = 0 ;
ctx - > ptr = - 1 ;
2018-09-07 12:34:24 -04:00
}
/* we have two inner loops here, one for the proxy, the other one for
* the buffer .
*/
2022-05-03 05:24:24 -04:00
while ( ctx - > px ) {
2018-09-07 12:34:24 -04:00
struct error_snapshot * es ;
2022-05-03 05:24:24 -04:00
HA_RWLOCK_RDLOCK ( PROXY_LOCK , & ctx - > px - > lock ) ;
2018-09-07 13:55:44 -04:00
2022-05-03 05:24:24 -04:00
if ( ( ctx - > flag & 1 ) = = 0 ) {
es = ctx - > px - > invalid_req ;
if ( ctx - > flag & 2 ) // skip req
2018-09-07 12:34:24 -04:00
goto next ;
}
else {
2022-05-03 05:24:24 -04:00
es = ctx - > px - > invalid_rep ;
if ( ctx - > flag & 4 ) // skip resp
2018-09-07 12:34:24 -04:00
goto next ;
}
2018-09-07 13:02:32 -04:00
if ( ! es )
2018-09-07 12:34:24 -04:00
goto next ;
2022-05-03 05:24:24 -04:00
if ( ctx - > iid > = 0 & &
ctx - > px - > uuid ! = ctx - > iid & &
( ! es - > oe | | es - > oe - > uuid ! = ctx - > iid ) )
2018-09-07 12:34:24 -04:00
goto next ;
2022-05-03 05:24:24 -04:00
if ( ctx - > ptr < 0 ) {
2018-09-07 12:34:24 -04:00
/* just print headers now */
char pn [ INET6_ADDRSTRLEN ] ;
struct tm tm ;
int port ;
get_localtime ( es - > when . tv_sec , & tm ) ;
chunk_appendf ( & trash , " \n [%02d/%s/%04d:%02d:%02d:%02d.%03d] " ,
tm . tm_mday , monthname [ tm . tm_mon ] , tm . tm_year + 1900 ,
tm . tm_hour , tm . tm_min , tm . tm_sec , ( int ) ( es - > when . tv_usec / 1000 ) ) ;
switch ( addr_to_str ( & es - > src , pn , sizeof ( pn ) ) ) {
case AF_INET :
case AF_INET6 :
port = get_host_port ( & es - > src ) ;
break ;
default :
port = 0 ;
}
2022-05-03 05:24:24 -04:00
switch ( ctx - > flag & 1 ) {
2018-09-07 12:34:24 -04:00
case 0 :
chunk_appendf ( & trash ,
" frontend %s (#%d): invalid request \n "
" backend %s (#%d) " ,
2022-05-03 05:24:24 -04:00
ctx - > px - > id , ctx - > px - > uuid ,
2020-03-12 10:30:17 -04:00
( es - > oe & & es - > oe - > cap & PR_CAP_BE ) ? es - > oe - > id : " <NONE> " ,
( es - > oe & & es - > oe - > cap & PR_CAP_BE ) ? es - > oe - > uuid : - 1 ) ;
2018-09-07 12:34:24 -04:00
break ;
case 1 :
chunk_appendf ( & trash ,
" backend %s (#%d): invalid response \n "
" frontend %s (#%d) " ,
2022-05-03 05:24:24 -04:00
ctx - > px - > id , ctx - > px - > uuid ,
2020-03-12 10:30:17 -04:00
es - > oe ? es - > oe - > id : " <NONE> " , es - > oe ? es - > oe - > uuid : - 1 ) ;
2018-09-07 12:34:24 -04:00
break ;
}
chunk_appendf ( & trash ,
" , server %s (#%d), event #%u, src %s:%d \n "
" buffer starts at %llu (including %u out), %u free, \n "
" len %u, wraps at %u, error at position %u \n " ,
es - > srv ? es - > srv - > id : " <NONE> " ,
es - > srv ? es - > srv - > puid : - 1 ,
es - > ev_id , pn , port ,
es - > buf_ofs , es - > buf_out ,
2026-01-28 04:54:41 -05:00
es - > buf_size - es - > buf_out - es - > buf_len ,
2018-09-07 12:34:24 -04:00
es - > buf_len , es - > buf_wrap , es - > buf_err ) ;
if ( es - > show )
es - > show ( & trash , es ) ;
chunk_appendf ( & trash , " \n " ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2018-09-07 13:55:44 -04:00
goto cant_send_unlock ;
2022-05-03 05:24:24 -04:00
ctx - > ptr = 0 ;
ctx - > ev_id = es - > ev_id ;
2018-09-07 12:34:24 -04:00
}
2022-05-03 05:24:24 -04:00
if ( ctx - > ev_id ! = es - > ev_id ) {
2018-09-07 12:34:24 -04:00
/* the snapshot changed while we were dumping it */
chunk_appendf ( & trash ,
" WARNING! update detected on this snapshot, dump interrupted. Please re-check! \n " ) ;
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2018-09-07 13:55:44 -04:00
goto cant_send_unlock ;
2018-09-07 12:34:24 -04:00
goto next ;
}
/* OK, ptr >= 0, so we have to dump the current line */
2026-01-28 04:54:41 -05:00
while ( ctx - > ptr < es - > buf_len & & ctx - > ptr < es - > buf_size ) {
2018-09-07 12:34:24 -04:00
int newptr ;
int newline ;
2022-05-03 05:24:24 -04:00
newline = ctx - > bol ;
2026-01-28 04:54:41 -05:00
newptr = dump_text_line ( & trash , es - > buf , es - > buf_size , es - > buf_len , & newline , ctx - > ptr ) ;
2023-05-05 05:28:45 -04:00
if ( newptr = = ctx - > ptr ) {
2024-02-15 07:34:05 -05:00
applet_fl_set ( appctx , APPCTX_FL_OUTBLK_FULL ) ;
2018-09-07 13:55:44 -04:00
goto cant_send_unlock ;
2023-05-05 05:28:45 -04:00
}
2018-09-07 13:55:44 -04:00
2022-05-18 09:07:19 -04:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
2018-09-07 13:55:44 -04:00
goto cant_send_unlock ;
2018-09-07 12:34:24 -04:00
2022-05-03 05:24:24 -04:00
ctx - > ptr = newptr ;
ctx - > bol = newline ;
2018-09-07 12:34:24 -04:00
} ;
next :
2022-05-03 05:24:24 -04:00
HA_RWLOCK_RDUNLOCK ( PROXY_LOCK , & ctx - > px - > lock ) ;
ctx - > bol = 0 ;
ctx - > ptr = - 1 ;
ctx - > flag ^ = 1 ;
if ( ! ( ctx - > flag & 1 ) )
ctx - > px = ctx - > px - > next ;
2018-09-07 12:34:24 -04:00
}
/* dump complete */
return 1 ;
2018-09-07 13:55:44 -04:00
cant_send_unlock :
2022-05-03 05:24:24 -04:00
HA_RWLOCK_RDUNLOCK ( PROXY_LOCK , & ctx - > px - > lock ) ;
2018-09-07 13:55:44 -04:00
cant_send :
return 0 ;
2018-09-07 12:34:24 -04:00
}
2016-11-18 20:25:36 -05:00
/* register cli keywords */
static struct cli_kw_list cli_kws = { { } , {
2025-12-17 04:57:40 -05:00
{ { " add " , " backend " , NULL } , " add backend <backend> : add a new backend " , cli_parse_add_backend , NULL , NULL , NULL , ACCESS_EXPERIMENTAL } ,
2021-05-07 05:38:37 -04:00
{ { " disable " , " frontend " , NULL } , " disable frontend <frontend> : temporarily disable specific frontend " , cli_parse_disable_frontend , NULL , NULL } ,
{ { " enable " , " frontend " , NULL } , " enable frontend <frontend> : re-enable specific frontend " , cli_parse_enable_frontend , NULL , NULL } ,
2026-01-06 05:04:18 -05:00
{ { " publish " , " backend " , NULL } , " publish backend <backend> : mark backend as ready for traffic " , cli_parse_publish_backend , NULL , NULL } ,
2021-05-07 05:38:37 -04:00
{ { " set " , " maxconn " , " frontend " , NULL } , " set maxconn frontend <frontend> <value> : change a frontend's maxconn setting " , cli_parse_set_maxconn_frontend , NULL } ,
{ { " show " , " servers " , " conn " , NULL } , " show servers conn [<backend>] : dump server connections status (all or for a single backend) " , cli_parse_show_servers , cli_io_handler_servers_state } ,
{ { " show " , " servers " , " state " , NULL } , " show servers state [<backend>] : dump volatile server information (all or for a single backend) " , cli_parse_show_servers , cli_io_handler_servers_state } ,
{ { " show " , " backend " , NULL } , " show backend : list backends in the current running config " , NULL , cli_io_handler_show_backend } ,
{ { " shutdown " , " frontend " , NULL } , " shutdown frontend <frontend> : stop a specific frontend " , cli_parse_shutdown_frontend , NULL , NULL } ,
{ { " set " , " dynamic-cookie-key " , " backend " , NULL } , " set dynamic-cookie-key backend <bk> <k> : change a backend secret key for dynamic cookies " , cli_parse_set_dyncookie_key_backend , NULL } ,
2026-01-06 05:04:18 -05:00
{ { " unpublish " , " backend " , NULL } , " unpublish backend <backend> : remove backend for traffic processing " , cli_parse_unpublish_backend , NULL , NULL } ,
2021-05-07 05:38:37 -04:00
{ { " enable " , " dynamic-cookie " , " backend " , NULL } , " enable dynamic-cookie backend <bk> : enable dynamic cookies on a specific backend " , cli_parse_enable_dyncookie_backend , NULL } ,
{ { " disable " , " dynamic-cookie " , " backend " , NULL } , " disable dynamic-cookie backend <bk> : disable dynamic cookies on a specific backend " , cli_parse_disable_dyncookie_backend , NULL } ,
{ { " show " , " errors " , NULL } , " show errors [<px>] [request|response] : report last request and/or response errors for each proxy " , cli_parse_show_errors , cli_io_handler_show_errors , NULL } ,
2016-11-18 20:25:36 -05:00
{ { } , }
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , cli_register_kw , & cli_kws ) ;
2006-06-25 20:48:02 -04:00
/*
* Local variables :
* c - indent - level : 8
* c - basic - offset : 8
* End :
*/