Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package haproxy for openSUSE:Factory checked 
in at 2026-02-12 17:30:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/haproxy (Old)
 and      /work/SRC/openSUSE:Factory/.haproxy.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "haproxy"

Thu Feb 12 17:30:48 2026 rev:176 rq:1332730 version:3.3.3+git0.465d8e2fc

Changes:
--------
--- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes  2026-02-06 
19:18:01.791520873 +0100
+++ /work/SRC/openSUSE:Factory/.haproxy.new.1977/haproxy.changes        
2026-02-12 17:30:57.244416434 +0100
@@ -1,0 +2,25 @@
+Thu Feb 12 15:16:46 UTC 2026 - Marcus Rueckert <[email protected]>
+
+- Update to version 3.3.3+git0.465d8e2fc:
+  (boo#1257976 CVE-2026-26081 CVE-2026-26080)
+  * [RELEASE] Released version 3.3.3
+  * BUG/MAJOR: quic: fix parsing frame type
+  * BUG/MAJOR: quic: reject invalid token
+  * BUG/MINOR: backend: fix access on shared counters array
+  * BUG/MINOR: quic: ensure handshake speed up is only run once per conn
+  * BUG/MINOR: ssl: SSL_CERT_DIR environment variable doesn't affect haproxy
+  * MINOR: activity: allow to switch per-task lock/memory profiling at runtime
+  * MEDIUM: activity: apply and use new finegrained task profiling settings
+  * MINOR: activity: support setting/clearing lock/memory watching for task 
profiling
+  * BUG/MINOR: startup: handle a possible strdup() failure
+  * BUG/MINOR: startup: fix allocation error message of progname string
+  * BUG/MINOR: config: Fix setting of alt_proto
+  * MEDIUM: backend: make "balance random" consider req rate when loads are 
equal
+  * DOC: config: mention the limitation on server id range for consistent hash
+  * BUG/MEDIUM: lb-chash: always properly initialize lb_nodes with dynamic 
servers
+  * CLEANUP: lb-chash: free lb_nodes from chash's deinit(), not global
+  * BUG/MINOR: cpu-topo: count cores not cpus to distinguish core types
+  * CLEANUP: haproxy: fix bad line wrapping in run_poll_loop()
+  * BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED
+
+-------------------------------------------------------------------

Old:
----
  haproxy-3.3.2+git3.bc0fb5969.tar.gz

New:
----
  haproxy-3.3.3+git0.465d8e2fc.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ haproxy.spec ++++++
--- /var/tmp/diff_new_pack.w07BoB/_old  2026-02-12 17:30:58.276460227 +0100
+++ /var/tmp/diff_new_pack.w07BoB/_new  2026-02-12 17:30:58.280460397 +0100
@@ -49,7 +49,7 @@
 %bcond_with ech
 
 Name:           haproxy
-Version:        3.3.2+git3.bc0fb5969
+Version:        3.3.3+git0.465d8e2fc
 Release:        0
 #
 Summary:        The Reliable, High Performance TCP/HTTP Load Balancer

++++++ _service ++++++
--- /var/tmp/diff_new_pack.w07BoB/_old  2026-02-12 17:30:58.388464980 +0100
+++ /var/tmp/diff_new_pack.w07BoB/_new  2026-02-12 17:30:58.392465150 +0100
@@ -6,10 +6,7 @@
     <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="versionrewrite-replacement">\1</param>
-    <!--
-    <param name="revision">v3.3.2</param>
-    -->
-    <param name="revision">master</param>
+    <param name="revision">v3.3.3</param>
     <param name="changesgenerate">enable</param>
   </service>
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.w07BoB/_old  2026-02-12 17:30:58.424466508 +0100
+++ /var/tmp/diff_new_pack.w07BoB/_new  2026-02-12 17:30:58.440467187 +0100
@@ -5,7 +5,7 @@
   </service>
   <service name="tar_scm">
     <param name="url">http://git.haproxy.org/git/haproxy-3.3.git/</param>
-    <param 
name="changesrevision">bc0fb5969e500ea5702bf885dd1fea110f6b3ce6</param>
+    <param 
name="changesrevision">465d8e2fcfcbf4bbcf36c3f53a801369f4e7e922</param>
   </service>
 </servicedata>
 (No newline at EOF)

++++++ haproxy-3.3.2+git3.bc0fb5969.tar.gz -> 
haproxy-3.3.3+git0.465d8e2fc.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/CHANGELOG 
new/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG
--- old/haproxy-3.3.2+git3.bc0fb5969/CHANGELOG  2026-01-30 09:56:50.000000000 
+0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG  2026-02-12 14:25:57.000000000 
+0100
@@ -1,6 +1,29 @@
 ChangeLog :
 ===========
 
+2026/02/12 : 3.3.3
+    - MEDIUM: h1: strictly verify quoting in chunk extensions
+    - DOC: internals: cleanup few typos in master-worker documentation
+    - BUG/MEDIUM: applet: Fix test on shut flags for legacy applets
+    - BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED
+    - CLEANUP: haproxy: fix bad line wrapping in run_poll_loop()
+    - BUG/MINOR: cpu-topo: count cores not cpus to distinguish core types
+    - CLEANUP: lb-chash: free lb_nodes from chash's deinit(), not global
+    - BUG/MEDIUM: lb-chash: always properly initialize lb_nodes with dynamic 
servers
+    - DOC: config: mention the limitation on server id range for consistent 
hash
+    - MEDIUM: backend: make "balance random" consider req rate when loads are 
equal
+    - BUG/MINOR: config: Fix setting of alt_proto
+    - BUG/MINOR: startup: fix allocation error message of progname string
+    - BUG/MINOR: startup: handle a possible strdup() failure
+    - MINOR: activity: support setting/clearing lock/memory watching for task 
profiling
+    - MEDIUM: activity: apply and use new finegrained task profiling settings
+    - MINOR: activity: allow to switch per-task lock/memory profiling at 
runtime
+    - BUG/MINOR: ssl: SSL_CERT_DIR environment variable doesn't affect haproxy
+    - BUG/MINOR: quic: ensure handshake speed up is only run once per conn
+    - BUG/MINOR: backend: fix access on shared counters array
+    - BUG/MAJOR: quic: reject invalid token
+    - BUG/MAJOR: quic: fix parsing frame type
+
 2026/01/29 : 3.3.2
     - MINOR: mux-h2: add missing glitch count for non-decodable H2 headers
     - MINOR: mux-h2: perform a graceful close at 75% glitches threshold
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/VERDATE 
new/haproxy-3.3.3+git0.465d8e2fc/VERDATE
--- old/haproxy-3.3.2+git3.bc0fb5969/VERDATE    2026-01-30 09:56:50.000000000 
+0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/VERDATE    2026-02-12 14:25:57.000000000 
+0100
@@ -1,2 +1,2 @@
 $Format:%ci$
-2026/01/29
+2026/02/12
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/VERSION 
new/haproxy-3.3.3+git0.465d8e2fc/VERSION
--- old/haproxy-3.3.2+git3.bc0fb5969/VERSION    2026-01-30 09:56:50.000000000 
+0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/VERSION    2026-02-12 14:25:57.000000000 
+0100
@@ -1 +1 @@
-3.3.2
+3.3.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/doc/configuration.txt 
new/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt
--- old/haproxy-3.3.2+git3.bc0fb5969/doc/configuration.txt      2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt      2026-02-12 
14:25:57.000000000 +0100
@@ -3,7 +3,7 @@
                           Configuration Manual
                          ----------------------
                               version 3.3
-                              2026/01/29
+                              2026/02/12
 
 
 This document covers the configuration language as implemented in the version
@@ -3962,7 +3962,7 @@
   use in production. The same may be achieved at run time on the CLI using the
   "set profiling memory" command, please consult the management manual.
 
-profiling.tasks { auto | on | off }
+profiling.tasks { auto | on | off | lock | no-lock | memory | no-memory }*
   Enables ('on') or disables ('off') per-task CPU profiling. When set to 'auto'
   the profiling automatically turns on a thread when it starts to suffer from
   an average latency of 1000 microseconds or higher as reported in the
@@ -3973,6 +3973,18 @@
   systems, containers, or virtual machines, or when the system swaps (which
   must absolutely never happen on a load balancer).
 
+  When task profiling is enabled, HAProxy can also collect the time each task
+  spends with a lock held or waiting for a lock, as well as the time spent
+  waiting for a memory allocation to succeed in case of a pool cache miss. This
+  can sometimes help understand certain causes of latency. For this, the extra
+  keywords "lock" (to enable lock time collection), "no-lock" (to disable it),
+  "memory" (to enable memory allocation time collection) or "no-memory" (to
+  disable it) may additionally be passed. By default they are not enabled since
+  they can have a non-negligible CPU impact on highly loaded systems (3-10%).
+  Note that the overhead is only taken when profiling is effectively running,
+  so that when running in "auto" mode, it will only appear when HAProxy decides
+  to turn it on.
+
   CPU profiling per task can be very convenient to report where the time is
   spent and which requests have what effect on which other request. Enabling
   it will typically affect the overall's performance by less than 1%, thus it
@@ -6182,8 +6194,16 @@
                   will take away N-1 of the highest loaded servers at the
                   expense of performance. With very high values, the algorithm
                   will converge towards the leastconn's result but much slower.
+                  In addition, for large server farms with very low loads (or
+                  perfect balance), comparing loads will often lead to a tie,
+                  so in case of equal loads between all measured servers, their
+                  request rate over the last second are compared, which allows
+                  to better balance server usage over time in the same spirit
+                  as roundrobin does, and smooth consistent hash unfairness.
                   The default value is 2, which generally shows very good
-                  distribution and performance. This algorithm is also known as
+                  distribution and performance. For large farms with low loads
+                  (less than a few requests per second per server), it may help
+                  to raise it to 3 or even 4. This algorithm is also known as
                   the Power of Two Random Choices and is described here :
                   
http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf
 
@@ -18190,7 +18210,10 @@
 
       id         The node keys will be derived from the server's numeric
                  identifier as set from "id" or which defaults to its position
-                 in the server list.
+                 in the server list. This is the default. Note that only the 28
+                 lowest bits of the ID will be used (i.e. (id % 268435456)), so
+                 better only use values comprised between 1 and this value to
+                 avoid overlap.
 
       addr       The node keys will be derived from the server's address, when
                  available, or else fall back on "id".
@@ -18202,7 +18225,9 @@
   HAProxy processes are balancing traffic to the same set of servers. If the
   server order of each process is different (because, for example, DNS records
   were resolved in different orders) then this will allow each independent
-  HAProxy processes to agree on routing decisions.
+  HAProxy processes to agree on routing decisions. Note: "balance random" also
+  uses "hash-type consistent", and the quality of the distribution will depend
+  on the quality of the keys.
 
 id <value>
   May be used in the following contexts: tcp, http, log
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/doc/management.txt 
new/haproxy-3.3.3+git0.465d8e2fc/doc/management.txt
--- old/haproxy-3.3.2+git3.bc0fb5969/doc/management.txt 2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/doc/management.txt 2026-02-12 
14:25:57.000000000 +0100
@@ -2529,7 +2529,8 @@
   delayed until the threshold is reached. A value of zero restores the initial
   setting.
 
-set profiling { tasks | memory } { auto | on | off }
+set profiling memory { on | off }
+set profiling tasks { auto | on | off | lock | no-lock | memory | no-memory }
   Enables or disables CPU or memory profiling for the indicated subsystem. This
   is equivalent to setting or clearing the "profiling" settings in the "global"
   section of the configuration file. Please also see "show profiling". Note
@@ -2539,6 +2540,13 @@
   on the linux-glibc target), and requires USE_MEMORY_PROFILING to be set at
   compile time.
 
+. For tasks profiling, it is possible to enable or disable the collection of
+  per-task lock and memory timings at runtime, but the change is only taken
+  into account next time the profiler switches from off/auto to on (either
+  automatically or manually). Thus when using "no-lock" to disable per-task
+  lock profiling and save CPU cycles, it is recommended to flip the task
+  profiling off then on to commit the change.
+
 set rate-limit connections global <value>
   Change the process-wide connection rate limit, which is set by the global
   'maxconnrate' setting. A value of zero disables the limitation. This limit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/activity-t.h 
new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/activity-t.h
--- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/activity-t.h       
2026-01-30 09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/activity-t.h       
2026-02-12 14:25:57.000000000 +0100
@@ -33,6 +33,8 @@
 #define HA_PROF_TASKS_MASK  0x00000003     /* per-task CPU profiling mask */
 
 #define HA_PROF_MEMORY      0x00000004     /* memory profiling */
+#define HA_PROF_TASKS_MEM   0x00000008     /* per-task CPU profiling with 
memory */
+#define HA_PROF_TASKS_LOCK  0x00000010     /* per-task CPU profiling with 
locks */
 
 
 #ifdef USE_MEMORY_PROFILING
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/backend-t.h 
new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/backend-t.h
--- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/backend-t.h        
2026-01-30 09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/backend-t.h        
2026-02-12 14:25:57.000000000 +0100
@@ -192,6 +192,7 @@
        void (*server_requeue)(struct server *);         /* function used to 
place the server where it must be */
        void (*proxy_deinit)(struct proxy *);            /* to be called when 
we're destroying the proxy */
        void (*server_deinit)(struct server *);          /* to be called when 
we're destroying the server */
+       int (*server_init)(struct server *);             /* initialize a 
freshly added server (runtime); <0=fail. */
 };
 
 #endif /* _HAPROXY_BACKEND_T_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/ssl_ckch.h 
new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_ckch.h
--- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/ssl_ckch.h 2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_ckch.h 2026-02-12 
14:25:57.000000000 +0100
@@ -80,6 +80,7 @@
 int ssl_store_load_ca_from_buf(struct cafile_entry *ca_e, char *cert_buf, int 
append);
 int ssl_store_load_locations_file(char *path, int create_if_none, enum 
cafile_type type);
 int __ssl_store_load_locations_file(char *path, int create_if_none, enum 
cafile_type type, int shuterror);
+const char *ha_default_cert_dir();
 
 extern struct cert_exts cert_exts[];
 extern int (*ssl_commit_crlfile_cb)(const char *path, X509_STORE *ctx, char 
**err);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/thread.h 
new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/thread.h
--- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/thread.h   2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/thread.h   2026-02-12 
14:25:57.000000000 +0100
@@ -364,15 +364,19 @@
                extern uint64_t now_mono_time(void);                    \
                if (_LK_ != _LK_UN) {                                   \
                        th_ctx->lock_level += bal;                      \
-                       if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) \
+                       if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \
+                                    
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \
                                lock_start = now_mono_time();           \
                }                                                       \
                (void)(expr);                                           \
                if (_LK_ == _LK_UN) {                                   \
                        th_ctx->lock_level += bal;                      \
-                       if (th_ctx->lock_level == 0 && unlikely(th_ctx->flags & 
TH_FL_TASK_PROFILING)) \
+                       if (th_ctx->lock_level == 0 &&\
+                           unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \
+                                    
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) \
                                th_ctx->locked_total += now_mono_time() - 
th_ctx->lock_start_date; \
-               } else if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \
+               } else if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \
+                                    
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \
                        uint64_t now = now_mono_time();                 \
                        if (lock_start)                                 \
                                th_ctx->lock_wait_total += now - lock_start; \
@@ -386,7 +390,8 @@
                typeof(expr) _expr = (expr);                            \
                if (_expr == 0) {                                       \
                        th_ctx->lock_level += bal;                      \
-                       if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) { \
+                       if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L)) == \
+                                    
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_L))) { \
                                if (_LK_ == _LK_UN && th_ctx->lock_level == 0) \
                                        th_ctx->locked_total += now_mono_time() 
- th_ctx->lock_start_date; \
                                else if (_LK_ != _LK_UN && th_ctx->lock_level 
== 1) \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/tinfo-t.h 
new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/tinfo-t.h
--- old/haproxy-3.3.2+git3.bc0fb5969/include/haproxy/tinfo-t.h  2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/tinfo-t.h  2026-02-12 
14:25:57.000000000 +0100
@@ -69,6 +69,8 @@
 #define TH_FL_IN_DBG_HANDLER    0x00000100  /* thread currently in the debug 
signal handler */
 #define TH_FL_IN_WDT_HANDLER    0x00000200  /* thread currently in the wdt 
signal handler */
 #define TH_FL_IN_ANY_HANDLER    0x00000380  /* mask to test if the thread is 
in any signal handler */
+#define TH_FL_TASK_PROFILING_L  0x00000400  /* task profiling in locks (also 
requires TASK_PROFILING) */
+#define TH_FL_TASK_PROFILING_M  0x00000800  /* task profiling in mem alloc 
(also requires TASK_PROFILING) */
 
 /* we have 4 buffer-wait queues, in highest to lowest emergency order */
 #define DYNBUF_NBQ              4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/activity.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/activity.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/activity.c     2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/activity.c     2026-02-12 
14:25:57.000000000 +0100
@@ -659,8 +659,20 @@
        if (!(_HA_ATOMIC_LOAD(&th_ctx->flags) & TH_FL_TASK_PROFILING)) {
                if (unlikely((profiling & HA_PROF_TASKS_MASK) == 
HA_PROF_TASKS_ON ||
                             ((profiling & HA_PROF_TASKS_MASK) == 
HA_PROF_TASKS_AON &&
-                            swrate_avg(run_time, TIME_STATS_SAMPLES) >= up)))
+                             swrate_avg(run_time, TIME_STATS_SAMPLES) >= up))) 
{
+
+                       if (profiling & HA_PROF_TASKS_LOCK)
+                               _HA_ATOMIC_OR(&th_ctx->flags, 
TH_FL_TASK_PROFILING_L);
+                       else
+                               _HA_ATOMIC_AND(&th_ctx->flags, 
~TH_FL_TASK_PROFILING_L);
+
+                       if (profiling & HA_PROF_TASKS_MEM)
+                               _HA_ATOMIC_OR(&th_ctx->flags, 
TH_FL_TASK_PROFILING_M);
+                       else
+                               _HA_ATOMIC_AND(&th_ctx->flags, 
~TH_FL_TASK_PROFILING_M);
+
                        _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_TASK_PROFILING);
+               }
        } else {
                if (unlikely((profiling & HA_PROF_TASKS_MASK) == 
HA_PROF_TASKS_OFF ||
                             ((profiling & HA_PROF_TASKS_MASK) == 
HA_PROF_TASKS_AOFF &&
@@ -692,26 +704,41 @@
 }
 #endif // USE_MEMORY_PROFILING
 
-/* config parser for global "profiling.tasks", accepts "on" or "off" */
+/* config parser for global "profiling.tasks", accepts "on", "off", 'auto",
+ * "lock", "no-lock", "memory", "no-memory".
+ */
 static int cfg_parse_prof_tasks(char **args, int section_type, struct proxy 
*curpx,
                                 const struct proxy *defpx, const char *file, 
int line,
                                 char **err)
 {
-       if (too_many_args(1, args, err, NULL))
-               return -1;
+       int arg;
 
-       if (strcmp(args[1], "on") == 0) {
-               profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_ON;
-               HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
-       }
-       else if (strcmp(args[1], "auto") == 0) {
-               profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AOFF;
-               HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+       for (arg = 1; *args[arg]; arg++) {
+               if (strcmp(args[arg], "on") == 0) {
+                       profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_ON;
+                       HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+               }
+               else if (strcmp(args[arg], "auto") == 0) {
+                       profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AOFF;
+                       HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+               }
+               else if (strcmp(args[arg], "off") == 0)
+                       profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_OFF;
+               else if (strcmp(args[arg], "lock") == 0)
+                       profiling |= HA_PROF_TASKS_LOCK;
+               else if (strcmp(args[arg], "no-lock") == 0)
+                       profiling &= ~HA_PROF_TASKS_LOCK;
+               else if (strcmp(args[arg], "memory") == 0)
+                       profiling |= HA_PROF_TASKS_MEM;
+               else if (strcmp(args[arg], "no-memory") == 0)
+                       profiling &= ~HA_PROF_TASKS_MEM;
+               else
+                       break;
        }
-       else if (strcmp(args[1], "off") == 0)
-               profiling = (profiling & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_OFF;
-       else {
-               memprintf(err, "'%s' expects either 'on', 'auto', or 'off' but 
got '%s'.", args[0], args[1]);
+
+       /* either no arg or invalid arg */
+       if (arg == 1 || *args[arg]) {
+               memprintf(err, "'%s' expects a combination of either 'on', 
'auto', 'off', 'lock', 'no-lock', 'memory', or 'no-memory', but got '%s'.", 
args[0], args[arg]);
                return -1;
        }
        return 0;
@@ -720,6 +747,8 @@
 /* parse a "set profiling" command. It always returns 1. */
 static int cli_parse_set_profiling(char **args, char *payload, struct appctx 
*appctx, void *private)
 {
+       int arg;
+
        if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
                return 1;
 
@@ -765,52 +794,66 @@
        if (strcmp(args[2], "tasks") != 0)
                return cli_err(appctx, "Expects either 'tasks' or 'memory'.\n");
 
-       if (strcmp(args[3], "on") == 0) {
-               unsigned int old = profiling;
-               int i;
-
-               while (!_HA_ATOMIC_CAS(&profiling, &old, (old & 
~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON))
-                       ;
-
-               HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
-               HA_ATOMIC_STORE(&prof_task_stop_ns, 0);
-
-               /* also flush current profiling stats */
-               for (i = 0; i < SCHED_ACT_HASH_BUCKETS; i++) {
-                       HA_ATOMIC_STORE(&sched_activity[i].calls, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].cpu_time, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].lat_time, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].lkw_time, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].lkd_time, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].mem_time, 0);
-                       HA_ATOMIC_STORE(&sched_activity[i].func, NULL);
-                       HA_ATOMIC_STORE(&sched_activity[i].caller, NULL);
-               }
-       }
-       else if (strcmp(args[3], "auto") == 0) {
-               unsigned int old = profiling;
-               unsigned int new;
-
-               do {
-                       if ((old & HA_PROF_TASKS_MASK) >= HA_PROF_TASKS_AON)
-                               new = (old & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AON;
-                       else
-                               new = (old & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AOFF;
-               } while (!_HA_ATOMIC_CAS(&profiling, &old, new));
+       for (arg = 3; *args[arg]; arg++) {
+               if (strcmp(args[arg], "on") == 0) {
+                       unsigned int old = profiling;
+                       int i;
 
-               HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
-               HA_ATOMIC_STORE(&prof_task_stop_ns, 0);
-       }
-       else if (strcmp(args[3], "off") == 0) {
-               unsigned int old = profiling;
-               while (!_HA_ATOMIC_CAS(&profiling, &old, (old & 
~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF))
-                       ;
+                       while (!_HA_ATOMIC_CAS(&profiling, &old, (old & 
~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_ON))
+                               ;
+
+                       HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+                       HA_ATOMIC_STORE(&prof_task_stop_ns, 0);
+
+                       /* also flush current profiling stats */
+                       for (i = 0; i < SCHED_ACT_HASH_BUCKETS; i++) {
+                               HA_ATOMIC_STORE(&sched_activity[i].calls, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].cpu_time, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].lat_time, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].lkw_time, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].lkd_time, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].mem_time, 0);
+                               HA_ATOMIC_STORE(&sched_activity[i].func, NULL);
+                               HA_ATOMIC_STORE(&sched_activity[i].caller, 
NULL);
+                       }
+               }
+               else if (strcmp(args[arg], "auto") == 0) {
+                       unsigned int old = profiling;
+                       unsigned int new;
+
+                       do {
+                               if ((old & HA_PROF_TASKS_MASK) >= 
HA_PROF_TASKS_AON)
+                                       new = (old & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AON;
+                               else
+                                       new = (old & ~HA_PROF_TASKS_MASK) | 
HA_PROF_TASKS_AOFF;
+                       } while (!_HA_ATOMIC_CAS(&profiling, &old, new));
 
-               if (HA_ATOMIC_LOAD(&prof_task_start_ns))
-                       HA_ATOMIC_STORE(&prof_task_stop_ns, now_ns);
+                       HA_ATOMIC_STORE(&prof_task_start_ns, now_ns);
+                       HA_ATOMIC_STORE(&prof_task_stop_ns, 0);
+               }
+               else if (strcmp(args[arg], "off") == 0) {
+                       unsigned int old = profiling;
+                       while (!_HA_ATOMIC_CAS(&profiling, &old, (old & 
~HA_PROF_TASKS_MASK) | HA_PROF_TASKS_OFF))
+                               ;
+
+                       if (HA_ATOMIC_LOAD(&prof_task_start_ns))
+                               HA_ATOMIC_STORE(&prof_task_stop_ns, now_ns);
+               }
+               else if (strcmp(args[arg], "lock") == 0)
+                       HA_ATOMIC_OR(&profiling, HA_PROF_TASKS_LOCK);
+               else if (strcmp(args[arg], "no-lock") == 0)
+                       HA_ATOMIC_AND(&profiling, ~HA_PROF_TASKS_LOCK);
+               else if (strcmp(args[arg], "memory") == 0)
+                       HA_ATOMIC_OR(&profiling, HA_PROF_TASKS_MEM);
+               else if (strcmp(args[arg], "no-memory") == 0)
+                       HA_ATOMIC_AND(&profiling, ~HA_PROF_TASKS_MEM);
+               else
+                       break; // unknown arg
        }
-       else
-               return cli_err(appctx, "Expects 'on', 'auto', or 'off'.\n");
+
+       /* either no arg or invalid one */
+       if (arg == 3 || *args[arg])
+               return cli_err(appctx, "Expects a combination of either 'on', 
'auto', 'off', 'lock', 'no-lock', 'memory' or 'no-memory'.\n");
 
        return 1;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/backend.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/backend.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/backend.c      2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/backend.c      2026-02-12 
14:25:57.000000000 +0100
@@ -576,9 +576,20 @@
                /* compare the new server to the previous best choice and pick
                 * the one with the least currently served requests.
                 */
-               if (prev && prev != curr &&
-                   curr->served * prev->cur_eweight > prev->served * 
curr->cur_eweight)
-                       curr = prev;
+               if (prev && prev != curr) {
+                       uint64_t wcurr = (uint64_t)curr->served * 
prev->cur_eweight;
+                       uint64_t wprev = (uint64_t)prev->served * 
curr->cur_eweight;
+
+                       if (wcurr > wprev)
+                               curr = prev;
+                       else if (wcurr == wprev && 
curr->counters.shared.tg[tgid - 1] && prev->counters.shared.tg[tgid - 1]) {
+                               /* same load: pick the lowest weighted request 
rate */
+                               wcurr = 
read_freq_ctr_period_estimate(&curr->counters._sess_per_sec, MS_TO_TICKS(1000));
+                               wprev = 
read_freq_ctr_period_estimate(&prev->counters._sess_per_sec, MS_TO_TICKS(1000));
+                               if (wprev * curr->cur_eweight < wcurr * 
prev->cur_eweight)
+                                       curr = prev;
+                       }
+               }
        } while (--draws > 0);
 
        /* if the selected server is full, pretend we have none so that we reach
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/cpu_topo.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/cpu_topo.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/cpu_topo.c     2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/cpu_topo.c     2026-02-12 
14:25:57.000000000 +0100
@@ -640,7 +640,10 @@
 {
        const struct ha_cpu_cluster *l = (const struct ha_cpu_cluster *)a;
        const struct ha_cpu_cluster *r = (const struct ha_cpu_cluster *)b;
-       return r->capa - l->capa;
+
+       if (!r->nb_cores || !l->nb_cores)
+               return r->nb_cores - l->nb_cores;
+       return r->capa * l->nb_cores - l->capa * r->nb_cores;
 }
 
 /* re-order a cluster array by cluster index only */
@@ -1341,7 +1344,7 @@
 
        capa = 0;
        for (cluster = 0; cluster < cpu_topo_maxcpus; cluster++) {
-               if (capa && ha_cpu_clusters[cluster].capa * 10 < 
ha_cpu_clusters[cluster].nb_cpu * capa * 8) {
+               if (capa && ha_cpu_clusters[cluster].capa * 10 < 
ha_cpu_clusters[cluster].nb_cores * capa * 8) {
                        /* This cluster is made of cores delivering less than
                         * 80% of the performance of those of the previous
                         * cluster, previous one, we're not interested in
@@ -1352,8 +1355,8 @@
                                        ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED;
                        }
                }
-               else if (ha_cpu_clusters[cluster].nb_cpu)
-                       capa = ha_cpu_clusters[cluster].capa / 
ha_cpu_clusters[cluster].nb_cpu;
+               else if (ha_cpu_clusters[cluster].nb_cores)
+                       capa = ha_cpu_clusters[cluster].capa / 
ha_cpu_clusters[cluster].nb_cores;
                else
                        capa = 0;
        }
@@ -1386,7 +1389,7 @@
 
        capa = 0;
        for (cluster = cpu_topo_maxcpus - 1; cluster >= 0; cluster--) {
-               if (capa && ha_cpu_clusters[cluster].capa * 8 >= 
ha_cpu_clusters[cluster].nb_cpu * capa * 10) {
+               if (capa && ha_cpu_clusters[cluster].capa * 8 >= 
ha_cpu_clusters[cluster].nb_cores * capa * 10) {
                        /* This cluster is made of cores each at last 25% faster
                         * than those of the previous cluster, previous one, 
we're
                         * not interested in using it.
@@ -1396,8 +1399,8 @@
                                        ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED;
                        }
                }
-               else if (ha_cpu_clusters[cluster].nb_cpu)
-                       capa = ha_cpu_clusters[cluster].capa / 
ha_cpu_clusters[cluster].nb_cpu;
+               else if (ha_cpu_clusters[cluster].nb_cores)
+                       capa = ha_cpu_clusters[cluster].capa / 
ha_cpu_clusters[cluster].nb_cores;
                else
                        capa = 0;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/haproxy.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/haproxy.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/haproxy.c      2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/haproxy.c      2026-02-12 
14:25:57.000000000 +0100
@@ -1434,11 +1434,15 @@
        len = strlen(progname);
        progname = strdup(progname);
        if (!progname) {
-               ha_alert("Cannot allocate memory for log_tag.\n");
+               ha_alert("Cannot allocate memory for progname.\n");
                exit(EXIT_FAILURE);
        }
 
        chunk_initlen(&global.log_tag, strdup(progname), len, len);
+       if (b_orig(&global.log_tag) == NULL) {
+               ha_alert("Cannot allocate memory for log_tag.\n");
+               exit(EXIT_FAILURE);
+       }
 }
 
 /* handles program arguments. Very minimal parsing is performed, variables are
@@ -2900,9 +2904,11 @@
                if (thread_has_tasks())
                        activity[tid].wake_tasks++;
                else {
-                       _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING);
-                       _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED);
-                       __ha_barrier_atomic_store();
+                       unsigned int flags = _HA_ATOMIC_LOAD(&th_ctx->flags);
+
+                       while (unlikely(!HA_ATOMIC_CAS(&th_ctx->flags, &flags, 
(flags | TH_FL_SLEEPING) & ~TH_FL_NOTIFIED)))
+                               __ha_cpu_relax();
+
                        if (thread_has_tasks()) {
                                activity[tid].wake_tasks++;
                                _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/lb_chash.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/lb_chash.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/lb_chash.c     2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/lb_chash.c     2026-02-12 
14:25:57.000000000 +0100
@@ -552,6 +552,32 @@
        return srv;
 }
 
+/* Allocates and initializes lb nodes for server <srv>. Returns < 0 on error.
+ * This is called by chash_init_server_tree() as well as from srv_alloc_lb()
+ * for runtime addition.
+ */
+int chash_server_init(struct server *srv)
+{
+       int node;
+
+       srv->lb_nodes = calloc(srv->lb_nodes_tot, sizeof(*srv->lb_nodes));
+       if (!srv->lb_nodes)
+               return -1;
+
+       srv->lb_server_key = chash_compute_server_key(srv);
+       for (node = 0; node < srv->lb_nodes_tot; node++) {
+               srv->lb_nodes[node].server = srv;
+               srv->lb_nodes[node].node.key = chash_compute_node_key(srv, 
node);
+       }
+       return 0;
+}
+
+/* Releases the allocated lb_nodes for this server */
+void chash_server_deinit(struct server *srv)
+{
+       ha_free(&srv->lb_nodes);
+}
+
 /* This function is responsible for building the active and backup trees for
  * consistent hashing. The servers receive an array of initialized nodes
  * with their assigned keys. It also sets p->lbprm.wdiv to the eweight to
@@ -562,11 +588,12 @@
 {
        struct server *srv;
        struct eb_root init_head = EB_ROOT;
-       int node;
 
        p->lbprm.set_server_status_up   = chash_set_server_status_up;
        p->lbprm.set_server_status_down = chash_set_server_status_down;
        p->lbprm.update_server_eweight  = chash_update_server_weight;
+       p->lbprm.server_init            = chash_server_init;
+       p->lbprm.server_deinit          = chash_server_deinit;
        p->lbprm.server_take_conn = NULL;
        p->lbprm.server_drop_conn = NULL;
 
@@ -588,17 +615,11 @@
                srv->lb_tree = (srv->flags & SRV_F_BACKUP) ? 
&p->lbprm.chash.bck : &p->lbprm.chash.act;
                srv->lb_nodes_tot = srv->uweight * BE_WEIGHT_SCALE;
                srv->lb_nodes_now = 0;
-               srv->lb_nodes = calloc(srv->lb_nodes_tot,
-                                      sizeof(*srv->lb_nodes));
-               if (!srv->lb_nodes) {
+
+               if (chash_server_init(srv) < 0) {
                        ha_alert("failed to allocate lb_nodes for server 
%s.\n", srv->id);
                        return -1;
                }
-               srv->lb_server_key = chash_compute_server_key(srv);
-               for (node = 0; node < srv->lb_nodes_tot; node++) {
-                       srv->lb_nodes[node].server = srv;
-                       srv->lb_nodes[node].node.key = 
chash_compute_node_key(srv, node);
-               }
 
                if (srv_currently_usable(srv))
                        chash_queue_dequeue_srv(srv);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/pool.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/pool.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/pool.c 2026-01-30 09:56:50.000000000 
+0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/pool.c 2026-02-12 14:25:57.000000000 
+0100
@@ -794,7 +794,8 @@
        if (unlikely(pool_cache_bytes > global.tune.pool_cache_size * 3 / 4)) {
                uint64_t mem_wait_start = 0;
 
-               if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING))
+               if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
+                            (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
                        mem_wait_start = now_mono_time();
 
                if (ph->count >= 16 + pool_cache_count / 8 + 
CONFIG_HAP_POOL_CLUSTER_SIZE)
@@ -957,7 +958,8 @@
        uint64_t mem_wait_start = 0;
        int isolated = thread_isolated();
 
-       if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING))
+       if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
+                    (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
                mem_wait_start = now_mono_time();
 
        if (!isolated)
@@ -1019,7 +1021,8 @@
                /* count allocation time only for cache misses */
                uint64_t mem_wait_start = 0;
 
-               if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING))
+               if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
+                            (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
                        mem_wait_start = now_mono_time();
 
                p = pool_alloc_nocache(pool, caller);
@@ -1097,7 +1100,8 @@
                     global.tune.pool_cache_size < pool->size)) {
                uint64_t mem_wait_start = 0;
 
-               if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING))
+               if (unlikely((th_ctx->flags & 
(TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)) ==
+                            (TH_FL_TASK_PROFILING|TH_FL_TASK_PROFILING_M)))
                        mem_wait_start = now_mono_time();
 
                pool_free_nocache(pool, ptr);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_frame.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/quic_frame.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_frame.c   2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_frame.c   2026-02-12 
14:25:57.000000000 +0100
@@ -1166,7 +1166,12 @@
                goto leave;
        }
 
-       quic_dec_int(&frm->type, pos, end);
+       if (!quic_dec_int(&frm->type, pos, end)) {
+               TRACE_ERROR("malformed frame type", QUIC_EV_CONN_PRSFRM, qc);
+               quic_set_connection_close(qc, 
quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR));
+               goto leave;
+       }
+
        if (!quic_frame_type_is_known(frm->type)) {
                /* RFC 9000 12.4. Frames and Frame Types
                 *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_rx.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/quic_rx.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_rx.c      2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_rx.c      2026-02-12 
14:25:57.000000000 +0100
@@ -1155,7 +1155,17 @@
        if (frm)
                qc_frm_free(qc, &frm);
 
-       if (fast_retrans && qc->iel && qc->hel) {
+       /* RFC 9002 6.2.3. Speeding up Handshake Completion
+        *
+        * To speed up handshake completion under these conditions, an endpoint
+        * MAY, for a limited number of times per connection, send a packet
+        * containing unacknowledged CRYPTO data earlier than the PTO expiry,
+        * subject to the address validation limits in Section 8.1 of [QUIC-
+        * TRANSPORT]. Doing so at most once for each connection is adequate to
+        * quickly recover from a single packet loss.
+        */
+       if (fast_retrans && !(qc->flags & QUIC_FL_CONN_HANDSHAKE_SPEED_UP) &&
+           qc->iel && qc->hel) {
                struct quic_enc_level *iqel = qc->iel;
                struct quic_enc_level *hqel = qc->hel;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/quic_token.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/quic_token.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/quic_token.c   2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/quic_token.c   2026-02-12 
14:25:57.000000000 +0100
@@ -129,6 +129,11 @@
                goto err;
        }
 
+       if (tokenlen != QUIC_TOKEN_LEN) {
+               TRACE_ERROR("invalid token length", QUIC_EV_CONN_LPKT, qc);
+               goto err;
+       }
+
        /* Generate the AAD. */
        aadlen = ipaddrcpy(aad, &dgram->saddr);
        rand = token + tokenlen - QUIC_TOKEN_RAND_DLEN;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/server.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/server.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/server.c       2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/server.c       2026-02-12 
14:25:57.000000000 +0100
@@ -3186,7 +3186,6 @@
        free(srv->cc_algo);
        free(srv->tcp_md5sig);
        free(srv->addr_key);
-       free(srv->lb_nodes);
        counters_be_shared_drop(&srv->counters.shared);
        if (srv->log_target) {
                deinit_log_target(srv->log_target);
@@ -5891,25 +5890,13 @@
  */
 static int srv_alloc_lb(struct server *sv, struct proxy *be)
 {
-       int node;
-
        sv->lb_tree = (sv->flags & SRV_F_BACKUP) ?
                      &be->lbprm.chash.bck : &be->lbprm.chash.act;
        sv->lb_nodes_tot = sv->uweight * BE_WEIGHT_SCALE;
        sv->lb_nodes_now = 0;
 
-       if (((be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_RR | 
BE_LB_RR_RANDOM)) ||
-           ((be->lbprm.algo & (BE_LB_KIND | BE_LB_HASH_TYPE)) == 
(BE_LB_KIND_HI | BE_LB_HASH_CONS))) {
-               sv->lb_nodes = calloc(sv->lb_nodes_tot, sizeof(*sv->lb_nodes));
-
-               if (!sv->lb_nodes)
-                       return 0;
-
-               for (node = 0; node < sv->lb_nodes_tot; node++) {
-                       sv->lb_nodes[node].server = sv;
-                       sv->lb_nodes[node].node.key = full_hash(sv->puid * 
SRV_EWGHT_RANGE + node);
-               }
-       }
+       if (be->lbprm.server_init && be->lbprm.server_init(sv) < 0)
+               return 0; // typically out of memory
 
        return 1;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/ssl_ckch.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/ssl_ckch.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/ssl_ckch.c     2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/ssl_ckch.c     2026-02-12 
14:25:57.000000000 +0100
@@ -1488,6 +1488,25 @@
 }
 
 /*
+ * return the default verify cert directory.
+ *
+ * It might provided by the SSL library or set in an environment variable
+ *  (commonly SSL_CERT_DIR)
+ */
+const char *ha_default_cert_dir()
+{
+        const char *dir = NULL;
+        const char *certdir_varname = X509_get_default_cert_dir_env();
+
+        if (certdir_varname)
+                dir = getenv(certdir_varname);
+        if (dir == NULL)
+                dir = X509_get_default_cert_dir();
+
+        return dir;
+}
+
+/*
  * Try to load a ca-file from disk into the ca-file cache.
  *  <shuterror> allows you to to stop emitting the errors.
  *  Return 0 upon error
@@ -1516,7 +1535,7 @@
                }
 
                if (strcmp(path, "@system-ca") == 0) {
-                       dir = X509_get_default_cert_dir();
+                       dir = ha_default_cert_dir();
                        if (!dir) {
                                if (!shuterror)
                                        ha_alert("Couldn't get the system CA 
directory from X509_get_default_cert_dir().\n");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-3.3.2+git3.bc0fb5969/src/tools.c 
new/haproxy-3.3.3+git0.465d8e2fc/src/tools.c
--- old/haproxy-3.3.2+git3.bc0fb5969/src/tools.c        2026-01-30 
09:56:50.000000000 +0100
+++ new/haproxy-3.3.3+git0.465d8e2fc/src/tools.c        2026-02-12 
14:25:57.000000000 +0100
@@ -987,6 +987,11 @@
        int new_fd = -1;
        enum proto_type proto_type = 0; // to shut gcc warning
        int ctrl_type = 0; // to shut gcc warning
+       /*
+        * Indicates that we want to use an alternate protocol instead of the
+        * default one.
+        * Currently, only MPTCP is defined as an alternate protocol for TCP
+        */
        int alt_proto = 0;
 
        portl = porth = porta = 0;
@@ -1011,7 +1016,6 @@
            ((opts & (PA_O_STREAM|PA_O_DGRAM)) == (PA_O_DGRAM|PA_O_STREAM) && 
(opts & PA_O_DEFAULT_DGRAM))) {
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        } else {
                proto_type = PROTO_TYPE_STREAM;
                ctrl_type = SOCK_STREAM;
@@ -1026,7 +1030,6 @@
                str2 += 6;
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        }
        else if (strncmp(str2, "quic+", 5) == 0) {
                str2 += 5;
@@ -1043,7 +1046,6 @@
                ss.ss_family = AF_UNIX;
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        }
        else if (strncmp(str2, "uxst@", 5) == 0) {
                str2 += 5;
@@ -1089,7 +1091,6 @@
                ss.ss_family = AF_INET;
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        }
        else if (strncmp(str2, "tcp6@", 5) == 0) {
                str2 += 5;
@@ -1109,7 +1110,6 @@
                ss.ss_family = AF_INET6;
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        }
        else if (strncmp(str2, "tcp@", 4) == 0) {
                str2 += 4;
@@ -1129,7 +1129,6 @@
                ss.ss_family = AF_UNSPEC;
                proto_type = PROTO_TYPE_DGRAM;
                ctrl_type = SOCK_DGRAM;
-               alt_proto = 1;
        }
        else if (strncmp(str2, "quic4@", 6) == 0) {
                str2 += 6;
@@ -1399,6 +1398,8 @@
        }
 
        if (proto || (opts & PA_O_CONNECT)) {
+               // if the socket type is SOCK_DGRAM, use by default an 
alternate protocol
+               alt_proto = alt_proto || (ctrl_type == SOCK_DGRAM);
                /* Note: if the caller asks for a proto, we must find one,
                 * except if we inherit from a raw FD (family == 
AF_CUST_EXISTING_FD)
                 * orif we return with an fqdn that will resolve later,

Reply via email to